84char *option[N_OPTIONS] = {
98 "Usage: sddsfindin2dgrid [<input>] [<output>] [-pipe=[input][,output]]\n"
99 " -gridVariables=<gridColumnName1>,<gridColumnName2>\n"
101 " -findLocationOf=<columnName1>,<columnName2>\n"
102 " {-valuesFile=<filename> | -atValues=<value1>,<value2>}\n"
103 " [-interpolate] [-mode={onePairPerPage|reuseFirstPage|all}]\n"
106 " This program searches a 2D grid to find the location (gridColumnName1, gridColumnName2)\n"
107 " where columnName1 and columnName2 are closest to the given values.\n\n"
109 " -gridVariables Names the two columns that are laid out on a grid.\n"
110 " -presorted Data is sorted by grid variables using 'sddssort'.\n"
111 " Pre-sorting can save considerable time if data is used repeatedly.\n"
112 " -findLocationOf Names the two columns to locate on the grid by finding optimal values.\n"
113 " -valuesFile Specifies a file containing pairs of values to find locations for.\n"
114 " -atValues Directly provides values to be found. This option may be repeated.\n"
115 " -interpolate Performs 2D linear interpolation to refine the location.\n"
116 " -mode Determines processing mode:\n"
117 " onePairPerPage - One pair per input page (default).\n"
118 " reuseFirstPage - Use all pairs with the first input page.\n"
119 " all - Use all pairs with all input pages.\n"
120 " -inverse Performs the inverse operation, interpolating to find values from grid locations.\n\n"
121 "Program Information:\n"
122 " Program by Michael Borland. (" __DATE__
" " __TIME__
", SVN revision: " SVN_VERSION
")\n";
124#define MODE_ONEPAIRPERPAGE 0x01UL
125#define MODE_REUSEFIRSTPAGE 0x02UL
126#define MODE_ALL 0x04UL
128static double *gridValue[2] = {NULL, NULL}, *valueAtLocation[2] = {NULL, NULL};
129static uint64_t ng[2] = {0, 0};
132void gridifyData(
char *gridVariable[2], uint64_t gridPoints,
short presorted);
133int findLocationInGrid(
double at1,
double at2,
double *location,
double *value,
short interpolate);
135int main(
int argc,
char **argv) {
138 SCANNED_ARG *scanned;
139 unsigned long pipeFlags;
140 uint64_t gridPoints = 0, atValues = 0, iv = 0, irow = 0;
141 char *input = NULL, *output = NULL, *fileForValues = NULL;
142 char *findLocationOf[2] = {NULL, NULL}, *gridVariable[2] = {NULL, NULL};
143 double *atValue[2] = {NULL, NULL}, value[2] = {0.0, 0.0};
144 short interpolate = 0, restarted = 0, needPage = 0, presorted = 0, inverse = 0;
145 unsigned long mode = MODE_ALL;
149 argc =
scanargs(&scanned, argc, argv);
151 fprintf(stderr,
"%s", USAGE);
155 for (iArg = 1; iArg < argc; iArg++) {
156 if (scanned[iArg].arg_type == OPTION) {
158 switch (
match_string(scanned[iArg].list[0], option, N_OPTIONS, 0)) {
159 case CLO_FINDLOCATIONOF:
160 if (scanned[iArg].n_items != 3 ||
161 !strlen(findLocationOf[0] = scanned[iArg].list[1]) ||
162 !strlen(findLocationOf[1] = scanned[iArg].list[2])) {
163 SDDS_Bomb(
"Invalid -findLocationOf syntax.\n");
165 if (strcmp(findLocationOf[0], findLocationOf[1]) == 0) {
166 SDDS_Bomb(
"Invalid -findLocationOf values: two variables are the same.\n");
169 case CLO_GRIDVARIABLES:
170 if (scanned[iArg].n_items != 3 ||
171 !strlen(gridVariable[0] = scanned[iArg].list[1]) ||
172 !strlen(gridVariable[1] = scanned[iArg].list[2])) {
173 SDDS_Bomb(
"Invalid -gridVariables syntax.\n");
175 if (strcmp(gridVariable[0], gridVariable[1]) == 0) {
176 SDDS_Bomb(
"Invalid -gridVariables values: two variables are the same.\n");
180 if (scanned[iArg].n_items != 2 ||
181 !strlen(fileForValues = scanned[iArg].list[1])) {
182 SDDS_Bomb(
"Invalid -valuesFile syntax.\n");
185 SDDS_Bomb(
"Cannot use -valuesFile and -atValues together.\n");
189 atValue[0] =
SDDS_Realloc(atValue[0],
sizeof(
double) * (atValues + 1));
190 atValue[1] =
SDDS_Realloc(atValue[1],
sizeof(
double) * (atValues + 1));
191 if (scanned[iArg].n_items != 3 ||
192 sscanf(scanned[iArg].list[1],
"%le", &atValue[0][atValues]) != 1 ||
193 sscanf(scanned[iArg].list[2],
"%le", &atValue[1][atValues]) != 1) {
194 SDDS_Bomb(
"Invalid -atValues syntax.\n");
197 SDDS_Bomb(
"Cannot use -valuesFile and -atValues together.\n");
202 if (!
processPipeOption(scanned[iArg].list + 1, scanned[iArg].n_items - 1, &pipeFlags)) {
206 case CLO_INTERPOLATE:
214 if ((scanned[iArg].n_items -= 1) != 1 ||
215 !
scanItemList(&mode, scanned[iArg].list + 1, &scanned[iArg].n_items, 0,
216 "onepairperpage", -1, NULL, 0, MODE_ONEPAIRPERPAGE,
217 "reusefirstpage", -1, NULL, 0, MODE_REUSEFIRSTPAGE,
218 "all", -1, NULL, 0, MODE_ALL,
228 fprintf(stderr,
"Invalid option: %s\n", scanned[iArg].list[0]);
229 fprintf(stderr,
"%s", USAGE);
234 input = scanned[iArg].list[0];
235 }
else if (!output) {
236 output = scanned[iArg].list[0];
238 SDDS_Bomb(
"Too many filenames provided.\n");
243 if (!findLocationOf[0] || !findLocationOf[1]) {
244 SDDS_Bomb(
"Must provide -findLocationOf option.\n");
246 if (!gridVariable[0] || !gridVariable[1]) {
247 SDDS_Bomb(
"Must provide -gridVariables option.\n");
249 if (!atValues && !fileForValues) {
250 SDDS_Bomb(
"Must provide either -atValues or -valuesFile option.\n");
260 SDDS_Bomb(
"Unable to read values file.\n");
262 if ((atValues = SDDS_RowCount(&SDDSvalues)) > 0) {
265 SDDS_Bomb(
"Unable to retrieve values of first grid variable in values file.\n");
268 SDDS_Bomb(
"Unable to retrieve values of second grid variable in values file.\n");
272 SDDS_Bomb(
"Unable to retrieve values of first findLocationOf variable in values file.\n");
275 SDDS_Bomb(
"Unable to retrieve values of second findLocationOf variable in values file.\n");
280 SDDS_Bomb(
"Values file contains multiple pages, which is not supported.\n");
307 needPage = (irow == 0) ? 1 : 0;
308 if (mode == MODE_ONEPAIRPERPAGE) {
309 if (iv == atValues) {
313 }
else if (mode == MODE_REUSEFIRSTPAGE) {
314 if (iv == atValues) {
320 }
else if (mode == MODE_ALL) {
321 if (iv == atValues) {
331 SDDS_Bomb(
"Too few pages in input file for number of location requests.\n");
338 free(valueAtLocation[0]);
339 free(valueAtLocation[1]);
340 gridValue[0] = gridValue[1] = valueAtLocation[0] = valueAtLocation[1] = NULL;
342 if ((gridPoints = SDDS_RowCount(&SDDSin)) <= 0) {
343 SDDS_Bomb(
"First page of input file is empty.\n");
347 SDDS_Bomb(
"Grid variables are missing from input file.\n");
351 SDDS_Bomb(
"Location variables are missing from input file.\n");
354 gridifyData(gridVariable, gridPoints, presorted);
359 double xmin, ymin, xmax, ymax, dx, dy, v1, v2, fx, fy;
363 xmin = gridValue[0][0];
364 ymin = gridValue[1][0];
365 xmax = gridValue[0][gridPoints - 1];
366 ymax = gridValue[1][gridPoints - 1];
367 dx = (xmax - xmin) / (ng[0] - 1);
368 dy = (ymax - ymin) / (ng[1] - 1);
371 ix = (x - xmin) / dx;
375 if (ix >= (int64_t)(ng[0] - 1)) {
378 iy = (y - ymin) / dy;
382 if (iy >= (int64_t)(ng[1] - 1)) {
385 fx = (x - (ix * dx + xmin)) / dx;
386 fy = (y - (iy * dy + ymin)) / dy;
388 ig = ix * ng[1] + iy;
389 v1 = valueAtLocation[0][ig] * (1 - fx) + valueAtLocation[0][ig + ng[1]] * fx;
390 ig = ix * ng[1] + iy + 1;
391 v2 = valueAtLocation[0][ig] * (1 - fx) + valueAtLocation[0][ig + ng[1]] * fx;
392 location[0] = v1 * (1 - fy) + v2 * fy;
395 ig = ix * ng[1] + iy;
396 v1 = valueAtLocation[1][ig] * (1 - fx) + valueAtLocation[1][ig + ng[1]] * fx;
397 ig = ix * ng[1] + iy + 1;
398 v2 = valueAtLocation[1][ig] * (1 - fx) + valueAtLocation[1][ig + ng[1]] * fx;
399 location[1] = v1 * (1 - fy) + v2 * fy;
402 0, value[0], 1, value[1], 2, location[0], 3, location[1],
407 if (!findLocationInGrid(atValue[0][iv], atValue[1][iv], &location[0], &value[0],
interpolate)) {
408 fprintf(stderr,
"Couldn't find location for %s=%.6le, %s=%.6le\n",
409 findLocationOf[0], atValue[0][iv],
410 findLocationOf[1], atValue[1][iv]);
414 0, location[0], 1, location[1], 2, value[0], 3, value[1],
429 free(valueAtLocation[0]);
430 free(valueAtLocation[1]);
431 gridValue[0] = gridValue[1] = valueAtLocation[0] = valueAtLocation[1] = NULL;
436double target[2], achieved[2];
438double distance(
double *position,
long *invalid) {
444 if (position[0] < 0 || position[0] >= ng[0] || position[1] < 0 || position[1] >= ng[1]) {
446 printf(
"Invalid position: %.6le, %.6le for ng=%" PRIu64
", %" PRIu64
"\n", position[0], position[1],
454 if (ix == (ng[0] - 1)) {
457 if (iy == (ng[1] - 1)) {
461 fx = position[0] - ix;
462 fy = position[1] - iy;
464 for (i = 0; i < 2; i++) {
465 double v00, v10, v01, v11, v0, v1;
466 v00 = valueAtLocation[i][(ix + 0) * ng[1] + (iy + 0)];
467 v10 = valueAtLocation[i][(ix + 1) * ng[1] + (iy + 0)];
468 v01 = valueAtLocation[i][(ix + 0) * ng[1] + (iy + 1)];
469 v11 = valueAtLocation[i][(ix + 1) * ng[1] + (iy + 1)];
470 v0 = v00 + (v10 - v00) * fx;
471 v1 = v01 + (v11 - v01) * fx;
472 v[i] = v0 + (v1 - v0) * fy;
476 return pow(target[0] - v[0], 2) + pow(target[1] - v[1], 2);
479int findLocationInGrid(
double at1,
double at2,
double *location,
double *value,
short interpolate) {
481 uint64_t ixBest = ng[0] / 2, iyBest = ng[1] / 2;
482 double delta, bestDelta = DBL_MAX;
485 for (ix = 0; ix < ng[0]; ix++) {
486 for (iy = 0; iy < ng[1]; iy++) {
488 delta = pow(valueAtLocation[0][j] - at1, 2) + pow(valueAtLocation[1][j] - at2, 2);
489 if (delta < bestDelta) {
490 location[0] = gridValue[0][j];
491 location[1] = gridValue[1][j];
492 value[0] = valueAtLocation[0][j];
493 value[1] = valueAtLocation[1][j];
502 double result, start[2], step[2], lower[2], upper[2];
505 step[0] = step[1] = 0.1;
506 lower[0] = lower[1] = 0;
507 upper[0] = ng[0] - 1;
508 upper[1] = ng[1] - 1;
511 if (
simplexMin(&result, start, step, lower, upper, NULL, 2, 0, 1e-14, distance,
512 NULL, 1500, 3, 12, 3, 1, 0) >= 0) {
513 double a00, a01, a10, a11, a0, a1, fx, fy;
518 if (ix >= (int64_t)(ng[0] - 1))
522 if (iy >= (int64_t)(ng[1] - 1))
527 for (i = 0; i < 2; i++) {
528 a00 = gridValue[i][(ix + 0) * ng[1] + (iy + 0)];
529 a10 = gridValue[i][(ix + 1) * ng[1] + (iy + 0)];
530 a01 = gridValue[i][(ix + 0) * ng[1] + (iy + 1)];
531 a11 = gridValue[i][(ix + 1) * ng[1] + (iy + 1)];
532 a0 = a00 + (a10 - a00) * fx;
533 a1 = a01 + (a11 - a01) * fx;
534 location[i] = a0 + (a1 - a0) * fy;
535 value[i] = achieved[i];
543int compareGridLocations(
const void *data1,
const void *data2) {
544 uint64_t i1 = *((uint64_t *)data1);
545 uint64_t i2 = *((uint64_t *)data2);
546 double diff = -(gridValue[0][i1] - gridValue[0][i2]);
548 diff = -(gridValue[1][i1] - gridValue[1][i2]);
551 return (diff < 0 ? 1 : (diff > 0 ? -1 : 0));
554void gridifyData(
char *gridVariable[2], uint64_t gridPoints,
short presorted) {
560 for (i = 0; i < 2; i++) {
561 double *copy =
tmalloc(
sizeof(
double) * gridPoints);
562 memcpy(copy, gridValue[i], gridPoints *
sizeof(
double));
563 qsort((
void *)copy, gridPoints,
sizeof(
double),
double_cmpasc);
565 for (j = 1; j < gridPoints; j++) {
566 if (copy[j - 1] != copy[j]) {
571 if (ng[i] == gridPoints) {
572 snprintf(s,
sizeof(s),
"Grid variable %s has only unique values.\n", gridVariable[i]);
576 snprintf(s,
sizeof(s),
"Grid variable %s has only one unique value.\n", gridVariable[i]);
580 if (ng[0] * ng[1] != gridPoints) {
581 snprintf(s,
sizeof(s),
"Input data does not form a grid (nx = %" PRIu64
", ny = %" PRIu64
", rows = %" PRIu64
")\n",
582 ng[0], ng[1], gridPoints);
588 index =
tmalloc(
sizeof(uint64_t) * gridPoints);
589 for (j = 0; j < gridPoints; j++) {
593 qsort((
void *)index, gridPoints,
sizeof(uint64_t), compareGridLocations);
596 for (i = 0; i < 2; i++) {
597 buffer =
tmalloc(
sizeof(
double) * gridPoints);
598 for (j = 0; j < gridPoints; j++) {
599 buffer[j] = gridValue[i][index[j]];
602 gridValue[i] = buffer;
604 buffer =
tmalloc(
sizeof(
double) * gridPoints);
605 for (j = 0; j < gridPoints; j++) {
606 buffer[j] = valueAtLocation[i][index[j]];
608 free(valueAtLocation[i]);
609 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.