138 {
139 double *xData = NULL, *yData = NULL, *xError = NULL, *yError = NULL, *integral = NULL, *integralError = NULL;
140 char *input = NULL, *output = NULL, *xName = NULL, *xErrorName = NULL;
141 char **yName = NULL, **yErrorName = NULL, **yOutputName = NULL, **yOutputErrorName = NULL, *ptr = NULL, **colMatch = NULL;
142 char **yOutputUnits = NULL, **yExcludeName = NULL;
143 char *mainTemplate[3] = {"%yNameInteg", "Integral w.r.t. %xSymbol of %ySymbol", "$sI$e %ySymbol d%xSymbol"};
144 char *errorTemplate[3] = {"%yNameIntegSigma", "Sigma of integral w.r.t. %xSymbol of %ySymbol",
145 "Sigma[$sI$e %ySymbol d%xSymbol]"};
146 char *GMErrorTemplate[3] = {"%yNameIntegError", "Error estimate for integral w.r.t. %xSymbol of %ySymbol",
147 "Error[$sI$e %ySymbol d%xSymbol]"};
148 long i, iArg, yNames = 0, yExcludeNames = 0;
149 int32_t colMatches = 0;
150 int64_t rows;
152 SCANNED_ARG *scanned = NULL;
153 unsigned long flags = 0, pipeFlags = 0, printFlags = 0, majorOrderFlag = 0;
154 FILE *fpPrint = stderr;
155 char *printFormat = "%21.15e";
156 int methodCode = TRAPAZOID_METHOD;
157 short columnMajorOrder = -1;
158
160
161 argc =
scanargs(&scanned, argc, argv);
162 if (argc == 1) {
163 fprintf(stderr, "%s\n", USAGE);
164 return EXIT_FAILURE;
165 }
166
167 colMatch = NULL;
168 colMatches = 0;
169 input = output = xName = xErrorName = NULL;
170 yName = yErrorName = yExcludeName = NULL;
171 integral = integralError = yError = yData = xData = xError = NULL;
172 yNames = yExcludeNames = 0;
173 pipeFlags = printFlags = 0;
174 fpPrint = stderr;
175 printFormat = "%21.15e";
176 methodCode = TRAPAZOID_METHOD;
177
178 for (iArg = 1; iArg < argc; iArg++) {
179 if (scanned[iArg].arg_type == OPTION) {
180
181 switch (
match_string(scanned[iArg].list[0], option, N_OPTIONS, 0)) {
182 case CLO_MAJOR_ORDER:
183 majorOrderFlag = 0;
184 scanned[iArg].n_items--;
185 if (scanned[iArg].n_items > 0 &&
186 !
scanItemList(&majorOrderFlag, scanned[iArg].list + 1, &scanned[iArg].n_items, 0,
187 "row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
188 "column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL)) {
189 SDDS_Bomb(
"invalid -majorOrder syntax/values");
190 }
191 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
192 columnMajorOrder = 1;
193 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
194 columnMajorOrder = 0;
195 break;
196 case CLO_INTEGRATE:
197 if (scanned[iArg].n_items != 2 && scanned[iArg].n_items != 3)
199 yName =
SDDS_Realloc(yName,
sizeof(*yName) * (yNames + 1));
200 yErrorName =
SDDS_Realloc(yErrorName,
sizeof(*yErrorName) * (yNames + 1));
201 yName[yNames] = scanned[iArg].list[1];
202 if (scanned[iArg].n_items == 3)
203 yErrorName[yNames] = scanned[iArg].list[2];
204 else
205 yErrorName[yNames] = NULL;
206 yNames++;
207 break;
208 case CLO_EXCLUDE:
209 if (scanned[iArg].n_items < 2)
211 moveToStringArray(&yExcludeName, &yExcludeNames, scanned[iArg].list + 1, scanned[iArg].n_items - 1);
212 break;
213 case CLO_VERSUS:
214 if (xName)
216 if (scanned[iArg].n_items != 2 && scanned[iArg].n_items != 3)
218 xName = scanned[iArg].list[1];
219 if (scanned[iArg].n_items == 3)
220 xErrorName = scanned[iArg].list[2];
221 else
222 xErrorName = NULL;
223 break;
224 case CLO_METHOD:
225 if (scanned[iArg].n_items != 2 ||
226 (methodCode =
match_string(scanned[iArg].list[1], methodOption, N_METHODS, 0)) < 0)
228 break;
229 case CLO_PRINTFINAL:
230 if ((scanned[iArg].n_items -= 1) >= 1) {
231 if (!
scanItemList(&printFlags, scanned[iArg].list + 1, &scanned[iArg].n_items, 0,
232 "bare", -1, NULL, 0, BARE_PRINTOUT,
233 "stdout", -1, NULL, 0, STDOUT_PRINTOUT,
234 "format",
SDDS_STRING, &printFormat, 1, 0, NULL)) {
236 }
237 }
238 if (!(printFlags & BARE_PRINTOUT))
239 printFlags |= NORMAL_PRINTOUT;
240 break;
241 case CLO_MAINTEMPLATE:
242 if (scanned[iArg].n_items < 2)
243 SDDS_Bomb(
"invalid -mainTemplate syntax");
244 scanned[iArg].n_items--;
245 if (!
scanItemList(&flags, scanned[iArg].list + 1, &scanned[iArg].n_items, 0,
247 "description",
SDDS_STRING, mainTemplate + 1, 1, 0,
248 "symbol",
SDDS_STRING, mainTemplate + 2, 1, 0, NULL)) {
249 SDDS_Bomb(
"invalid -mainTemplate syntax");
250 }
251 break;
252 case CLO_ERRORTEMPLATE:
253 if (scanned[iArg].n_items < 2)
254 SDDS_Bomb(
"invalid -errorTemplate syntax");
255 scanned[iArg].n_items--;
256 if (!
scanItemList(&flags, scanned[iArg].list + 1, &scanned[iArg].n_items, 0,
258 "description",
SDDS_STRING, errorTemplate + 1, 1, 0,
259 "symbol",
SDDS_STRING, errorTemplate + 2, 1, 0, NULL)) {
260 SDDS_Bomb(
"invalid -errorTemplate syntax");
261 }
262 break;
263 case CLO_PIPE:
264 if (!
processPipeOption(scanned[iArg].list + 1, scanned[iArg].n_items - 1, &pipeFlags))
266 break;
267 case CLO_COPY:
268 if (scanned[iArg].n_items < 2)
269 SDDS_Bomb(
"Invalid copycolumns syntax provided.");
270 colMatch =
tmalloc(
sizeof(*colMatch) * (colMatches = scanned[iArg].n_items - 1));
271 for (i = 0; i < colMatches; i++)
272 colMatch[i] = scanned[iArg].list[i + 1];
273 break;
274 default:
275 fprintf(stderr, "invalid option seen: %s\n", scanned[iArg].list[0]);
276 return EXIT_FAILURE;
277 }
278 } else {
279 if (!input)
280 input = scanned[iArg].list[0];
281 else if (!output)
282 output = scanned[iArg].list[0];
283 else
285 }
286 }
287
289
290 if (methodCode != TRAPAZOID_METHOD) {
291 xErrorName = NULL;
292 for (i = 0; i < yNames; i++)
293 yErrorName[i] = NULL;
294 }
295
296 if (printFlags & STDOUT_PRINTOUT)
297 fpPrint = stdout;
298
299 if (yNames == 0)
300 SDDS_Bomb(
"-integrate option must be given at least once");
301 if (!checkErrorNames(yErrorName, yNames))
302 SDDS_Bomb(
"either all -integrate quantities must have errors, or none");
303
306
307 if (!(ptr =
SDDS_FindColumn(&SDDSin, FIND_NUMERIC_TYPE, xName, NULL))) {
308 fprintf(stderr, "error: column %s doesn't exist\n", xName);
309 return EXIT_FAILURE;
310 }
311 free(xName);
312 xName = ptr;
313
314 if (xErrorName) {
315 if (!(ptr =
SDDS_FindColumn(&SDDSin, FIND_NUMERIC_TYPE, xErrorName, NULL))) {
316 fprintf(stderr, "error: column %s doesn't exist\n", xErrorName);
317 return EXIT_FAILURE;
318 } else {
319 free(xErrorName);
320 xErrorName = ptr;
321 }
322 }
323
324 if (!(yNames = expandColumnPairNames(&SDDSin, &yName, &yErrorName, yNames, yExcludeName, yExcludeNames, FIND_NUMERIC_TYPE, 0))) {
325 fprintf(stderr, "error: no quantities to integrate found in file\n");
326 return EXIT_FAILURE;
327 }
328
329 if (!setupOutputFile(&SDDSout, &SDDSin, output, &yOutputName, &yOutputErrorName, &yOutputUnits,
330 xName, xErrorName, yName, yErrorName, yNames,
331 mainTemplate, (methodCode == GILLMILLER_METHOD) ? (char **)GMErrorTemplate : (char **)errorTemplate,
332 methodCode, columnMajorOrder, colMatch, colMatches)) {
333 SDDS_Bomb(
"Failed to set up output file.");
334 }
335
338 integral =
SDDS_Realloc(integral,
sizeof(*integral) * rows);
339 integralError =
SDDS_Realloc(integralError,
sizeof(*integralError) * rows);
343
344 xError = NULL;
348
352
353 for (i = 0; i < yNames; i++) {
354 yError = NULL;
356 (yErrorName && yErrorName[i] &&
359
360 switch (methodCode) {
361 case TRAPAZOID_METHOD:
362 trapizoid(xData, yData, xError, yError, rows, integral, integralError);
363 break;
364 case GILLMILLER_METHOD:
366 SDDS_Bomb(
"Problem with integration: check for monotonically changing independent variable values");
367 break;
368 }
369
371 (yOutputErrorName && yOutputErrorName[i] &&
374
375 if (printFlags & BARE_PRINTOUT) {
376 fprintf(fpPrint, printFormat, integral[rows - 1]);
377 if (xError || yError || (yOutputErrorName && yOutputErrorName[i])) {
378 fputc(' ', fpPrint);
379 fprintf(fpPrint, printFormat, integralError[rows - 1]);
380 }
381 fputc('\n', fpPrint);
382 } else if (printFlags & NORMAL_PRINTOUT) {
383 fprintf(fpPrint, "%s: ", yName[i]);
384 fprintf(fpPrint, printFormat, integral[rows - 1]);
385 if (xError || yError || (yOutputErrorName && yOutputErrorName[i])) {
386 fputs(" +/- ", fpPrint);
387 fprintf(fpPrint, printFormat, integralError[rows - 1]);
388 fputs(yOutputUnits[i], fpPrint);
389 }
390 fputc('\n', fpPrint);
391 }
392
393 if (yData)
394 free(yData);
395 if (yError)
396 free(yError);
397 yData = yError = NULL;
398 }
399
402
403 if (xData)
404 free(xData);
405 if (xError)
406 free(xError);
407 xData = xError = NULL;
408 }
409
412 return EXIT_FAILURE;
413 }
414
415 if (integral)
416 free(integral);
417 if (integralError)
418 free(integralError);
419 if (colMatch)
420 free(colMatch);
421
422 return EXIT_SUCCESS;
423}
int GillMillerIntegration(double *integral, double *error, double *f, double *x, long n)
Performs numerical integration using the Gill-Miller method.
int32_t SDDS_CopyPage(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 * tmalloc(uint64_t size_of_block)
Allocates a memory block of the specified size with zero initialization.
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.