79char *option[N_OPTIONS] = {
93 "Usage: sddsfindin2dgrid [<input>] [<output>]\n"
94 " [-pipe=[input][,output]]\n"
95 " -gridVariables=<gridColumnName1>,<gridColumnName2>\n"
96 " -findLocationOf=<columnName1>,<columnName2>\n"
97 " {-valuesFile=<filename> | -atValues=<value1>,<value2>}\n"
99 " [-interpolate] [-mode={onePairPerPage|reuseFirstPage|all}]\n"
102 " This program searches a 2D grid to find the location (gridColumnName1, gridColumnName2)\n"
103 " where columnName1 and columnName2 are closest to the given values.\n\n"
105 " -gridVariables Names the two columns that are laid out on a grid.\n"
106 " -presorted Data is sorted by grid variables using 'sddssort'.\n"
107 " Pre-sorting can save considerable time if data is used repeatedly.\n"
108 " -findLocationOf Names the two columns to locate on the grid by finding optimal values.\n"
109 " -valuesFile Specifies a file containing pairs of values to find locations for.\n"
110 " -atValues Directly provides values to be found. This option may be repeated.\n"
111 " -interpolate Performs 2D linear interpolation to refine the location.\n"
112 " -mode Determines processing mode:\n"
113 " onePairPerPage - One pair per input page (default).\n"
114 " reuseFirstPage - Use all pairs with the first input page.\n"
115 " all - Use all pairs with all input pages.\n"
116 " -inverse Performs the inverse operation, interpolating to find values from grid locations.\n\n"
117 "Program Information:\n"
118 " Program by Michael Borland. (" __DATE__
" " __TIME__
", SVN revision: " SVN_VERSION
")\n";
120#define MODE_ONEPAIRPERPAGE 0x01UL
121#define MODE_REUSEFIRSTPAGE 0x02UL
122#define MODE_ALL 0x04UL
124static double *gridValue[2] = {NULL, NULL}, *valueAtLocation[2] = {NULL, NULL};
125static uint64_t ng[2] = {0, 0};
128void gridifyData(
char *gridVariable[2], uint64_t gridPoints,
short presorted);
129int findLocationInGrid(
double at1,
double at2,
double *location,
double *value,
short interpolate);
131int main(
int argc,
char **argv) {
134 SCANNED_ARG *scanned;
135 unsigned long pipeFlags;
136 uint64_t gridPoints = 0, atValues = 0, iv = 0, irow = 0;
137 char *input = NULL, *output = NULL, *fileForValues = NULL;
138 char *findLocationOf[2] = {NULL, NULL}, *gridVariable[2] = {NULL, NULL};
139 double *atValue[2] = {NULL, NULL}, value[2] = {0.0, 0.0};
140 short interpolate = 0, restarted = 0, needPage = 0, presorted = 0, inverse = 0;
141 unsigned long mode = MODE_ALL;
145 argc =
scanargs(&scanned, argc, argv);
147 fprintf(stderr,
"%s", USAGE);
151 for (iArg = 1; iArg < argc; iArg++) {
152 if (scanned[iArg].arg_type == OPTION) {
154 switch (
match_string(scanned[iArg].list[0], option, N_OPTIONS, 0)) {
155 case CLO_FINDLOCATIONOF:
156 if (scanned[iArg].n_items != 3 ||
157 !strlen(findLocationOf[0] = scanned[iArg].list[1]) ||
158 !strlen(findLocationOf[1] = scanned[iArg].list[2])) {
159 SDDS_Bomb(
"Invalid -findLocationOf syntax.\n");
161 if (strcmp(findLocationOf[0], findLocationOf[1]) == 0) {
162 SDDS_Bomb(
"Invalid -findLocationOf values: two variables are the same.\n");
165 case CLO_GRIDVARIABLES:
166 if (scanned[iArg].n_items != 3 ||
167 !strlen(gridVariable[0] = scanned[iArg].list[1]) ||
168 !strlen(gridVariable[1] = scanned[iArg].list[2])) {
169 SDDS_Bomb(
"Invalid -gridVariables syntax.\n");
171 if (strcmp(gridVariable[0], gridVariable[1]) == 0) {
172 SDDS_Bomb(
"Invalid -gridVariables values: two variables are the same.\n");
176 if (scanned[iArg].n_items != 2 ||
177 !strlen(fileForValues = scanned[iArg].list[1])) {
178 SDDS_Bomb(
"Invalid -valuesFile syntax.\n");
181 SDDS_Bomb(
"Cannot use -valuesFile and -atValues together.\n");
185 atValue[0] =
SDDS_Realloc(atValue[0],
sizeof(
double) * (atValues + 1));
186 atValue[1] =
SDDS_Realloc(atValue[1],
sizeof(
double) * (atValues + 1));
187 if (scanned[iArg].n_items != 3 ||
188 sscanf(scanned[iArg].list[1],
"%le", &atValue[0][atValues]) != 1 ||
189 sscanf(scanned[iArg].list[2],
"%le", &atValue[1][atValues]) != 1) {
190 SDDS_Bomb(
"Invalid -atValues syntax.\n");
193 SDDS_Bomb(
"Cannot use -valuesFile and -atValues together.\n");
198 if (!
processPipeOption(scanned[iArg].list + 1, scanned[iArg].n_items - 1, &pipeFlags)) {
202 case CLO_INTERPOLATE:
210 if ((scanned[iArg].n_items -= 1) != 1 ||
211 !
scanItemList(&mode, scanned[iArg].list + 1, &scanned[iArg].n_items, 0,
212 "onepairperpage", -1, NULL, 0, MODE_ONEPAIRPERPAGE,
213 "reusefirstpage", -1, NULL, 0, MODE_REUSEFIRSTPAGE,
214 "all", -1, NULL, 0, MODE_ALL,
224 fprintf(stderr,
"Invalid option: %s\n", scanned[iArg].list[0]);
225 fprintf(stderr,
"%s", USAGE);
230 input = scanned[iArg].list[0];
231 }
else if (!output) {
232 output = scanned[iArg].list[0];
234 SDDS_Bomb(
"Too many filenames provided.\n");
239 if (!findLocationOf[0] || !findLocationOf[1]) {
240 SDDS_Bomb(
"Must provide -findLocationOf option.\n");
242 if (!gridVariable[0] || !gridVariable[1]) {
243 SDDS_Bomb(
"Must provide -gridVariables option.\n");
245 if (!atValues && !fileForValues) {
246 SDDS_Bomb(
"Must provide either -atValues or -valuesFile option.\n");
256 SDDS_Bomb(
"Unable to read values file.\n");
258 if ((atValues = SDDS_RowCount(&SDDSvalues)) > 0) {
261 SDDS_Bomb(
"Unable to retrieve values of first grid variable in values file.\n");
264 SDDS_Bomb(
"Unable to retrieve values of second grid variable in values file.\n");
268 SDDS_Bomb(
"Unable to retrieve values of first findLocationOf variable in values file.\n");
271 SDDS_Bomb(
"Unable to retrieve values of second findLocationOf variable in values file.\n");
276 SDDS_Bomb(
"Values file contains multiple pages, which is not supported.\n");
303 needPage = (irow == 0) ? 1 : 0;
304 if (mode == MODE_ONEPAIRPERPAGE) {
305 if (iv == atValues) {
309 }
else if (mode == MODE_REUSEFIRSTPAGE) {
310 if (iv == atValues) {
316 }
else if (mode == MODE_ALL) {
317 if (iv == atValues) {
327 SDDS_Bomb(
"Too few pages in input file for number of location requests.\n");
334 free(valueAtLocation[0]);
335 free(valueAtLocation[1]);
336 gridValue[0] = gridValue[1] = valueAtLocation[0] = valueAtLocation[1] = NULL;
338 if ((gridPoints = SDDS_RowCount(&SDDSin)) <= 0) {
339 SDDS_Bomb(
"First page of input file is empty.\n");
343 SDDS_Bomb(
"Grid variables are missing from input file.\n");
347 SDDS_Bomb(
"Location variables are missing from input file.\n");
350 gridifyData(gridVariable, gridPoints, presorted);
355 double xmin, ymin, xmax, ymax, dx, dy, v1, v2, fx, fy;
359 xmin = gridValue[0][0];
360 ymin = gridValue[1][0];
361 xmax = gridValue[0][gridPoints - 1];
362 ymax = gridValue[1][gridPoints - 1];
363 dx = (xmax - xmin) / (ng[0] - 1);
364 dy = (ymax - ymin) / (ng[1] - 1);
367 ix = (x - xmin) / dx;
371 if (ix >= (int64_t)(ng[0] - 1)) {
374 iy = (y - ymin) / dy;
378 if (iy >= (int64_t)(ng[1] - 1)) {
381 fx = (x - (ix * dx + xmin)) / dx;
382 fy = (y - (iy * dy + ymin)) / dy;
384 ig = ix * ng[1] + iy;
385 v1 = valueAtLocation[0][ig] * (1 - fx) + valueAtLocation[0][ig + ng[1]] * fx;
386 ig = ix * ng[1] + iy + 1;
387 v2 = valueAtLocation[0][ig] * (1 - fx) + valueAtLocation[0][ig + ng[1]] * fx;
388 location[0] = v1 * (1 - fy) + v2 * fy;
391 ig = ix * ng[1] + iy;
392 v1 = valueAtLocation[1][ig] * (1 - fx) + valueAtLocation[1][ig + ng[1]] * fx;
393 ig = ix * ng[1] + iy + 1;
394 v2 = valueAtLocation[1][ig] * (1 - fx) + valueAtLocation[1][ig + ng[1]] * fx;
395 location[1] = v1 * (1 - fy) + v2 * fy;
398 0, value[0], 1, value[1], 2, location[0], 3, location[1],
403 if (!findLocationInGrid(atValue[0][iv], atValue[1][iv], &location[0], &value[0],
interpolate)) {
404 fprintf(stderr,
"Couldn't find location for %s=%.6le, %s=%.6le\n",
405 findLocationOf[0], atValue[0][iv],
406 findLocationOf[1], atValue[1][iv]);
410 0, location[0], 1, location[1], 2, value[0], 3, value[1],
425 free(valueAtLocation[0]);
426 free(valueAtLocation[1]);
427 gridValue[0] = gridValue[1] = valueAtLocation[0] = valueAtLocation[1] = NULL;
432double target[2], achieved[2];
434double distance(
double *position,
long *invalid) {
440 if (position[0] < 0 || position[0] >= ng[0] || position[1] < 0 || position[1] >= ng[1]) {
442 printf(
"Invalid position: %.6le, %.6le for ng=%" PRIu64
", %" PRIu64
"\n", position[0], position[1],
450 if (ix == (ng[0] - 1)) {
453 if (iy == (ng[1] - 1)) {
457 fx = position[0] - ix;
458 fy = position[1] - iy;
460 for (i = 0; i < 2; i++) {
461 double v00, v10, v01, v11, v0, v1;
462 v00 = valueAtLocation[i][(ix + 0) * ng[1] + (iy + 0)];
463 v10 = valueAtLocation[i][(ix + 1) * ng[1] + (iy + 0)];
464 v01 = valueAtLocation[i][(ix + 0) * ng[1] + (iy + 1)];
465 v11 = valueAtLocation[i][(ix + 1) * ng[1] + (iy + 1)];
466 v0 = v00 + (v10 - v00) * fx;
467 v1 = v01 + (v11 - v01) * fx;
468 v[i] = v0 + (v1 - v0) * fy;
472 return pow(target[0] - v[0], 2) + pow(target[1] - v[1], 2);
475int findLocationInGrid(
double at1,
double at2,
double *location,
double *value,
short interpolate) {
477 uint64_t ixBest = ng[0] / 2, iyBest = ng[1] / 2;
478 double delta, bestDelta = DBL_MAX;
481 for (ix = 0; ix < ng[0]; ix++) {
482 for (iy = 0; iy < ng[1]; iy++) {
484 delta = pow(valueAtLocation[0][j] - at1, 2) + pow(valueAtLocation[1][j] - at2, 2);
485 if (delta < bestDelta) {
486 location[0] = gridValue[0][j];
487 location[1] = gridValue[1][j];
488 value[0] = valueAtLocation[0][j];
489 value[1] = valueAtLocation[1][j];
498 double result, start[2], step[2], lower[2], upper[2];
501 step[0] = step[1] = 0.1;
502 lower[0] = lower[1] = 0;
503 upper[0] = ng[0] - 1;
504 upper[1] = ng[1] - 1;
507 if (
simplexMin(&result, start, step, lower, upper, NULL, 2, 0, 1e-14, distance,
508 NULL, 1500, 3, 12, 3, 1, 0) >= 0) {
509 double a00, a01, a10, a11, a0, a1, fx, fy;
514 if (ix >= (int64_t)(ng[0] - 1))
518 if (iy >= (int64_t)(ng[1] - 1))
523 for (i = 0; i < 2; i++) {
524 a00 = gridValue[i][(ix + 0) * ng[1] + (iy + 0)];
525 a10 = gridValue[i][(ix + 1) * ng[1] + (iy + 0)];
526 a01 = gridValue[i][(ix + 0) * ng[1] + (iy + 1)];
527 a11 = gridValue[i][(ix + 1) * ng[1] + (iy + 1)];
528 a0 = a00 + (a10 - a00) * fx;
529 a1 = a01 + (a11 - a01) * fx;
530 location[i] = a0 + (a1 - a0) * fy;
531 value[i] = achieved[i];
539int compareGridLocations(
const void *data1,
const void *data2) {
540 uint64_t i1 = *((uint64_t *)data1);
541 uint64_t i2 = *((uint64_t *)data2);
542 double diff = -(gridValue[0][i1] - gridValue[0][i2]);
544 diff = -(gridValue[1][i1] - gridValue[1][i2]);
547 return (diff < 0 ? 1 : (diff > 0 ? -1 : 0));
550void gridifyData(
char *gridVariable[2], uint64_t gridPoints,
short presorted) {
556 for (i = 0; i < 2; i++) {
557 double *copy =
tmalloc(
sizeof(
double) * gridPoints);
558 memcpy(copy, gridValue[i], gridPoints *
sizeof(
double));
559 qsort((
void *)copy, gridPoints,
sizeof(
double),
double_cmpasc);
561 for (j = 1; j < gridPoints; j++) {
562 if (copy[j - 1] != copy[j]) {
567 if (ng[i] == gridPoints) {
568 snprintf(s,
sizeof(s),
"Grid variable %s has only unique values.\n", gridVariable[i]);
572 snprintf(s,
sizeof(s),
"Grid variable %s has only one unique value.\n", gridVariable[i]);
576 if (ng[0] * ng[1] != gridPoints) {
577 snprintf(s,
sizeof(s),
"Input data does not form a grid (nx = %" PRIu64
", ny = %" PRIu64
", rows = %" PRIu64
")\n",
578 ng[0], ng[1], gridPoints);
584 index =
tmalloc(
sizeof(uint64_t) * gridPoints);
585 for (j = 0; j < gridPoints; j++) {
589 qsort((
void *)index, gridPoints,
sizeof(uint64_t), compareGridLocations);
592 for (i = 0; i < 2; i++) {
593 buffer =
tmalloc(
sizeof(
double) * gridPoints);
594 for (j = 0; j < gridPoints; j++) {
595 buffer[j] = gridValue[i][index[j]];
598 gridValue[i] = buffer;
600 buffer =
tmalloc(
sizeof(
double) * gridPoints);
601 for (j = 0; j < gridPoints; j++) {
602 buffer[j] = valueAtLocation[i][index[j]];
604 free(valueAtLocation[i]);
605 valueAtLocation[i] = buffer;
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
int32_t SDDS_SetRowValues(SDDS_DATASET *SDDS_dataset, int32_t mode, int64_t row,...)
int32_t SDDS_StartPage(SDDS_DATASET *SDDS_dataset, int64_t expected_n_rows)
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_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_TransferAllParameterDefinitions(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source, uint32_t mode)
Transfers all parameter definitions from a source dataset to a target dataset.
void SDDS_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
void SDDS_ClearErrors()
Clears all recorded error messages from the SDDS error stack.
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
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.
void * tmalloc(uint64_t size_of_block)
Allocates a memory block of the specified size with zero initialization.
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)
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.
long simplexMin(double *yReturn, double *xGuess, double *dxGuess, double *xLowerLimit, double *xUpperLimit, short *disable, long dimensions, double target, double tolerance, double(*func)(double *x, long *invalid), void(*report)(double ymin, double *xmin, long pass, long evals, long dims), long maxEvaluations, long maxPasses, long maxDivisions, double divisorFactor, double passRangeFactor, unsigned long flags)
Top-level convenience function for simplex-based minimization.
int double_cmpasc(const void *a, const void *b)
Compare two doubles in ascending order.