204 {
205 int iArg, j;
206 char *freqUnits;
207 char *indepQuantity, **depenQuantity, **exclude, **realQuan = NULL, **imagQuan = NULL;
208 long depenQuantities, excludes;
209 char *input, *output;
210 long sampleInterval, readCode, noWarnings, complexInput, inverse, spectrumFoldParExist = 0, colsToUse;
211 int64_t i, rows, rowsToUse, primeRows, pow2Rows, n_freq, fftrows;
212 int32_t spectrumFolded = 0, page = 0, index;
213 unsigned long flags, pipeFlags, complexInputFlags = 0, fullOutputFlags = 0, majorOrderFlag;
214 long primeCols, pow2Cols;
215 SCANNED_ARG *scanned;
217 double *tdata, rintegCutOffFreq, unwrapLimit = 0;
218 long padFactor;
219 short columnMajorOrder = -1;
220 double length, *real_imag = NULL, **real = NULL, **imag = NULL, *real_imag1 = NULL, *fdata = NULL, df, t0, factor;
221 double dtf_real, dtf_imag, *arg = NULL, *magData = NULL;
222 char str[256], *tempStr = NULL;
223
225 argc =
scanargs(&scanned, argc, argv);
226 if (argc < 3 || argc > (3 + N_OPTIONS)) {
227 fprintf(stderr, "%s%s", USAGE1, USAGE2);
228 exit(EXIT_FAILURE);
229 }
230 rintegCutOffFreq = 0;
231 output = input = NULL;
232 flags = pipeFlags = excludes = complexInput = inverse = 0;
233 sampleInterval = 1;
234 indepQuantity = NULL;
235 depenQuantity = exclude = NULL;
236 depenQuantities = 0;
237 noWarnings = 0;
238 padFactor = 0;
239
240 for (iArg = 1; iArg < argc; iArg++) {
241 if (scanned[iArg].arg_type == OPTION) {
242
243 switch (
match_string(scanned[iArg].list[0], option, N_OPTIONS, 0)) {
244 case SET_NORMALIZE:
245 flags |= FL_NORMALIZE;
246 break;
247 case SET_PADWITHZEROES:
248 flags |= FL_PADWITHZEROES;
249 if (scanned[iArg].n_items != 1) {
250 if (scanned[iArg].n_items != 2 || sscanf(scanned[iArg].list[1], "%ld", &padFactor) != 1 || padFactor < 1)
251 SDDS_Bomb(
"invalid -padwithzeroes syntax");
252 }
253 break;
254 case SET_TRUNCATE:
255 flags |= FL_TRUNCATE;
256 break;
257 case SET_SUPPRESSAVERAGE:
258 flags |= FL_SUPPRESSAVERAGE;
259 break;
260 case SET_SAMPLEINTERVAL:
261 if (scanned[iArg].n_items != 2 || sscanf(scanned[iArg].list[1], "%ld", &sampleInterval) != 1 || sampleInterval <= 0)
262 SDDS_Bomb(
"invalid -sampleinterval syntax");
263 break;
264 case SET_COLUMNS:
265 if (indepQuantity)
266 SDDS_Bomb(
"only one -columns option may be given");
267 if (scanned[iArg].n_items < 2)
269 indepQuantity = scanned[iArg].list[1];
270 if (scanned[iArg].n_items >= 2) {
271 depenQuantity =
tmalloc(
sizeof(*depenQuantity) * (depenQuantities = scanned[iArg].n_items - 2));
272 for (i = 0; i < depenQuantities; i++)
274 }
275 break;
276 case SET_FULLOUTPUT:
277 flags |= FL_FULLOUTPUT;
278 if (scanned[iArg].n_items >= 2) {
279 scanned[iArg].n_items--;
280 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))
282 scanned[iArg].n_items++;
283 if (fullOutputFlags & FL_FULLOUTPUT_UNFOLDED)
284 flags |= FL_FULLOUTPUT_UNFOLDED;
285 else
286 flags |= FL_FULLOUTPUT_FOLDED;
287 if (fullOutputFlags & FL_UNWRAP_PHASE)
288 flags |= FL_UNWRAP_PHASE;
289 }
290 break;
291 case SET_PIPE:
292 if (!
processPipeOption(scanned[iArg].list + 1, scanned[iArg].n_items - 1, &pipeFlags))
294 break;
295 case SET_PSDOUTPUT:
296 if (scanned[iArg].n_items > 1) {
297 unsigned long tmpFlags;
298 if (strchr(scanned[iArg].list[1], '=') == NULL) {
299 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))
301 } else {
302 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))
304 }
305 flags |= tmpFlags;
306 } else {
307 flags |= FL_PSDOUTPUT;
308 }
309 if ((flags & FL_PSDINTEGOUTPUT) && (flags & FL_PSDRINTEGOUTPUT))
310 SDDS_Bomb(
"invalid -psdOutput syntax: give only one of integrated or rintegrated");
311 break;
312 case SET_EXCLUDE:
313 if (scanned[iArg].n_items < 2)
315 moveToStringArray(&exclude, &excludes, scanned[iArg].list + 1, scanned[iArg].n_items - 1);
316 break;
317 case SET_NOWARNINGS:
318 noWarnings = 1;
319 break;
320 case SET_COMPLEXINPUT:
321 complexInput = 1;
322 if (scanned[iArg].n_items == 2) {
323 scanned[iArg].n_items--;
324 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))
325 SDDS_Bomb(
"Invalid -complexInput syntax");
326 scanned[iArg].n_items++;
327 }
328 break;
329 case SET_INVERSE:
330 inverse = 1;
331 break;
332 case SET_MAJOR_ORDER:
333 majorOrderFlag = 0;
334 scanned[iArg].n_items--;
335 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)))
336 SDDS_Bomb(
"invalid -majorOrder syntax/values");
337 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
338 columnMajorOrder = 1;
339 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
340 columnMajorOrder = 0;
341 break;
342 default:
343 fprintf(stderr, "error: unknown/ambiguous option: %s\n", scanned[iArg].list[0]);
344 exit(EXIT_FAILURE);
345 break;
346 }
347 } else {
348 if (!input)
349 input = scanned[iArg].list[0];
350 else if (!output)
351 output = scanned[iArg].list[0];
352 else
354 }
355 }
356 if (!complexInput) {
357 if (!noWarnings && inverse)
358 fprintf(stderr, "Warning: The inverse option is ignored since it only works with -complexInput.\n");
359 inverse = 0;
360 }
361 if (!noWarnings && inverse && (flags & FL_FULLOUTPUT_FOLDED))
362 fprintf(stderr, "Warning: The combination of -inverse and -fullOutput=folded will be changed to -inverse -fullOutput=unfolded.\n");
363
365
366 if (!indepQuantity)
367 SDDS_Bomb(
"Supply the independent quantity name with the -columns option");
368
369 if ((flags & FL_TRUNCATE) && (flags & FL_PADWITHZEROES))
370 SDDS_Bomb(
"Specify only one of -padwithzeroes and -truncate");
371 if (!inverse) {
372
373 flags |= FL_FULLOUTPUT;
374 flags |= FL_FULLOUTPUT_UNFOLDED;
375 }
378
380 exit(EXIT_FAILURE);
381
382 excludes = appendToStringArray(&exclude, excludes, indepQuantity);
383 if (!depenQuantities)
384 depenQuantities = appendToStringArray(&depenQuantity, depenQuantities, "*");
385
386 if (!complexInput) {
387 if ((depenQuantities = expandColumnPairNames(&SDDSin, &depenQuantity, NULL, depenQuantities, exclude, excludes, FIND_NUMERIC_TYPE, 0)) <= 0) {
389 SDDS_Bomb(
"No quantities selected to FFT");
390 }
391 } else {
392 if ((depenQuantities = expandComplexColumnPairNames(&SDDSin, depenQuantity, &realQuan, &imagQuan, depenQuantities, exclude, excludes, FIND_NUMERIC_TYPE, 0)) <= 0) {
394 SDDS_Bomb(
"No quantities selected to FFT");
395 }
396 }
397
398#if 0
399 fprintf(stderr, "%ld dependent quantities:\n", depenQuantities);
400 for (i = 0; i < depenQuantities; i++)
401 fprintf(stderr, " %s\n", depenQuantity[i]);
402#endif
403
404 if (!(freqUnits = makeFrequencyUnits(&SDDSin, indepQuantity)) ||
406 !create_fft_frequency_column(&SDDSout, &SDDSin, indepQuantity, freqUnits, inverse) ||
410 if (columnMajorOrder != -1)
411 SDDSout.layout.data_mode.column_major = columnMajorOrder;
412 else
413 SDDSout.layout.data_mode.column_major = SDDSin.layout.data_mode.column_major;
414
417 if (complexInput) {
418 if (!complexInputFlags) {
420 spectrumFoldParExist = 1;
421 } else if (complexInputFlags & FL_COMPLEXINPUT_UNFOLDED)
422 flags |= FL_COMPLEXINPUT_UNFOLDED;
423 else
424 flags |= FL_COMPLEXINPUT_FOLDED;
425 }
426 for (i = 0; i < depenQuantities; i++) {
427 if (!complexInput)
428 create_fft_columns(&SDDSout, &SDDSin, depenQuantity[i], indepQuantity, freqUnits,
429 flags & FL_FULLOUTPUT, flags & (FL_PSDOUTPUT + FL_PSDINTEGOUTPUT + FL_PSDRINTEGOUTPUT),
430 0, inverse, flags & FL_UNWRAP_PHASE);
431 else
432 create_fft_columns(&SDDSout, &SDDSin, realQuan[i], indepQuantity, freqUnits,
433 flags & FL_FULLOUTPUT, flags & (FL_PSDOUTPUT + FL_PSDINTEGOUTPUT + FL_PSDRINTEGOUTPUT),
434 1, inverse, flags & FL_UNWRAP_PHASE);
435 }
436
439
440 colsToUse = depenQuantities;
441 primeCols = greatestProductOfSmallPrimes(depenQuantities);
442 if (depenQuantities != primeCols || padFactor) {
443 if (flags & FL_PADWITHZEROES) {
444 pow2Cols =
ipow(2., ((
long)(log((
double)depenQuantities) / log(2.0F))) + (padFactor ? padFactor : 1));
445 if ((primeCols = greatestProductOfSmallPrimes(pow2Cols)) > depenQuantities)
446 colsToUse = primeCols;
447 else
448 colsToUse = pow2Cols;
449 fprintf(stdout, "Using %ld columns\n", colsToUse);
450 } else if (flags & FL_TRUNCATE)
451 colsToUse = greatestProductOfSmallPrimes(depenQuantities);
453 fputs("Warning: Number of dependent columns has large prime factors.\nThis could take a very long time.\nConsider using the -truncate option.\n", stderr);
454 }
455 real_imag =
tmalloc(
sizeof(*real_imag) * (2 * colsToUse + 2));
456 real = malloc(sizeof(*real) * colsToUse);
457 imag = malloc(sizeof(*imag) * colsToUse);
458
460 page++;
463 if (page == 1 && spectrumFoldParExist) {
466 if (spectrumFolded)
467 flags |= FL_COMPLEXINPUT_FOLDED;
468 else
469 flags |= FL_COMPLEXINPUT_UNFOLDED;
470 }
471 if (rows) {
472 rowsToUse = rows;
473 primeRows = greatestProductOfSmallPrimes(rows);
474 if (rows != primeRows || padFactor) {
475 if (flags & FL_PADWITHZEROES) {
476 pow2Rows =
ipow(2., ((
long)(log((
double)rows) / log(2.0F))) + (padFactor ? padFactor : 1));
477 if ((primeRows = greatestProductOfSmallPrimes(pow2Rows)) > rows)
478 rowsToUse = primeRows;
479 else
480 rowsToUse = pow2Rows;
481 fprintf(stdout, "Using %" PRId64 " rows\n", rowsToUse);
482 } else if (flags & FL_TRUNCATE)
483 rowsToUse = greatestProductOfSmallPrimes(rows);
485 fputs("Warning: Number of points has large prime factors.\nThis could take a very long time.\nConsider using the -truncate option.\n", stderr);
486 }
489
490 for (j = 0; j < colsToUse; j++) {
491 real[j] = imag[j] = NULL;
492 if (j < depenQuantities) {
493 if (complexInput) {
497 } else {
500 imag[j] = calloc(sizeof(**imag), rowsToUse);
501 }
502 if (rows < rowsToUse) {
503 real[j] =
SDDS_Realloc(real[j],
sizeof(**real) * rowsToUse);
504 imag[j] =
SDDS_Realloc(imag[j],
sizeof(**imag) * rowsToUse);
505 }
506 } else {
507 real[j] = calloc(sizeof(**real), rowsToUse);
508 imag[j] = calloc(sizeof(**imag), rowsToUse);
509 }
510 }
511 fdata = malloc(sizeof(*fdata) * rowsToUse);
512 if (rows < rowsToUse) {
513 length = ((double)rows) * (tdata[rows - 1] - tdata[0]) / ((double)rows - 1.0);
514 } else
515 length = tdata[rows - 1] - tdata[0];
516 t0 = tdata[0];
517 df = factor = 1.0 / length;
518 free(tdata);
519 for (i = 0; i < rows; i++)
520 fdata[i] = i * df;
521 for (i = rows; i < rowsToUse; i++) {
522 fdata[i] = i * df;
523 }
524
525 for (i = 0; i < rows; i++) {
526 for (j = 0; j < colsToUse; j++) {
527 real_imag[2 * j] = real_imag[2 * j + 1] = 0;
528 if (j < depenQuantities) {
529 real_imag[2 * j] = real[j][i];
530 if (imag[j])
531 real_imag[2 * j + 1] = imag[j][i];
532 else
533 real_imag[2 * j + 1] = 0;
534 }
535 }
536 complexFFT(real_imag, colsToUse, inverse);
537 for (j = 0; j < colsToUse; j++) {
538 real[j][i] = real_imag[2 * j];
539 imag[j][i] = real_imag[2 * j + 1];
540 }
541 }
542
543 n_freq = rowsToUse;
544 fftrows = rowsToUse;
545 arg = malloc(sizeof(*arg) * rowsToUse);
546 magData = malloc(sizeof(*magData) * rowsToUse);
547 real_imag1 = calloc(sizeof(*real_imag1), 2 * fftrows + 2);
548
549 for (j = 0; j < depenQuantities; j++) {
550 for (i = 0; i < rowsToUse; i++) {
551 if (i < rows) {
552 real_imag1[2 * i] = real[j][i];
553 real_imag1[2 * i + 1] = imag[j][i];
554 } else {
555 real_imag1[2 * i] = 0;
556 real_imag1[2 * i + 1] = 0;
557 }
558 }
559 complexFFT(real_imag1, rowsToUse, inverse);
560 for (i = 0; i < n_freq; i++) {
561 dtf_real = cos(-2 * PI * fdata[i] * t0);
562 dtf_imag = sin(-2 * PI * fdata[i] * t0);
563 real[j][i] = real_imag1[2 * i] * dtf_real - real_imag1[2 * i + 1] * dtf_imag;
564 imag[j][i] = real_imag1[2 * i + 1] * dtf_real + real_imag1[2 * i] * dtf_imag;
565 magData[i] = sqrt(sqr(real[j][i]) + sqr(imag[j][i]));
566 if (real[j][i] || imag[j][i])
567 arg[i] = 180.0 / PI * atan2(imag[j][i], real[j][i]);
568 else
569 arg[i] = 0;
570 }
571 if (flags & FL_NORMALIZE) {
572 factor = -DBL_MAX;
573 for (i = 0; i < n_freq; i++)
574 if (magData[i] > factor)
575 factor = magData[i];
576 if (factor != -DBL_MAX)
577 for (i = 0; i < n_freq; i++) {
578 real[j][i] /= factor;
579 imag[j][i] /= factor;
580 magData[i] /= factor;
581 }
582 }
583 if (!inverse)
584 sprintf(str, "FFT%s", depenQuantity[j] + (imagQuan ? 4 : 0));
585 else {
586 if (complexInput)
587 tempStr = realQuan[j];
588 else
589 tempStr = depenQuantity[j];
590
591 if (strncmp(tempStr, "FFT", 3) == 0)
592 sprintf(str, "%s", tempStr + 3);
593 else if (strncmp(tempStr, "RealFFT", 7) == 0)
594 sprintf(str, "%s", tempStr + 7);
595 else
596 sprintf(str, "%s", tempStr);
597 }
599 exit(EXIT_FAILURE);
602 !
SDDS_SetParameters(&SDDSout, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE,
"fftFrequencies", n_freq,
"fftFrequencySpacing", df, NULL))
604 if (flags & FL_FULLOUTPUT) {
605 if (!
SDDS_SetColumn(&SDDSout, SDDS_SET_BY_INDEX, magData, n_freq, index) ||
606 !
SDDS_SetColumn(&SDDSout, SDDS_SET_BY_INDEX, real[j], n_freq, index + 1) ||
607 !
SDDS_SetColumn(&SDDSout, SDDS_SET_BY_INDEX, imag[j], n_freq, index + 2) ||
608 !
SDDS_SetColumn(&SDDSout, SDDS_SET_BY_INDEX, arg, n_freq, index + 3))
610 } else {
611 if (!
SDDS_SetColumn(&SDDSout, SDDS_SET_BY_INDEX, real[j], n_freq, index))
613 }
614 }
615 if (!
SDDS_SetColumn(&SDDSout, SDDS_SET_BY_INDEX, fdata, n_freq, 0))
617 free(fdata);
618 free(arg);
619 free(magData);
620 for (j = 0; j < colsToUse; j++) {
621 if (real[j])
622 free(real[j]);
623 if (imag[j])
624 free(imag[j]);
625 }
626 free(real_imag1);
627 } else {
630 }
633 }
636 exit(EXIT_FAILURE);
637 }
640 exit(EXIT_FAILURE);
641 }
642 if (excludes) {
644 free(exclude);
645 }
646 free(real);
647 free(imag);
648 if (realQuan) {
651 free(realQuan);
652 free(imagQuan);
653 } else {
655 free(depenQuantity);
656 }
657 free(real_imag);
659 return EXIT_SUCCESS;
660}
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.