127 {
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;
134 int64_t rows;
135 int32_t interval;
137 SCANNED_ARG *scanned;
138 unsigned long flags, pipeFlags, majorOrderFlag;
139 long SGLeft, SGRight, SGOrder, SGDerivOrder, intervalGiven, yErrorsSeen;
140 short columnMajorOrder = -1;
141
143
144 argc =
scanargs(&scanned, argc, argv);
145 if (argc == 1)
147
148 input = output = xName = xErrorName = NULL;
149 yName = yErrorName = yExcludeName = NULL;
150 derivative = derivativeError = derivativePosition = yError = yData = xData = xError = NULL;
151 yNames = yExcludeNames = 0;
152 pipeFlags = 0;
153 interval = 2;
154 SGOrder = -1;
155 SGDerivOrder = 1;
156 intervalGiven = 0;
157 yErrorsSeen = 0;
158
159 for (iArg = 1; iArg < argc; iArg++) {
160 if (scanned[iArg].arg_type == OPTION) {
161
162 switch (
match_string(scanned[iArg].list[0], option, N_OPTIONS, 0)) {
163 case CLO_MAJOR_ORDER:
164 majorOrderFlag = 0;
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;
172 break;
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) {
180 yErrorsSeen = 1;
181 yErrorName[yNames] = scanned[iArg].list[2];
182 } else
183 yErrorName[yNames] = NULL;
184 yNames++;
185 break;
186 case CLO_EXCLUDE:
187 if (scanned[iArg].n_items < 2)
189 moveToStringArray(&yExcludeName, &yExcludeNames, scanned[iArg].list + 1, scanned[iArg].n_items - 1);
190 break;
191 case CLO_VERSUS:
192 if (xName)
194 if (scanned[iArg].n_items != 2)
196 xName = scanned[iArg].list[1];
197 xErrorName = NULL;
198 break;
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");
205 break;
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");
212 break;
213 case CLO_PIPE:
214 if (!
processPipeOption(scanned[iArg].list + 1, scanned[iArg].n_items - 1, &pipeFlags))
216 break;
217 case CLO_INTERVAL:
218 if (scanned[iArg].n_items != 2 || sscanf(scanned[iArg].list[1], "%" SCNd32, &interval) != 1 || interval <= 0)
219 SDDS_Bomb(
"invalid -interval syntax/value");
220 intervalGiven = 1;
221 break;
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) ||
228 SGLeft < 0 ||
229 SGRight < 0 ||
230 (SGLeft + SGRight) < SGOrder ||
231 SGOrder < 0 ||
232 SGDerivOrder < 0)
233 SDDS_Bomb(
"invalid -SavitzkyGolay syntax/values");
234 break;
235 default:
236 fprintf(stderr, "invalid option seen: %s\n", scanned[iArg].list[0]);
237 exit(EXIT_FAILURE);
238 break;
239 }
240 } else {
241 if (!input)
242 input = scanned[iArg].list[0];
243 else if (!output)
244 output = scanned[iArg].list[0];
245 else
247 }
248 }
249
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");
254
256
257 if (!yNames)
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");
261
264 if (!(ptr =
SDDS_FindColumn(&SDDSin, FIND_NUMERIC_TYPE, xName, NULL))) {
265 fprintf(stderr, "error: column %s doesn't exist\n", xName);
266 exit(EXIT_FAILURE);
267 }
268 free(xName);
269 xName = ptr;
270 if (xErrorName) {
271 if (!(ptr =
SDDS_FindColumn(&SDDSin, FIND_NUMERIC_TYPE, xErrorName, NULL))) {
272 fprintf(stderr, "error: column %s doesn't exist\n", xErrorName);
273 exit(EXIT_FAILURE);
274 } else {
275 free(xErrorName);
276 xErrorName = ptr;
277 }
278 }
279
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");
282 exit(EXIT_FAILURE);
283 }
284
285 setupOutputFile(&SDDSout, &SDDSin, output, &yOutputName, &yOutputErrorName, &yOutputUnits, xName, xErrorName, yName, yErrorName, yNames, mainTemplate, errorTemplate, interval, SGOrder >= 0 ? SGDerivOrder : 1, columnMajorOrder);
286
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);
295 xError = NULL;
299 for (i = 0; i < yNames; i++) {
300 yError = NULL;
304 if (SGOrder >= 0)
305 takeSGDerivative(xData, yData, rows, derivative, derivativePosition, SGLeft, SGRight, SGOrder, SGDerivOrder);
306 else
307 takeDerivative(xData, yData, yError, rows, derivative, derivativeError, derivativePosition, interval);
309 (yOutputErrorName && yOutputErrorName[i] && !
SDDS_SetColumnFromDoubles(&SDDSout, SDDS_BY_NAME, derivativeError, rows, yOutputErrorName[i])))
311 if (yData)
312 free(yData);
313 if (yError)
314 free(yError);
315 yData = yError = NULL;
316 }
322 if (xData)
323 free(xData);
324 if (xError)
325 free(xError);
326 xData = xError = NULL;
327 }
330 exit(EXIT_FAILURE);
331 }
332 if (derivative)
333 free(derivative);
334 if (derivativeError)
335 free(derivativeError);
336 if (derivativePosition)
337 free(derivativePosition);
338 return EXIT_SUCCESS;
339}
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_WritePage(SDDS_DATASET *SDDS_dataset)
Writes the current data table to the output file.
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
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.
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.
void bomb(char *error, char *usage)
Reports error messages to the terminal and aborts the program.
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.