243 {
244 int iArg;
245 char *freqUnits;
246 char *indepQuantity, **depenQuantity, **exclude, **realQuan = NULL, **imagQuan = NULL;
247 long depenQuantities, excludes;
248 char *input, *output;
249 long i, readCode, noWarnings, complexInput, inverse, spectrumFoldParExist = 0;
250 int64_t rows, rowsToUse, sampleInterval;
251 int32_t spectrumFolded = 0, page = 0;
252 unsigned long flags, pipeFlags, complexInputFlags = 0, fullOutputFlags = 0, majorOrderFlag;
253 long windowType = -1;
254 SCANNED_ARG *scanned;
256 double *tdata, rintegCutOffFreq, unwrapLimit = 0;
257 long padFactor, correctWindowEffects = 0;
258 short columnMajorOrder = -1;
259 int threads = 1;
260
262 argc =
scanargs(&scanned, argc, argv);
263 if (argc < 3 || argc > (3 + N_OPTIONS)) {
264 fprintf(stderr, "%s%s", USAGE1, USAGE2);
265 exit(EXIT_FAILURE);
266
267 }
268 rintegCutOffFreq = 0;
269 output = input = NULL;
270 flags = pipeFlags = excludes = complexInput = inverse = 0;
271 sampleInterval = 1;
272 indepQuantity = NULL;
273 depenQuantity = exclude = NULL;
274 depenQuantities = 0;
275 noWarnings = 0;
276 padFactor = 0;
277 for (iArg = 1; iArg < argc; iArg++) {
278 if (scanned[iArg].arg_type == OPTION) {
279
280 switch (
match_string(scanned[iArg].list[0], option, N_OPTIONS, 0)) {
281 case SET_NORMALIZE:
282 flags |= FL_NORMALIZE;
283 break;
284 case SET_WINDOW:
285 if (scanned[iArg].n_items != 1) {
286 if ((i =
match_string(scanned[iArg].list[1], window_type, N_WINDOW_TYPES, 0)) < 0)
288 windowType = i;
289 if (scanned[iArg].n_items > 2) {
290 if (strncmp(scanned[iArg].list[2], "correct", strlen(scanned[iArg].list[2])) == 0)
291 correctWindowEffects = 1;
292 else
294 }
295 } else
296 windowType = 0;
297 break;
298 case SET_PADWITHZEROES:
299 flags |= FL_PADWITHZEROES;
300 if (scanned[iArg].n_items != 1) {
301 if (scanned[iArg].n_items != 2 || sscanf(scanned[iArg].list[1], "%ld", &padFactor) != 1 || padFactor < 1)
302 SDDS_Bomb(
"invalid -padwithzeroes syntax");
303 }
304 break;
305 case SET_TRUNCATE:
306 flags |= FL_TRUNCATE;
307 break;
308 case SET_SUPPRESSAVERAGE:
309 flags |= FL_SUPPRESSAVERAGE;
310 break;
311 case SET_SAMPLEINTERVAL:
312 if (scanned[iArg].n_items != 2 || sscanf(scanned[iArg].list[1], "%" SCNd64, &sampleInterval) != 1 || sampleInterval <= 0)
313 SDDS_Bomb(
"invalid -sampleinterval syntax");
314 break;
315 case SET_COLUMNS:
316 if (indepQuantity)
317 SDDS_Bomb(
"only one -columns option may be given");
318 if (scanned[iArg].n_items < 2)
320 indepQuantity = scanned[iArg].list[1];
321 if (scanned[iArg].n_items >= 2) {
322 depenQuantity =
tmalloc(
sizeof(*depenQuantity) * (depenQuantities = scanned[iArg].n_items - 2));
323 for (i = 0; i < depenQuantities; i++)
324 depenQuantity[i] = scanned[iArg].list[i + 2];
325 }
326 break;
327 case SET_FULLOUTPUT:
328 flags |= FL_FULLOUTPUT;
329 if (scanned[iArg].n_items >= 2) {
330 scanned[iArg].n_items--;
331 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))
333 scanned[iArg].n_items++;
334 if (fullOutputFlags & FL_FULLOUTPUT_UNFOLDED)
335 flags |= FL_FULLOUTPUT_UNFOLDED;
336 else
337 flags |= FL_FULLOUTPUT_FOLDED;
338 if (fullOutputFlags & FL_UNWRAP_PHASE)
339 flags |= FL_UNWRAP_PHASE;
340 }
341 break;
342 case SET_PIPE:
343 if (!
processPipeOption(scanned[iArg].list + 1, scanned[iArg].n_items - 1, &pipeFlags))
345 break;
346 case SET_PSDOUTPUT:
347 if (scanned[iArg].n_items -= 1) {
348 unsigned long tmpFlags;
349 if (strchr(scanned[iArg].list[1], '=') <= 0) {
350 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))
352 } else {
353 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))
355 }
356 flags |= tmpFlags;
357 } else
358 flags |= FL_PSDOUTPUT;
359 if (flags & FL_PSDINTEGOUTPUT && flags & FL_PSDRINTEGOUTPUT)
360 SDDS_Bomb(
"invalid -psdOutput syntax: give only one of integrated or rintegrated");
361 break;
362 case SET_EXCLUDE:
363 if (scanned[iArg].n_items < 2)
365 moveToStringArray(&exclude, &excludes, scanned[iArg].list + 1, scanned[iArg].n_items - 1);
366 break;
367 case SET_NOWARNINGS:
368 noWarnings = 1;
369 break;
370 case SET_COMPLEXINPUT:
371 complexInput = 1;
372 if (scanned[iArg].n_items == 2) {
373 scanned[iArg].n_items--;
374 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))
375 SDDS_Bomb(
"Invalid -complexInput syntax");
376 scanned[iArg].n_items++;
377 }
378 break;
379 case SET_INVERSE:
380 inverse = 1;
381 break;
382 case SET_MAJOR_ORDER:
383 majorOrderFlag = 0;
384 scanned[iArg].n_items--;
385 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)))
386 SDDS_Bomb(
"invalid -majorOrder syntax/values");
387 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
388 columnMajorOrder = 1;
389 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
390 columnMajorOrder = 0;
391 break;
392 case SET_THREADS:
393 if (scanned[iArg].n_items != 2 ||
394 sscanf(scanned[iArg].list[1], "%d", &threads) != 1 || threads < 1)
396 break;
397 default:
398 fprintf(stderr, "error: unknown/ambiguous option: %s\n", scanned[iArg].list[0]);
399 exit(EXIT_FAILURE);
400 break;
401 }
402 } else {
403 if (!input)
404 input = scanned[iArg].list[0];
405 else if (!output)
406 output = scanned[iArg].list[0];
407 else
409 }
410 }
411 if (!complexInput) {
412 if (!noWarnings && inverse)
413 fprintf(stderr, "Warning: the inverse option is ignored since it only works with -complexInput.\n");
414 inverse = 0;
415 }
416 if (!noWarnings && inverse && flags & FL_FULLOUTPUT_FOLDED)
417 fprintf(stderr, "Warning: the -inverse -fullOutput=folded will be changed to -inverse -fullOutput=unfolded.\n");
418
420
421 if (!indepQuantity)
422 SDDS_Bomb(
"Supply the independent quantity name with the -columns option.");
423
424 if (flags & FL_TRUNCATE && flags & FL_PADWITHZEROES)
425 SDDS_Bomb(
"Specify only one of -padwithzeroes and -truncate.");
426
429
431 exit(EXIT_FAILURE);
432
433 excludes = appendToStringArray(&exclude, excludes, indepQuantity);
434 if (!depenQuantities)
435 depenQuantities = appendToStringArray(&depenQuantity, depenQuantities, "*");
436
437 if (!complexInput) {
438 if ((depenQuantities = expandColumnPairNames(&SDDSin, &depenQuantity, NULL, depenQuantities, exclude, excludes, FIND_NUMERIC_TYPE, 0)) <= 0) {
440 SDDS_Bomb(
"No quantities selected to FFT.");
441 }
442 } else {
443 if ((depenQuantities = expandComplexColumnPairNames(&SDDSin, depenQuantity, &realQuan, &imagQuan, depenQuantities, exclude, excludes, FIND_NUMERIC_TYPE, 0)) <= 0) {
445 SDDS_Bomb(
"No quantities selected to FFT.");
446 }
447 }
448
449#if 0
450 fprintf(stderr, "%ld dependent quantities:\n", depenQuantities);
451 for (i = 0; i < depenQuantities; i++)
452 fprintf(stderr, " %s\n", depenQuantity[i]);
453#endif
454
455 if (!(freqUnits = makeFrequencyUnits(&SDDSin, indepQuantity)) ||
457 !create_fft_frequency_column(&SDDSout, &SDDSin, indepQuantity, freqUnits, inverse) ||
461 if (columnMajorOrder != -1)
462 SDDSout.layout.data_mode.column_major = columnMajorOrder;
463 else
464 SDDSout.layout.data_mode.column_major = SDDSin.layout.data_mode.column_major;
465
468 if (complexInput) {
469 if (!complexInputFlags) {
471 spectrumFoldParExist = 1;
472 } else if (complexInputFlags & FL_COMPLEXINPUT_UNFOLDED)
473 flags |= FL_COMPLEXINPUT_UNFOLDED;
474 else
475 flags |= FL_COMPLEXINPUT_FOLDED;
476 }
477 for (i = 0; i < depenQuantities; i++) {
478 if (!complexInput)
479 create_fft_columns(&SDDSout, &SDDSin, depenQuantity[i], indepQuantity, freqUnits,
480 flags & FL_FULLOUTPUT,
481 flags & (FL_PSDOUTPUT + FL_PSDINTEGOUTPUT + FL_PSDRINTEGOUTPUT),
482 0, inverse, flags & FL_UNWRAP_PHASE);
483 else
484 create_fft_columns(&SDDSout, &SDDSin, realQuan[i], indepQuantity, freqUnits,
485 flags & FL_FULLOUTPUT,
486 flags & (FL_PSDOUTPUT + FL_PSDINTEGOUTPUT + FL_PSDRINTEGOUTPUT),
487 1, inverse, flags & FL_UNWRAP_PHASE);
488 }
489
493
495 page++;
498 if (page == 1 && spectrumFoldParExist) {
501 if (spectrumFolded)
502 flags |= FL_COMPLEXINPUT_FOLDED;
503 else
504 flags |= FL_COMPLEXINPUT_UNFOLDED;
505 }
506 if (rows) {
507 int64_t primeRows, pow2Rows;
508 if (rows < 2)
509 SDDS_Bomb(
"sddsfft requires at least two rows on each nonempty page");
510 rowsToUse = rows;
511 primeRows = greatestProductOfSmallPrimes(rows);
512 if (rows != primeRows || padFactor) {
513 if (flags & FL_PADWITHZEROES) {
514 pow2Rows =
ipow(2., ((int64_t)(log((
double)rows) / log(2.0F))) + (padFactor ? padFactor : 1.0));
515 if ((primeRows = greatestProductOfSmallPrimes(pow2Rows)) > rows)
516 rowsToUse = primeRows;
517 else
518 rowsToUse = pow2Rows;
519 } else if (flags & FL_TRUNCATE)
520 rowsToUse = greatestProductOfSmallPrimes(rows);
522 fputs("Warning: number of points has large prime factors.\nThis could take a very long time.\nConsider using the -truncate option.\n", stderr);
523 }
528 for (i = 0; i < depenQuantities; i++)
529 if (!process_data(&SDDSout, &SDDSin, tdata, rows, rowsToUse,
530 complexInput ? realQuan[i] : depenQuantity[i],
531 complexInput ? imagQuan[i] : NULL,
532 flags | (i == 0 ? FL_MAKEFREQDATA : 0),
533 windowType, sampleInterval, correctWindowEffects, inverse,
534 rintegCutOffFreq, unwrapLimit, threads)) {
536 exit(EXIT_FAILURE);
537 }
538 free(tdata);
539 } else {
542 }
545 }
546
549 exit(EXIT_FAILURE);
550 }
553 exit(EXIT_FAILURE);
554 }
555
556 return EXIT_SUCCESS;
557}
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_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_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.
#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)
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.