70char *option[N_OPTIONS] = {
81static const char *USAGE =
82 "Usage: sddsinterpset [<input>] [<output>] \n"
83 " [-pipe=[input][,output]] \n"
84 " [-order=<number>] \n"
86 " [-data=fileColumn=<colName>,interpolate=<colName>,functionof=<colName>,\n"
87 " column=<colName> | atValue=<value>] \n"
88 " [-majorOrder=row|column] \n"
89 " [-belowRange={value=<value>|skip|saturate|extrapolate|wrap}[,{abort|warn}]] \n"
90 " [-aboveRange={value=<value>|skip|saturate|extrapolate|wrap}[,{abort|warn}]]\n"
91 " [-threads=<number>]\n\n"
93 " -verbose Print detailed processing messages.\n"
94 " -pipe Use standard SDDS Toolkit pipe options for input and output.\n"
95 " -order Specify the order of the polynomials used for interpolation.\n"
96 " Default is 1 (linear interpolation).\n"
97 " -data Define data interpolation parameters:\n"
98 " - fileColumn=<colName> : Column with data file names.\n"
99 " - interpolate=<colName> : Column to interpolate.\n"
100 " - functionof=<colName> : Independent variable column name.\n"
101 " - column=<colName> : Specify interpolation point as a column.\n"
103 " - atValue=<value> : Specify a fixed interpolation value.\n"
104 " -majorOrder Specify data ordering for output: 'row' or 'column'.\n"
105 " Default inherits from input file.\n"
106 " -belowRange Define behavior for interpolation points below data range:\n"
107 " Options: value=<value>, skip, saturate, extrapolate, wrap, abort, warn.\n"
108 " -aboveRange Define behavior for interpolation points above data range:\n"
109 " Options: value=<value>, skip, saturate, extrapolate, wrap, abort, warn.\n\n"
110 " -threads Number of referenced data files to read concurrently.\n"
112 "Program by Hairong Shang. ("__DATE__
114 ", SVN revision: " SVN_VERSION
")\n";
116#define AT_COLUMN 0x00000001
117#define AT_VALUE 0x00000002
128 unsigned long hasdata;
132long checkMonotonicity(
double *indepValue, int64_t rows);
133void freedatacontrol(
DATA_CONTROL *data_control,
long dataControls);
134static long interpolateDataFile(
char *filename,
DATA_CONTROL *control,
double atValue,
135 OUTRANGE_CONTROL *belowRange, OUTRANGE_CONTROL *aboveRange,
136 long order,
double *result,
unsigned long *interpCode,
137 char *errorMessage,
long errorMessageSize);
139int main(
int argc,
char **argv) {
141 char *input = NULL, *output = NULL, **interpCol = NULL, **funcOf = NULL;
142 long order = 1, dataControls = 0, valid_option = 1;
145 OUTRANGE_CONTROL aboveRange, belowRange;
147 unsigned long pipeFlags = 0, majorOrderFlag;
149 double ***out_depenValue = NULL, atValue = 0;
150 int32_t **rowFlag = NULL;
151 long valid_data = 0, index, pages = 0;
152 int64_t *rows = NULL;
154 short columnMajorOrder = -1;
158 argc =
scanargs(&s_arg, argc, argv);
160 fprintf(stderr,
"%s", USAGE);
164 aboveRange.flags = belowRange.flags = OUTRANGE_SATURATE;
166 for (i_arg = 1; i_arg < argc; i_arg++) {
167 if (s_arg[i_arg].arg_type == OPTION) {
168 switch (
match_string(s_arg[i_arg].list[0], option, N_OPTIONS, 0)) {
169 case CLO_MAJOR_ORDER:
171 s_arg[i_arg].n_items--;
172 if (s_arg[i_arg].n_items > 0 &&
173 !
scanItemList(&majorOrderFlag, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
174 "row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
175 "column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL)) {
176 SDDS_Bomb(
"invalid -majorOrder syntax/values");
178 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
179 columnMajorOrder = 1;
180 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
181 columnMajorOrder = 0;
184 if (s_arg[i_arg].n_items != 2 ||
185 sscanf(s_arg[i_arg].list[1],
"%d", &threads) != 1 ||
187 SDDS_Bomb(
"invalid -threads syntax/value");
192 if (s_arg[i_arg].n_items != 2 ||
193 sscanf(s_arg[i_arg].list[1],
"%ld", &order) != 1 ||
195 SDDS_Bomb(
"invalid -order syntax/value");
200 if (!
processPipeOption(s_arg[i_arg].list + 1, s_arg[i_arg].n_items - 1, &pipeFlags)) {
206 s_arg[i_arg].n_items -= 1;
207 if (s_arg[i_arg].n_items < 1 ||
208 !
scanItemList(&aboveRange.flags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
209 "value",
SDDS_DOUBLE, &aboveRange.value, 1, OUTRANGE_VALUE,
210 "skip", -1, NULL, 0, OUTRANGE_SKIP,
211 "saturate", -1, NULL, 0, OUTRANGE_SATURATE,
212 "extrapolate", -1, NULL, 0, OUTRANGE_EXTRAPOLATE,
213 "wrap", -1, NULL, 0, OUTRANGE_WRAP,
214 "abort", -1, NULL, 0, OUTRANGE_ABORT,
215 "warn", -1, NULL, 0, OUTRANGE_WARN, NULL)) {
216 SDDS_Bomb(
"invalid -aboveRange syntax/value");
218 if ((i =
bitsSet(aboveRange.flags & (OUTRANGE_VALUE | OUTRANGE_SKIP | OUTRANGE_SATURATE |
219 OUTRANGE_EXTRAPOLATE | OUTRANGE_WRAP | OUTRANGE_ABORT))) > 1) {
220 SDDS_Bomb(
"incompatible keywords given for -aboveRange");
223 aboveRange.flags |= OUTRANGE_SATURATE;
231 s_arg[i_arg].n_items -= 1;
232 if (s_arg[i_arg].n_items < 1 ||
233 !
scanItemList(&belowRange.flags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
234 "value",
SDDS_DOUBLE, &belowRange.value, 1, OUTRANGE_VALUE,
235 "skip", -1, NULL, 0, OUTRANGE_SKIP,
236 "saturate", -1, NULL, 0, OUTRANGE_SATURATE,
237 "extrapolate", -1, NULL, 0, OUTRANGE_EXTRAPOLATE,
238 "wrap", -1, NULL, 0, OUTRANGE_WRAP,
239 "abort", -1, NULL, 0, OUTRANGE_ABORT,
240 "warn", -1, NULL, 0, OUTRANGE_WARN, NULL)) {
241 SDDS_Bomb(
"invalid -belowRange syntax/value");
243 if ((i =
bitsSet(belowRange.flags & (OUTRANGE_VALUE | OUTRANGE_SKIP | OUTRANGE_SATURATE |
244 OUTRANGE_EXTRAPOLATE | OUTRANGE_WRAP | OUTRANGE_ABORT))) > 1) {
245 SDDS_Bomb(
"incompatible keywords given for -belowRange");
248 belowRange.flags |= OUTRANGE_SATURATE;
252 s_arg[i_arg].n_items -= 1;
253 if (s_arg[i_arg].n_items < 4) {
256 data_control =
SDDS_Realloc(data_control,
sizeof(*data_control) * (dataControls + 1));
257 data_control[dataControls].fileColumn = data_control[dataControls].interpCol =
258 data_control[dataControls].funcOfCol = data_control[dataControls].atCol = NULL;
259 data_control[dataControls].file = NULL;
260 data_control[dataControls].files = 0;
261 data_control[dataControls].hasdata = 0;
262 data_control[dataControls].colValue = NULL;
263 data_control[dataControls].flags = 0;
265 if (!
scanItemList(&data_control[dataControls].flags, s_arg[i_arg].list + 1,
266 &s_arg[i_arg].n_items, 0,
267 "fileColumn",
SDDS_STRING, &(data_control[dataControls].fileColumn), 1, 0,
268 "interpolate",
SDDS_STRING, &(data_control[dataControls].interpCol), 1, 0,
269 "functionof",
SDDS_STRING, &(data_control[dataControls].funcOfCol), 1, 0,
270 "column",
SDDS_STRING, &(data_control[dataControls].atCol), 1, AT_COLUMN,
271 "atValue",
SDDS_DOUBLE, &(data_control[dataControls].atValue), 1, AT_VALUE, NULL) ||
272 !data_control[dataControls].fileColumn ||
273 !data_control[dataControls].interpCol ||
274 !data_control[dataControls].funcOfCol) {
278 if (!(data_control[dataControls].flags & AT_COLUMN) &&
279 !(data_control[dataControls].flags & AT_VALUE)) {
280 SDDS_Bomb(
"Invalid -data syntax: either column or atValue option should be given.");
283 if ((data_control[dataControls].flags & AT_COLUMN) &&
284 (data_control[dataControls].flags & AT_VALUE)) {
285 SDDS_Bomb(
"Invalid -data syntax: column and atValue options are not compatible.");
290 if (
match_string(data_control[dataControls].funcOfCol, funcOf, dataControls, EXACT_MATCH) > 0) {
291 fprintf(stderr,
"Multiple independent columns provided!\n");
294 if (
match_string(data_control[dataControls].interpCol, interpCol, dataControls, EXACT_MATCH) > 0) {
295 fprintf(stderr,
"Warning: Interpolate column '%s' has been used.\n", data_control[dataControls].interpCol);
301 interpCol =
SDDS_Realloc(interpCol,
sizeof(*interpCol) * (dataControls + 1));
302 funcOf =
SDDS_Realloc(funcOf,
sizeof(*funcOf) * (dataControls + 1));
303 interpCol[dataControls] = data_control[dataControls].interpCol;
304 funcOf[dataControls] = data_control[dataControls].funcOfCol;
310 fprintf(stderr,
"Error: Unknown or ambiguous option '%s'\n", s_arg[i_arg].list[0]);
316 input = s_arg[i_arg].list[0];
318 output = s_arg[i_arg].list[0];
320 SDDS_Bomb(
"Too many filenames provided.");
329 for (i = 0; i < dataControls; i++) {
331 fprintf(stderr,
"Warning: Column '%s' does not exist in input file '%s'.\n",
332 data_control[i].fileColumn, input);
336 fprintf(stderr,
"Error: Column '%s' in input file '%s' is not a string column.\n",
337 data_control[i].fileColumn, input);
340 if (data_control[i].atCol) {
342 fprintf(stderr,
"Warning: Column '%s' does not exist in input file '%s'.\n",
343 data_control[i].atCol, input);
347 fprintf(stderr,
"Error: Column '%s' in input file '%s' is not a numeric column.\n",
348 data_control[i].atCol, input);
352 data_control[i].hasdata = 1;
357 fprintf(stderr,
"Error: No valid -data options provided for processing.\n");
364 if (columnMajorOrder != -1)
365 SDDSout.layout.data_mode.column_major = columnMajorOrder;
367 SDDSout.layout.data_mode.column_major = SDDSin.layout.data_mode.column_major;
371 out_depenValue =
SDDS_Realloc(out_depenValue,
sizeof(*out_depenValue) * (pages + 1));
372 rowFlag =
SDDS_Realloc(rowFlag,
sizeof(*rowFlag) * (pages + 1));
375 fprintf(stderr,
"Error: No data found in input file '%s'.\n", input);
379 rowFlag[pages] = (int32_t *)malloc(
sizeof(**rowFlag) * rows[pages]);
380 out_depenValue[pages] = calloc(dataControls,
sizeof(*out_depenValue[pages]));
381 if (!out_depenValue[pages])
384 for (i = 0; i < rows[pages]; i++)
385 rowFlag[pages][i] = 1;
387 for (i = 0; i < dataControls; i++) {
388 if (data_control[i].hasdata) {
389 unsigned long *interpCodeRow = NULL;
390 char errorMessage[1024];
393 out_depenValue[pages][i] = malloc(
sizeof(*out_depenValue[pages][i]) * rows[pages]);
394 if (!out_depenValue[pages][i])
397 data_control[i].files = rows[pages];
398 if (!(data_control[i].file = (
char **)
SDDS_GetColumn(&SDDSin, data_control[i].fileColumn))) {
402 if (data_control[i].atCol) {
408 if (!data_control[i].atCol)
409 atValue = data_control[i].atValue;
417 case SDDS_CHECK_OKAY:
422 fprintf(stderr,
"Error: Column '%s' missing or invalid in file '%s'.\n",
423 data_control[i].interpCol, data_control[i].file[j]);
429 case SDDS_CHECK_OKAY:
430 if (!(data_control[i].atCol) &&
435 fprintf(stderr,
"Error: Column '%s' missing or invalid in file '%s'.\n",
436 data_control[i].funcOfCol, data_control[i].file[j]);
445 interpCodeRow = calloc(rows[pages],
sizeof(*interpCodeRow));
450#pragma omp parallel for if (threads > 1 && rows[pages] > 1) num_threads(threads) schedule(dynamic)
451 for (j = 0; j < rows[pages]; j++) {
452 double localAtValue, localResult;
453 unsigned long localInterpCode;
454 char localError[1024];
455 localAtValue = data_control[i].atCol ? data_control[i].colValue[j] : atValue;
460 if (!interpolateDataFile(data_control[i].file[j], &data_control[i], localAtValue,
461 &belowRange, &aboveRange, order, &localResult, &localInterpCode,
462 localError,
sizeof(localError))) {
467 snprintf(errorMessage,
sizeof(errorMessage),
"%s", localError);
471 out_depenValue[pages][i][j] = localResult;
472 interpCodeRow[j] = localInterpCode;
473 if (localInterpCode & OUTRANGE_SKIP)
474 rowFlag[pages][j] = 0;
479 fprintf(stderr,
"%s\n", errorMessage);
483 for (j = 0; j < rows[pages]; j++) {
484 if (interpCodeRow[j] & OUTRANGE_ABORT) {
485 fprintf(stderr,
"Error: Value %e out of range for column '%s'.\n",
486 data_control[i].atCol ? data_control[i].colValue[j] : atValue, data_control[i].interpCol);
489 if (interpCodeRow[j] & OUTRANGE_WARN)
490 fprintf(stderr,
"Warning: Value %e out of range for column '%s'.\n",
491 data_control[i].atCol ? data_control[i].colValue[j] : atValue, data_control[i].interpCol);
496 for (j = 0; j < data_control[i].files; j++)
497 free(data_control[i].file[j]);
498 free(data_control[i].file);
499 data_control[i].file = NULL;
501 if (data_control[i].colValue) {
502 free(data_control[i].colValue);
503 data_control[i].colValue = NULL;
512 if (!SDDS_StartTable(&SDDSout, rows[pages]))
521 for (i = 0; i < dataControls; i++) {
522 if (data_control[i].hasdata) {
524 rows[pages], data_control[i].interpCol)) {
527 if (!(data_control[i].atCol)) {
528 for (row = 0; row < rows[pages]; row++) {
530 data_control[i].funcOfCol, data_control[i].atValue, NULL)) {
555 freedatacontrol(data_control, dataControls);
557 if (out_depenValue) {
558 for (i = 0; i < pages; i++) {
559 for (j = 0; j < dataControls; j++)
560 free(out_depenValue[i][j]);
561 free(out_depenValue[i]);
564 free(out_depenValue);
579static long interpolateDataFile(
char *filename,
DATA_CONTROL *control,
double atValue,
580 OUTRANGE_CONTROL *belowRange, OUTRANGE_CONTROL *aboveRange,
581 long order,
double *result,
unsigned long *interpCode,
582 char *errorMessage,
long errorMessageSize) {
584 double *indepValue = NULL, *depenValue = NULL;
590 snprintf(errorMessage, errorMessageSize,
"Error: unable to open input data file '%s'.", filename);
596 snprintf(errorMessage, errorMessageSize,
"Error: Column '%s' missing or invalid in file '%s'.",
597 control->interpCol, filename);
602 snprintf(errorMessage, errorMessageSize,
"Error: Column '%s' missing or invalid in file '%s'.",
603 control->funcOfCol, filename);
608 snprintf(errorMessage, errorMessageSize,
"Error: unable to read data page from file '%s'.", filename);
614 snprintf(errorMessage, errorMessageSize,
"Error: No data found in file '%s'.", filename);
619 snprintf(errorMessage, errorMessageSize,
"Error: problem getting column '%s' from file '%s'.",
620 control->funcOfCol, filename);
625 snprintf(errorMessage, errorMessageSize,
"Error: problem getting column '%s' from file '%s'.",
626 control->interpCol, filename);
632 snprintf(errorMessage, errorMessageSize,
"Error: problem closing data file '%s'.", filename);
639 if (!(monotonicity = checkMonotonicity(indepValue, datarows))) {
640 snprintf(errorMessage, errorMessageSize,
"Error: Independent (%s) data in file '%s' is not monotonic.",
641 control->funcOfCol, filename);
647 *result =
interpolate(depenValue, indepValue, datarows, atValue,
648 belowRange, aboveRange, order, interpCode, monotonicity);
654long checkMonotonicity(
double *indepValue, int64_t rows) {
658 if (indepValue[rows - 1] > indepValue[0]) {
660 if (indepValue[rows] < indepValue[rows - 1])
665 if (indepValue[rows] > indepValue[rows - 1])
671void freedatacontrol(
DATA_CONTROL *data_control,
long dataControls) {
673 for (i = 0; i < dataControls; i++) {
674 free(data_control[i].interpCol);
675 free(data_control[i].funcOfCol);
676 free(data_control[i].fileColumn);
677 if (data_control[i].atCol)
678 free(data_control[i].atCol);
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
int32_t SDDS_CopyColumns(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source)
int32_t SDDS_CopyParameters(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source)
int32_t SDDS_InitializeCopy(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source, char *filename, char *filemode)
int32_t SDDS_SetRowValues(SDDS_DATASET *SDDS_dataset, int32_t mode, int64_t row,...)
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_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_GetColumnIndex(SDDS_DATASET *SDDS_dataset, char *name)
Retrieves the index of a named column in the SDDS dataset.
int32_t SDDS_CheckColumn(SDDS_DATASET *SDDS_dataset, char *name, char *units, int32_t type, FILE *fp_message)
Checks if a column exists in the SDDS dataset with the specified name, units, and type.
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.
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_ANY_NUMERIC_TYPE
Special identifier used by SDDS_Check*() routines to accept any numeric 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.
long bitsSet(unsigned long data)
Counts the number of set bits (1s) in the given data.
double interpolate(double *f, double *x, int64_t n, double xo, OUTRANGE_CONTROL *belowRange, OUTRANGE_CONTROL *aboveRange, long order, unsigned long *returnCode, long M)
Performs interpolation with range control options.
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)
void free_scanargs(SCANNED_ARG **scanned, int argc)
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.