67char *option[N_OPTIONS] = {
77static const char *USAGE =
78 "Usage: sddsinterpset [<input>] [<output>] \n"
79 " [-pipe=[input][,output]] \n"
80 " [-order=<number>] \n"
82 " [-data=fileColumn=<colName>,interpolate=<colName>,functionof=<colName>,\n"
83 " column=<colName> | atValue=<value>] \n"
84 " [-majorOrder=row|column] \n"
85 " [-belowRange={value=<value>|skip|saturate|extrapolate|wrap}[,{abort|warn}]] \n"
86 " [-aboveRange={value=<value>|skip|saturate|extrapolate|wrap}[,{abort|warn}]]\n\n"
88 " -verbose Print detailed processing messages.\n"
89 " -pipe Use standard SDDS Toolkit pipe options for input and output.\n"
90 " -order Specify the order of the polynomials used for interpolation.\n"
91 " Default is 1 (linear interpolation).\n"
92 " -data Define data interpolation parameters:\n"
93 " - fileColumn=<colName> : Column with data file names.\n"
94 " - interpolate=<colName> : Column to interpolate.\n"
95 " - functionof=<colName> : Independent variable column name.\n"
96 " - column=<colName> : Specify interpolation point as a column.\n"
98 " - atValue=<value> : Specify a fixed interpolation value.\n"
99 " -majorOrder Specify data ordering for output: 'row' or 'column'.\n"
100 " Default inherits from input file.\n"
101 " -belowRange Define behavior for interpolation points below data range:\n"
102 " Options: value=<value>, skip, saturate, extrapolate, wrap, abort, warn.\n"
103 " -aboveRange Define behavior for interpolation points above data range:\n"
104 " Options: value=<value>, skip, saturate, extrapolate, wrap, abort, warn.\n\n"
105 "Program by Hairong Shang. ("__DATE__
107 ", SVN revision: " SVN_VERSION
")\n";
109#define AT_COLUMN 0x00000001
110#define AT_VALUE 0x00000002
121 unsigned long hasdata;
125long checkMonotonicity(
double *indepValue, int64_t rows);
126void freedatacontrol(
DATA_CONTROL *data_control,
long dataControls);
128int main(
int argc,
char **argv) {
130 char *input = NULL, *output = NULL, **interpCol = NULL, **funcOf = NULL;
131 long order = 1, dataControls = 0, valid_option = 1, monotonicity;
134 OUTRANGE_CONTROL aboveRange, belowRange;
136 unsigned long pipeFlags = 0, interpCode = 0, majorOrderFlag;
138 double *indepValue = NULL, *depenValue = NULL, **out_depenValue = NULL, atValue = 0;
139 int32_t **rowFlag = NULL;
140 long valid_data = 0, index, pages = 0;
141 int64_t *rows = NULL;
142 int64_t i, j, datarows, row;
143 short columnMajorOrder = -1;
146 argc =
scanargs(&s_arg, argc, argv);
148 fprintf(stderr,
"%s", USAGE);
152 aboveRange.flags = belowRange.flags = OUTRANGE_SATURATE;
154 for (i_arg = 1; i_arg < argc; i_arg++) {
155 if (s_arg[i_arg].arg_type == OPTION) {
156 switch (
match_string(s_arg[i_arg].list[0], option, N_OPTIONS, 0)) {
157 case CLO_MAJOR_ORDER:
159 s_arg[i_arg].n_items--;
160 if (s_arg[i_arg].n_items > 0 &&
161 !
scanItemList(&majorOrderFlag, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
162 "row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
163 "column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL)) {
164 SDDS_Bomb(
"invalid -majorOrder syntax/values");
166 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
167 columnMajorOrder = 1;
168 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
169 columnMajorOrder = 0;
173 if (s_arg[i_arg].n_items != 2 ||
174 sscanf(s_arg[i_arg].list[1],
"%ld", &order) != 1 ||
176 SDDS_Bomb(
"invalid -order syntax/value");
181 if (!
processPipeOption(s_arg[i_arg].list + 1, s_arg[i_arg].n_items - 1, &pipeFlags)) {
187 s_arg[i_arg].n_items -= 1;
188 if (s_arg[i_arg].n_items < 1 ||
189 !
scanItemList(&aboveRange.flags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
190 "value",
SDDS_DOUBLE, &aboveRange.value, 1, OUTRANGE_VALUE,
191 "skip", -1, NULL, 0, OUTRANGE_SKIP,
192 "saturate", -1, NULL, 0, OUTRANGE_SATURATE,
193 "extrapolate", -1, NULL, 0, OUTRANGE_EXTRAPOLATE,
194 "wrap", -1, NULL, 0, OUTRANGE_WRAP,
195 "abort", -1, NULL, 0, OUTRANGE_ABORT,
196 "warn", -1, NULL, 0, OUTRANGE_WARN, NULL)) {
197 SDDS_Bomb(
"invalid -aboveRange syntax/value");
199 if ((i =
bitsSet(aboveRange.flags & (OUTRANGE_VALUE | OUTRANGE_SKIP | OUTRANGE_SATURATE |
200 OUTRANGE_EXTRAPOLATE | OUTRANGE_WRAP | OUTRANGE_ABORT))) > 1) {
201 SDDS_Bomb(
"incompatible keywords given for -aboveRange");
204 aboveRange.flags |= OUTRANGE_SATURATE;
212 s_arg[i_arg].n_items -= 1;
213 if (s_arg[i_arg].n_items < 1 ||
214 !
scanItemList(&belowRange.flags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
215 "value",
SDDS_DOUBLE, &belowRange.value, 1, OUTRANGE_VALUE,
216 "skip", -1, NULL, 0, OUTRANGE_SKIP,
217 "saturate", -1, NULL, 0, OUTRANGE_SATURATE,
218 "extrapolate", -1, NULL, 0, OUTRANGE_EXTRAPOLATE,
219 "wrap", -1, NULL, 0, OUTRANGE_WRAP,
220 "abort", -1, NULL, 0, OUTRANGE_ABORT,
221 "warn", -1, NULL, 0, OUTRANGE_WARN, NULL)) {
222 SDDS_Bomb(
"invalid -belowRange syntax/value");
224 if ((i =
bitsSet(belowRange.flags & (OUTRANGE_VALUE | OUTRANGE_SKIP | OUTRANGE_SATURATE |
225 OUTRANGE_EXTRAPOLATE | OUTRANGE_WRAP | OUTRANGE_ABORT))) > 1) {
226 SDDS_Bomb(
"incompatible keywords given for -belowRange");
229 belowRange.flags |= OUTRANGE_SATURATE;
233 s_arg[i_arg].n_items -= 1;
234 if (s_arg[i_arg].n_items < 4) {
237 data_control =
SDDS_Realloc(data_control,
sizeof(*data_control) * (dataControls + 1));
238 data_control[dataControls].fileColumn = data_control[dataControls].interpCol =
239 data_control[dataControls].funcOfCol = data_control[dataControls].atCol = NULL;
240 data_control[dataControls].file = NULL;
241 data_control[dataControls].files = 0;
242 data_control[dataControls].hasdata = 0;
243 data_control[dataControls].colValue = NULL;
244 data_control[dataControls].flags = 0;
246 if (!
scanItemList(&data_control[dataControls].flags, s_arg[i_arg].list + 1,
247 &s_arg[i_arg].n_items, 0,
248 "fileColumn",
SDDS_STRING, &(data_control[dataControls].fileColumn), 1, 0,
249 "interpolate",
SDDS_STRING, &(data_control[dataControls].interpCol), 1, 0,
250 "functionof",
SDDS_STRING, &(data_control[dataControls].funcOfCol), 1, 0,
251 "column",
SDDS_STRING, &(data_control[dataControls].atCol), 1, AT_COLUMN,
252 "atValue",
SDDS_DOUBLE, &(data_control[dataControls].atValue), 1, AT_VALUE, NULL) ||
253 !data_control[dataControls].fileColumn ||
254 !data_control[dataControls].interpCol ||
255 !data_control[dataControls].funcOfCol) {
259 if (!(data_control[dataControls].flags & AT_COLUMN) &&
260 !(data_control[dataControls].flags & AT_VALUE)) {
261 SDDS_Bomb(
"Invalid -data syntax: either column or atValue option should be given.");
264 if ((data_control[dataControls].flags & AT_COLUMN) &&
265 (data_control[dataControls].flags & AT_VALUE)) {
266 SDDS_Bomb(
"Invalid -data syntax: column and atValue options are not compatible.");
271 if (
match_string(data_control[dataControls].funcOfCol, funcOf, dataControls, EXACT_MATCH) > 0) {
272 fprintf(stderr,
"Multiple independent columns provided!\n");
275 if (
match_string(data_control[dataControls].interpCol, interpCol, dataControls, EXACT_MATCH) > 0) {
276 fprintf(stderr,
"Warning: Interpolate column '%s' has been used.\n", data_control[dataControls].interpCol);
282 interpCol =
SDDS_Realloc(interpCol,
sizeof(*interpCol) * (dataControls + 1));
283 funcOf =
SDDS_Realloc(funcOf,
sizeof(*funcOf) * (dataControls + 1));
284 interpCol[dataControls] = data_control[dataControls].interpCol;
285 funcOf[dataControls] = data_control[dataControls].funcOfCol;
291 fprintf(stderr,
"Error: Unknown or ambiguous option '%s'\n", s_arg[i_arg].list[0]);
297 input = s_arg[i_arg].list[0];
299 output = s_arg[i_arg].list[0];
301 SDDS_Bomb(
"Too many filenames provided.");
310 for (i = 0; i < dataControls; i++) {
312 fprintf(stderr,
"Warning: Column '%s' does not exist in input file '%s'.\n",
313 data_control[i].fileColumn, input);
317 fprintf(stderr,
"Error: Column '%s' in input file '%s' is not a string column.\n",
318 data_control[i].fileColumn, input);
321 if (data_control[i].atCol) {
323 fprintf(stderr,
"Warning: Column '%s' does not exist in input file '%s'.\n",
324 data_control[i].atCol, input);
328 fprintf(stderr,
"Error: Column '%s' in input file '%s' is not a numeric column.\n",
329 data_control[i].atCol, input);
333 data_control[i].hasdata = 1;
338 fprintf(stderr,
"Error: No valid -data options provided for processing.\n");
345 if (columnMajorOrder != -1)
346 SDDSout.layout.data_mode.column_major = columnMajorOrder;
348 SDDSout.layout.data_mode.column_major = SDDSin.layout.data_mode.column_major;
352 out_depenValue =
SDDS_Realloc(out_depenValue,
sizeof(*out_depenValue) * (pages + 1));
353 rowFlag =
SDDS_Realloc(rowFlag,
sizeof(*rowFlag) * (pages + 1));
356 fprintf(stderr,
"Error: No data found in input file '%s'.\n", input);
360 rowFlag[pages] = (int32_t *)malloc(
sizeof(**rowFlag) * rows[pages]);
361 out_depenValue[pages] = (
double *)malloc(
sizeof(**out_depenValue) * rows[pages]);
363 for (i = 0; i < rows[pages]; i++)
364 rowFlag[pages][i] = 1;
366 for (i = 0; i < dataControls; i++) {
367 if (data_control[i].hasdata) {
368 data_control[i].files = rows[pages];
369 if (!(data_control[i].file = (
char **)
SDDS_GetColumn(&SDDSin, data_control[i].fileColumn))) {
373 if (data_control[i].atCol) {
379 if (!data_control[i].atCol)
380 atValue = data_control[i].atValue;
382 for (j = 0; j < rows[pages]; j++) {
387 case SDDS_CHECK_OKAY:
388 if (j == (rows[pages] - 1)) {
396 fprintf(stderr,
"Error: Column '%s' missing or invalid in file '%s'.\n",
397 data_control[i].interpCol, data_control[i].file[j]);
403 case SDDS_CHECK_OKAY:
404 if (j == (rows[pages] - 1)) {
405 if ((!pages) && !(data_control[i].atCol)) {
412 fprintf(stderr,
"Error: Column '%s' missing or invalid in file '%s'.\n",
413 data_control[i].funcOfCol, data_control[i].file[j]);
433 if (!(monotonicity = checkMonotonicity(indepValue, datarows))) {
434 fprintf(stderr,
"Error: Independent (%s) data in file '%s' is not monotonic.\n",
435 data_control[i].funcOfCol, data_control[i].file[j]);
439 if (data_control[i].atCol)
440 atValue = data_control[i].colValue[j];
442 out_depenValue[pages][j] =
interpolate(depenValue, indepValue, datarows, atValue,
443 &belowRange, &aboveRange, order, &interpCode, monotonicity);
446 if (interpCode & OUTRANGE_ABORT) {
447 fprintf(stderr,
"Error: Value %e out of range for column '%s'.\n",
448 atValue, data_control[i].interpCol);
451 if (interpCode & OUTRANGE_WARN)
452 fprintf(stderr,
"Warning: Value %e out of range for column '%s'.\n",
453 atValue, data_control[i].interpCol);
454 if (interpCode & OUTRANGE_SKIP)
455 rowFlag[pages][j] = 0;
463 for (j = 0; j < data_control[i].files; j++)
464 free(data_control[i].file[j]);
465 free(data_control[i].file);
466 data_control[i].file = NULL;
468 if (data_control[i].colValue) {
469 free(data_control[i].colValue);
470 data_control[i].colValue = NULL;
479 if (!SDDS_StartTable(&SDDSout, rows[pages]))
488 for (i = 0; i < dataControls; i++) {
489 if (data_control[i].hasdata) {
491 rows[pages], data_control[i].interpCol)) {
494 if (!(data_control[i].atCol)) {
495 for (row = 0; row < rows[pages]; row++) {
497 data_control[i].funcOfCol, data_control[i].atValue, NULL)) {
522 freedatacontrol(data_control, dataControls);
524 if (out_depenValue) {
525 for (i = 0; i < pages; i++) {
526 free(out_depenValue[i]);
529 free(out_depenValue);
544long checkMonotonicity(
double *indepValue, int64_t rows) {
548 if (indepValue[rows - 1] > indepValue[0]) {
550 if (indepValue[rows] < indepValue[rows - 1])
555 if (indepValue[rows] > indepValue[rows - 1])
561void freedatacontrol(
DATA_CONTROL *data_control,
long dataControls) {
563 for (i = 0; i < dataControls; i++) {
564 free(data_control[i].interpCol);
565 free(data_control[i].funcOfCol);
566 free(data_control[i].fileColumn);
567 if (data_control[i].atCol)
568 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.