57 "Usage: sddsderiv [<input>] [<output>]\n"
58 " [-pipe=[input][,output]]\n"
59 " -differentiate=<column-name>[,<sigma-name>]...\n"
60 " [-exclude=<column-name>[,...]]\n"
61 " -versus=<column-name>\n"
62 " [-interval=<integer>]\n"
63 " [-SavitzkyGolay=<left>,<right>,<fitOrder>[,<derivOrder>]]\n"
64 " [-mainTemplates=<item>=<string>[,...]]\n"
65 " [-errorTemplates=<item>=<string>[,...]]\n"
66 " [-majorOrder=row|column]\n\n"
68 " -pipe=[input][,output] Use standard input/output.\n"
69 " -differentiate=<col>[,<sigma-col>]... Columns to differentiate, optionally specifying sigma columns.\n"
70 " -exclude=<col>[,...] Columns to exclude from differentiation.\n"
71 " -versus=<col> Column to differentiate with respect to.\n"
72 " -interval=<integer> Interval for finite difference.\n"
73 " -SavitzkyGolay=<left>,<right>,<fitOrder>[,<derivOrder>]\n"
74 " Apply Savitzky-Golay filter with specified parameters.\n"
75 " -mainTemplates=<item>=<string>[,...] Templates for main output columns. Items: name, symbol, description.\n"
76 " -errorTemplates=<item>=<string>[,...] Templates for error output columns. Items: name, symbol, description.\n"
77 " -majorOrder=row|column Set major order of data.\n\n"
78 "The -templates <item> may be \"name\", \"symbol\" or \"description\".\n"
79 "The default main name, description, and symbol templates are \"%yNameDeriv\",\n"
80 " \"Derivative w.r.t %xSymbol of %ySymbol\", and \"d[%ySymbol]/d[%xSymbol]\", respectively.\n"
81 "The default error name, description, and symbol templates are \"%yNameDerivSigma\",\n"
82 " \"Sigma of derivative w.r.t %xSymbol of %ySymbol\", and \"Sigma[d[%ySymbol]/d[%xSymbol]]\", respectively.\n"
83 "Program by Michael Borland. (" __DATE__
" " __TIME__
", SVN revision: " SVN_VERSION
")";
99static char *option[N_OPTIONS] = {
111long checkErrorNames(
char **yErrorName,
long nDerivatives);
112void makeSubstitutions(
char *buffer1,
char *buffer2,
char *
template,
char *nameRoot,
char *symbolRoot,
char *xName,
char *xSymbol);
113char *changeInformation(
SDDS_DATASET *SDDSout,
char *name,
char *nameRoot,
char *symbolRoot,
char *xName,
char *xSymbol,
char **
template,
char *newUnits);
115 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);
116long findDerivIndices(int64_t *i1, int64_t *i2,
long interval, int64_t i, int64_t rows);
117void takeDerivative(
double *x,
double *y,
double *sy, int64_t rows,
double *deriv,
double *derivSigma,
double *derivPosition,
long interval);
118void takeSGDerivative(
double *x,
double *y, int64_t rows,
double *deriv,
double *derivPosition,
long left,
long right,
long sgOrder,
long derivOrder);
120int main(
int argc,
char **argv) {
121 double *xData, *yData, *xError, *yError, *derivative, *derivativeError, *derivativePosition;
122 char *input, *output, *xName, *xErrorName, **yName, **yErrorName, **yOutputName, **yOutputErrorName, *ptr;
123 char **yOutputUnits, **yExcludeName;
124 char *mainTemplate[3] = {NULL, NULL, NULL};
125 char *errorTemplate[3] = {NULL, NULL, NULL};
126 long i, iArg, yNames, yExcludeNames;
130 SCANNED_ARG *scanned;
131 unsigned long flags, pipeFlags, majorOrderFlag;
132 long SGLeft, SGRight, SGOrder, SGDerivOrder, intervalGiven, yErrorsSeen;
133 short columnMajorOrder = -1;
137 argc =
scanargs(&scanned, argc, argv);
141 input = output = xName = xErrorName = NULL;
142 yName = yErrorName = yExcludeName = NULL;
143 derivative = derivativeError = derivativePosition = yError = yData = xData = xError = NULL;
144 yNames = yExcludeNames = 0;
152 for (iArg = 1; iArg < argc; iArg++) {
153 if (scanned[iArg].arg_type == OPTION) {
155 switch (
match_string(scanned[iArg].list[0], option, N_OPTIONS, 0)) {
156 case CLO_MAJOR_ORDER:
158 scanned[iArg].n_items--;
159 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)))
160 SDDS_Bomb(
"invalid -majorOrder syntax/values");
161 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
162 columnMajorOrder = 1;
163 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
164 columnMajorOrder = 0;
166 case CLO_DIFFERENTIATE:
167 if (scanned[iArg].n_items != 2 && scanned[iArg].n_items != 3)
168 SDDS_Bomb(
"invalid -differentiate syntax");
169 yName =
SDDS_Realloc(yName,
sizeof(*yName) * (yNames + 1));
170 yErrorName =
SDDS_Realloc(yErrorName,
sizeof(*yErrorName) * (yNames + 1));
171 yName[yNames] = scanned[iArg].list[1];
172 if (scanned[iArg].n_items == 3) {
174 yErrorName[yNames] = scanned[iArg].list[2];
176 yErrorName[yNames] = NULL;
180 if (scanned[iArg].n_items < 2)
182 moveToStringArray(&yExcludeName, &yExcludeNames, scanned[iArg].list + 1, scanned[iArg].n_items - 1);
187 if (scanned[iArg].n_items != 2)
189 xName = scanned[iArg].list[1];
192 case CLO_MAINTEMPLATE:
193 if (scanned[iArg].n_items < 2)
194 SDDS_Bomb(
"invalid -mainTemplate syntax");
195 scanned[iArg].n_items--;
196 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))
197 SDDS_Bomb(
"invalid -mainTemplate syntax");
199 case CLO_ERRORTEMPLATE:
200 if (scanned[iArg].n_items < 2)
201 SDDS_Bomb(
"invalid -errorTemplate syntax");
202 scanned[iArg].n_items--;
203 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))
204 SDDS_Bomb(
"invalid -errorTemplate syntax");
207 if (!
processPipeOption(scanned[iArg].list + 1, scanned[iArg].n_items - 1, &pipeFlags))
211 if (scanned[iArg].n_items != 2 || sscanf(scanned[iArg].list[1],
"%" SCNd32, &interval) != 1 || interval <= 0)
212 SDDS_Bomb(
"invalid -interval syntax/value");
215 case CLO_SAVITZKYGOLAY:
216 if ((scanned[iArg].n_items != 4 && scanned[iArg].n_items != 5) ||
217 sscanf(scanned[iArg].list[1],
"%ld", &SGLeft) != 1 ||
218 sscanf(scanned[iArg].list[2],
"%ld", &SGRight) != 1 ||
219 sscanf(scanned[iArg].list[3],
"%ld", &SGOrder) != 1 ||
220 (scanned[iArg].n_items == 5 && sscanf(scanned[iArg].list[4],
"%ld", &SGDerivOrder) != 1) ||
223 (SGLeft + SGRight) < SGOrder ||
226 SDDS_Bomb(
"invalid -SavitzkyGolay syntax/values");
229 fprintf(stderr,
"invalid option seen: %s\n", scanned[iArg].list[0]);
235 input = scanned[iArg].list[0];
237 output = scanned[iArg].list[0];
243 if (intervalGiven && SGOrder >= 0)
244 SDDS_Bomb(
"-interval and -SavitzkyGolay options are incompatible");
245 if (SGOrder >= 0 && (xErrorName || yErrorsSeen))
246 SDDS_Bomb(
"Savitzky-Golay method does not support errors in data");
251 SDDS_Bomb(
"-differentiate option must be given at least once");
252 if (!checkErrorNames(yErrorName, yNames))
253 SDDS_Bomb(
"either all -differentiate quantities must have errors, or none");
257 if (!(ptr =
SDDS_FindColumn(&SDDSin, FIND_NUMERIC_TYPE, xName, NULL))) {
258 fprintf(stderr,
"error: column %s doesn't exist\n", xName);
264 if (!(ptr =
SDDS_FindColumn(&SDDSin, FIND_NUMERIC_TYPE, xErrorName, NULL))) {
265 fprintf(stderr,
"error: column %s doesn't exist\n", xErrorName);
273 if (!(yNames = expandColumnPairNames(&SDDSin, &yName, &yErrorName, yNames, yExcludeName, yExcludeNames, FIND_NUMERIC_TYPE, 0))) {
274 fprintf(stderr,
"error: no quantities to differentiate found in file\n");
278 setupOutputFile(&SDDSout, &SDDSin, output, &yOutputName, &yOutputErrorName, &yOutputUnits, xName, xErrorName, yName, yErrorName, yNames, mainTemplate, errorTemplate, interval, SGOrder >= 0 ? SGDerivOrder : 1, columnMajorOrder);
282 SDDS_Bomb(
"Can't compute derivatives: too little data.");
283 derivative =
SDDS_Realloc(derivative,
sizeof(*derivative) * rows);
284 derivativeError =
SDDS_Realloc(derivativeError,
sizeof(*derivativeError) * rows);
285 derivativePosition =
SDDS_Realloc(derivativePosition,
sizeof(*derivativePosition) * rows);
292 for (i = 0; i < yNames; i++) {
298 takeSGDerivative(xData, yData, rows, derivative, derivativePosition, SGLeft, SGRight, SGOrder, SGDerivOrder);
300 takeDerivative(xData, yData, yError, rows, derivative, derivativeError, derivativePosition, interval);
302 (yOutputErrorName && yOutputErrorName[i] && !
SDDS_SetColumnFromDoubles(&SDDSout, SDDS_BY_NAME, derivativeError, rows, yOutputErrorName[i])))
308 yData = yError = NULL;
319 xData = xError = NULL;
328 free(derivativeError);
329 if (derivativePosition)
330 free(derivativePosition);
334void takeSGDerivative(
double *x,
double *y, int64_t rows,
double *deriv,
double *derivPosition,
long left,
long right,
long sgOrder,
long derivOrder) {
338 spacing = (x[rows - 1] - x[0]) / (rows - 1);
340 for (i = 0; i < rows; i++) {
341 derivPosition[i] = x[i];
342 deriv[i] = df * y[i];
347void takeDerivative(
double *x,
double *y,
double *sy, int64_t rows,
double *deriv,
double *derivSigma,
double *derivPosition,
long interval) {
352 for (i = 0; i < rows; i++) {
353 if (findDerivIndices(&i1, &i2, interval, i, rows) && (dx = x[i2] - x[i1])) {
354 deriv[i] = (y[i2] - y[i1]) / dx;
355 derivSigma[i] = sqrt(sqr(sy[i1]) + sqr(sy[i2])) / fabs(dx);
356 derivPosition[i] = (x[i2] + x[i1]) / 2;
358 deriv[i] = derivSigma[i] = derivPosition[i] = DBL_MAX;
361 for (i = 0; i < rows; i++) {
362 if (findDerivIndices(&i1, &i2, interval, i, rows) && (dx = x[i2] - x[i1])) {
363 deriv[i] = (y[i2] - y[i1]) / dx;
364 derivPosition[i] = (x[i2] + x[i1]) / 2;
366 deriv[i] = derivPosition[i] = DBL_MAX;
371long findDerivIndices(int64_t *i1, int64_t *i2,
long interval, int64_t i, int64_t rows) {
372 int64_t index, rows1;
375 *i1 = index = i - interval / 2;
385 *i2 = i + interval / 2;
402 if (*i2 < rows && *i1 >= 0)
408 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) {
410 char *xSymbol, *ySymbol;
411 char *mainTemplate[3] = {
"%yNameDeriv",
"Derivative w.r.t. %xSymbol of %ySymbol",
"d[%ySymbol]/d[%xSymbol]"};
412 char *errorTemplate[3] = {
"%yNameDerivSigma",
"Sigma of derivative w.r.t. %xSymbol of %ySymbol",
413 "Sigma[d[%ySymbol]/d[%xSymbol]]"};
416 for (i = 0; i < 3; i++) {
417 if (!mainTemplate0[i]) {
422 snprintf(buffer,
sizeof(buffer),
"%%yNameDeriv%ld", order);
426 snprintf(buffer,
sizeof(buffer),
"Derivative %ld w.r.t. %%xSymbol of %%ySymbol", order);
430 snprintf(buffer,
sizeof(buffer),
"d[%s%ld]/d[%s]",
"ySymbol", order,
"xSymbol");
433 cp_str(&mainTemplate[i], buffer);
436 mainTemplate[i] = mainTemplate0[i];
438 if (errorTemplate0[i]) {
439 errorTemplate[i] = errorTemplate0[i];
443 *yOutputName =
tmalloc(
sizeof(**yOutputName) * yNames);
444 *yOutputErrorName =
tmalloc(
sizeof(**yOutputErrorName) * yNames);
445 *yOutputUnits =
tmalloc(
sizeof(**yOutputUnits) * yNames);
453 fprintf(stderr,
"error: problem getting symbol for column %s\n", xName);
458 for (i = 0; i < yNames; i++) {
460 fprintf(stderr,
"error: problem transferring definition for column %s\n", yName[i]);
464 fprintf(stderr,
"error: problem getting symbol for column %s\n", yName[i]);
469 (*yOutputUnits)[i] = divideColumnUnits(SDDSout, yName[i], xName);
470 (*yOutputName)[i] = changeInformation(SDDSout, yName[i], yName[i], ySymbol, xName, xSymbol, mainTemplate, (*yOutputUnits)[i]);
471 if (yErrorName || xErrorName) {
472 if (yErrorName && yErrorName[i]) {
474 fprintf(stderr,
"error: problem transferring definition for column %s\n", yErrorName[i]);
477 (*yOutputErrorName)[i] = changeInformation(SDDSout, yErrorName[i], yName[i], ySymbol, xName, xSymbol, errorTemplate, (*yOutputUnits)[i]);
480 fprintf(stderr,
"error: problem transferring error definition for column %s\n", yName[i]);
483 (*yOutputErrorName)[i] = changeInformation(SDDSout, yName[i], yName[i], ySymbol, xName, xSymbol, errorTemplate, (*yOutputUnits)[i]);
486 (*yOutputErrorName)[i] = NULL;
489 if (columnMajorOrder != -1)
490 SDDSout->layout.data_mode.column_major = columnMajorOrder;
492 SDDSout->layout.data_mode.column_major = SDDSin->layout.data_mode.column_major;
499char *changeInformation(
SDDS_DATASET *SDDSout,
char *name,
char *nameRoot,
char *symbolRoot,
char *xName,
char *xSymbol,
char **
template,
char *newUnits) {
500 char buffer1[SDDS_MAXLINE], buffer2[SDDS_MAXLINE], *ptr;
505 makeSubstitutions(buffer1, buffer2,
template[2], nameRoot, symbolRoot, xName, xSymbol);
509 makeSubstitutions(buffer1, buffer2,
template[1], nameRoot, symbolRoot, xName, xSymbol);
513 makeSubstitutions(buffer1, buffer2,
template[0], nameRoot, symbolRoot, xName, xSymbol);
520void makeSubstitutions(
char *buffer1,
char *buffer2,
char *
template,
char *nameRoot,
char *symbolRoot,
char *xName,
char *xSymbol) {
521 strcpy(buffer2,
template);
526 strcpy(buffer1, buffer2);
529long checkErrorNames(
char **yErrorName,
long yNames) {
532 for (i = 1; i < yNames; i++)
536 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.
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.