SDDS ToolKit Programs and Libraries for C and Python
All Classes Files Functions Variables Macros Pages
sddspoly.c
Go to the documentation of this file.
1/**
2 * @file sddspoly.c
3 * @brief Evaluates polynomials for N-dimensional input from SDDS files.
4 *
5 * @details
6 * This program reads input data from SDDS files and evaluates polynomials defined in an auxiliary SDDS file.
7 * It supports multiple input columns and generates an output SDDS file containing evaluated results.
8 *
9 * @section Usage
10 * ```
11 * sddspoly [<inputfile>] [<outputfile>] \
12 * [-pipe=[input][,output]] \
13 * -evaluate=filename=<polyFilename>,output=<column>,coefficients=<column>, \
14 * input0=<inputColumn>,power0=<powerColumn>[,input1=<inputColumn>,power1=<powerColumn>]...
15 * ```
16 *
17 * @section Options
18 * | Required | Description |
19 * |---------------------------------------|---------------------------------------------------------------------------------------|
20 * | `-evaluate` | Defines polynomial evaluation using options such as input and output file columns, coefficient, and power definitions. |
21 *
22 * | Optional | Description |
23 * |---------------------------------------|---------------------------------------------------------------------------------------|
24 * | `-pipe` | Allows input and output streams to be read/written directly to/from a pipeline. |
25 *
26 * @subsection spec_req Specific Requirements
27 * - For `-evaluate`:
28 * - Each `input<n>` and `power<n>` must be paired correctly to define variables and their exponents.
29 *
30 * @copyright
31 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
32 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
33 *
34 * @license
35 * This file is distributed under the terms of the Software License Agreement
36 * found in the file LICENSE included with this distribution.
37 *
38 * @authors
39 * M. Borland, H. Shang, R. Soliday
40 */
41
42#include "mdb.h"
43#include "SDDS.h"
44#include "scan.h"
45#include "SDDSutils.h"
46#include <ctype.h>
47
48/* Enumeration for option types */
49enum option_type {
50 CLO_PIPE,
51 CLO_EVALUATE,
52 N_OPTIONS
53};
54
55char *option[N_OPTIONS] = {
56 "pipe",
57 "evaluate",
58};
59
60static char *USAGE =
61 "sddspoly [<inputfile>] [<outputfile>] "
62 "[-pipe=[input][,output]]\n"
63 " -evaluate=filename=<polyFilename>,output=<column>,coefficients=<column>,\n"
64 " input0=<inputColumn>,power0=<powerColumn>[,input1=<inputColumn>,power1=<polyColumn>][,...]\n"
65 " [-evaluate=...]\n\n"
66 "Options:\n"
67 " -pipe Standard SDDS Toolkit pipe option.\n"
68 " -evaluate Specifies evaluation of a polynomial defined in <polyFilename>.\n"
69 " The results are stored in <outputfile> under the column name\n"
70 " specified by output=<column>.\n"
71 " The coefficients are taken from the column named\n"
72 " coefficients=<column>.\n"
73 " The input<n> qualifiers specify the column names in <inputfile>\n"
74 " that serve as inputs to the polynomial.\n"
75 " The power<n> qualifiers specify the column names in\n"
76 " <polyFilename> that provide the exponents for each input.\n\n"
77 "Program by Michael Borland. (" __DATE__ " " __TIME__ ", SVN revision: " SVN_VERSION ")\n";
78
79#define POLY_FILE_SEEN 0x0001U
80#define POLY_OUTPUT_SEEN 0x0002U
81#define POLY_COEF_SEEN 0x0004U
82#define POLY_IN0_SEEN 0x0008U
83#define POLY_OUT0_SEEN 0x0010U
84#define POLY_IN1_SEEN 0x0020U
85#define POLY_OUT1_SEEN 0x0040U
86#define POLY_IN2_SEEN 0x0080U
87#define POLY_OUT2_SEEN 0x0100U
88#define POLY_IN3_SEEN 0x0200U
89#define POLY_OUT3_SEEN 0x0400U
90#define POLY_IN4_SEEN 0x0800U
91#define POLY_OUT4_SEEN 0x1000U
92
93typedef struct {
94 unsigned long flags;
95 char *filename;
96 char *outputColumn;
97 char *coefColumn;
98 char **inputColumn;
99 char **powerColumn;
100 long nInputs;
101 long nTerms;
102 int32_t **power;
103 double *coef;
104 double **inputData;
105 double *input;
106} POLYNOMIAL;
107
108void initializePolynomial(POLYNOMIAL *poly, SDDS_DATASET *SDDSin, SDDS_DATASET *SDDSout);
109double evaluatePoly(double *coef, int32_t **power, long nCoef, double *input, long nInputs);
110void FreePolynormialMemory(POLYNOMIAL *poly, long npoly);
111
112int main(int argc, char **argv) {
114 long nPoly, iPoly, iInput;
115 int64_t row, rows;
116 int iArg;
117 char *input, *output;
118 unsigned long pipeFlags;
119 SCANNED_ARG *scanned;
120 SDDS_DATASET SDDSin, SDDSout;
121 double *outputData;
122
124 argc = scanargs(&scanned, argc, argv);
125 if (argc < 3) {
126 bomb(NULL, USAGE);
127 }
128
129 outputData = NULL;
130 input = output = NULL;
131 pipeFlags = 0;
132 poly = NULL;
133 nPoly = 0;
134
135 for (iArg = 1; iArg < argc; iArg++) {
136 if (scanned[iArg].arg_type == OPTION) {
137 /* process options here */
138 switch (match_string(scanned[iArg].list[0], option, N_OPTIONS, 0)) {
139 case CLO_EVALUATE:
140 poly = SDDS_Realloc(poly, sizeof(*poly) * (nPoly + 1));
141 if (!poly ||
142 !(poly[nPoly].inputColumn = SDDS_Malloc(sizeof(*(poly[nPoly].inputColumn)) * 5)) ||
143 !(poly[nPoly].powerColumn = SDDS_Malloc(sizeof(*(poly[nPoly].powerColumn)) * 5))) {
144 SDDS_Bomb("memory allocation failure");
145 }
146
147 scanned[iArg].n_items -= 1;
148 if (!scanItemList(&poly[nPoly].flags,
149 scanned[iArg].list + 1,
150 &scanned[iArg].n_items,
151 0,
152 "filename", SDDS_STRING, &(poly[nPoly].filename), 1, POLY_FILE_SEEN,
153 "output", SDDS_STRING, &(poly[nPoly].outputColumn), 1, POLY_OUTPUT_SEEN,
154 "coefficients", SDDS_STRING, &(poly[nPoly].coefColumn), 1, POLY_COEF_SEEN,
155 "input0", SDDS_STRING, poly[nPoly].inputColumn + 0, 1, POLY_IN0_SEEN,
156 "power0", SDDS_STRING, poly[nPoly].powerColumn + 0, 1, POLY_OUT0_SEEN,
157 "input1", SDDS_STRING, poly[nPoly].inputColumn + 1, 1, POLY_IN1_SEEN,
158 "power1", SDDS_STRING, poly[nPoly].powerColumn + 1, 1, POLY_OUT1_SEEN,
159 "input2", SDDS_STRING, poly[nPoly].inputColumn + 2, 1, POLY_IN2_SEEN,
160 "power2", SDDS_STRING, poly[nPoly].powerColumn + 2, 1, POLY_OUT2_SEEN,
161 "input3", SDDS_STRING, poly[nPoly].inputColumn + 3, 1, POLY_IN3_SEEN,
162 "power3", SDDS_STRING, poly[nPoly].powerColumn + 3, 1, POLY_OUT3_SEEN,
163 "input4", SDDS_STRING, poly[nPoly].inputColumn + 4, 1, POLY_IN4_SEEN,
164 "power4", SDDS_STRING, poly[nPoly].powerColumn + 4, 1, POLY_OUT4_SEEN,
165 NULL) ||
166 !(poly[nPoly].flags & POLY_FILE_SEEN) ||
167 !(poly[nPoly].flags & POLY_OUTPUT_SEEN) ||
168 !(poly[nPoly].flags & POLY_COEF_SEEN) ||
169 !(poly[nPoly].flags & POLY_IN0_SEEN) ||
170 !(poly[nPoly].flags & POLY_OUT0_SEEN)) {
171 SDDS_Bomb("invalid -evaluate syntax");
172 }
173 nPoly++;
174 break;
175
176 case CLO_PIPE:
177 if (!processPipeOption(scanned[iArg].list + 1,
178 scanned[iArg].n_items - 1,
179 &pipeFlags)) {
180 SDDS_Bomb("invalid -pipe syntax");
181 }
182 break;
183
184 default:
185 fprintf(stderr, "error: unknown/ambiguous option: %s\n", scanned[iArg].list[0]);
186 exit(EXIT_FAILURE);
187 break;
188 }
189 } else {
190 if (!input) {
191 input = scanned[iArg].list[0];
192 } else if (!output) {
193 output = scanned[iArg].list[0];
194 } else {
195 SDDS_Bomb("too many filenames seen");
196 }
197 }
198 }
199
200 processFilenames("sddspoly", &input, &output, pipeFlags, 0, NULL);
201
202 if (nPoly == 0) {
203 SDDS_Bomb("give at least one -evaluate option");
204 }
205
206 if (!SDDS_InitializeInput(&SDDSin, input)) {
207 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
208 }
209
210 if (!SDDS_InitializeCopy(&SDDSout, &SDDSin, output, "w")) {
211 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
212 }
213
214 for (iPoly = 0; iPoly < nPoly; iPoly++) {
215 initializePolynomial(&poly[iPoly], &SDDSin, &SDDSout);
216 }
217
218 if (!SDDS_WriteLayout(&SDDSout)) {
219 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
220 }
221
222 while (SDDS_ReadPage(&SDDSin) > 0) {
223 rows = SDDS_CountRowsOfInterest(&SDDSin);
224 if (!SDDS_CopyPage(&SDDSout, &SDDSin)) {
225 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
226 }
227
228 outputData = SDDS_Realloc(outputData, sizeof(*outputData) * rows);
229 if (!outputData) {
230 SDDS_Bomb("memory allocation failure");
231 }
232
233 for (iPoly = 0; iPoly < nPoly; iPoly++) {
234 for (iInput = 0; iInput < poly[iPoly].nInputs; iInput++) {
235 poly[iPoly].inputData[iInput] =
236 SDDS_GetColumnInDoubles(&SDDSin, poly[iPoly].inputColumn[iInput]);
237 if (!poly[iPoly].inputData[iInput]) {
238 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
239 }
240 }
241
242 for (row = 0; row < rows; row++) {
243 for (iInput = 0; iInput < poly[iPoly].nInputs; iInput++) {
244 poly[iPoly].input[iInput] = poly[iPoly].inputData[iInput][row];
245 }
246 outputData[row] = evaluatePoly(poly[iPoly].coef,
247 poly[iPoly].power,
248 poly[iPoly].nTerms,
249 poly[iPoly].input,
250 poly[iPoly].nInputs);
251 }
252
253 if (!SDDS_SetColumn(&SDDSout, SDDS_SET_BY_NAME, outputData, rows, poly[iPoly].outputColumn)) {
254 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
255 }
256 }
257
258 if (!SDDS_WritePage(&SDDSout)) {
259 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
260 }
261 }
262
263 free(outputData);
264
265 if (!SDDS_Terminate(&SDDSin)) {
266 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
267 exit(EXIT_FAILURE);
268 }
269
270 if (!SDDS_Terminate(&SDDSout)) {
271 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
272 exit(EXIT_FAILURE);
273 }
274
275 free_scanargs(&scanned, argc);
276 FreePolynormialMemory(poly, nPoly);
277 free(poly);
278
279 return EXIT_SUCCESS;
280}
281
282double evaluatePoly(double *coef, int32_t **power, long nCoef, double *input, long nInputs) {
283 double sum = 0.0, term;
284 long iCoef, iInput;
285
286 for (iCoef = 0; iCoef < nCoef; iCoef++) {
287 term = coef[iCoef];
288 for (iInput = 0; iInput < nInputs; iInput++) {
289 term *= ipow(input[iInput], power[iInput][iCoef]);
290 }
291 sum += term;
292 }
293
294 return sum;
295}
296
297void initializePolynomial(POLYNOMIAL *poly, SDDS_DATASET *SDDSin, SDDS_DATASET *SDDSout) {
298 long i;
299 SDDS_DATASET SDDSpoly;
300 char buffer[1024];
301
302 for (i = 1; i < 5; i++) {
303 if ((poly->flags & (POLY_IN0_SEEN << (2 * i))) &&
304 !(poly->flags & (POLY_OUT0_SEEN << (2 * i)))) {
305 SDDS_Bomb("input qualifier seen without matching output qualifier");
306 }
307 if (!(poly->flags & (POLY_IN0_SEEN << (2 * i))) &&
308 (poly->flags & (POLY_OUT0_SEEN << (2 * i)))) {
309 SDDS_Bomb("output qualifier seen without matching input qualifier");
310 }
311 if (!(poly->flags & (POLY_IN0_SEEN << (2 * i))) &&
312 !(poly->flags & (POLY_OUT0_SEEN << (2 * i)))) {
313 break;
314 }
315 }
316 poly->nInputs = i;
317
318 for (i++; i < 5; i++) {
319 if ((poly->flags & (POLY_IN0_SEEN << (2 * i))) ||
320 (poly->flags & (POLY_OUT0_SEEN << (2 * i)))) {
321 SDDS_Bomb("input<n> or output<n> qualifiers skipped");
322 }
323 }
324
325 if (!SDDS_InitializeInput(&SDDSpoly, poly->filename)) {
326 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
327 }
328
329 if (SDDS_GetColumnIndex(&SDDSpoly, poly->outputColumn) == -1) {
330 if (!SDDS_DefineSimpleColumn(SDDSout, poly->outputColumn, NULL, SDDS_DOUBLE)) {
331 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
332 }
333 } else {
334 if (SDDS_CheckColumn(&SDDSpoly, poly->outputColumn, NULL, SDDS_ANY_NUMERIC_TYPE, stderr) != SDDS_CHECK_OKAY) {
335 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
336 }
337 }
338
339 if (SDDS_CheckColumn(&SDDSpoly, poly->coefColumn, NULL, SDDS_ANY_NUMERIC_TYPE, stderr) != SDDS_CHECK_OKAY) {
340 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
341 }
342
343 for (i = 0; i < poly->nInputs; i++) {
344 if (SDDS_CheckColumn(SDDSin, poly->inputColumn[i], NULL, SDDS_ANY_NUMERIC_TYPE, stderr) != SDDS_CHECK_OKAY) {
345 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
346 }
347 if (SDDS_CheckColumn(&SDDSpoly, poly->powerColumn[i], NULL, SDDS_ANY_NUMERIC_TYPE, stderr) != SDDS_CHECK_OKAY) {
348 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
349 }
350 }
351
352 if (SDDS_ReadPage(&SDDSpoly) <= 0) {
353 snprintf(buffer, sizeof(buffer), "problem with file %s\n", poly->filename);
354 SDDS_SetError(buffer);
355 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
356 }
357
358 if ((poly->nTerms = SDDS_RowCount(&SDDSpoly)) <= 0) {
359 snprintf(buffer, sizeof(buffer), "problem with file %s: no rows\n", poly->filename);
360 SDDS_SetError(buffer);
361 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
362 }
363
364 poly->coef = SDDS_GetColumnInDoubles(&SDDSpoly, poly->coefColumn);
365 if (!poly->coef) {
366 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
367 }
368
369 poly->power = SDDS_Malloc(sizeof(*(poly->power)) * poly->nInputs);
370 if (!poly->power) {
371 SDDS_Bomb("memory allocation failure");
372 }
373
374 for (i = 0; i < poly->nInputs; i++) {
375 poly->power[i] = SDDS_GetColumnInLong(&SDDSpoly, poly->powerColumn[i]);
376 if (!poly->power[i]) {
377 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
378 }
379 }
380
381 if (!SDDS_Terminate(&SDDSpoly)) {
382 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
383 }
384
385 poly->input = SDDS_Malloc(sizeof(*(poly->input)) * poly->nInputs);
386 if (!poly->input) {
387 SDDS_Bomb("memory allocation failure");
388 }
389
390 poly->inputData = SDDS_Malloc(sizeof(*(poly->inputData)) * poly->nInputs);
391 if (!poly->inputData) {
392 SDDS_Bomb("memory allocation failure");
393 }
394}
395
396void FreePolynormialMemory(POLYNOMIAL *poly, long npoly) {
397 long i, j;
398
399 for (i = 0; i < npoly; i++) {
400 for (j = 0; j < poly[i].nInputs; j++) {
401 free(poly[i].power[j]);
402 free(poly[i].inputData[j]);
403 free(poly[i].inputColumn[j]);
404 free(poly[i].powerColumn[j]);
405 }
406 free(poly[i].powerColumn);
407 free(poly[i].inputColumn);
408 free(poly[i].power);
409 free(poly[i].input);
410 free(poly[i].inputData);
411 free(poly[i].coef);
412 free(poly[i].filename);
413 free(poly[i].coefColumn);
414 free(poly[i].outputColumn);
415 }
416}
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
int32_t SDDS_InitializeCopy(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source, char *filename, char *filemode)
Definition SDDS_copy.c:40
int32_t SDDS_CopyPage(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source)
Definition SDDS_copy.c:578
int32_t SDDS_SetColumn(SDDS_DATASET *SDDS_dataset, int32_t mode, void *data, int64_t rows,...)
Sets the values for one data column in the current data table of an SDDS dataset.
int64_t SDDS_CountRowsOfInterest(SDDS_DATASET *SDDS_dataset)
Counts the number of rows marked as "of interest" in the current data table.
int32_t * SDDS_GetColumnInLong(SDDS_DATASET *SDDS_dataset, char *column_name)
Retrieves the data of a specified numerical column as an array of 32-bit integers,...
double * SDDS_GetColumnInDoubles(SDDS_DATASET *SDDS_dataset, char *column_name)
Retrieves the data of a specified numerical column as an array of doubles, considering only rows mark...
int32_t SDDS_InitializeInput(SDDS_DATASET *SDDS_dataset, char *filename)
Definition SDDS_input.c:49
int32_t SDDS_Terminate(SDDS_DATASET *SDDS_dataset)
int32_t SDDS_ReadPage(SDDS_DATASET *SDDS_dataset)
int32_t SDDS_DefineSimpleColumn(SDDS_DATASET *SDDS_dataset, const char *name, const char *unit, int32_t type)
Defines a simple data column within the SDDS 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.
void SDDS_SetError(char *error_text)
Records an error message in the SDDS error stack.
Definition SDDS_utils.c:379
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.
Definition SDDS_utils.c:432
void * SDDS_Malloc(size_t size)
Allocates memory of a specified size.
Definition SDDS_utils.c:639
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
Definition SDDS_utils.c:288
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
Definition SDDS_utils.c:342
void * SDDS_Realloc(void *old_ptr, size_t new_size)
Reallocates memory to a new size.
Definition SDDS_utils.c:677
#define SDDS_STRING
Identifier for the string data type.
Definition SDDStypes.h:85
#define SDDS_ANY_NUMERIC_TYPE
Special identifier used by SDDS_Check*() routines to accept any numeric type.
Definition SDDStypes.h:157
#define SDDS_DOUBLE
Identifier for the double data type.
Definition SDDStypes.h:37
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.
Definition bomb.c:26
double ipow(const double x, const int64_t p)
Compute x raised to the power p (x^p).
Definition ipow.c:33
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.
double poly(double *a, long n, double x)
Evaluate a polynomial at a given point.
Definition poly.c:30
int scanargs(SCANNED_ARG **scanned, int argc, char **argv)
Definition scanargs.c:36
long processPipeOption(char **item, long items, unsigned long *flags)
Definition scanargs.c:356
void processFilenames(char *programName, char **input, char **output, unsigned long pipeFlags, long noWarnings, long *tmpOutputUsed)
Definition scanargs.c:390
void free_scanargs(SCANNED_ARG **scanned, int argc)
Definition scanargs.c:584
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.