211 {
212 int iArg, j;
213 char *freqUnits;
214 char *indepQuantity, **depenQuantity, **exclude, **realQuan = NULL, **imagQuan = NULL;
215 long depenQuantities, excludes;
216 char *input, *output;
217 long sampleInterval, readCode, noWarnings, complexInput, inverse, spectrumFoldParExist = 0, colsToUse;
218 int64_t i, rows, rowsToUse, primeRows, pow2Rows, n_freq, fftrows;
219 int32_t spectrumFolded = 0, page = 0, index;
220 unsigned long flags, pipeFlags, complexInputFlags = 0, fullOutputFlags = 0, majorOrderFlag;
221 long primeCols, pow2Cols;
222 SCANNED_ARG *scanned;
224 double *tdata, rintegCutOffFreq, unwrapLimit = 0;
225 long padFactor;
226 short columnMajorOrder = -1;
227 int threads = 1;
228 double length, *real_imag = NULL, **real = NULL, **imag = NULL, *real_imag1 = NULL, *fdata = NULL, df, t0, factor;
229 double dtf_real, dtf_imag, *arg = NULL, *magData = NULL;
230 char str[256], *tempStr = NULL;
231
233 argc =
scanargs(&scanned, argc, argv);
234 if (argc < 3 || argc > (3 + N_OPTIONS)) {
235 fprintf(stderr, "%s%s", USAGE1, USAGE2);
236 exit(EXIT_FAILURE);
237 }
238 rintegCutOffFreq = 0;
239 output = input = NULL;
240 flags = pipeFlags = excludes = complexInput = inverse = 0;
241 sampleInterval = 1;
242 indepQuantity = NULL;
243 depenQuantity = exclude = NULL;
244 depenQuantities = 0;
245 noWarnings = 0;
246 padFactor = 0;
247
248 for (iArg = 1; iArg < argc; iArg++) {
249 if (scanned[iArg].arg_type == OPTION) {
250
251 switch (
match_string(scanned[iArg].list[0], option, N_OPTIONS, 0)) {
252 case SET_NORMALIZE:
253 flags |= FL_NORMALIZE;
254 break;
255 case SET_PADWITHZEROES:
256 flags |= FL_PADWITHZEROES;
257 if (scanned[iArg].n_items != 1) {
258 if (scanned[iArg].n_items != 2 || sscanf(scanned[iArg].list[1], "%ld", &padFactor) != 1 || padFactor < 1)
259 SDDS_Bomb(
"invalid -padwithzeroes syntax");
260 }
261 break;
262 case SET_TRUNCATE:
263 flags |= FL_TRUNCATE;
264 break;
265 case SET_SUPPRESSAVERAGE:
266 flags |= FL_SUPPRESSAVERAGE;
267 break;
268 case SET_SAMPLEINTERVAL:
269 if (scanned[iArg].n_items != 2 || sscanf(scanned[iArg].list[1], "%ld", &sampleInterval) != 1 || sampleInterval <= 0)
270 SDDS_Bomb(
"invalid -sampleinterval syntax");
271 break;
272 case SET_COLUMNS:
273 if (indepQuantity)
274 SDDS_Bomb(
"only one -columns option may be given");
275 if (scanned[iArg].n_items < 2)
277 indepQuantity = scanned[iArg].list[1];
278 if (scanned[iArg].n_items >= 2) {
279 depenQuantity =
tmalloc(
sizeof(*depenQuantity) * (depenQuantities = scanned[iArg].n_items - 2));
280 for (i = 0; i < depenQuantities; i++)
282 }
283 break;
284 case SET_FULLOUTPUT:
285 flags |= FL_FULLOUTPUT;
286 if (scanned[iArg].n_items >= 2) {
287 scanned[iArg].n_items--;
288 if (!
scanItemList(&fullOutputFlags, scanned[iArg].list + 1, &scanned[iArg].n_items, 0,
"folded", -1, NULL, 0, FL_FULLOUTPUT_FOLDED,
"unfolded", -1, NULL, 0, FL_FULLOUTPUT_UNFOLDED,
"unwrapLimit",
SDDS_DOUBLE, &unwrapLimit, 0, FL_UNWRAP_PHASE, NULL))
290 scanned[iArg].n_items++;
291 if (fullOutputFlags & FL_FULLOUTPUT_UNFOLDED)
292 flags |= FL_FULLOUTPUT_UNFOLDED;
293 else
294 flags |= FL_FULLOUTPUT_FOLDED;
295 if (fullOutputFlags & FL_UNWRAP_PHASE)
296 flags |= FL_UNWRAP_PHASE;
297 }
298 break;
299 case SET_PIPE:
300 if (!
processPipeOption(scanned[iArg].list + 1, scanned[iArg].n_items - 1, &pipeFlags))
302 break;
303 case SET_PSDOUTPUT:
304 if (scanned[iArg].n_items > 1) {
305 unsigned long tmpFlags;
306 if (strchr(scanned[iArg].list[1], '=') == NULL) {
307 if (!
scanItemList(&tmpFlags, scanned[iArg].list + 1, &scanned[iArg].n_items, 0,
"integrated", -1, NULL, 0, FL_PSDINTEGOUTPUT,
"rintegrated", -1, NULL, 0, FL_PSDRINTEGOUTPUT,
"plain", -1, NULL, 0, FL_PSDOUTPUT, NULL))
309 } else {
310 if (!
scanItemList(&tmpFlags, scanned[iArg].list + 1, &scanned[iArg].n_items, 0,
"integrated", -1, NULL, 0, FL_PSDINTEGOUTPUT,
"rintegrated",
SDDS_DOUBLE, &rintegCutOffFreq, 0, FL_PSDRINTEGOUTPUT,
"plain", -1, NULL, 0, FL_PSDOUTPUT, NULL))
312 }
313 flags |= tmpFlags;
314 } else {
315 flags |= FL_PSDOUTPUT;
316 }
317 if ((flags & FL_PSDINTEGOUTPUT) && (flags & FL_PSDRINTEGOUTPUT))
318 SDDS_Bomb(
"invalid -psdOutput syntax: give only one of integrated or rintegrated");
319 break;
320 case SET_EXCLUDE:
321 if (scanned[iArg].n_items < 2)
323 for (j = 1; j < scanned[iArg].n_items; j++)
324 excludes = appendToStringArray(&exclude, excludes, scanned[iArg].list[j]);
325 break;
326 case SET_NOWARNINGS:
327 noWarnings = 1;
328 break;
329 case SET_COMPLEXINPUT:
330 complexInput = 1;
331 if (scanned[iArg].n_items == 2) {
332 scanned[iArg].n_items--;
333 if (!
scanItemList(&complexInputFlags, scanned[iArg].list + 1, &scanned[iArg].n_items, 0,
"folded", -1, NULL, 0, FL_COMPLEXINPUT_FOLDED,
"unfolded", -1, NULL, 0, FL_COMPLEXINPUT_UNFOLDED, NULL))
334 SDDS_Bomb(
"Invalid -complexInput syntax");
335 scanned[iArg].n_items++;
336 }
337 break;
338 case SET_INVERSE:
339 inverse = 1;
340 break;
341 case SET_MAJOR_ORDER:
342 majorOrderFlag = 0;
343 scanned[iArg].n_items--;
344 if (scanned[iArg].n_items > 0 && (!
scanItemList(&majorOrderFlag, scanned[iArg].list + 1, &scanned[iArg].n_items, 0,
"row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
"column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL)))
345 SDDS_Bomb(
"invalid -majorOrder syntax/values");
346 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
347 columnMajorOrder = 1;
348 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
349 columnMajorOrder = 0;
350 break;
351 case SET_THREADS:
352 if (scanned[iArg].n_items != 2 ||
353 sscanf(scanned[iArg].list[1], "%d", &threads) != 1 || threads < 1)
355 break;
356 default:
357 fprintf(stderr, "error: unknown/ambiguous option: %s\n", scanned[iArg].list[0]);
358 exit(EXIT_FAILURE);
359 break;
360 }
361 } else {
362 if (!input)
363 input = scanned[iArg].list[0];
364 else if (!output)
365 output = scanned[iArg].list[0];
366 else
368 }
369 }
370 if (!complexInput) {
371 if (!noWarnings && inverse)
372 fprintf(stderr, "Warning: The inverse option is ignored since it only works with -complexInput.\n");
373 inverse = 0;
374 }
375 if (!noWarnings && inverse && (flags & FL_FULLOUTPUT_FOLDED))
376 fprintf(stderr, "Warning: The combination of -inverse and -fullOutput=folded will be changed to -inverse -fullOutput=unfolded.\n");
377
379
380 if (!indepQuantity)
381 SDDS_Bomb(
"Supply the independent quantity name with the -columns option");
382
383 if ((flags & FL_TRUNCATE) && (flags & FL_PADWITHZEROES))
384 SDDS_Bomb(
"Specify only one of -padwithzeroes and -truncate");
385 if (!inverse) {
386
387 flags |= FL_FULLOUTPUT;
388 flags |= FL_FULLOUTPUT_UNFOLDED;
389 }
392
394 exit(EXIT_FAILURE);
395
396 excludes = appendToStringArray(&exclude, excludes, indepQuantity);
397 if (!depenQuantities)
398 depenQuantities = appendToStringArray(&depenQuantity, depenQuantities, "*");
399
400 if (!complexInput) {
401 if ((depenQuantities = expandColumnPairNames(&SDDSin, &depenQuantity, NULL, depenQuantities, exclude, excludes, FIND_NUMERIC_TYPE, 0)) <= 0) {
403 SDDS_Bomb(
"No quantities selected to FFT");
404 }
405 } else {
406 if ((depenQuantities = expandComplexColumnPairNames(&SDDSin, depenQuantity, &realQuan, &imagQuan, depenQuantities, exclude, excludes, FIND_NUMERIC_TYPE, 0)) <= 0) {
408 SDDS_Bomb(
"No quantities selected to FFT");
409 }
410 }
411
412#if 0
413 fprintf(stderr, "%ld dependent quantities:\n", depenQuantities);
414 for (i = 0; i < depenQuantities; i++)
415 fprintf(stderr, " %s\n", depenQuantity[i]);
416#endif
417
418 if (!(freqUnits = makeFrequencyUnits(&SDDSin, indepQuantity)) ||
420 !create_fft_frequency_column(&SDDSout, &SDDSin, indepQuantity, freqUnits, inverse) ||
424 if (columnMajorOrder != -1)
425 SDDSout.layout.data_mode.column_major = columnMajorOrder;
426 else
427 SDDSout.layout.data_mode.column_major = SDDSin.layout.data_mode.column_major;
428
431 if (complexInput) {
432 if (!complexInputFlags) {
434 spectrumFoldParExist = 1;
435 } else if (complexInputFlags & FL_COMPLEXINPUT_UNFOLDED)
436 flags |= FL_COMPLEXINPUT_UNFOLDED;
437 else
438 flags |= FL_COMPLEXINPUT_FOLDED;
439 }
440 for (i = 0; i < depenQuantities; i++) {
441 if (!complexInput)
442 create_fft_columns(&SDDSout, &SDDSin, depenQuantity[i], indepQuantity, freqUnits,
443 flags & FL_FULLOUTPUT, flags & (FL_PSDOUTPUT + FL_PSDINTEGOUTPUT + FL_PSDRINTEGOUTPUT),
444 0, inverse, flags & FL_UNWRAP_PHASE);
445 else
446 create_fft_columns(&SDDSout, &SDDSin, realQuan[i], indepQuantity, freqUnits,
447 flags & FL_FULLOUTPUT, flags & (FL_PSDOUTPUT + FL_PSDINTEGOUTPUT + FL_PSDRINTEGOUTPUT),
448 1, inverse, flags & FL_UNWRAP_PHASE);
449 }
450
453
454 colsToUse = depenQuantities;
455 primeCols = greatestProductOfSmallPrimes(depenQuantities);
456 if (depenQuantities != primeCols || padFactor) {
457 if (flags & FL_PADWITHZEROES) {
458 pow2Cols =
ipow(2., ((
long)(log((
double)depenQuantities) / log(2.0F))) + (padFactor ? padFactor : 1));
459 if ((primeCols = greatestProductOfSmallPrimes(pow2Cols)) > depenQuantities)
460 colsToUse = primeCols;
461 else
462 colsToUse = pow2Cols;
463 fprintf(stdout, "Using %ld columns\n", colsToUse);
464 } else if (flags & FL_TRUNCATE)
465 colsToUse = greatestProductOfSmallPrimes(depenQuantities);
467 fputs("Warning: Number of dependent columns has large prime factors.\nThis could take a very long time.\nConsider using the -truncate option.\n", stderr);
468 }
469 real_imag =
tmalloc(
sizeof(*real_imag) * (2 * colsToUse + 2));
470 real = malloc(sizeof(*real) * colsToUse);
471 imag = malloc(sizeof(*imag) * colsToUse);
472
474 page++;
477 if (page == 1 && spectrumFoldParExist) {
480 if (spectrumFolded)
481 flags |= FL_COMPLEXINPUT_FOLDED;
482 else
483 flags |= FL_COMPLEXINPUT_UNFOLDED;
484 }
485 if (rows) {
486 rowsToUse = rows;
487 primeRows = greatestProductOfSmallPrimes(rows);
488 if (rows != primeRows || padFactor) {
489 if (flags & FL_PADWITHZEROES) {
490 pow2Rows =
ipow(2., ((
long)(log((
double)rows) / log(2.0F))) + (padFactor ? padFactor : 1));
491 if ((primeRows = greatestProductOfSmallPrimes(pow2Rows)) > rows)
492 rowsToUse = primeRows;
493 else
494 rowsToUse = pow2Rows;
495 fprintf(stdout, "Using %" PRId64 " rows\n", rowsToUse);
496 } else if (flags & FL_TRUNCATE)
497 rowsToUse = greatestProductOfSmallPrimes(rows);
499 fputs("Warning: Number of points has large prime factors.\nThis could take a very long time.\nConsider using the -truncate option.\n", stderr);
500 }
503
504 for (j = 0; j < colsToUse; j++) {
505 real[j] = imag[j] = NULL;
506 if (j < depenQuantities) {
507 if (complexInput) {
511 } else {
514 imag[j] = calloc(sizeof(**imag), rowsToUse);
515 }
516 if (rows < rowsToUse) {
517 real[j] =
SDDS_Realloc(real[j],
sizeof(**real) * rowsToUse);
518 imag[j] =
SDDS_Realloc(imag[j],
sizeof(**imag) * rowsToUse);
519 }
520 } else {
521 real[j] = calloc(sizeof(**real), rowsToUse);
522 imag[j] = calloc(sizeof(**imag), rowsToUse);
523 }
524 }
525 fdata = malloc(sizeof(*fdata) * rowsToUse);
526 if (rows < rowsToUse) {
527 length = ((double)rows) * (tdata[rows - 1] - tdata[0]) / ((double)rows - 1.0);
528 } else
529 length = tdata[rows - 1] - tdata[0];
530 t0 = tdata[0];
531 df = factor = 1.0 / length;
532 free(tdata);
533 for (i = 0; i < rows; i++)
534 fdata[i] = i * df;
535 for (i = rows; i < rowsToUse; i++) {
536 fdata[i] = i * df;
537 }
538
539 if (threads <= 1) {
540 for (i = 0; i < rows; i++) {
541 for (j = 0; j < colsToUse; j++) {
542 real_imag[2 * j] = real_imag[2 * j + 1] = 0;
543 if (j < depenQuantities) {
544 real_imag[2 * j] = real[j][i];
545 if (imag[j])
546 real_imag[2 * j + 1] = imag[j][i];
547 else
548 real_imag[2 * j + 1] = 0;
549 }
550 }
551 complexFFT(real_imag, colsToUse, inverse);
552 for (j = 0; j < colsToUse; j++) {
553 real[j][i] = real_imag[2 * j];
554 imag[j][i] = real_imag[2 * j + 1];
555 }
556 }
557 } else {
558#pragma omp parallel if (threads > 1) num_threads(threads)
559 {
560 double *real_imag_thread =
tmalloc(
sizeof(*real_imag_thread) * (2 * colsToUse + 2));
561 int64_t row;
562#pragma omp for private(j)
563 for (row = 0; row < rows; row++) {
564 for (j = 0; j < colsToUse; j++) {
565 real_imag_thread[2 * j] = real_imag_thread[2 * j + 1] = 0;
566 if (j < depenQuantities) {
567 real_imag_thread[2 * j] = real[j][row];
568 if (imag[j])
569 real_imag_thread[2 * j + 1] = imag[j][row];
570 else
571 real_imag_thread[2 * j + 1] = 0;
572 }
573 }
574 complexFFT(real_imag_thread, colsToUse, inverse);
575 for (j = 0; j < colsToUse; j++) {
576 real[j][row] = real_imag_thread[2 * j];
577 imag[j][row] = real_imag_thread[2 * j + 1];
578 }
579 }
580 free(real_imag_thread);
581 }
582 }
583
584 n_freq = rowsToUse;
585 fftrows = rowsToUse;
586 arg = malloc(sizeof(*arg) * rowsToUse);
587 magData = malloc(sizeof(*magData) * rowsToUse);
588 real_imag1 = calloc(sizeof(*real_imag1), 2 * fftrows + 2);
589
590 for (j = 0; j < depenQuantities; j++) {
591 for (i = 0; i < rowsToUse; i++) {
592 if (i < rows) {
593 real_imag1[2 * i] = real[j][i];
594 real_imag1[2 * i + 1] = imag[j][i];
595 } else {
596 real_imag1[2 * i] = 0;
597 real_imag1[2 * i + 1] = 0;
598 }
599 }
600 complexFFT(real_imag1, rowsToUse, inverse);
601 for (i = 0; i < n_freq; i++) {
602 dtf_real = cos(-2 * PI * fdata[i] * t0);
603 dtf_imag = sin(-2 * PI * fdata[i] * t0);
604 real[j][i] = real_imag1[2 * i] * dtf_real - real_imag1[2 * i + 1] * dtf_imag;
605 imag[j][i] = real_imag1[2 * i + 1] * dtf_real + real_imag1[2 * i] * dtf_imag;
606 magData[i] = sqrt(sqr(real[j][i]) + sqr(imag[j][i]));
607 if (real[j][i] || imag[j][i])
608 arg[i] = 180.0 / PI * atan2(imag[j][i], real[j][i]);
609 else
610 arg[i] = 0;
611 }
612 if (flags & FL_NORMALIZE) {
613 factor = -DBL_MAX;
614 for (i = 0; i < n_freq; i++)
615 if (magData[i] > factor)
616 factor = magData[i];
617 if (factor != -DBL_MAX)
618 for (i = 0; i < n_freq; i++) {
619 real[j][i] /= factor;
620 imag[j][i] /= factor;
621 magData[i] /= factor;
622 }
623 }
624 if (!inverse)
625 sprintf(str, "FFT%s", depenQuantity[j] + (imagQuan ? 4 : 0));
626 else {
627 if (complexInput)
628 tempStr = realQuan[j];
629 else
630 tempStr = depenQuantity[j];
631
632 if (strncmp(tempStr, "FFT", 3) == 0)
633 sprintf(str, "%s", tempStr + 3);
634 else if (strncmp(tempStr, "RealFFT", 7) == 0)
635 sprintf(str, "%s", tempStr + 7);
636 else
637 sprintf(str, "%s", tempStr);
638 }
640 exit(EXIT_FAILURE);
643 !
SDDS_SetParameters(&SDDSout, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE,
"fftFrequencies", n_freq,
"fftFrequencySpacing", df, NULL))
645 if (flags & FL_FULLOUTPUT) {
646 if (!
SDDS_SetColumn(&SDDSout, SDDS_SET_BY_INDEX, magData, n_freq, index) ||
647 !
SDDS_SetColumn(&SDDSout, SDDS_SET_BY_INDEX, real[j], n_freq, index + 1) ||
648 !
SDDS_SetColumn(&SDDSout, SDDS_SET_BY_INDEX, imag[j], n_freq, index + 2) ||
649 !
SDDS_SetColumn(&SDDSout, SDDS_SET_BY_INDEX, arg, n_freq, index + 3))
651 } else {
652 if (!
SDDS_SetColumn(&SDDSout, SDDS_SET_BY_INDEX, real[j], n_freq, index))
654 }
655 }
656 if (!
SDDS_SetColumn(&SDDSout, SDDS_SET_BY_INDEX, fdata, n_freq, 0))
658 free(fdata);
659 free(arg);
660 free(magData);
661 for (j = 0; j < colsToUse; j++) {
662 if (real[j])
663 free(real[j]);
664 if (imag[j])
665 free(imag[j]);
666 }
667 free(real_imag1);
668 } else {
671 }
674 }
677 exit(EXIT_FAILURE);
678 }
681 exit(EXIT_FAILURE);
682 }
683 if (excludes) {
685 free(exclude);
686 }
687 free(real);
688 free(imag);
689 if (realQuan) {
692 free(realQuan);
693 free(imagQuan);
694 } else {
696 free(depenQuantity);
697 }
698 free(real_imag);
700 return EXIT_SUCCESS;
701}
int32_t SDDS_CopyParameters(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source)
int32_t SDDS_StartPage(SDDS_DATASET *SDDS_dataset, int64_t expected_n_rows)
int32_t SDDS_SetParameters(SDDS_DATASET *SDDS_dataset, int32_t mode,...)
int32_t SDDS_SetColumn(SDDS_DATASET *SDDS_dataset, int32_t mode, void *data, int64_t rows,...)
Sets the values for one data column in the current data table of an SDDS dataset.
int32_t SDDS_InitializeOutput(SDDS_DATASET *SDDS_dataset, int32_t data_mode, int32_t lines_per_row, const char *description, const char *contents, const char *filename)
Initializes the SDDS output dataset.
int32_t SDDS_WritePage(SDDS_DATASET *SDDS_dataset)
Writes the current data table to the output file.
int32_t SDDS_WriteLayout(SDDS_DATASET *SDDS_dataset)
Writes the SDDS layout header to the output file.
int32_t SDDS_DefineParameter(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, char *fixed_value)
Defines a data parameter with a fixed string value.
int32_t SDDS_TransferAllParameterDefinitions(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source, uint32_t mode)
Transfers all parameter definitions from a source dataset to a target dataset.
int32_t SDDS_FreeStringArray(char **string, int64_t strings)
Frees an array of strings by deallocating each individual string.
int32_t SDDS_GetColumnIndex(SDDS_DATASET *SDDS_dataset, char *name)
Retrieves the index of a named column in the SDDS dataset.
int32_t SDDS_CheckColumn(SDDS_DATASET *SDDS_dataset, char *name, char *units, int32_t type, FILE *fp_message)
Checks if a column exists in the SDDS dataset with the specified name, units, and type.
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
int32_t SDDS_CheckParameter(SDDS_DATASET *SDDS_dataset, char *name, char *units, int32_t type, FILE *fp_message)
Checks if a parameter exists in the SDDS dataset with the specified name, units, and type.
void * SDDS_Realloc(void *old_ptr, size_t new_size)
Reallocates memory to a new size.
#define SDDS_LONG
Identifier for the signed 32-bit integer data type.
#define SDDS_ANY_NUMERIC_TYPE
Special identifier used by SDDS_Check*() routines to accept any numeric type.
void * tmalloc(uint64_t size_of_block)
Allocates a memory block of the specified size with zero initialization.
int64_t largest_prime_factor(int64_t number)
Find the largest prime factor of a number.
double ipow(const double x, const int64_t p)
Compute x raised to the power p (x^p).
long match_string(char *string, char **option, long n_options, long mode)
Matches a given string against an array of option strings based on specified modes.
int scanargs(SCANNED_ARG **scanned, int argc, char **argv)
long processPipeOption(char **item, long items, unsigned long *flags)
void processFilenames(char *programName, char **input, char **output, unsigned long pipeFlags, long noWarnings, long *tmpOutputUsed)
void free_scanargs(SCANNED_ARG **scanned, int argc)
long scanItemList(unsigned long *flags, char **item, long *items, unsigned long mode,...)
Scans a list of items and assigns values based on provided keywords and types.