87 SET_STANDARDDEVIATION,
104char *option[N_OPTIONS] = {
126char *statSuffix[N_STATS] = {
139#define TOPLIMIT_GIVEN 0x0001U
140#define BOTTOMLIMIT_GIVEN 0x0002U
141#define INDEPENDENT_GIVEN 0x0004U
147 char **sourceColumn, *independentColumn;
148 long sourceColumns, sumPower, optionCode;
150 double topLimit, bottomLimit;
158 char **sourceColumn, **resultColumn, *independentColumn;
159 long sourceColumns, optionCode, *resultIndex, sumPower;
161 double topLimit, bottomLimit;
164long addStatRequests(
STAT_REQUEST **statRequest,
long requests,
char **item,
long items,
long code,
unsigned long flag);
167static double computeRunningStatistic(
STAT_DEFINITION *stat,
double *inputDataOffset,
double *indepDataOffset, int64_t pointsToStat);
170 "sddsrunstats [<input>] [<output>] [-pipe[=input][,output]]\n"
171 " [{-points=<integer> | -window=column=<column>,width=<value>}]\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"
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";
198int main(
int argc,
char **argv) {
203 SCANNED_ARG *scanned;
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;
216 unsigned long pipeFlags, scanFlags, majorOrderFlag;
218 long lastRegion, region, windowRef, partialOk;
219 short columnMajorOrder = -1;
223 argc =
scanargs(&scanned, argc, argv);
225 bomb(
"too few arguments", USAGE);
227 input = output = NULL;
230 stats = requests = pipeFlags = 0;
237 for (iArg = 1; iArg < argc; iArg++) {
239 if (scanned[iArg].arg_type == OPTION) {
241 switch (code =
match_string(scanned[iArg].list[0], option, N_OPTIONS, 0)) {
242 case SET_MAJOR_ORDER:
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;
256 if (scanned[iArg].n_items != 2 ||
257 sscanf(scanned[iArg].list[1],
"%d", &threads) != 1 ||
262 if (scanned[iArg].n_items != 2 || sscanf(scanned[iArg].list[1],
"%" SCNd64, &pointsToStat) != 1 ||
263 (pointsToStat <= 2 && pointsToStat != 0))
272 case SET_STANDARDDEVIATION:
277 if (scanned[iArg].n_items < 2) {
278 fprintf(stderr,
"error: invalid -%s syntax\n", option[code]);
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]);
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;
293 if (scanned[iArg].n_items < 2) {
294 fprintf(stderr,
"error: invalid -%s syntax\n", option[code]);
298 if (!
scanItemList(&scanFlags, scanned[iArg].list, &scanned[iArg].n_items,
299 SCANITEMLIST_UNKNOWN_VALUE_OK | SCANITEMLIST_REMOVE_USED_ITEMS | SCANITEMLIST_IGNORE_VALUELESS,
301 "toplimit",
SDDS_DOUBLE, &topLimit, 1, TOPLIMIT_GIVEN,
302 "bottomlimit",
SDDS_DOUBLE, &bottomLimit, 1, BOTTOMLIMIT_GIVEN, NULL))
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;
310 if (scanned[iArg].n_items < 2) {
311 fprintf(stderr,
"error: invalid -%s syntax\n", option[code]);
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,
318 !(scanFlags & INDEPENDENT_GIVEN))
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;
325 if (!
processPipeOption(scanned[iArg].list + 1, scanned[iArg].n_items - 1, &pipeFlags))
331 scanned[iArg].n_items -= 1;
332 if (!
scanItemList(&scanFlags, scanned[iArg].list + 1, &scanned[iArg].n_items, 0,
336 !strlen(windowColumn) ||
338 SDDS_Bomb(
"invalid -window syntax/values");
344 fprintf(stderr,
"error: unknown option '%s' given\n", scanned[iArg].list[0]);
351 input = scanned[iArg].list[0];
353 output = scanned[iArg].list[0];
359 if (pointsToStat < 0 && !windowColumn) {
370 if (!(stat = compileStatDefinitions(&inData, request, requests)))
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);
386 if (!setupOutputFile(&outData, output, &inData, stat, stats, columnMajorOrder))
393 SDDS_Bomb(
"Window column is not numeric");
398 pointsToStat0 = pointsToStat;
401 pointsToStat = pointsToStat0;
402 if (pointsToStat == 0)
408 if (rows < pointsToStat) {
415 outputRows = rows - pointsToStat + 1;
417 outputRows = rows / pointsToStat;
425 if (outputRows > outputRowsMax &&
426 !(outputData =
SDDS_Realloc(outputData,
sizeof(*outputData) * (outputRowsMax = outputRows))))
428 for (iStat = 0; iStat < stats; iStat++) {
429 for (iColumn = 0; iColumn < stat[iStat].sourceColumns; iColumn++) {
436 if (stat[iStat].independentColumn &&
439 rowsToSet = outputRows;
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,
450 for (outputRow = startRow = 0; outputRow < outputRows; outputRow++, startRow += (overlap ? 1 : pointsToStat)) {
451 short windowFound = 0;
456 for (pointsToStat = 1; pointsToStat < outputRows - startRow; pointsToStat++) {
457 region = (windowData[startRow + pointsToStat] - windowData[windowRef]) / windowWidth;
458 if (region != lastRegion) {
464 if (!windowFound && pointsToStat < 2)
466 if (startRow + pointsToStat > rows) {
467 pointsToStat = rows - startRow - 1;
468 if (pointsToStat <= 0)
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]);
474 inputDataOffset = inputData + startRow;
475 outputData[outputRow] = computeRunningStatistic(&stat[iStat], inputDataOffset,
476 indepData ? indepData + startRow : NULL,
479 rowsToSet = outputRow;
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;
510 switch (stat->optionCode) {
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))
517 if (inputDataOffset[rowOffset] > result)
518 result = inputDataOffset[rowOffset];
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))
527 if (inputDataOffset[rowOffset] < result)
528 result = inputDataOffset[rowOffset];
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))
538 result += inputDataOffset[rowOffset];
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))
554 newData =
SDDS_Realloc(newData,
sizeof(*newData) * (count + 1));
555 newData[count] = inputDataOffset[rowOffset];
565 case SET_STANDARDDEVIATION:
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))
572 sum1 += inputDataOffset[rowOffset];
573 sum2 += inputDataOffset[rowOffset] * inputDataOffset[rowOffset];
577 if ((result = sum2 / count - sqr(sum1 / count)) <= 0)
580 result = sqrt(result * count / (count - 1.0));
581 if (stat->optionCode == SET_SIGMA)
582 result /= sqrt(count);
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))
592 sum2 += inputDataOffset[rowOffset] * inputDataOffset[rowOffset];
596 result = sqrt(sum2 / count);
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))
606 sum1 +=
ipow(inputDataOffset[rowOffset], stat->sumPower);
615 if (!indepDataOffset ||
616 !
unweightedLinearFit(indepDataOffset, inputDataOffset, pointsToStat, &slope, &intercept, &variance)) {
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))
627 result = inputDataOffset[rowOffset];
632 fprintf(stderr,
"Unknown statistics code %ld in sddsrunstats\n", stat->optionCode);
639long addStatRequests(
STAT_REQUEST **statRequest,
long requests,
char **item,
long items,
long code,
unsigned long flags) {
641 if (!(*statRequest =
SDDS_Realloc(*statRequest,
sizeof(**statRequest) * (requests + 1))) ||
642 !((*statRequest)[requests].sourceColumn = (
char **)malloc(
sizeof(*(*statRequest)[requests].sourceColumn) * items)))
644 for (i = 0; i < items; i++) {
645 (*statRequest)[requests].sourceColumn[i] = item[i];
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;
658 char s[SDDS_MAXLINE];
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]);
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))) {
675 for (iName = 0; iName < stat[iReq].sourceColumns; iName++) {
676 sprintf(s,
"%s%s", stat[iReq].sourceColumn[iName], statSuffix[request[iReq].optionCode]);
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;
692 char s[SDDS_MAXLINE];
696 if (columnMajorOrder != -1)
697 outData->layout.data_mode.column_major = columnMajorOrder;
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++) {
703 sprintf(s,
"Problem transferring definition of column %s to %s\n", stat[iStat].sourceColumn[column], stat[iStat].resultColumn[column]);
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]);
715 sprintf(s,
"Problem changing attributes of new column %s", stat[iStat].resultColumn[column]);
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_CopyArrays(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_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.
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.
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
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.
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.
#define SDDS_DOUBLE
Identifier for the double data type.
#define SDDS_NUMERIC_TYPE(type)
Checks if the given type identifier corresponds to any numeric type.
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.
double ipow(const double x, const int64_t p)
Compute x raised to the power p (x^p).
long unweightedLinearFit(double *xData, double *yData, long nData, double *slope, double *intercept, double *variance)
Performs an unweighted linear fit on the provided data.
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.