198 {
200 long stats;
202 long requests;
203 SCANNED_ARG *scanned;
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
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)
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))
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]);
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,
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;
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))
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))
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,
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
350 if (!input)
351 input = scanned[iArg].list[0];
352 else if (!output)
353 output = scanned[iArg].list[0];
354 else
356 }
357 }
358
359 if (pointsToStat < 0 && !windowColumn) {
360 pointsToStat = 10;
361 }
363
364 if (!requests)
366
369
370 if (!(stat = compileStatDefinitions(&inData, request, requests)))
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))
388
389 if (windowColumn) {
393 SDDS_Bomb(
"Window column is not numeric");
394 }
395
396 outputData = NULL;
397 outputRowsMax = 0;
398 pointsToStat0 = pointsToStat;
401 pointsToStat = pointsToStat0;
402 if (pointsToStat == 0)
403 pointsToStat = rows;
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
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++) {
430 double *indepData;
431 lastRegion = 0;
432 windowRef = 0;
433 indepData = NULL;
436 if (stat[iStat].independentColumn &&
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 }
483 free(inputData);
484 free(indepData);
485 }
486 }
487 if (windowColumn)
488 free(windowData);
491 }
494 return EXIT_FAILURE;
495 }
498 return EXIT_FAILURE;
499 }
500 if (outputData)
501 free(outputData);
502 return EXIT_SUCCESS;
503}
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_WritePage(SDDS_DATASET *SDDS_dataset)
Writes the current data table to the output file.
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.
#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.
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.