70char *option[N_OPTIONS] = {
86 "Usage: sddseventhist [<inputfile>] [<outputfile>]\n"
87 " [-pipe=<input>,<output>]\n"
88 " -dataColumn=<columnName>\n"
89 " -eventIdentifier=<columnName>\n"
90 " [-overlapEvent=<eventValue>]\n"
91 " [{-bins=<number> | -sizeOfBins=<value>}]\n"
92 " [-lowerLimit=<value>]\n"
93 " [-upperLimit=<value>]\n"
95 " [-normalize[={sum|area|peak}]]\n"
96 " [-majorOrder=row|column]\n";
98static char *additional_help =
"\n\
99dataColumn : Name of the column to histogram.\n\
100eventIdentifier : Name of the column used to identify events.\n\
101 A separate histogram is created for each unique value in this column.\n\
102 The column must contain string or integer data;\n\
103 if string data, the values must be valid SDDS column names.\n\
104overlapEvent : If specified, histograms are multiplied bin-by-bin with this event's histogram.\n\
105bins : Number of bins for the histogram.\n\
106sizeOfBins : Size of each bin for the histogram.\n\
107lowerLimit : Lower limit of the histogram range.\n\
108upperLimit : Upper limit of the histogram range.\n\
109normalize : Normalize the histogram by sum, area, or peak.\n\
110sides : Adds sides to the histogram down to the zero level.\n\
111majorOrder : Specifies the major order for the output file (row or column).\n\n\
112Program by Michael Borland. (" __DATE__
" " __TIME__
", SVN revision: " SVN_VERSION
")\n";
114#define NORMALIZE_PEAK 0
115#define NORMALIZE_AREA 1
116#define NORMALIZE_SUM 2
117#define NORMALIZE_NO 3
118#define N_NORMALIZE_OPTIONS 4
120char *normalize_option[N_NORMALIZE_OPTIONS] = {
121 "peak",
"area",
"sum",
"no"};
129 long histogramIndex, overlapIndex;
139 char *inputfile,
char *dataColumn,
char *eventIDColumn,
char *overlapEventID,
140 EVENT_DATA **eventDataRet, int64_t *eventIDsRet,
double **dataRet,
long bins,
141 double binSize,
long normalizeMode,
short columnMajorOrder);
142long makeEventHistogram(
double *hist,
long bins,
double lowerLimit,
double dx,
EVENT_DATA *eventRefData);
143void makeEventOverlap(
double *overlap,
double *hist,
double *overlapHist,
long bins);
144int event_cmpasc(
const void *ep1,
const void *ep2);
146int main(
int argc,
char **argv) {
148 long binsGiven, lowerLimitGiven, upperLimitGiven;
153 double *overlap, *overlapHist;
154 double lowerLimit, upperLimit;
155 double givenLowerLimit, givenUpperLimit;
156 double range, binSize;
158 char *dataColumn, *eventIDColumn, *overlapEventID;
159 SCANNED_ARG *scanned;
160 char *inputfile, *outputfile;
163 long normalizeMode, doSides, verbose = 0, readCode;
164 unsigned long pipeFlags, majorOrderFlag;
165 long eventIDIndex, eventIDType;
166 int64_t eventRefIDs = 0;
169 int64_t i, points, iEvent;
170 short columnMajorOrder = -1;
174 argc =
scanargs(&scanned, argc, argv);
176 fprintf(stderr,
"Usage: %s\n", USAGE);
177 fputs(additional_help, stderr);
181 hist = overlap = overlapHist = NULL;
182 binsGiven = lowerLimitGiven = upperLimitGiven = 0;
183 binSize = doSides = 0;
184 inputfile = outputfile = NULL;
185 dataColumn = eventIDColumn = overlapEventID = NULL;
186 normalizeMode = NORMALIZE_NO;
189 for (i = 1; i < argc; i++) {
190 if (scanned[i].arg_type == OPTION) {
191 switch (
match_string(scanned[i].list[0], option, N_OPTIONS, 0)) {
192 case SET_MAJOR_ORDER:
194 scanned[i].n_items--;
195 if (scanned[i].n_items > 0 && (!
scanItemList(&majorOrderFlag, scanned[i].list + 1, &scanned[i].n_items, 0,
"row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
"column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL)))
196 SDDS_Bomb(
"invalid -majorOrder syntax/values");
197 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
198 columnMajorOrder = 1;
199 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
200 columnMajorOrder = 0;
204 SDDS_Bomb(
"-bins specified more than once");
206 if (sscanf(scanned[i].list[1],
"%ld", &bins) != 1 || bins <= 0)
211 SDDS_Bomb(
"-lowerLimit specified more than once");
213 if (sscanf(scanned[i].list[1],
"%lf", &givenLowerLimit) != 1)
214 SDDS_Bomb(
"invalid value for lowerLimit");
218 SDDS_Bomb(
"-upperLimit specified more than once");
220 if (sscanf(scanned[i].list[1],
"%lf", &givenUpperLimit) != 1)
221 SDDS_Bomb(
"invalid value for upperLimit");
225 SDDS_Bomb(
"-dataColumn specified more than once");
226 if (scanned[i].n_items != 2)
227 SDDS_Bomb(
"invalid -dataColumn syntax---supply name");
228 dataColumn = scanned[i].list[1];
230 case SET_EVENTIDENTIFIER:
232 SDDS_Bomb(
"-eventIdentifier specified more than once");
233 if (scanned[i].n_items != 2)
234 SDDS_Bomb(
"invalid -eventIdentifier syntax---supply name");
235 eventIDColumn = scanned[i].list[1];
237 case SET_OVERLAPEVENT:
239 SDDS_Bomb(
"-overlapEvent specified more than once");
240 if (scanned[i].n_items != 2)
241 SDDS_Bomb(
"invalid -overlapEvent syntax---supply value");
242 overlapEventID = scanned[i].list[1];
243 if (!strlen(overlapEventID))
244 SDDS_Bomb(
"invalid -overlapEvent syntax---supply value");
247 if (scanned[i].n_items == 1)
248 normalizeMode = NORMALIZE_SUM;
249 else if (scanned[i].n_items != 2 || (normalizeMode =
match_string(scanned[i].list[1], normalize_option, N_NORMALIZE_OPTIONS, 0)) < 0)
256 if (sscanf(scanned[i].list[1],
"%le", &binSize) != 1 || binSize <= 0)
264 fprintf(stderr,
"Error: option %s not recognized\n", scanned[i].list[0]);
271 inputfile = scanned[i].list[0];
272 else if (!outputfile)
273 outputfile = scanned[i].list[0];
275 SDDS_Bomb(
"Too many filenames provided.");
279 processFilenames(
"sddseventhist", &inputfile, &outputfile, pipeFlags, 0, NULL);
281 if (binSize && binsGiven)
282 SDDS_Bomb(
"Specify either -binSize or -bins, not both.");
286 SDDS_Bomb(
"-dataColumn must be specified.");
288 SDDS_Bomb(
"-eventIdentifier must be specified.");
290 if (!(indep =
SDDS_Malloc(
sizeof(*indep) * (bins + 2))) ||
291 !(hist =
SDDS_Malloc(
sizeof(*hist) * (bins + 2))) ||
292 !(overlap =
SDDS_Malloc(
sizeof(*overlap) * (bins + 2))) ||
293 !(overlapHist =
SDDS_Malloc(
sizeof(*overlapHist) * (bins + 2))))
303 SDDS_Bomb(
"Event ID column must be of string type.");
305 SDDS_Bomb(
"Data column must be of a numeric data type.");
310 SDDS_Bomb(
"This program cannot process multi-page files.");
317 if (!setupOutputFile(&outTable, outputfile, &inTable, inputfile, dataColumn, eventIDColumn, overlapEventID, &eventRefData, &eventRefIDs, &data, bins, binSize, normalizeMode, columnMajorOrder))
320 if (!lowerLimitGiven) {
323 lowerLimit = data[0];
324 for (i = 0; i < points; i++)
325 if (lowerLimit > data[i])
326 lowerLimit = data[i];
328 lowerLimit = givenLowerLimit;
331 if (!upperLimitGiven) {
334 upperLimit = data[0];
335 for (i = 0; i < points; i++)
336 if (upperLimit < data[i])
337 upperLimit = data[i];
339 upperLimit = givenUpperLimit;
344 range = upperLimit - lowerLimit;
345 if (!lowerLimitGiven)
346 lowerLimit -= range * 1e-7;
347 if (!upperLimitGiven)
348 upperLimit += range * 1e-7;
349 if (upperLimit == lowerLimit) {
351 upperLimit += binSize / 2;
352 lowerLimit -= binSize / 2;
353 }
else if (fabs(upperLimit) < sqrt(DBL_MIN)) {
354 upperLimit = sqrt(DBL_MIN);
355 lowerLimit = -sqrt(DBL_MIN);
357 upperLimit += upperLimit * (1 + 2 * DBL_EPSILON);
358 lowerLimit -= upperLimit * (1 - 2 * DBL_EPSILON);
361 dx = (upperLimit - lowerLimit) / bins;
365 range = ((range / binSize) + 1) * binSize;
366 middle = (lowerLimit + upperLimit) / 2;
367 lowerLimit = middle - range / 2;
368 upperLimit = middle + range / 2;
370 bins = range / binSize + 0.5;
371 if (bins < 1 && !doSides)
373 if (!(indep =
SDDS_Realloc(indep,
sizeof(*indep) * (bins + 2))) ||
374 !(hist =
SDDS_Realloc(hist,
sizeof(*hist) * (bins + 2))) ||
375 !(overlap =
SDDS_Realloc(overlap,
sizeof(*overlap) * (bins + 2))) ||
376 !(overlapHist =
SDDS_Realloc(overlapHist,
sizeof(*overlapHist) * (bins + 2))))
380 for (i = -1; i < bins + 1; i++) {
381 indep[i + 1] = (i + 0.5) * dx + lowerLimit;
383 if (!
SDDS_StartPage(&outTable, points ? (doSides ? bins + 2 : bins) : 0) ||
385 (points && (!
SDDS_SetColumnFromDoubles(&outTable, SDDS_SET_BY_NAME, indep + (doSides ? 0 : 1), doSides ? bins + 2 : bins, dataColumn))))
388 if (overlapEventID) {
389 for (iEvent = 0; iEvent < eventRefIDs; iEvent++) {
390 if (strcmp(eventRefData[iEvent].
string, overlapEventID) == 0)
393 if (iEvent == eventRefIDs)
394 SDDS_Bomb(
"Cannot create overlap as the specified overlap event is not present.");
395 makeEventHistogram(overlapHist, bins, lowerLimit, dx, eventRefData + iEvent);
398 for (iEvent = pointsBinned = 0; iEvent < eventRefIDs; iEvent++) {
399 pointsBinned += makeEventHistogram(hist, bins, lowerLimit, dx, eventRefData + iEvent);
400 if (normalizeMode != NORMALIZE_NO) {
402 switch (normalizeMode) {
408 for (i = 0; i < bins; i++)
410 if (normalizeMode == NORMALIZE_AREA)
414 SDDS_Bomb(
"Invalid normalization mode.");
418 for (i = 0; i < bins; i++)
422 if (!
SDDS_SetColumnFromDoubles(&outTable, SDDS_SET_BY_INDEX, hist + (doSides ? 0 : 1), doSides ? bins + 2 : bins, eventRefData[iEvent].histogramIndex))
424 if (overlapEventID) {
425 makeEventOverlap(overlap, hist, overlapHist, bins + 2);
426 if (!
SDDS_SetColumnFromDoubles(&outTable, SDDS_SET_BY_INDEX, overlap + (doSides ? 0 : 1), doSides ? bins + 2 : bins, eventRefData[iEvent].overlapIndex))
429 free(eventRefData[iEvent].data);
433 "sddseventhistBins", bins,
434 "sddseventhistBinSize", dx,
435 "sddseventhistPointsBinned", pointsBinned,
440 fprintf(stderr,
"%ld points of %" PRId64
" from page %ld histogrammed in %ld bins\n", pointsBinned, points, readCode, bins);
464 char *inputfile,
char *dataColumn,
char *eventIDColumn,
char *overlapEventID,
465 EVENT_DATA **eventDataRet, int64_t *eventIDsRet,
double **dataRet,
long bins,
466 double binSize,
long normalizeMode,
short columnMajorOrder) {
467 char **eventValue, buffer[SDDS_MAXLINE];
468 int64_t eventRows, uniqueRows, row;
471 double *eventDataValue;
472 int64_t row0, iEvent, drow;
476 (eventRows = SDDS_RowCount(inTable)) == 0 ||
480 if (columnMajorOrder != -1)
481 outTable->layout.data_mode.column_major = columnMajorOrder;
483 outTable->layout.data_mode.column_major = inTable->layout.data_mode.column_major;
485 if (!(eventPair =
SDDS_Malloc(
sizeof(*eventPair) * eventRows)))
489 for (row = 0; row < eventRows; row++) {
490 eventPair[row].string = eventValue[row];
491 eventPair[row].data = eventDataValue[row];
493 qsort(eventPair, eventRows,
sizeof(*eventPair), event_cmpasc);
497 for (row = 1; row < eventRows; row++) {
498 if (strcmp(eventPair[row - 1].
string, eventPair[row].
string) != 0)
501 *eventIDsRet = uniqueRows;
504 if (!(eventData = *eventDataRet =
SDDS_Malloc(
sizeof(**eventDataRet) * uniqueRows)))
508 for (row = 1; row < eventRows; row++) {
509 if (row == (eventRows - 1) || strcmp(eventPair[row].
string, eventPair[row0].
string) != 0) {
511 eventData[iEvent].events = row - row0;
512 if (!
SDDS_CopyString(&eventData[iEvent].
string, eventPair[row0].
string) ||
513 !(eventData[iEvent].data =
SDDS_Malloc(
sizeof(*eventData[iEvent].data) * eventData[iEvent].events)))
515 for (drow = 0; drow < eventData[iEvent].events; drow++) {
516 eventData[iEvent].data[drow] = eventPair[row0 + drow].data;
519 if (row == (eventRows - 1) && strcmp(eventPair[row].
string, eventPair[row0].
string) != 0) {
531 for (row = 0; row < eventRows; row++)
532 free(eventValue[row]);
534 if (iEvent != uniqueRows)
537 if (overlapEventID && strlen(overlapEventID)) {
538 for (iEvent = 0; iEvent < uniqueRows; iEvent++) {
539 if (strcmp(overlapEventID, eventData[iEvent].
string) == 0)
542 if (iEvent == uniqueRows)
546 for (row = 0; row < uniqueRows; row++) {
547 snprintf(buffer,
sizeof(buffer),
"%sFrequency", eventData[row].
string);
550 eventData[row].overlapIndex = -1;
551 if (overlapEventID) {
552 snprintf(buffer,
sizeof(buffer),
"%s.%sOverlap", eventData[row].
string, overlapEventID);
574long makeEventHistogram(
double *hist,
long bins,
double lowerLimit,
double dx,
EVENT_DATA *eventRefData) {
575 long iBin, pointsBinned;
579 for (iBin = 0; iBin <= bins + 1; iBin++)
581 for (iRow = 0; iRow < eventRefData->events; iRow++) {
582 iBin = (eventRefData->data[iRow] - lowerLimit) / dx;
583 if (iBin >= 0 && iBin < bins)
586 for (iBin = pointsBinned = 0; iBin < bins; iBin++)
587 pointsBinned += hist1[iBin];
591void makeEventOverlap(
double *overlap,
double *hist,
double *overlapHist,
long bins) {
593 for (i = 0; i < bins; i++) {
594 overlap[i] = fmin(hist[i], overlapHist[i]);
598int event_cmpasc(
const void *ep1,
const void *ep2) {
603 if ((comp = strcmp(ev1->string, ev2->string)) != 0)
605 if (ev1->data < ev2->data)
607 else if (ev1->data > ev2->data)
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_StartPage(SDDS_DATASET *SDDS_dataset, int64_t expected_n_rows)
int32_t SDDS_SetParameters(SDDS_DATASET *SDDS_dataset, int32_t mode,...)
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_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_DefineColumn(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, int32_t field_length)
Defines a data column within the SDDS dataset.
int32_t SDDS_WriteLayout(SDDS_DATASET *SDDS_dataset)
Writes the SDDS layout header to the output file.
int32_t SDDS_DefineParameter(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, char *fixed_value)
Defines a data parameter with a fixed string value.
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_TransferAllParameterDefinitions(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source, uint32_t mode)
Transfers all parameter definitions from a source dataset to a target dataset.
int32_t SDDS_GetNamedColumnType(SDDS_DATASET *SDDS_dataset, char *name)
Retrieves the data type of a column in the SDDS dataset by its name.
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_Malloc(size_t size)
Allocates memory of a specified size.
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.
double max_in_array(double *array, long n)
Finds the maximum value in an array of doubles.
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.