64 "sddsderiv [<input>] [<output>]\n"
65 " [-pipe=[input][,output]]\n"
66 " -differentiate=<column-name>[,<sigma-name>] ...\n"
67 " [-exclude=<column-name>[,...]]\n"
68 " -versus=<column-name>\n"
69 " [-interval=<integer>]\n"
70 " [-SavitzkyGolay=<left>,<right>,<fitOrder>[,<derivOrder>]]\n"
71 " [-mainTemplates=<item>=<string>[,...]]\n"
72 " [-errorTemplates=<item>=<string>[,...]]\n"
73 " [-majorOrder=row|column]\n\n"
75 " -pipe=[input][,output] Use standard input/output.\n"
76 " -differentiate=<col>[,<sigma-col>] ... Columns to differentiate, optionally specifying sigma columns.\n"
77 " -exclude=<col>[,...] Columns to exclude from differentiation.\n"
78 " -versus=<col> Column to differentiate with respect to.\n"
79 " -interval=<integer> Interval for finite difference.\n"
80 " -SavitzkyGolay=<left>,<right>,<fitOrder>[,<derivOrder>]\n"
81 " Apply Savitzky-Golay filter with specified parameters.\n"
82 " -mainTemplates=<item>=<string>[,...] Templates for main output columns. Items: name, symbol, description.\n"
83 " -errorTemplates=<item>=<string>[,...] Templates for error output columns. Items: name, symbol, description.\n"
84 " -majorOrder=row|column Set major order of data.\n\n"
85 "The -templates <item> may be \"name\", \"symbol\" or \"description\".\n"
86 "The default main name, description, and symbol templates are \"%yNameDeriv\",\n"
87 " \"Derivative w.r.t %xSymbol of %ySymbol\", and \"d[%ySymbol]/d[%xSymbol]\", respectively.\n"
88 "The default error name, description, and symbol templates are \"%yNameDerivSigma\",\n"
89 " \"Sigma of derivative w.r.t %xSymbol of %ySymbol\", and \"Sigma[d[%ySymbol]/d[%xSymbol]]\", respectively.\n"
90 "Program by Michael Borland. (" __DATE__
" " __TIME__
", SVN revision: " SVN_VERSION
")";
106static char *option[N_OPTIONS] = {
118long checkErrorNames(
char **yErrorName,
long nDerivatives);
119void makeSubstitutions(
char *buffer1,
char *buffer2,
char *
template,
char *nameRoot,
char *symbolRoot,
char *xName,
char *xSymbol);
120char *changeInformation(
SDDS_DATASET *SDDSout,
char *name,
char *nameRoot,
char *symbolRoot,
char *xName,
char *xSymbol,
char **
template,
char *newUnits);
122 char ***yOutputName,
char ***yOutputErrorName,
char ***yOutputUnits,
char *xName,
char *xErrorName,
char **yName,
char **yErrorName,
long yNames,
char **mainTemplate,
char **errorTemplate, int32_t interval,
long order,
short columnMajorOrder);
123long findDerivIndices(int64_t *i1, int64_t *i2,
long interval, int64_t i, int64_t rows);
124void takeDerivative(
double *x,
double *y,
double *sy, int64_t rows,
double *deriv,
double *derivSigma,
double *derivPosition,
long interval);
125void takeSGDerivative(
double *x,
double *y, int64_t rows,
double *deriv,
double *derivPosition,
long left,
long right,
long sgOrder,
long derivOrder);
127int main(
int argc,
char **argv) {
128 double *xData, *yData, *xError, *yError, *derivative, *derivativeError, *derivativePosition;
129 char *input, *output, *xName, *xErrorName, **yName, **yErrorName, **yOutputName, **yOutputErrorName, *ptr;
130 char **yOutputUnits, **yExcludeName;
131 char *mainTemplate[3] = {NULL, NULL, NULL};
132 char *errorTemplate[3] = {NULL, NULL, NULL};
133 long i, iArg, yNames, yExcludeNames;
137 SCANNED_ARG *scanned;
138 unsigned long flags, pipeFlags, majorOrderFlag;
139 long SGLeft, SGRight, SGOrder, SGDerivOrder, intervalGiven, yErrorsSeen;
140 short columnMajorOrder = -1;
144 argc =
scanargs(&scanned, argc, argv);
148 input = output = xName = xErrorName = NULL;
149 yName = yErrorName = yExcludeName = NULL;
150 derivative = derivativeError = derivativePosition = yError = yData = xData = xError = NULL;
151 yNames = yExcludeNames = 0;
159 for (iArg = 1; iArg < argc; iArg++) {
160 if (scanned[iArg].arg_type == OPTION) {
162 switch (
match_string(scanned[iArg].list[0], option, N_OPTIONS, 0)) {
163 case CLO_MAJOR_ORDER:
165 scanned[iArg].n_items--;
166 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)))
167 SDDS_Bomb(
"invalid -majorOrder syntax/values");
168 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
169 columnMajorOrder = 1;
170 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
171 columnMajorOrder = 0;
173 case CLO_DIFFERENTIATE:
174 if (scanned[iArg].n_items != 2 && scanned[iArg].n_items != 3)
175 SDDS_Bomb(
"invalid -differentiate syntax");
176 yName =
SDDS_Realloc(yName,
sizeof(*yName) * (yNames + 1));
177 yErrorName =
SDDS_Realloc(yErrorName,
sizeof(*yErrorName) * (yNames + 1));
178 yName[yNames] = scanned[iArg].list[1];
179 if (scanned[iArg].n_items == 3) {
181 yErrorName[yNames] = scanned[iArg].list[2];
183 yErrorName[yNames] = NULL;
187 if (scanned[iArg].n_items < 2)
189 moveToStringArray(&yExcludeName, &yExcludeNames, scanned[iArg].list + 1, scanned[iArg].n_items - 1);
194 if (scanned[iArg].n_items != 2)
196 xName = scanned[iArg].list[1];
199 case CLO_MAINTEMPLATE:
200 if (scanned[iArg].n_items < 2)
201 SDDS_Bomb(
"invalid -mainTemplate syntax");
202 scanned[iArg].n_items--;
203 if (!
scanItemList(&flags, scanned[iArg].list + 1, &scanned[iArg].n_items, 0,
"name",
SDDS_STRING, mainTemplate + 0, 1, 0,
"description",
SDDS_STRING, mainTemplate + 1, 1, 0,
"symbol",
SDDS_STRING, mainTemplate + 2, 1, 0, NULL))
204 SDDS_Bomb(
"invalid -mainTemplate syntax");
206 case CLO_ERRORTEMPLATE:
207 if (scanned[iArg].n_items < 2)
208 SDDS_Bomb(
"invalid -errorTemplate syntax");
209 scanned[iArg].n_items--;
210 if (!
scanItemList(&flags, scanned[iArg].list + 1, &scanned[iArg].n_items, 0,
"name",
SDDS_STRING, errorTemplate + 0, 1, 0,
"description",
SDDS_STRING, errorTemplate + 1, 1, 0,
"symbol",
SDDS_STRING, errorTemplate + 2, 1, 0, NULL))
211 SDDS_Bomb(
"invalid -errorTemplate syntax");
214 if (!
processPipeOption(scanned[iArg].list + 1, scanned[iArg].n_items - 1, &pipeFlags))
218 if (scanned[iArg].n_items != 2 || sscanf(scanned[iArg].list[1],
"%" SCNd32, &interval) != 1 || interval <= 0)
219 SDDS_Bomb(
"invalid -interval syntax/value");
222 case CLO_SAVITZKYGOLAY:
223 if ((scanned[iArg].n_items != 4 && scanned[iArg].n_items != 5) ||
224 sscanf(scanned[iArg].list[1],
"%ld", &SGLeft) != 1 ||
225 sscanf(scanned[iArg].list[2],
"%ld", &SGRight) != 1 ||
226 sscanf(scanned[iArg].list[3],
"%ld", &SGOrder) != 1 ||
227 (scanned[iArg].n_items == 5 && sscanf(scanned[iArg].list[4],
"%ld", &SGDerivOrder) != 1) ||
230 (SGLeft + SGRight) < SGOrder ||
233 SDDS_Bomb(
"invalid -SavitzkyGolay syntax/values");
236 fprintf(stderr,
"invalid option seen: %s\n", scanned[iArg].list[0]);
242 input = scanned[iArg].list[0];
244 output = scanned[iArg].list[0];
250 if (intervalGiven && SGOrder >= 0)
251 SDDS_Bomb(
"-interval and -SavitzkyGolay options are incompatible");
252 if (SGOrder >= 0 && (xErrorName || yErrorsSeen))
253 SDDS_Bomb(
"Savitzky-Golay method does not support errors in data");
258 SDDS_Bomb(
"-differentiate option must be given at least once");
259 if (!checkErrorNames(yErrorName, yNames))
260 SDDS_Bomb(
"either all -differentiate quantities must have errors, or none");
264 if (!(ptr =
SDDS_FindColumn(&SDDSin, FIND_NUMERIC_TYPE, xName, NULL))) {
265 fprintf(stderr,
"error: column %s doesn't exist\n", xName);
271 if (!(ptr =
SDDS_FindColumn(&SDDSin, FIND_NUMERIC_TYPE, xErrorName, NULL))) {
272 fprintf(stderr,
"error: column %s doesn't exist\n", xErrorName);
280 if (!(yNames = expandColumnPairNames(&SDDSin, &yName, &yErrorName, yNames, yExcludeName, yExcludeNames, FIND_NUMERIC_TYPE, 0))) {
281 fprintf(stderr,
"error: no quantities to differentiate found in file\n");
285 setupOutputFile(&SDDSout, &SDDSin, output, &yOutputName, &yOutputErrorName, &yOutputUnits, xName, xErrorName, yName, yErrorName, yNames, mainTemplate, errorTemplate, interval, SGOrder >= 0 ? SGDerivOrder : 1, columnMajorOrder);
289 SDDS_Bomb(
"Can't compute derivatives: too little data.");
290 derivative =
SDDS_Realloc(derivative,
sizeof(*derivative) * rows);
291 derivativeError =
SDDS_Realloc(derivativeError,
sizeof(*derivativeError) * rows);
292 derivativePosition =
SDDS_Realloc(derivativePosition,
sizeof(*derivativePosition) * rows);
299 for (i = 0; i < yNames; i++) {
305 takeSGDerivative(xData, yData, rows, derivative, derivativePosition, SGLeft, SGRight, SGOrder, SGDerivOrder);
307 takeDerivative(xData, yData, yError, rows, derivative, derivativeError, derivativePosition, interval);
309 (yOutputErrorName && yOutputErrorName[i] && !
SDDS_SetColumnFromDoubles(&SDDSout, SDDS_BY_NAME, derivativeError, rows, yOutputErrorName[i])))
315 yData = yError = NULL;
326 xData = xError = NULL;
335 free(derivativeError);
336 if (derivativePosition)
337 free(derivativePosition);
341void takeSGDerivative(
double *x,
double *y, int64_t rows,
double *deriv,
double *derivPosition,
long left,
long right,
long sgOrder,
long derivOrder) {
345 spacing = (x[rows - 1] - x[0]) / (rows - 1);
347 for (i = 0; i < rows; i++) {
348 derivPosition[i] = x[i];
349 deriv[i] = df * y[i];
354void takeDerivative(
double *x,
double *y,
double *sy, int64_t rows,
double *deriv,
double *derivSigma,
double *derivPosition,
long interval) {
359 for (i = 0; i < rows; i++) {
360 if (findDerivIndices(&i1, &i2, interval, i, rows) && (dx = x[i2] - x[i1])) {
361 deriv[i] = (y[i2] - y[i1]) / dx;
362 derivSigma[i] = sqrt(sqr(sy[i1]) + sqr(sy[i2])) / fabs(dx);
363 derivPosition[i] = (x[i2] + x[i1]) / 2;
365 deriv[i] = derivSigma[i] = derivPosition[i] = DBL_MAX;
368 for (i = 0; i < rows; i++) {
369 if (findDerivIndices(&i1, &i2, interval, i, rows) && (dx = x[i2] - x[i1])) {
370 deriv[i] = (y[i2] - y[i1]) / dx;
371 derivPosition[i] = (x[i2] + x[i1]) / 2;
373 deriv[i] = derivPosition[i] = DBL_MAX;
378long findDerivIndices(int64_t *i1, int64_t *i2,
long interval, int64_t i, int64_t rows) {
379 int64_t index, rows1;
382 *i1 = index = i - interval / 2;
392 *i2 = i + interval / 2;
409 if (*i2 < rows && *i1 >= 0)
415 char ***yOutputName,
char ***yOutputErrorName,
char ***yOutputUnits,
char *xName,
char *xErrorName,
char **yName,
char **yErrorName,
long yNames,
char **mainTemplate0,
char **errorTemplate0, int32_t interval,
long order,
short columnMajorOrder) {
417 char *xSymbol, *ySymbol;
418 char *mainTemplate[3] = {
"%yNameDeriv",
"Derivative w.r.t. %xSymbol of %ySymbol",
"d[%ySymbol]/d[%xSymbol]"};
419 char *errorTemplate[3] = {
"%yNameDerivSigma",
"Sigma of derivative w.r.t. %xSymbol of %ySymbol",
420 "Sigma[d[%ySymbol]/d[%xSymbol]]"};
423 for (i = 0; i < 3; i++) {
424 if (!mainTemplate0[i]) {
429 snprintf(buffer,
sizeof(buffer),
"%%yNameDeriv%ld", order);
433 snprintf(buffer,
sizeof(buffer),
"Derivative %ld w.r.t. %%xSymbol of %%ySymbol", order);
437 snprintf(buffer,
sizeof(buffer),
"d[%s%ld]/d[%s]",
"ySymbol", order,
"xSymbol");
440 cp_str(&mainTemplate[i], buffer);
443 mainTemplate[i] = mainTemplate0[i];
445 if (errorTemplate0[i]) {
446 errorTemplate[i] = errorTemplate0[i];
450 *yOutputName =
tmalloc(
sizeof(**yOutputName) * yNames);
451 *yOutputErrorName =
tmalloc(
sizeof(**yOutputErrorName) * yNames);
452 *yOutputUnits =
tmalloc(
sizeof(**yOutputUnits) * yNames);
460 fprintf(stderr,
"error: problem getting symbol for column %s\n", xName);
465 for (i = 0; i < yNames; i++) {
467 fprintf(stderr,
"error: problem transferring definition for column %s\n", yName[i]);
471 fprintf(stderr,
"error: problem getting symbol for column %s\n", yName[i]);
476 (*yOutputUnits)[i] = divideColumnUnits(SDDSout, yName[i], xName);
477 (*yOutputName)[i] = changeInformation(SDDSout, yName[i], yName[i], ySymbol, xName, xSymbol, mainTemplate, (*yOutputUnits)[i]);
478 if (yErrorName || xErrorName) {
479 if (yErrorName && yErrorName[i]) {
481 fprintf(stderr,
"error: problem transferring definition for column %s\n", yErrorName[i]);
484 (*yOutputErrorName)[i] = changeInformation(SDDSout, yErrorName[i], yName[i], ySymbol, xName, xSymbol, errorTemplate, (*yOutputUnits)[i]);
487 fprintf(stderr,
"error: problem transferring error definition for column %s\n", yName[i]);
490 (*yOutputErrorName)[i] = changeInformation(SDDSout, yName[i], yName[i], ySymbol, xName, xSymbol, errorTemplate, (*yOutputUnits)[i]);
493 (*yOutputErrorName)[i] = NULL;
496 if (columnMajorOrder != -1)
497 SDDSout->layout.data_mode.column_major = columnMajorOrder;
499 SDDSout->layout.data_mode.column_major = SDDSin->layout.data_mode.column_major;
506char *changeInformation(
SDDS_DATASET *SDDSout,
char *name,
char *nameRoot,
char *symbolRoot,
char *xName,
char *xSymbol,
char **
template,
char *newUnits) {
507 char buffer1[SDDS_MAXLINE], buffer2[SDDS_MAXLINE], *ptr;
512 makeSubstitutions(buffer1, buffer2,
template[2], nameRoot, symbolRoot, xName, xSymbol);
516 makeSubstitutions(buffer1, buffer2,
template[1], nameRoot, symbolRoot, xName, xSymbol);
520 makeSubstitutions(buffer1, buffer2,
template[0], nameRoot, symbolRoot, xName, xSymbol);
527void makeSubstitutions(
char *buffer1,
char *buffer2,
char *
template,
char *nameRoot,
char *symbolRoot,
char *xName,
char *xSymbol) {
528 strcpy(buffer2,
template);
533 strcpy(buffer1, buffer2);
536long checkErrorNames(
char **yErrorName,
long yNames) {
539 for (i = 1; i < yNames; i++)
543 for (i = 1; i < yNames; i++)
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
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_SetColumnFromDoubles(SDDS_DATASET *SDDS_dataset, int32_t mode, double *data, int64_t rows,...)
Sets the values for a single data column using double-precision floating-point numbers.
int32_t SDDS_ChangeColumnInformation(SDDS_DATASET *SDDS_dataset, char *field_name, void *memory, int32_t mode,...)
Modifies a specific field in a column definition within the SDDS dataset.
int32_t SDDS_GetColumnInformation(SDDS_DATASET *SDDS_dataset, char *field_name, void *memory, int32_t mode,...)
Retrieves information about a specified column in the SDDS dataset.
int32_t SDDS_DefineParameter1(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, void *fixed_value)
Defines a data parameter with a fixed numerical value.
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_TransferColumnDefinition(SDDS_DATASET *target, SDDS_DATASET *source, char *name, char *newName)
Transfers a column definition from a source dataset to a target dataset.
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.
void SDDS_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
int32_t SDDS_StringIsBlank(char *s)
Checks if a string is blank (contains only whitespace characters).
char * SDDS_FindColumn(SDDS_DATASET *SDDS_dataset, int32_t mode,...)
Finds the first column in the SDDS dataset that matches the specified criteria.
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
int32_t SDDS_CopyString(char **target, const char *source)
Copies a source string to a target string with memory allocation.
void * SDDS_Realloc(void *old_ptr, size_t new_size)
Reallocates memory to a new size.
#define SDDS_STRING
Identifier for the string data type.
#define SDDS_LONG
Identifier for the signed 32-bit integer data type.
Utility functions for SDDS dataset manipulation and string array operations.
void * tmalloc(uint64_t size_of_block)
Allocates a memory block of the specified size with zero initialization.
void bomb(char *error, char *usage)
Reports error messages to the terminal and aborts the program.
char * cp_str(char **s, char *t)
Copies a string, allocating memory for storage.
double dfactorial(long n)
Computes the factorial of a given number as a double.
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 replace_string(char *t, char *s, char *orig, char *repl)
Replace all occurrences of one string with another string.
long SavitzkyGolaySmooth(double *data, long rows, long order, long nLeft, long nRight, long derivativeOrder)
Applies Savitzky-Golay smoothing or differentiation to a data array.
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.