82char *option[N_OPTIONS] = {
97 "Usage: sddsfindin2dgrid [<input>] [<output>]\n"
98 " [-pipe=[input][,output]]\n"
99 " -gridVariables=<gridColumnName1>,<gridColumnName2>\n"
100 " -findLocationOf=<columnName1>,<columnName2>\n"
101 " {-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"
121 " -verbose Prints possibly useful information while running\n\n"
122 "Program Information:\n"
123 " Program by Michael Borland. (" __DATE__
" " __TIME__
", SVN revision: " SVN_VERSION
")\n";
125#define MODE_ONEPAIRPERPAGE 0x01UL
126#define MODE_REUSEFIRSTPAGE 0x02UL
127#define MODE_ALL 0x04UL
129static double *gridValue[2] = {NULL, NULL}, *valueAtLocation[2] = {NULL, NULL};
130static uint64_t ng[2] = {0, 0};
133void gridifyData(
char *gridVariable[2], uint64_t gridPoints,
short presorted);
134int findLocationInGrid(
double at1,
double at2,
double *location,
double *value,
short interpolate);
135uint64_t findGridInterval(
double value,
short dimension);
137int main(
int argc,
char **argv) {
140 SCANNED_ARG *scanned;
141 unsigned long pipeFlags = 0;
142 uint64_t gridPoints = 0, atValues = 0, iv = 0, irow = 0;
143 char *input = NULL, *output = NULL, *fileForValues = NULL;
144 char *findLocationOf[2] = {NULL, NULL}, *gridVariable[2] = {NULL, NULL};
145 double *atValue[2] = {NULL, NULL}, value[2] = {0.0, 0.0};
146 short interpolate = 0, restarted = 0, needPage = 0, presorted = 0, inverse = 0, verbose = 0;
147 unsigned long mode = MODE_ALL;
151 argc =
scanargs(&scanned, argc, argv);
153 fprintf(stderr,
"%s", USAGE);
157 for (iArg = 1; iArg < argc; iArg++) {
158 if (scanned[iArg].arg_type == OPTION) {
160 switch (
match_string(scanned[iArg].list[0], option, N_OPTIONS, 0)) {
161 case CLO_FINDLOCATIONOF:
162 if (scanned[iArg].n_items != 3 ||
163 !strlen(findLocationOf[0] = scanned[iArg].list[1]) ||
164 !strlen(findLocationOf[1] = scanned[iArg].list[2])) {
165 SDDS_Bomb(
"Invalid -findLocationOf syntax.\n");
167 if (strcmp(findLocationOf[0], findLocationOf[1]) == 0) {
168 SDDS_Bomb(
"Invalid -findLocationOf values: two variables are the same.\n");
171 case CLO_GRIDVARIABLES:
172 if (scanned[iArg].n_items != 3 ||
173 !strlen(gridVariable[0] = scanned[iArg].list[1]) ||
174 !strlen(gridVariable[1] = scanned[iArg].list[2])) {
175 SDDS_Bomb(
"Invalid -gridVariables syntax.\n");
177 if (strcmp(gridVariable[0], gridVariable[1]) == 0) {
178 SDDS_Bomb(
"Invalid -gridVariables values: two variables are the same.\n");
182 if (scanned[iArg].n_items != 2 ||
183 !strlen(fileForValues = scanned[iArg].list[1])) {
184 SDDS_Bomb(
"Invalid -valuesFile syntax.\n");
187 SDDS_Bomb(
"Cannot use -valuesFile and -atValues together.\n");
191 atValue[0] =
SDDS_Realloc(atValue[0],
sizeof(
double) * (atValues + 1));
192 atValue[1] =
SDDS_Realloc(atValue[1],
sizeof(
double) * (atValues + 1));
193 if (scanned[iArg].n_items != 3 ||
194 sscanf(scanned[iArg].list[1],
"%le", &atValue[0][atValues]) != 1 ||
195 sscanf(scanned[iArg].list[2],
"%le", &atValue[1][atValues]) != 1) {
196 SDDS_Bomb(
"Invalid -atValues syntax.\n");
199 SDDS_Bomb(
"Cannot use -valuesFile and -atValues together.\n");
204 if (!
processPipeOption(scanned[iArg].list + 1, scanned[iArg].n_items - 1, &pipeFlags)) {
208 case CLO_INTERPOLATE:
216 if ((scanned[iArg].n_items -= 1) != 1 ||
217 !
scanItemList(&mode, scanned[iArg].list + 1, &scanned[iArg].n_items, 0,
218 "onepairperpage", -1, NULL, 0, MODE_ONEPAIRPERPAGE,
219 "reusefirstpage", -1, NULL, 0, MODE_REUSEFIRSTPAGE,
220 "all", -1, NULL, 0, MODE_ALL,
233 fprintf(stderr,
"Invalid option: %s\n", scanned[iArg].list[0]);
234 fprintf(stderr,
"%s", USAGE);
239 input = scanned[iArg].list[0];
240 }
else if (!output) {
241 output = scanned[iArg].list[0];
243 SDDS_Bomb(
"Too many filenames provided.\n");
248 if (!findLocationOf[0] || !findLocationOf[1]) {
249 SDDS_Bomb(
"Must provide -findLocationOf option.\n");
251 if (!gridVariable[0] || !gridVariable[1]) {
252 SDDS_Bomb(
"Must provide -gridVariables option.\n");
254 if (!atValues && !fileForValues) {
255 SDDS_Bomb(
"Must provide either -atValues or -valuesFile option.\n");
265 SDDS_Bomb(
"Unable to read values file.\n");
267 if ((atValues = SDDS_RowCount(&SDDSvalues)) > 0) {
269 fprintf(stderr,
"%" PRIu64
" values in values file\n", atValues);
272 SDDS_Bomb(
"Unable to retrieve values of first grid variable in values file.\n");
275 SDDS_Bomb(
"Unable to retrieve values of second grid variable in values file.\n");
279 SDDS_Bomb(
"Unable to retrieve values of first findLocationOf variable in values file.\n");
282 SDDS_Bomb(
"Unable to retrieve values of second findLocationOf variable in values file.\n");
287 SDDS_Bomb(
"Values file contains multiple pages, which is not supported.\n");
314 needPage = (irow == 0) ? 1 : 0;
315 if (mode == MODE_ONEPAIRPERPAGE) {
316 if (iv == atValues) {
320 }
else if (mode == MODE_REUSEFIRSTPAGE) {
321 if (iv == atValues) {
327 }
else if (mode == MODE_ALL) {
328 if (iv == atValues) {
338 SDDS_Bomb(
"Too few pages in input file for number of location requests.\n");
345 free(valueAtLocation[0]);
346 free(valueAtLocation[1]);
347 gridValue[0] = gridValue[1] = valueAtLocation[0] = valueAtLocation[1] = NULL;
349 if ((gridPoints = SDDS_RowCount(&SDDSin)) <= 0) {
350 SDDS_Bomb(
"First page of input file is empty.\n");
354 SDDS_Bomb(
"Grid variables are missing from input file.\n");
358 SDDS_Bomb(
"Location variables are missing from input file.\n");
361 gridifyData(gridVariable, gridPoints, presorted);
366 double x0, x1, y0, y1, v1, v2, fx, fy;
372 ix = findGridInterval(x, 0);
373 iy = findGridInterval(y, 1);
374 x0 = gridValue[0][ix * ng[1]];
375 x1 = gridValue[0][(ix + 1) * ng[1]];
376 y0 = gridValue[1][iy];
377 y1 = gridValue[1][iy + 1];
378 fx = (x - x0) / (x1 - x0);
379 fy = (y - y0) / (y1 - y0);
381 ig = ix * ng[1] + iy;
382 v1 = valueAtLocation[0][ig] * (1 - fx) + valueAtLocation[0][ig + ng[1]] * fx;
383 ig = ix * ng[1] + iy + 1;
384 v2 = valueAtLocation[0][ig] * (1 - fx) + valueAtLocation[0][ig + ng[1]] * fx;
385 location[0] = v1 * (1 - fy) + v2 * fy;
388 ig = ix * ng[1] + iy;
389 v1 = valueAtLocation[1][ig] * (1 - fx) + valueAtLocation[1][ig + ng[1]] * fx;
390 ig = ix * ng[1] + iy + 1;
391 v2 = valueAtLocation[1][ig] * (1 - fx) + valueAtLocation[1][ig + ng[1]] * fx;
392 location[1] = v1 * (1 - fy) + v2 * fy;
395 0, value[0], 1, value[1], 2, location[0], 3, location[1],
401 fprintf(stderr,
"Finding location for values (%le, %le)\n", atValue[0][iv], atValue[1][iv]);
402 if (!findLocationInGrid(atValue[0][iv], atValue[1][iv], &location[0], &value[0],
interpolate)) {
403 fprintf(stderr,
"Couldn't find location for %s=%.6le, %s=%.6le\n",
404 findLocationOf[0], atValue[0][iv],
405 findLocationOf[1], atValue[1][iv]);
409 fprintf(stderr,
"Location is (%le, %le) with values (%le, %le)\n", location[0], location[1], value[0], value[1]);
411 0, location[0], 1, location[1], 2, value[0], 3, value[1],
426 free(valueAtLocation[0]);
427 free(valueAtLocation[1]);
428 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 v[0] = target[0] - v[0];
477 v[1] = target[1] - v[1];
478 return v[0] * v[0] + v[1] * v[1];
481int findLocationInGrid(
double at1,
double at2,
double *location,
double *value,
short interpolate) {
483 uint64_t ixBest = ng[0] / 2, iyBest = ng[1] / 2;
484 double delta, bestDelta = DBL_MAX;
487 for (ix = 0; ix < ng[0]; ix++) {
488 for (iy = 0; iy < ng[1]; iy++) {
490 double delta0 = valueAtLocation[0][j] - at1;
491 double delta1 = valueAtLocation[1][j] - at2;
492 delta = delta0 * delta0 + delta1 * delta1;
493 if (delta < bestDelta) {
494 location[0] = gridValue[0][j];
495 location[1] = gridValue[1][j];
496 value[0] = valueAtLocation[0][j];
497 value[1] = valueAtLocation[1][j];
506 double result, start[2], step[2], lower[2], upper[2];
509 step[0] = step[1] = 0.1;
510 lower[0] = lower[1] = 0;
511 upper[0] = ng[0] - 1;
512 upper[1] = ng[1] - 1;
515 if (
simplexMin(&result, start, step, lower, upper, NULL, 2, 0, 1e-14, distance,
516 NULL, 1500, 3, 12, 3, 1, 0) >= 0) {
517 double a00, a01, a10, a11, a0, a1, fx, fy;
518 int64_t cellX = start[0] < 0 ? 0 : (int64_t)start[0];
519 int64_t cellY = start[1] < 0 ? 0 : (int64_t)start[1];
520 if (cellX >= (int64_t)(ng[0] - 1))
522 if (cellY >= (int64_t)(ng[1] - 1))
524 fx = start[0] - cellX;
525 fy = start[1] - cellY;
527 for (i = 0; i < 2; i++) {
528 a00 = gridValue[i][(cellX + 0) * ng[1] + (cellY + 0)];
529 a10 = gridValue[i][(cellX + 1) * ng[1] + (cellY + 0)];
530 a01 = gridValue[i][(cellX + 0) * ng[1] + (cellY + 1)];
531 a11 = gridValue[i][(cellX + 1) * ng[1] + (cellY + 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];
543uint64_t findGridInterval(
double value,
short dimension) {
544 uint64_t lower = 0, upper = ng[dimension] - 1, middle;
547 coordinate = dimension == 0 ? gridValue[0][0] : gridValue[1][0];
548 if (value <= coordinate)
550 coordinate = dimension == 0 ? gridValue[0][upper * ng[1]] : gridValue[1][upper];
551 if (value >= coordinate)
554 while (upper - lower > 1) {
555 middle = lower + (upper - lower) / 2;
556 coordinate = dimension == 0 ? gridValue[0][middle * ng[1]] : gridValue[1][middle];
557 if (value < coordinate)
565int compareGridLocations(
const void *data1,
const void *data2) {
566 uint64_t i1 = *((uint64_t *)data1);
567 uint64_t i2 = *((uint64_t *)data2);
568 double diff = -(gridValue[0][i1] - gridValue[0][i2]);
570 diff = -(gridValue[1][i1] - gridValue[1][i2]);
573 return (diff < 0 ? 1 : (diff > 0 ? -1 : 0));
576void gridifyData(
char *gridVariable[2], uint64_t gridPoints,
short presorted) {
582 for (i = 0; i < 2; i++) {
583 double *copy =
tmalloc(
sizeof(
double) * gridPoints);
584 memcpy(copy, gridValue[i], gridPoints *
sizeof(
double));
585 qsort((
void *)copy, gridPoints,
sizeof(
double),
double_cmpasc);
587 for (j = 1; j < gridPoints; j++) {
588 if (copy[j - 1] != copy[j]) {
593 if (ng[i] == gridPoints) {
594 snprintf(s,
sizeof(s),
"Grid variable %s has only unique values.\n", gridVariable[i]);
598 snprintf(s,
sizeof(s),
"Grid variable %s has only one unique value.\n", gridVariable[i]);
602 if (ng[0] * ng[1] != gridPoints) {
603 snprintf(s,
sizeof(s),
"Input data does not form a grid (nx = %" PRIu64
", ny = %" PRIu64
", rows = %" PRIu64
")\n",
604 ng[0], ng[1], gridPoints);
610 index =
tmalloc(
sizeof(uint64_t) * gridPoints);
611 for (j = 0; j < gridPoints; j++) {
615 qsort((
void *)index, gridPoints,
sizeof(uint64_t), compareGridLocations);
618 for (i = 0; i < 2; i++) {
619 buffer =
tmalloc(
sizeof(
double) * gridPoints);
620 for (j = 0; j < gridPoints; j++) {
621 buffer[j] = gridValue[i][index[j]];
624 gridValue[i] = buffer;
626 buffer =
tmalloc(
sizeof(
double) * gridPoints);
627 for (j = 0; j < gridPoints; j++) {
628 buffer[j] = valueAtLocation[i][index[j]];
630 free(valueAtLocation[i]);
631 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)
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.
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.