161 {
162 int iArg, j;
163 char *freqUnits;
164 char *indepQuantity, **depenQuantity, **exclude, **realQuan = NULL, **imagQuan = NULL;
165 long depenQuantities, excludes;
166 char *input, *output;
167 long sampleInterval, readCode, noWarnings, complexInput, inverse, spectrumFoldParExist = 0, colsToUse;
168 int64_t i, rows, rowsToUse, primeRows, pow2Rows, n_freq, fftrows;
169 int32_t spectrumFolded = 0, page = 0, index;
170 unsigned long flags, pipeFlags, complexInputFlags = 0, fullOutputFlags = 0, majorOrderFlag;
171 long primeCols, pow2Cols;
172 SCANNED_ARG *scanned;
174 double *tdata, rintegCutOffFreq, unwrapLimit = 0;
175 long padFactor;
176 short columnMajorOrder = -1;
177 double length, *real_imag = NULL, **real = NULL, **imag = NULL, *real_imag1 = NULL, *fdata = NULL, df, t0, factor;
178 double dtf_real, dtf_imag, *arg = NULL, *magData = NULL;
179 char str[256], *tempStr = NULL;
180
182 argc =
scanargs(&scanned, argc, argv);
183 if (argc < 3 || argc > (3 + N_OPTIONS)) {
184 fprintf(stderr, "%s%s", USAGE1, USAGE2);
185 exit(EXIT_FAILURE);
186 }
187 rintegCutOffFreq = 0;
188 output = input = NULL;
189 flags = pipeFlags = excludes = complexInput = inverse = 0;
190 sampleInterval = 1;
191 indepQuantity = NULL;
192 depenQuantity = exclude = NULL;
193 depenQuantities = 0;
194 noWarnings = 0;
195 padFactor = 0;
196
197 for (iArg = 1; iArg < argc; iArg++) {
198 if (scanned[iArg].arg_type == OPTION) {
199
200 switch (
match_string(scanned[iArg].list[0], option, N_OPTIONS, 0)) {
201 case SET_NORMALIZE:
202 flags |= FL_NORMALIZE;
203 break;
204 case SET_PADWITHZEROES:
205 flags |= FL_PADWITHZEROES;
206 if (scanned[iArg].n_items != 1) {
207 if (scanned[iArg].n_items != 2 || sscanf(scanned[iArg].list[1], "%ld", &padFactor) != 1 || padFactor < 1)
208 SDDS_Bomb(
"invalid -padwithzeroes syntax");
209 }
210 break;
211 case SET_TRUNCATE:
212 flags |= FL_TRUNCATE;
213 break;
214 case SET_SUPPRESSAVERAGE:
215 flags |= FL_SUPPRESSAVERAGE;
216 break;
217 case SET_SAMPLEINTERVAL:
218 if (scanned[iArg].n_items != 2 || sscanf(scanned[iArg].list[1], "%ld", &sampleInterval) != 1 || sampleInterval <= 0)
219 SDDS_Bomb(
"invalid -sampleinterval syntax");
220 break;
221 case SET_COLUMNS:
222 if (indepQuantity)
223 SDDS_Bomb(
"only one -columns option may be given");
224 if (scanned[iArg].n_items < 2)
226 indepQuantity = scanned[iArg].list[1];
227 if (scanned[iArg].n_items >= 2) {
228 depenQuantity =
tmalloc(
sizeof(*depenQuantity) * (depenQuantities = scanned[iArg].n_items - 2));
229 for (i = 0; i < depenQuantities; i++)
231 }
232 break;
233 case SET_FULLOUTPUT:
234 flags |= FL_FULLOUTPUT;
235 if (scanned[iArg].n_items >= 2) {
236 scanned[iArg].n_items--;
237 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))
239 scanned[iArg].n_items++;
240 if (fullOutputFlags & FL_FULLOUTPUT_UNFOLDED)
241 flags |= FL_FULLOUTPUT_UNFOLDED;
242 else
243 flags |= FL_FULLOUTPUT_FOLDED;
244 if (fullOutputFlags & FL_UNWRAP_PHASE)
245 flags |= FL_UNWRAP_PHASE;
246 }
247 break;
248 case SET_PIPE:
249 if (!
processPipeOption(scanned[iArg].list + 1, scanned[iArg].n_items - 1, &pipeFlags))
251 break;
252 case SET_PSDOUTPUT:
253 if (scanned[iArg].n_items > 1) {
254 unsigned long tmpFlags;
255 if (strchr(scanned[iArg].list[1], '=') == NULL) {
256 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))
258 } else {
259 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))
261 }
262 flags |= tmpFlags;
263 } else {
264 flags |= FL_PSDOUTPUT;
265 }
266 if ((flags & FL_PSDINTEGOUTPUT) && (flags & FL_PSDRINTEGOUTPUT))
267 SDDS_Bomb(
"invalid -psdOutput syntax: give only one of integrated or rintegrated");
268 break;
269 case SET_EXCLUDE:
270 if (scanned[iArg].n_items < 2)
272 moveToStringArray(&exclude, &excludes, scanned[iArg].list + 1, scanned[iArg].n_items - 1);
273 break;
274 case SET_NOWARNINGS:
275 noWarnings = 1;
276 break;
277 case SET_COMPLEXINPUT:
278 complexInput = 1;
279 if (scanned[iArg].n_items == 2) {
280 scanned[iArg].n_items--;
281 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))
282 SDDS_Bomb(
"Invalid -complexInput syntax");
283 scanned[iArg].n_items++;
284 }
285 break;
286 case SET_INVERSE:
287 inverse = 1;
288 break;
289 case SET_MAJOR_ORDER:
290 majorOrderFlag = 0;
291 scanned[iArg].n_items--;
292 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)))
293 SDDS_Bomb(
"invalid -majorOrder syntax/values");
294 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
295 columnMajorOrder = 1;
296 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
297 columnMajorOrder = 0;
298 break;
299 default:
300 fprintf(stderr, "error: unknown/ambiguous option: %s\n", scanned[iArg].list[0]);
301 exit(EXIT_FAILURE);
302 break;
303 }
304 } else {
305 if (!input)
306 input = scanned[iArg].list[0];
307 else if (!output)
308 output = scanned[iArg].list[0];
309 else
311 }
312 }
313 if (!complexInput) {
314 if (!noWarnings && inverse)
315 fprintf(stderr, "Warning: The inverse option is ignored since it only works with -complexInput.\n");
316 inverse = 0;
317 }
318 if (!noWarnings && inverse && (flags & FL_FULLOUTPUT_FOLDED))
319 fprintf(stderr, "Warning: The combination of -inverse and -fullOutput=folded will be changed to -inverse -fullOutput=unfolded.\n");
320
322
323 if (!indepQuantity)
324 SDDS_Bomb(
"Supply the independent quantity name with the -columns option");
325
326 if ((flags & FL_TRUNCATE) && (flags & FL_PADWITHZEROES))
327 SDDS_Bomb(
"Specify only one of -padwithzeroes and -truncate");
328 if (!inverse) {
329
330 flags |= FL_FULLOUTPUT;
331 flags |= FL_FULLOUTPUT_UNFOLDED;
332 }
335
337 exit(EXIT_FAILURE);
338
339 excludes = appendToStringArray(&exclude, excludes, indepQuantity);
340 if (!depenQuantities)
341 depenQuantities = appendToStringArray(&depenQuantity, depenQuantities, "*");
342
343 if (!complexInput) {
344 if ((depenQuantities = expandColumnPairNames(&SDDSin, &depenQuantity, NULL, depenQuantities, exclude, excludes, FIND_NUMERIC_TYPE, 0)) <= 0) {
346 SDDS_Bomb(
"No quantities selected to FFT");
347 }
348 } else {
349 if ((depenQuantities = expandComplexColumnPairNames(&SDDSin, depenQuantity, &realQuan, &imagQuan, depenQuantities, exclude, excludes, FIND_NUMERIC_TYPE, 0)) <= 0) {
351 SDDS_Bomb(
"No quantities selected to FFT");
352 }
353 }
354
355#if 0
356 fprintf(stderr, "%ld dependent quantities:\n", depenQuantities);
357 for (i = 0; i < depenQuantities; i++)
358 fprintf(stderr, " %s\n", depenQuantity[i]);
359#endif
360
361 if (!(freqUnits = makeFrequencyUnits(&SDDSin, indepQuantity)) ||
363 !create_fft_frequency_column(&SDDSout, &SDDSin, indepQuantity, freqUnits, inverse) ||
367 if (columnMajorOrder != -1)
368 SDDSout.layout.data_mode.column_major = columnMajorOrder;
369 else
370 SDDSout.layout.data_mode.column_major = SDDSin.layout.data_mode.column_major;
371
374 if (complexInput) {
375 if (!complexInputFlags) {
377 spectrumFoldParExist = 1;
378 } else if (complexInputFlags & FL_COMPLEXINPUT_UNFOLDED)
379 flags |= FL_COMPLEXINPUT_UNFOLDED;
380 else
381 flags |= FL_COMPLEXINPUT_FOLDED;
382 }
383 for (i = 0; i < depenQuantities; i++) {
384 if (!complexInput)
385 create_fft_columns(&SDDSout, &SDDSin, depenQuantity[i], indepQuantity, freqUnits,
386 flags & FL_FULLOUTPUT, flags & (FL_PSDOUTPUT + FL_PSDINTEGOUTPUT + FL_PSDRINTEGOUTPUT),
387 0, inverse, flags & FL_UNWRAP_PHASE);
388 else
389 create_fft_columns(&SDDSout, &SDDSin, realQuan[i], indepQuantity, freqUnits,
390 flags & FL_FULLOUTPUT, flags & (FL_PSDOUTPUT + FL_PSDINTEGOUTPUT + FL_PSDRINTEGOUTPUT),
391 1, inverse, flags & FL_UNWRAP_PHASE);
392 }
393
396
397 colsToUse = depenQuantities;
398 primeCols = greatestProductOfSmallPrimes(depenQuantities);
399 if (depenQuantities != primeCols || padFactor) {
400 if (flags & FL_PADWITHZEROES) {
401 pow2Cols =
ipow(2., ((
long)(log((
double)depenQuantities) / log(2.0F))) + (padFactor ? padFactor : 1));
402 if ((primeCols = greatestProductOfSmallPrimes(pow2Cols)) > depenQuantities)
403 colsToUse = primeCols;
404 else
405 colsToUse = pow2Cols;
406 fprintf(stdout, "Using %ld columns\n", colsToUse);
407 } else if (flags & FL_TRUNCATE)
408 colsToUse = greatestProductOfSmallPrimes(depenQuantities);
410 fputs("Warning: Number of dependent columns has large prime factors.\nThis could take a very long time.\nConsider using the -truncate option.\n", stderr);
411 }
412 real_imag =
tmalloc(
sizeof(*real_imag) * (2 * colsToUse + 2));
413 real = malloc(sizeof(*real) * colsToUse);
414 imag = malloc(sizeof(*imag) * colsToUse);
415
417 page++;
420 if (page == 1 && spectrumFoldParExist) {
423 if (spectrumFolded)
424 flags |= FL_COMPLEXINPUT_FOLDED;
425 else
426 flags |= FL_COMPLEXINPUT_UNFOLDED;
427 }
428 if (rows) {
429 rowsToUse = rows;
430 primeRows = greatestProductOfSmallPrimes(rows);
431 if (rows != primeRows || padFactor) {
432 if (flags & FL_PADWITHZEROES) {
433 pow2Rows =
ipow(2., ((
long)(log((
double)rows) / log(2.0F))) + (padFactor ? padFactor : 1));
434 if ((primeRows = greatestProductOfSmallPrimes(pow2Rows)) > rows)
435 rowsToUse = primeRows;
436 else
437 rowsToUse = pow2Rows;
438 fprintf(stdout, "Using %" PRId64 " rows\n", rowsToUse);
439 } else if (flags & FL_TRUNCATE)
440 rowsToUse = greatestProductOfSmallPrimes(rows);
442 fputs("Warning: Number of points has large prime factors.\nThis could take a very long time.\nConsider using the -truncate option.\n", stderr);
443 }
446
447 for (j = 0; j < colsToUse; j++) {
448 real[j] = imag[j] = NULL;
449 if (j < depenQuantities) {
450 if (complexInput) {
454 } else {
457 imag[j] = calloc(sizeof(**imag), rowsToUse);
458 }
459 if (rows < rowsToUse) {
460 real[j] =
SDDS_Realloc(real[j],
sizeof(**real) * rowsToUse);
461 imag[j] =
SDDS_Realloc(imag[j],
sizeof(**imag) * rowsToUse);
462 }
463 } else {
464 real[j] = calloc(sizeof(**real), rowsToUse);
465 imag[j] = calloc(sizeof(**imag), rowsToUse);
466 }
467 }
468 fdata = malloc(sizeof(*fdata) * rowsToUse);
469 if (rows < rowsToUse) {
470 length = ((double)rows) * (tdata[rows - 1] - tdata[0]) / ((double)rows - 1.0);
471 } else
472 length = tdata[rows - 1] - tdata[0];
473 t0 = tdata[0];
474 df = factor = 1.0 / length;
475 free(tdata);
476 for (i = 0; i < rows; i++)
477 fdata[i] = i * df;
478 for (i = rows; i < rowsToUse; i++) {
479 fdata[i] = i * df;
480 }
481
482 for (i = 0; i < rows; i++) {
483 for (j = 0; j < colsToUse; j++) {
484 real_imag[2 * j] = real_imag[2 * j + 1] = 0;
485 if (j < depenQuantities) {
486 real_imag[2 * j] = real[j][i];
487 if (imag[j])
488 real_imag[2 * j + 1] = imag[j][i];
489 else
490 real_imag[2 * j + 1] = 0;
491 }
492 }
493 complexFFT(real_imag, colsToUse, inverse);
494 for (j = 0; j < colsToUse; j++) {
495 real[j][i] = real_imag[2 * j];
496 imag[j][i] = real_imag[2 * j + 1];
497 }
498 }
499
500 n_freq = rowsToUse;
501 fftrows = rowsToUse;
502 arg = malloc(sizeof(*arg) * rowsToUse);
503 magData = malloc(sizeof(*magData) * rowsToUse);
504 real_imag1 = calloc(sizeof(*real_imag1), 2 * fftrows + 2);
505
506 for (j = 0; j < depenQuantities; j++) {
507 for (i = 0; i < rowsToUse; i++) {
508 if (i < rows) {
509 real_imag1[2 * i] = real[j][i];
510 real_imag1[2 * i + 1] = imag[j][i];
511 } else {
512 real_imag1[2 * i] = 0;
513 real_imag1[2 * i + 1] = 0;
514 }
515 }
516 complexFFT(real_imag1, rowsToUse, inverse);
517 for (i = 0; i < n_freq; i++) {
518 dtf_real = cos(-2 * PI * fdata[i] * t0);
519 dtf_imag = sin(-2 * PI * fdata[i] * t0);
520 real[j][i] = real_imag1[2 * i] * dtf_real - real_imag1[2 * i + 1] * dtf_imag;
521 imag[j][i] = real_imag1[2 * i + 1] * dtf_real + real_imag1[2 * i] * dtf_imag;
522 magData[i] = sqrt(sqr(real[j][i]) + sqr(imag[j][i]));
523 if (real[j][i] || imag[j][i])
524 arg[i] = 180.0 / PI * atan2(imag[j][i], real[j][i]);
525 else
526 arg[i] = 0;
527 }
528 if (flags & FL_NORMALIZE) {
529 factor = -DBL_MAX;
530 for (i = 0; i < n_freq; i++)
531 if (magData[i] > factor)
532 factor = magData[i];
533 if (factor != -DBL_MAX)
534 for (i = 0; i < n_freq; i++) {
535 real[j][i] /= factor;
536 imag[j][i] /= factor;
537 magData[i] /= factor;
538 }
539 }
540 if (!inverse)
541 sprintf(str, "FFT%s", depenQuantity[j] + (imagQuan ? 4 : 0));
542 else {
543 if (complexInput)
544 tempStr = realQuan[j];
545 else
546 tempStr = depenQuantity[j];
547
548 if (strncmp(tempStr, "FFT", 3) == 0)
549 sprintf(str, "%s", tempStr + 3);
550 else if (strncmp(tempStr, "RealFFT", 7) == 0)
551 sprintf(str, "%s", tempStr + 7);
552 else
553 sprintf(str, "%s", tempStr);
554 }
556 exit(EXIT_FAILURE);
559 !
SDDS_SetParameters(&SDDSout, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE,
"fftFrequencies", n_freq,
"fftFrequencySpacing", df, NULL))
561 if (flags & FL_FULLOUTPUT) {
562 if (!
SDDS_SetColumn(&SDDSout, SDDS_SET_BY_INDEX, magData, n_freq, index) ||
563 !
SDDS_SetColumn(&SDDSout, SDDS_SET_BY_INDEX, real[j], n_freq, index + 1) ||
564 !
SDDS_SetColumn(&SDDSout, SDDS_SET_BY_INDEX, imag[j], n_freq, index + 2) ||
565 !
SDDS_SetColumn(&SDDSout, SDDS_SET_BY_INDEX, arg, n_freq, index + 3))
567 } else {
568 if (!
SDDS_SetColumn(&SDDSout, SDDS_SET_BY_INDEX, real[j], n_freq, index))
570 }
571 }
572 if (!
SDDS_SetColumn(&SDDSout, SDDS_SET_BY_INDEX, fdata, n_freq, 0))
574 free(fdata);
575 free(arg);
576 free(magData);
577 for (j = 0; j < colsToUse; j++) {
578 if (real[j])
579 free(real[j]);
580 if (imag[j])
581 free(imag[j]);
582 }
583 free(real_imag1);
584 } else {
587 }
590 }
593 exit(EXIT_FAILURE);
594 }
597 exit(EXIT_FAILURE);
598 }
599 if (excludes) {
601 free(exclude);
602 }
603 free(real);
604 free(imag);
605 if (realQuan) {
608 free(realQuan);
609 free(imagQuan);
610 } else {
612 free(depenQuantity);
613 }
614 free(real_imag);
616 return EXIT_SUCCESS;
617}
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.