SDDS ToolKit Programs and Libraries for C and Python
Loading...
Searching...
No Matches
sddsrunstats.c
Go to the documentation of this file.
1/**
2 * @file sddsrunstats.c
3 * @brief Computes running statistics on SDDS data columns.
4 *
5 * @details
6 * This program calculates various running statistics (e.g., mean, median, minimum, maximum, etc.)
7 * on columns of data from an SDDS (Self-Describing Data Set) file. The program supports multiple
8 * options for statistical analysis and allows for processing of sliding window or blocked statistics.
9 *
10 * @section Usage
11 * ```
12 * sddsrunstats [<input>] [<output>]
13 * [-pipe[=input][,output]]
14 * [-points=<integer>]
15 * [-window=column=<column>,width=<value>}]
16 * [-noOverlap]
17 * [-partialOk]
18 * [-mean=[<limitOps>],<columnNameList>]
19 * [-median=[<limitOps>],<columnNameList>]
20 * [-minimum=[<limitOps>],<columnNameList>]
21 * [-maximum=[<limitOps>],<columnNameList>]
22 * [-standardDeviation=[<limitOps>],<columnNameList>]
23 * [-sigma=[<limitOps>],<columnNameList>]
24 * [-sum=[<limitOps>][,power=<integer>],<columnNameList>]
25 * [-sample=[<limitOps>],<columnNameList>]
26 * [-slope=independent=<columnName>,<columnNameList>]
27 * [-majorOrder=row|column]
28 * [-threads=<number>]
29 *
30 * <limitOps> is of the form [topLimit=<value>,][bottomLimit=<value>]
31 * ```
32 *
33 * @section Options
34 * | Option | Description |
35 * |------------------------------|-----------------------------------------------------------------------------|
36 * | `-pipe` | Use standard input and/or output streams. |
37 * | `-points` | Number of points for running statistics. Use `0` for entire page statistics.|
38 * | `-window` | Defines a sliding window based on a column and window width. |
39 * | `-noOverlap` | Perform blocked statistics instead of sliding window statistics. |
40 * | `-partialOk` | Allow computations even if available rows are fewer than specified points. |
41 * | `-mean` | Compute mean of specified columns with optional limits. |
42 * | `-median` | Compute median of specified columns with optional limits. |
43 * | `-minimum` | Compute minimum of specified columns with optional limits. |
44 * | `-maximum` | Compute maximum of specified columns with optional limits. |
45 * | `-standardDeviation` | Compute standard deviation with optional limits. |
46 * | `-sigma` | Compute sigma of specified columns with optional limits. |
47 * | `-sum` | Compute sum (optionally raised to a power) with optional limits. |
48 * | `-sample` | Sample values from specified columns with optional limits. |
49 * | `-slope` | Compute slope of specified columns with a designated independent column. |
50 * | `-majorOrder` | Specify the major order for data processing. |
51 * | `-threads` | Number of threads for per-column running-statistic calculations. |
52 *
53 * @subsection Incompatibilities
54 * - Only one of the following may be specified:
55 * - `-points`
56 * - `-window`
57 *
58 * @copyright
59 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
60 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
61 *
62 * @license
63 * This file is distributed under the terms of the Software License Agreement
64 * found in the file LICENSE included with this distribution.
65 *
66 * @authors
67 * M. Borland,
68 * R. Soliday,
69 * H. Shang
70 */
71
72
73#include "mdb.h"
74#include "scan.h"
75#include "SDDS.h"
76#include "SDDSutils.h"
77#include <ctype.h>
78
79/* if statistics are added, they must be added before the SET_POINTS
80 item in this list and the following options array
81*/
82/* Enumeration for option types */
83enum option_type {
84 SET_MAXIMUM,
85 SET_MINIMUM,
86 SET_MEAN,
87 SET_STANDARDDEVIATION,
88 SET_RMS,
89 SET_SUM,
90 SET_SIGMA,
91 SET_SAMPLE,
92 SET_MEDIAN,
93 SET_SLOPE,
94 SET_POINTS,
95 SET_NOOVERLAP,
96 SET_PIPE,
97 SET_WINDOW,
98 SET_PARTIALOK,
99 SET_MAJOR_ORDER,
100 SET_THREADS,
101 N_OPTIONS
102};
103
104char *option[N_OPTIONS] = {
105 "maximum",
106 "minimum",
107 "mean",
108 "standarddeviation",
109 "rms",
110 "sum",
111 "sigma",
112 "sample",
113 "median",
114 "slope",
115 "points",
116 "nooverlap",
117 "pipe",
118 "window",
119 "partialok",
120 "majorOrder",
121 "threads",
122};
123
124#define N_STATS 10
125/* option[0-9] and statSuffix[0-9] arrays have to line up */
126char *statSuffix[N_STATS] = {
127 "Max",
128 "Min",
129 "Mean",
130 "StDev",
131 "RMS",
132 "Sum",
133 "Sigma",
134 "",
135 "Median",
136 "Slope"
137};
138
139#define TOPLIMIT_GIVEN 0x0001U
140#define BOTTOMLIMIT_GIVEN 0x0002U
141#define INDEPENDENT_GIVEN 0x0004U
142
143/* this structure stores a command-line request for statistics computation */
144/* individual elements of sourceColumn may contain wildcards */
145typedef struct
146{
147 char **sourceColumn, *independentColumn;
148 long sourceColumns, sumPower, optionCode;
149 unsigned long flags;
150 double topLimit, bottomLimit;
152
153/* this structure stores data necessary for accessing/creating SDDS columns and
154 * for computing a statistic
155 */
156typedef struct
157{
158 char **sourceColumn, **resultColumn, *independentColumn;
159 long sourceColumns, optionCode, *resultIndex, sumPower;
160 unsigned long flags;
161 double topLimit, bottomLimit;
163
164long addStatRequests(STAT_REQUEST **statRequest, long requests, char **item, long items, long code, unsigned long flag);
165STAT_DEFINITION *compileStatDefinitions(SDDS_DATASET *inTable, STAT_REQUEST *request, long requests);
166long setupOutputFile(SDDS_DATASET *outTable, char *output, SDDS_DATASET *inTable, STAT_DEFINITION *stat, long stats, short columnMajorOrder);
167static double computeRunningStatistic(STAT_DEFINITION *stat, double *inputDataOffset, double *indepDataOffset, int64_t pointsToStat);
168
169static char *USAGE =
170 "sddsrunstats [<input>] [<output>] [-pipe[=input][,output]]\n"
171 " [{-points=<integer> | -window=column=<column>,width=<value>}]\n"
172 " [-noOverlap]\n"
173 " [-partialOk]\n"
174 " [-mean=[<limitOps>],<columnNameList>]\n"
175 " [-median=[<limitOps>],<columnNameList>]\n"
176 " [-minimum=[<limitOps>],<columnNameList>]\n"
177 " [-maximum=[<limitOps>],<columnNameList>]\n"
178 " [-standardDeviation=[<limitOps>],<columnNameList>]\n"
179 " [-sigma=[<limitOps>],<columnNameList>]\n"
180 " [-sum=[<limitOps>][,power=<integer>],<columnNameList>]\n"
181 " [-sample=[<limitOps>],<columnNameList>]\n"
182 " [-slope=independent=<columnName>,<columnNameList>]\n"
183 " [-threads=<number>]\n"
184 "\n"
185 " <limitOps> is of the form [topLimit=<value>,][bottomLimit=<value>] [-majorOrder=row|column]\n\n"
186 "Computes running statistics of columns of data. The <columnNameList> may contain\n"
187 "wildcards, in which case an additional output column is produced for every matching\n"
188 "column. By default, statistics are done with a sliding window, so the values are\n"
189 "running statistics; for blocked statistics, use -noOverlap. For statistics on\n"
190 "the entire page, use -points=0.\n"
191 "The -partialOk option tells sddsrunstats to do computations even\n"
192 "if the number of available rows is less than the number of points\n"
193 "specified; by default, such data is simply ignored.\n"
194 "The -threads option controls parallel per-column running-statistic calculations.\n"
195 "Input and output SDDS operations are performed serially. The default is 1.\n"
196 "Program by Michael Borland. (" __DATE__ " " __TIME__ ", SVN revision: " SVN_VERSION ")\n";
197
198int main(int argc, char **argv) {
199 STAT_DEFINITION *stat;
200 long stats;
201 STAT_REQUEST *request;
202 long requests;
203 SCANNED_ARG *scanned;
204 SDDS_DATASET inData, outData;
205 char *independent;
206 int32_t power;
207 int64_t pointsToStat;
208 long pointsToStat0, overlap;
209 int64_t rows, outputRowsMax, outputRows, outputRow;
210 long iArg, code, iStat, iColumn;
211 int64_t startRow, rowsToSet;
212 char *input, *output, *windowColumn;
213 double *inputData, *outputData, topLimit, bottomLimit, *inputDataOffset;
214 double windowWidth, *windowData;
215 long windowIndex;
216 unsigned long pipeFlags, scanFlags, majorOrderFlag;
217 char s[100];
218 long lastRegion, region, windowRef, partialOk;
219 short columnMajorOrder = -1;
220 int threads = 1;
221
223 argc = scanargs(&scanned, argc, argv);
224 if (argc < 2) {
225 bomb("too few arguments", USAGE);
226 }
227 input = output = NULL;
228 stat = NULL;
229 request = NULL;
230 stats = requests = pipeFlags = 0;
231 pointsToStat = -1;
232 partialOk = 0;
233 overlap = 1;
234 windowColumn = NULL;
235 windowData = NULL;
236
237 for (iArg = 1; iArg < argc; iArg++) {
238 scanFlags = 0;
239 if (scanned[iArg].arg_type == OPTION) {
240 /* process options here */
241 switch (code = match_string(scanned[iArg].list[0], option, N_OPTIONS, 0)) {
242 case SET_MAJOR_ORDER:
243 majorOrderFlag = 0;
244 scanned[iArg].n_items--;
245 if (scanned[iArg].n_items > 0 &&
246 (!scanItemList(&majorOrderFlag, scanned[iArg].list + 1, &scanned[iArg].n_items, 0,
247 "row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
248 "column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL)))
249 SDDS_Bomb("invalid -majorOrder syntax/values");
250 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
251 columnMajorOrder = 1;
252 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
253 columnMajorOrder = 0;
254 break;
255 case SET_THREADS:
256 if (scanned[iArg].n_items != 2 ||
257 sscanf(scanned[iArg].list[1], "%d", &threads) != 1 ||
258 threads < 1)
259 SDDS_Bomb("invalid -threads syntax");
260 break;
261 case SET_POINTS:
262 if (scanned[iArg].n_items != 2 || sscanf(scanned[iArg].list[1], "%" SCNd64, &pointsToStat) != 1 ||
263 (pointsToStat <= 2 && pointsToStat != 0))
264 SDDS_Bomb("invalid -points syntax");
265 break;
266 case SET_NOOVERLAP:
267 overlap = 0;
268 break;
269 case SET_MAXIMUM:
270 case SET_MINIMUM:
271 case SET_MEAN:
272 case SET_STANDARDDEVIATION:
273 case SET_RMS:
274 case SET_SIGMA:
275 case SET_SAMPLE:
276 case SET_MEDIAN:
277 if (scanned[iArg].n_items < 2) {
278 fprintf(stderr, "error: invalid -%s syntax\n", option[code]);
279 exit(EXIT_FAILURE);
280 }
281 if (!scanItemList(&scanFlags, scanned[iArg].list, &scanned[iArg].n_items,
282 SCANITEMLIST_UNKNOWN_VALUE_OK | SCANITEMLIST_REMOVE_USED_ITEMS | SCANITEMLIST_IGNORE_VALUELESS,
283 "toplimit", SDDS_DOUBLE, &topLimit, 1, TOPLIMIT_GIVEN,
284 "bottomlimit", SDDS_DOUBLE, &bottomLimit, 1, BOTTOMLIMIT_GIVEN, NULL)) {
285 sprintf(s, "invalid -%s syntax", scanned[iArg].list[0]);
286 SDDS_Bomb(s);
287 }
288 requests = addStatRequests(&request, requests, scanned[iArg].list + 1, scanned[iArg].n_items - 1, code, scanFlags);
289 request[requests - 1].topLimit = topLimit;
290 request[requests - 1].bottomLimit = bottomLimit;
291 break;
292 case SET_SUM:
293 if (scanned[iArg].n_items < 2) {
294 fprintf(stderr, "error: invalid -%s syntax\n", option[code]);
295 exit(EXIT_FAILURE);
296 }
297 power = 1;
298 if (!scanItemList(&scanFlags, scanned[iArg].list, &scanned[iArg].n_items,
299 SCANITEMLIST_UNKNOWN_VALUE_OK | SCANITEMLIST_REMOVE_USED_ITEMS | SCANITEMLIST_IGNORE_VALUELESS,
300 "power", SDDS_LONG, &power, 1, 0,
301 "toplimit", SDDS_DOUBLE, &topLimit, 1, TOPLIMIT_GIVEN,
302 "bottomlimit", SDDS_DOUBLE, &bottomLimit, 1, BOTTOMLIMIT_GIVEN, NULL))
303 SDDS_Bomb("invalid -sum syntax");
304 requests = addStatRequests(&request, requests, scanned[iArg].list + 1, scanned[iArg].n_items - 1, code, scanFlags);
305 request[requests - 1].sumPower = power;
306 request[requests - 1].topLimit = topLimit;
307 request[requests - 1].bottomLimit = bottomLimit;
308 break;
309 case SET_SLOPE:
310 if (scanned[iArg].n_items < 2) {
311 fprintf(stderr, "error: invalid -%s syntax\n", option[code]);
312 exit(EXIT_FAILURE);
313 }
314 if (!scanItemList(&scanFlags, scanned[iArg].list, &scanned[iArg].n_items,
315 SCANITEMLIST_UNKNOWN_VALUE_OK | SCANITEMLIST_REMOVE_USED_ITEMS | SCANITEMLIST_IGNORE_VALUELESS,
316 "independent", SDDS_STRING, &independent, 1, INDEPENDENT_GIVEN,
317 NULL) ||
318 !(scanFlags & INDEPENDENT_GIVEN))
319 SDDS_Bomb("invalid -slope syntax");
320 requests = addStatRequests(&request, requests, scanned[iArg].list + 1, scanned[iArg].n_items - 1, code, scanFlags);
321 request[requests - 1].independentColumn = independent;
322 request[requests - 1].topLimit = request[requests - 1].bottomLimit = 0;
323 break;
324 case SET_PIPE:
325 if (!processPipeOption(scanned[iArg].list + 1, scanned[iArg].n_items - 1, &pipeFlags))
326 SDDS_Bomb("invalid -pipe syntax");
327 break;
328 case SET_WINDOW:
329 windowWidth = -1;
330 windowColumn = NULL;
331 scanned[iArg].n_items -= 1;
332 if (!scanItemList(&scanFlags, scanned[iArg].list + 1, &scanned[iArg].n_items, 0,
333 "column", SDDS_STRING, &windowColumn, 1, 0,
334 "width", SDDS_DOUBLE, &windowWidth, 1, 0, NULL) ||
335 !windowColumn ||
336 !strlen(windowColumn) ||
337 windowWidth <= 0)
338 SDDS_Bomb("invalid -window syntax/values");
339 break;
340 case SET_PARTIALOK:
341 partialOk = 1;
342 break;
343 default:
344 fprintf(stderr, "error: unknown option '%s' given\n", scanned[iArg].list[0]);
345 exit(EXIT_FAILURE);
346 break;
347 }
348 } else {
349 /* argument is filename */
350 if (!input)
351 input = scanned[iArg].list[0];
352 else if (!output)
353 output = scanned[iArg].list[0];
354 else
355 SDDS_Bomb("too many filenames seen");
356 }
357 }
358
359 if (pointsToStat < 0 && !windowColumn) {
360 pointsToStat = 10;
361 }
362 processFilenames("sddsrunstats", &input, &output, pipeFlags, 0, NULL);
363
364 if (!requests)
365 SDDS_Bomb("no statistics requested");
366
367 if (!SDDS_InitializeInput(&inData, input))
368 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
369
370 if (!(stat = compileStatDefinitions(&inData, request, requests)))
371 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
372 stats = requests;
373#ifdef DEBUG
374 fprintf(stderr, "%ld stats\n", stats);
375 for (iStat = 0; iStat < stats; iStat++) {
376 for (iColumn = 0; iColumn < stat[iStat].sourceColumns; iColumn++) {
377 fprintf(stderr, "iStat=%ld iColumn=%ld source=%s result=%s\n", iStat, iColumn, stat[iStat].sourceColumn[iColumn], stat[iStat].resultColumn[iColumn]);
378 if (stat[iStat].flags & BOTTOMLIMIT_GIVEN)
379 fprintf(stderr, " bottom = %e\n", stat[iStat].bottomLimit);
380 if (stat[iStat].flags & TOPLIMIT_GIVEN)
381 fprintf(stderr, " top = %e\n", stat[iStat].topLimit);
382 }
383 }
384#endif
385
386 if (!setupOutputFile(&outData, output, &inData, stat, stats, columnMajorOrder))
387 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
388
389 if (windowColumn) {
390 if ((windowIndex = SDDS_GetColumnIndex(&inData, windowColumn)) < 0)
391 SDDS_Bomb("Window column not present");
392 if (!SDDS_NUMERIC_TYPE(SDDS_GetColumnType(&inData, windowIndex)))
393 SDDS_Bomb("Window column is not numeric");
394 }
395
396 outputData = NULL;
397 outputRowsMax = 0;
398 pointsToStat0 = pointsToStat;
399 while ((code = SDDS_ReadPage(&inData)) > 0) {
400 rows = SDDS_CountRowsOfInterest(&inData);
401 pointsToStat = pointsToStat0;
402 if (pointsToStat == 0)
403 pointsToStat = rows;
404 if (windowColumn && !(windowData = SDDS_GetColumnInDoubles(&inData, windowColumn))) {
405 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
406 }
407 if (!windowColumn) {
408 if (rows < pointsToStat) {
409 if (partialOk)
410 pointsToStat = rows;
411 else
412 continue;
413 }
414 if (overlap) {
415 outputRows = rows - pointsToStat + 1;
416 } else
417 outputRows = rows / pointsToStat;
418 } else
419 outputRows = rows;
420
421 if (!SDDS_StartPage(&outData, outputRows) ||
422 !SDDS_CopyParameters(&outData, &inData) ||
423 !SDDS_CopyArrays(&outData, &inData))
424 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
425 if (outputRows > outputRowsMax &&
426 !(outputData = SDDS_Realloc(outputData, sizeof(*outputData) * (outputRowsMax = outputRows))))
427 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
428 for (iStat = 0; iStat < stats; iStat++) {
429 for (iColumn = 0; iColumn < stat[iStat].sourceColumns; iColumn++) {
430 double *indepData;
431 lastRegion = 0;
432 windowRef = 0;
433 indepData = NULL;
434 if (!(inputData = SDDS_GetColumnInDoubles(&inData, stat[iStat].sourceColumn[iColumn])))
435 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
436 if (stat[iStat].independentColumn &&
437 !(indepData = SDDS_GetColumnInDoubles(&inData, stat[iStat].independentColumn)))
438 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
439 rowsToSet = outputRows;
440 if (!windowColumn) {
441#pragma omp parallel for private(startRow, inputDataOffset) if (threads > 1 && outputRows > 1) num_threads(threads)
442 for (outputRow = 0; outputRow < outputRows; outputRow++) {
443 startRow = overlap ? outputRow : outputRow * pointsToStat;
444 inputDataOffset = inputData + startRow;
445 outputData[outputRow] = computeRunningStatistic(&stat[iStat], inputDataOffset,
446 indepData ? indepData + startRow : NULL,
447 pointsToStat);
448 }
449 } else {
450 for (outputRow = startRow = 0; outputRow < outputRows; outputRow++, startRow += (overlap ? 1 : pointsToStat)) {
451 short windowFound = 0;
452 if (overlap) {
453 windowRef += 1;
454 lastRegion = 0;
455 }
456 for (pointsToStat = 1; pointsToStat < outputRows - startRow; pointsToStat++) {
457 region = (windowData[startRow + pointsToStat] - windowData[windowRef]) / windowWidth;
458 if (region != lastRegion) {
459 lastRegion = region;
460 windowFound = 1;
461 break;
462 }
463 }
464 if (!windowFound && pointsToStat < 2)
465 break;
466 if (startRow + pointsToStat > rows) {
467 pointsToStat = rows - startRow - 1;
468 if (pointsToStat <= 0)
469 break;
470 }
471#ifdef DEBUG
472 fprintf(stderr, "row=%" PRId64 " pointsToStat=%" PRId64 " delta=%.9lf (%.9lf -> %.9lf)\n", startRow, pointsToStat, windowData[startRow + pointsToStat - 1] - windowData[startRow], windowData[startRow], windowData[startRow + pointsToStat - 1]);
473#endif
474 inputDataOffset = inputData + startRow;
475 outputData[outputRow] = computeRunningStatistic(&stat[iStat], inputDataOffset,
476 indepData ? indepData + startRow : NULL,
477 pointsToStat);
478 }
479 rowsToSet = outputRow;
480 }
481 if (!SDDS_SetColumnFromDoubles(&outData, SDDS_SET_BY_INDEX, outputData, rowsToSet, stat[iStat].resultIndex[iColumn]))
482 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
483 free(inputData);
484 free(indepData);
485 }
486 }
487 if (windowColumn)
488 free(windowData);
489 if (!SDDS_WritePage(&outData))
490 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
491 }
492 if (SDDS_Terminate(&inData) != 1) {
493 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
494 return EXIT_FAILURE;
495 }
496 if (SDDS_Terminate(&outData) != 1) {
497 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
498 return EXIT_FAILURE;
499 }
500 if (outputData)
501 free(outputData);
502 return EXIT_SUCCESS;
503}
504
505static double computeRunningStatistic(STAT_DEFINITION *stat, double *inputDataOffset, double *indepDataOffset, int64_t pointsToStat) {
506 int64_t rowOffset, count;
507 double result, sum1, sum2, slope, intercept, variance;
508 double *newData;
509
510 switch (stat->optionCode) {
511 case SET_MAXIMUM:
512 result = -DBL_MAX;
513 for (rowOffset = 0; rowOffset < pointsToStat; rowOffset++) {
514 if ((stat->flags & TOPLIMIT_GIVEN && inputDataOffset[rowOffset] > stat->topLimit) ||
515 (stat->flags & BOTTOMLIMIT_GIVEN && inputDataOffset[rowOffset] < stat->bottomLimit))
516 continue;
517 if (inputDataOffset[rowOffset] > result)
518 result = inputDataOffset[rowOffset];
519 }
520 break;
521 case SET_MINIMUM:
522 result = DBL_MAX;
523 for (rowOffset = 0; rowOffset < pointsToStat; rowOffset++) {
524 if ((stat->flags & TOPLIMIT_GIVEN && inputDataOffset[rowOffset] > stat->topLimit) ||
525 (stat->flags & BOTTOMLIMIT_GIVEN && inputDataOffset[rowOffset] < stat->bottomLimit))
526 continue;
527 if (inputDataOffset[rowOffset] < result)
528 result = inputDataOffset[rowOffset];
529 }
530 break;
531 case SET_MEAN:
532 result = 0;
533 count = 0;
534 for (rowOffset = 0; rowOffset < pointsToStat; rowOffset++) {
535 if ((stat->flags & TOPLIMIT_GIVEN && inputDataOffset[rowOffset] > stat->topLimit) ||
536 (stat->flags & BOTTOMLIMIT_GIVEN && inputDataOffset[rowOffset] < stat->bottomLimit))
537 continue;
538 result += inputDataOffset[rowOffset];
539 count++;
540 }
541 if (count)
542 result /= count;
543 else
544 result = DBL_MAX;
545 break;
546 case SET_MEDIAN:
547 result = 0;
548 count = 0;
549 newData = NULL;
550 for (rowOffset = 0; rowOffset < pointsToStat; rowOffset++) {
551 if ((stat->flags & TOPLIMIT_GIVEN && inputDataOffset[rowOffset] > stat->topLimit) ||
552 (stat->flags & BOTTOMLIMIT_GIVEN && inputDataOffset[rowOffset] < stat->bottomLimit))
553 continue;
554 newData = SDDS_Realloc(newData, sizeof(*newData) * (count + 1));
555 newData[count] = inputDataOffset[rowOffset];
556 count++;
557 }
558 if (count) {
559 if (!compute_median(&result, newData, count))
560 result = DBL_MAX;
561 free(newData);
562 } else
563 result = DBL_MAX;
564 break;
565 case SET_STANDARDDEVIATION:
566 case SET_SIGMA:
567 sum1 = sum2 = count = 0;
568 for (rowOffset = 0; rowOffset < pointsToStat; rowOffset++) {
569 if ((stat->flags & TOPLIMIT_GIVEN && inputDataOffset[rowOffset] > stat->topLimit) ||
570 (stat->flags & BOTTOMLIMIT_GIVEN && inputDataOffset[rowOffset] < stat->bottomLimit))
571 continue;
572 sum1 += inputDataOffset[rowOffset];
573 sum2 += inputDataOffset[rowOffset] * inputDataOffset[rowOffset];
574 count++;
575 }
576 if (count > 1) {
577 if ((result = sum2 / count - sqr(sum1 / count)) <= 0)
578 result = 0;
579 else
580 result = sqrt(result * count / (count - 1.0));
581 if (stat->optionCode == SET_SIGMA)
582 result /= sqrt(count);
583 } else
584 result = DBL_MAX;
585 break;
586 case SET_RMS:
587 sum2 = count = 0;
588 for (rowOffset = 0; rowOffset < pointsToStat; rowOffset++) {
589 if ((stat->flags & TOPLIMIT_GIVEN && inputDataOffset[rowOffset] > stat->topLimit) ||
590 (stat->flags & BOTTOMLIMIT_GIVEN && inputDataOffset[rowOffset] < stat->bottomLimit))
591 continue;
592 sum2 += inputDataOffset[rowOffset] * inputDataOffset[rowOffset];
593 count++;
594 }
595 if (count > 0)
596 result = sqrt(sum2 / count);
597 else
598 result = DBL_MAX;
599 break;
600 case SET_SUM:
601 sum1 = count = 0;
602 for (rowOffset = 0; rowOffset < pointsToStat; rowOffset++) {
603 if ((stat->flags & TOPLIMIT_GIVEN && inputDataOffset[rowOffset] > stat->topLimit) ||
604 (stat->flags & BOTTOMLIMIT_GIVEN && inputDataOffset[rowOffset] < stat->bottomLimit))
605 continue;
606 sum1 += ipow(inputDataOffset[rowOffset], stat->sumPower);
607 count++;
608 }
609 if (count > 0)
610 result = sum1;
611 else
612 result = DBL_MAX;
613 break;
614 case SET_SLOPE:
615 if (!indepDataOffset ||
616 !unweightedLinearFit(indepDataOffset, inputDataOffset, pointsToStat, &slope, &intercept, &variance)) {
617 result = DBL_MAX;
618 } else
619 result = slope;
620 break;
621 case SET_SAMPLE:
622 result = DBL_MAX;
623 for (rowOffset = 0; rowOffset < pointsToStat; rowOffset++) {
624 if ((stat->flags & TOPLIMIT_GIVEN && inputDataOffset[rowOffset] > stat->topLimit) ||
625 (stat->flags & BOTTOMLIMIT_GIVEN && inputDataOffset[rowOffset] < stat->bottomLimit))
626 continue;
627 result = inputDataOffset[rowOffset];
628 break;
629 }
630 break;
631 default:
632 fprintf(stderr, "Unknown statistics code %ld in sddsrunstats\n", stat->optionCode);
633 exit(EXIT_FAILURE);
634 break;
635 }
636 return result;
637}
638
639long addStatRequests(STAT_REQUEST **statRequest, long requests, char **item, long items, long code, unsigned long flags) {
640 long i;
641 if (!(*statRequest = SDDS_Realloc(*statRequest, sizeof(**statRequest) * (requests + 1))) ||
642 !((*statRequest)[requests].sourceColumn = (char **)malloc(sizeof(*(*statRequest)[requests].sourceColumn) * items)))
643 SDDS_Bomb("memory allocation failure");
644 for (i = 0; i < items; i++) {
645 (*statRequest)[requests].sourceColumn[i] = item[i];
646 }
647 (*statRequest)[requests].sourceColumns = items;
648 (*statRequest)[requests].optionCode = code;
649 (*statRequest)[requests].sumPower = 1;
650 (*statRequest)[requests].flags = flags;
651 (*statRequest)[requests].independentColumn = NULL;
652 return requests + 1;
653}
654
655STAT_DEFINITION *compileStatDefinitions(SDDS_DATASET *inData, STAT_REQUEST *request, long requests) {
656 STAT_DEFINITION *stat;
657 long iReq, iName;
658 char s[SDDS_MAXLINE];
659
660 if (!(stat = (STAT_DEFINITION *)malloc(sizeof(*stat) * requests)))
661 SDDS_Bomb("memory allocation failure");
662 for (iReq = 0; iReq < requests; iReq++) {
663 if ((stat[iReq].sourceColumns = expandColumnPairNames(inData, &request[iReq].sourceColumn, NULL, request[iReq].sourceColumns, NULL, 0, FIND_NUMERIC_TYPE, 0)) <= 0) {
664 fprintf(stderr, "Error: no match for column names (sddsrunstats):\n");
665 for (iName = 0; iName < request[iReq].sourceColumns; iName++)
666 fprintf(stderr, "%s, ", request[iReq].sourceColumn[iReq]);
667 fputc('\n', stderr);
668 exit(EXIT_FAILURE);
669 }
670 stat[iReq].sourceColumn = request[iReq].sourceColumn;
671 if (!(stat[iReq].resultColumn = malloc(sizeof(*stat[iReq].resultColumn) * stat[iReq].sourceColumns)) ||
672 !(stat[iReq].resultIndex = malloc(sizeof(*stat[iReq].resultIndex) * stat[iReq].sourceColumns))) {
673 SDDS_Bomb("memory allocation failure");
674 }
675 for (iName = 0; iName < stat[iReq].sourceColumns; iName++) {
676 sprintf(s, "%s%s", stat[iReq].sourceColumn[iName], statSuffix[request[iReq].optionCode]);
677 SDDS_CopyString(stat[iReq].resultColumn + iName, s);
678 }
679 stat[iReq].optionCode = request[iReq].optionCode;
680 stat[iReq].sumPower = request[iReq].sumPower;
681 stat[iReq].flags = request[iReq].flags;
682 stat[iReq].topLimit = request[iReq].topLimit;
683 stat[iReq].bottomLimit = request[iReq].bottomLimit;
684 stat[iReq].independentColumn = request[iReq].independentColumn;
685 }
686
687 return stat;
688}
689
690long setupOutputFile(SDDS_DATASET *outData, char *output, SDDS_DATASET *inData, STAT_DEFINITION *stat, long stats, short columnMajorOrder) {
691 long column, iStat;
692 char s[SDDS_MAXLINE];
693
694 if (!SDDS_InitializeOutput(outData, SDDS_BINARY, 1, NULL, NULL, output))
695 return 0;
696 if (columnMajorOrder != -1)
697 outData->layout.data_mode.column_major = columnMajorOrder;
698 else
699 outData->layout.data_mode.column_major = inData->layout.data_mode.column_major;
700 for (iStat = 0; iStat < stats; iStat++) {
701 for (column = 0; column < stat[iStat].sourceColumns; column++) {
702 if (!SDDS_TransferColumnDefinition(outData, inData, stat[iStat].sourceColumn[column], stat[iStat].resultColumn[column])) {
703 sprintf(s, "Problem transferring definition of column %s to %s\n", stat[iStat].sourceColumn[column], stat[iStat].resultColumn[column]);
704 SDDS_SetError(s);
705 return 0;
706 }
707 if ((stat[iStat].resultIndex[column] = SDDS_GetColumnIndex(outData, stat[iStat].resultColumn[column])) < 0) {
708 sprintf(s, "Problem creating column %s", stat[iStat].resultColumn[column]);
709 SDDS_SetError(s);
710 return 0;
711 }
712 if (!SDDS_ChangeColumnInformation(outData, "description", NULL, SDDS_SET_BY_NAME, stat[iStat].resultColumn[column]) ||
713 !SDDS_ChangeColumnInformation(outData, "symbol", NULL, SDDS_SET_BY_NAME, stat[iStat].resultColumn[column]) ||
714 !SDDS_ChangeColumnInformation(outData, "type", "double", SDDS_SET_BY_NAME | SDDS_PASS_BY_STRING, stat[iStat].resultColumn[column])) {
715 sprintf(s, "Problem changing attributes of new column %s", stat[iStat].resultColumn[column]);
716 SDDS_SetError(s);
717 return 0;
718 }
719 }
720 }
721 if (!SDDS_TransferAllParameterDefinitions(outData, inData, SDDS_TRANSFER_KEEPOLD) ||
722 !SDDS_TransferAllArrayDefinitions(outData, inData, 0) ||
723 !SDDS_WriteLayout(outData))
724 return 0;
725 return 1;
726}
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
int32_t SDDS_CopyParameters(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source)
Definition SDDS_copy.c:286
int32_t SDDS_CopyArrays(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source)
Definition SDDS_copy.c:334
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.
int64_t SDDS_CountRowsOfInterest(SDDS_DATASET *SDDS_dataset)
Counts the number of rows marked as "of interest" in the current data table.
double * SDDS_GetColumnInDoubles(SDDS_DATASET *SDDS_dataset, char *column_name)
Retrieves the data of a specified numerical column as an array of doubles, considering only rows mark...
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.
Definition SDDS_info.c:364
int32_t SDDS_InitializeInput(SDDS_DATASET *SDDS_dataset, char *filename)
Definition SDDS_input.c:50
int32_t SDDS_Terminate(SDDS_DATASET *SDDS_dataset)
int32_t SDDS_ReadPage(SDDS_DATASET *SDDS_dataset)
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_TransferAllArrayDefinitions(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source, uint32_t mode)
Transfers all array definitions 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_SetError(char *error_text)
Records an error message in the SDDS error stack.
Definition SDDS_utils.c:421
int32_t SDDS_GetColumnIndex(SDDS_DATASET *SDDS_dataset, char *name)
Retrieves the index of a named column in the SDDS dataset.
void SDDS_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
Definition SDDS_utils.c:474
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
Definition SDDS_utils.c:318
int32_t SDDS_GetColumnType(SDDS_DATASET *SDDS_dataset, int32_t index)
Retrieves the data type of a column in the SDDS dataset by its index.
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
Definition SDDS_utils.c:380
int32_t SDDS_CopyString(char **target, const char *source)
Copies a source string to a target string with memory allocation.
Definition SDDS_utils.c:922
void * SDDS_Realloc(void *old_ptr, size_t new_size)
Reallocates memory to a new size.
Definition SDDS_utils.c:743
#define SDDS_STRING
Identifier for the string data type.
Definition SDDStypes.h:85
#define SDDS_LONG
Identifier for the signed 32-bit integer data type.
Definition SDDStypes.h:61
#define SDDS_DOUBLE
Identifier for the double data type.
Definition SDDStypes.h:37
#define SDDS_NUMERIC_TYPE(type)
Checks if the given type identifier corresponds to any numeric type.
Definition SDDStypes.h:138
Utility functions for SDDS dataset manipulation and string array operations.
void bomb(char *error, char *usage)
Reports error messages to the terminal and aborts the program.
Definition bomb.c:26
double ipow(const double x, const int64_t p)
Compute x raised to the power p (x^p).
Definition ipow.c:33
long unweightedLinearFit(double *xData, double *yData, long nData, double *slope, double *intercept, double *variance)
Performs an unweighted linear fit on the provided data.
Definition linfit.c:37
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.
long compute_median(double *value, double *x, long n)
Computes the median of an array of doubles.
Definition median.c:29
int scanargs(SCANNED_ARG **scanned, int argc, char **argv)
Definition scanargs.c:36
long processPipeOption(char **item, long items, unsigned long *flags)
Definition scanargs.c:357
void processFilenames(char *programName, char **input, char **output, unsigned long pipeFlags, long noWarnings, long *tmpOutputUsed)
Definition scanargs.c:391
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.