143 {
144 double *xData = NULL, *yData = NULL, *syData = NULL;
145 int64_t nData = 0;
147 SCANNED_ARG *s_arg;
148 long i_arg;
149 char *input, *output, *xName, *yName, *syName;
150 long xIndex, yIndex, fitIndex, residualIndex, syIndex_out, retval;
151 double *fitData, *residualData, rmsResidual, chiSqr, sigLevel;
152 unsigned long guessFlags, dummyFlags, pipeFlags, majorOrderFlag;
153 double sigmaGuess, meanGuess, baselineGuess, heightGuess;
154 double tolerance, stepSize;
155 double a[4], da[4], lower, upper, result;
156 double aLow[4], aHigh[4];
157 short disable[4] = {0, 0, 0, 0};
158 int32_t nEvalMax = 5000, nPassMax = 100;
159 long nEval, verbosity, fullOutput = 0;
160 int64_t i;
161 short columnMajorOrder = -1;
162 char *lowerPar, *upperPar, *baselineGuessPar, *sigmaGuessPar, *meanGuessPar, *heightGuessPar;
163
165 argc =
scanargs(&s_arg, argc, argv);
166 if (argc < 2 || argc > (2 + N_OPTIONS)) {
168 }
169
170 for (i = 0; i < 4; i++) {
171 aLow[i] = -(aHigh[i] = DBL_MAX);
172 }
173 aLow[SIGMA_INDEX] = 0;
174 input = output = NULL;
175 stepSize = 1e-2;
176 tolerance = 1e-8;
177 verbosity = 0;
178 guessFlags = sigmaGuess = heightGuess = baselineGuess = meanGuess = pipeFlags = 0;
179 xName = yName = syName = NULL;
180 lower = upper = 0;
181 lowerPar = upperPar = sigmaGuessPar = heightGuessPar = baselineGuessPar = meanGuessPar = NULL;
182
183 for (i_arg = 1; i_arg < argc; i_arg++) {
184 if (s_arg[i_arg].arg_type == OPTION) {
185 switch (
match_string(s_arg[i_arg].list[0], option, N_OPTIONS, 0)) {
186 case SET_MAJOR_ORDER:
187 majorOrderFlag = 0;
188 s_arg[i_arg].n_items--;
189 if (s_arg[i_arg].n_items > 0 && (!
scanItemList(&majorOrderFlag, s_arg[i_arg].list + 1,
190 &s_arg[i_arg].n_items, 0, "row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
191 "column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL))) {
192 SDDS_Bomb(
"invalid -majorOrder syntax/values");
193 }
194 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER) {
195 columnMajorOrder = 1;
196 } else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER) {
197 columnMajorOrder = 0;
198 }
199 break;
200
201 case SET_FITRANGE:
202 if (s_arg[i_arg].n_items != 3) {
204 }
205 if (s_arg[i_arg].list[1][0] == '@') {
206 cp_str(&lowerPar, s_arg[i_arg].list[1] + 1);
207 } else if (sscanf(s_arg[i_arg].list[1], "%lf", &lower) != 1) {
208 SDDS_Bomb(
"invalid fitRange lower value provided");
209 }
210 if (s_arg[i_arg].list[2][0] == '@') {
211 cp_str(&upperPar, s_arg[i_arg].list[2] + 1);
212 } else if (sscanf(s_arg[i_arg].list[2], "%lf", &upper) != 1) {
213 SDDS_Bomb(
"invalid fitRange upper value provided");
214 }
215 break;
216
217 case SET_TOLERANCE:
218 if (s_arg[i_arg].n_items != 2 ||
219 sscanf(s_arg[i_arg].list[1], "%lf", &tolerance) != 1 ||
220 tolerance <= 0) {
221 SDDS_Bomb(
"incorrect -tolerance syntax");
222 }
223 break;
224
225 case SET_STEPSIZE:
226 if (s_arg[i_arg].n_items != 2 ||
227 sscanf(s_arg[i_arg].list[1], "%lf", &stepSize) != 1 ||
228 stepSize <= 0) {
230 }
231 break;
232
233 case SET_VERBOSITY:
234 if (s_arg[i_arg].n_items != 2 ||
235 sscanf(s_arg[i_arg].list[1], "%ld", &verbosity) != 1) {
236 SDDS_Bomb(
"incorrect -verbosity syntax");
237 }
238 break;
239
240 case SET_GUESSES:
241 if (s_arg[i_arg].n_items < 2) {
243 }
244 s_arg[i_arg].n_items -= 1;
245 dummyFlags = guessFlags;
246 if (!
scanItemList(&guessFlags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
247 "baseline",
SDDS_STRING, &baselineGuessPar, 1, GUESS_BASELINE_GIVEN,
248 "height",
SDDS_STRING, &heightGuessPar, 1, GUESS_HEIGHT_GIVEN,
249 "mean",
SDDS_STRING, &meanGuessPar, 1, GUESS_MEAN_GIVEN,
250 "sigma",
SDDS_STRING, &sigmaGuessPar, 1, GUESS_SIGMA_GIVEN, NULL)) {
252 }
253 if (baselineGuessPar) {
254 if (baselineGuessPar[0] == '@') {
255 baselineGuessPar++;
256 } else {
257 if (sscanf(baselineGuessPar, "%lf", &baselineGuess) != 1) {
258 SDDS_Bomb(
"Invalid baseline guess value provided.");
259 }
260 free(baselineGuessPar);
261 baselineGuessPar = NULL;
262 }
263 }
264 if (heightGuessPar) {
265 if (heightGuessPar[0] == '@') {
266 heightGuessPar++;
267 } else {
268 if (sscanf(heightGuessPar, "%lf", &heightGuess) != 1) {
269 SDDS_Bomb(
"Invalid height guess value provided.");
270 }
271 free(heightGuessPar);
272 heightGuessPar = NULL;
273 }
274 }
275 if (meanGuessPar) {
276 if (meanGuessPar[0] == '@') {
277 meanGuessPar++;
278 } else {
279 if (sscanf(meanGuessPar, "%lf", &meanGuess) != 1) {
280 SDDS_Bomb(
"Invalid mean guess value provided.");
281 }
282 free(meanGuessPar);
283 meanGuessPar = NULL;
284 }
285 }
286 if (sigmaGuessPar) {
287 if (sigmaGuessPar[0] == '@') {
288 sigmaGuessPar++;
289 } else {
290 if (sscanf(sigmaGuessPar, "%lf", &sigmaGuess) != 1) {
291 SDDS_Bomb(
"Invalid sigma guess value provided.");
292 }
293 free(sigmaGuessPar);
294 sigmaGuessPar = NULL;
295 }
296 }
297 if ((dummyFlags >> 4) & guessFlags) {
298 SDDS_Bomb(
"can't have -fixedValue and -guesses for the same item");
299 }
300 guessFlags |= dummyFlags;
301 break;
302
303 case SET_FIXVALUE:
304 if (s_arg[i_arg].n_items < 2) {
306 }
307 s_arg[i_arg].n_items -= 1;
308 dummyFlags = guessFlags;
309 if (!
scanItemList(&guessFlags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
310 "baseline",
SDDS_STRING, &baselineGuessPar, 1, FIX_BASELINE_GIVEN,
311 "height",
SDDS_STRING, &heightGuessPar, 1, FIX_HEIGHT_GIVEN,
312 "mean",
SDDS_STRING, &meanGuessPar, 1, FIX_MEAN_GIVEN,
313 "sigma",
SDDS_STRING, &sigmaGuessPar, 1, FIX_SIGMA_GIVEN, NULL)) {
315 }
316 if (dummyFlags & (guessFlags >> 4)) {
317 SDDS_Bomb(
"can't have -fixValue and -guesses for the same item");
318 }
319 guessFlags |= dummyFlags;
320 if (baselineGuessPar) {
321 if (baselineGuessPar[0] == '@') {
322 baselineGuessPar++;
323 } else {
324 if (sscanf(baselineGuessPar, "%lf", &baselineGuess) != 1) {
325 SDDS_Bomb(
"Invalid baseline guess value provided.");
326 }
327 free(baselineGuessPar);
328 baselineGuessPar = NULL;
329 }
330 }
331 if (heightGuessPar) {
332 if (heightGuessPar[0] == '@') {
333 heightGuessPar++;
334 } else {
335 if (sscanf(heightGuessPar, "%lf", &heightGuess) != 1) {
336 SDDS_Bomb(
"Invalid height guess value provided.");
337 }
338 free(heightGuessPar);
339 heightGuessPar = NULL;
340 }
341 }
342 if (meanGuessPar) {
343 if (meanGuessPar[0] == '@') {
344 meanGuessPar++;
345 } else {
346 if (sscanf(meanGuessPar, "%lf", &meanGuess) != 1) {
347 SDDS_Bomb(
"Invalid mean guess value provided.");
348 }
349 free(meanGuessPar);
350 meanGuessPar = NULL;
351 }
352 }
353 if (sigmaGuessPar) {
354 if (sigmaGuessPar[0] == '@') {
355 sigmaGuessPar++;
356 } else {
357 if (sscanf(sigmaGuessPar, "%lf", &sigmaGuess) != 1) {
358 SDDS_Bomb(
"Invalid sigma guess value provided.");
359 }
360 free(sigmaGuessPar);
361 sigmaGuessPar = NULL;
362 }
363 }
364 break;
365
366 case SET_COLUMNS:
367 if (s_arg[i_arg].n_items != 3 && s_arg[i_arg].n_items != 4) {
369 }
370 xName = s_arg[i_arg].list[1];
371 yName = s_arg[i_arg].list[2];
372 s_arg[i_arg].n_items -= 3;
373 if (!
scanItemList(&dummyFlags, s_arg[i_arg].list + 3, &s_arg[i_arg].n_items, 0,
376 }
377 break;
378
379 case SET_FULLOUTPUT:
380 fullOutput = 1;
381 break;
382
383 case SET_LIMITS:
384 if (s_arg[i_arg].n_items < 2) {
386 }
387 s_arg[i_arg].n_items -= 1;
388 if (!
scanItemList(&dummyFlags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
389 "evaluations",
SDDS_LONG, &nEvalMax, 1, 0,
390 "passes",
SDDS_LONG, &nPassMax, 1, 0, NULL) ||
391 nEvalMax <= 0 || nPassMax <= 0) {
393 }
394 break;
395
396 case SET_PIPE:
397 if (!
processPipeOption(s_arg[i_arg].list + 1, s_arg[i_arg].n_items - 1, &pipeFlags)) {
399 }
400 break;
401
402 default:
403 fprintf(stderr, "error: unknown/ambiguous option: %s\n", s_arg[i_arg].list[0]);
404 exit(EXIT_FAILURE);
405 break;
406 }
407 } else {
408 if (input == NULL) {
409 input = s_arg[i_arg].list[0];
410 } else if (output == NULL) {
411 output = s_arg[i_arg].list[0];
412 } else {
414 }
415 }
416 }
417
419
420 for (i = 0; i < 4; i++) {
421 if ((guessFlags >> 4) & (1 << i)) {
422 disable[i] = 1;
423 }
424 }
425
426 if (!xName || !yName) {
427 SDDS_Bomb(
"-columns option must be given");
428 }
429
432 }
435 (syName && !
SDDS_FindColumn(&InputTable, FIND_NUMERIC_TYPE, syName, NULL))) {
436 SDDS_Bomb(
"one or more of the given data columns is nonexistent or nonnumeric");
437 }
438
439 setupOutputFile(&OutputTable, &xIndex, &yIndex, &syIndex_out, &fitIndex, &residualIndex,
440 fullOutput, output, &InputTable, xName, yName, syName, columnMajorOrder);
441
443 xData = yData = syData = NULL;
444 fitData = residualData = NULL;
448 }
451 }
454 }
457 }
460 }
463 }
466 }
469 }
470
472 continue;
473 }
474 if (lower < upper) {
475 if ((nDataFit = makeFilteredCopy(&xDataFit, &yDataFit, &syDataFit, xData, yData, syData, nData, lower, upper)) < 5) {
476 continue;
477 }
478 } else {
479 xDataFit = xData;
480 yDataFit = yData;
481 syDataFit = syData;
482 nDataFit = nData;
483 }
484
485 if (!computeStartingPoint(a, da, xDataFit, yDataFit, nDataFit, guessFlags, sigmaGuess, meanGuess,
486 baselineGuess, heightGuess, stepSize)) {
487 fprintf(stderr, "error: couldn't compute starting point for page %ld--skipping\n", retval);
488 continue;
489 }
490 if (verbosity > 2) {
491 fprintf(stderr, "starting values: sigma=%.6e mean=%.6e baseline=%.6e height=%.6e\n",
492 a[SIGMA_INDEX], a[MEAN_INDEX], a[BASELINE_INDEX], a[HEIGHT_INDEX]);
493 }
494 if (verbosity > 3) {
495 fprintf(stderr, "starting steps: sigma=%.6e mean=%.6e baseline=%.6e height=%.6e\n",
496 da[SIGMA_INDEX], da[MEAN_INDEX], da[BASELINE_INDEX], da[HEIGHT_INDEX]);
497 }
498
499 nEval =
simplexMin(&result, a, da, aLow, aHigh, disable, 4, -DBL_MAX, tolerance,
500 fitFunction, (verbosity > 0 ? report : NULL),
501 nEvalMax, nPassMax, 12, 3, 1.0, 0);
502 if (xData != xDataFit) {
503 free(xDataFit);
504 free(yDataFit);
505 if (syDataFit) {
506 free(syDataFit);
507 }
508 }
509
510 if (verbosity > 3) {
511 fprintf(stderr, "%ld evaluations of fit function required, giving result %e\n", nEval, result);
512 }
513
514 fitData =
trealloc(fitData,
sizeof(*fitData) * nData);
515 residualData =
trealloc(residualData,
sizeof(*residualData) * nData);
516 for (i = 0, result = 0; i < nData; i++) {
517 fitData[i] = a[BASELINE_INDEX] + a[HEIGHT_INDEX] * exp(-
ipow((xData[i] - a[MEAN_INDEX]) / a[SIGMA_INDEX], 2) / 2);
518 residualData[i] = yData[i] - fitData[i];
519 result += sqr(residualData[i]);
520 }
521 rmsResidual = sqrt(result / nData);
522 if (syData) {
523 for (i = 0, chiSqr = 0; i < nData; i++) {
524 chiSqr += sqr(residualData[i] / syData[i]);
525 }
526 } else {
527 double sy2 = result / (nData - 4);
528 for (i = 0, chiSqr = 0; i < nData; i++) {
529 chiSqr += sqr(residualData[i]) / sy2;
530 }
531 }
533 if (verbosity > 0) {
534 fprintf(stderr, "sigma: %.15e\nmean: %.15e\nbaseline: %.15e\nheight: %.15e\n",
535 a[SIGMA_INDEX], a[MEAN_INDEX], a[BASELINE_INDEX], a[HEIGHT_INDEX]);
536 }
537 if (verbosity > 1) {
538 if (syData) {
539 fprintf(stderr, "Significance level: %.5e\n", sigLevel);
540 }
541 fprintf(stderr, "RMS deviation: %.15e\n", rmsResidual);
542 }
543
546 !
SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, xData, nData, xIndex) ||
547 !
SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, fitData, nData, fitIndex) ||
549 "gfitSigma", a[SIGMA_INDEX],
550 "gfitMean", a[MEAN_INDEX],
551 "gfitBaseline", a[BASELINE_INDEX],
552 "gfitHeight", a[HEIGHT_INDEX],
553 "gfitRmsResidual", rmsResidual,
554 "gfitSigLevel", sigLevel, NULL) ||
555 (fullOutput &&
556 (!
SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, yData, nData, yIndex) ||
557 !
SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, residualData, nData, residualIndex) ||
558 (syName && !
SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, syData, nData, syIndex_out)))) ||
561 }
562
563 if (xData) {
564 free(xData);
565 }
566 if (yData) {
567 free(yData);
568 }
569 if (syData) {
570 free(syData);
571 }
572 if (fitData) {
573 free(fitData);
574 }
575 if (residualData) {
576 free(residualData);
577 }
578 }
579
582 exit(EXIT_FAILURE);
583 }
584 if (lowerPar) {
585 free(lowerPar);
586 }
587 if (upperPar) {
588 free(upperPar);
589 }
590 if (baselineGuessPar) {
591 free(baselineGuessPar);
592 }
593 if (heightGuessPar) {
594 free(heightGuessPar);
595 }
596 if (sigmaGuessPar) {
597 free(sigmaGuessPar);
598 }
600 return EXIT_SUCCESS;
601}
int32_t SDDS_CopyParameters(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source)
int32_t SDDS_StartPage(SDDS_DATASET *SDDS_dataset, int64_t expected_n_rows)
int32_t SDDS_SetParameters(SDDS_DATASET *SDDS_dataset, int32_t mode,...)
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.
int32_t SDDS_WritePage(SDDS_DATASET *SDDS_dataset)
Writes the current data table to the output file.
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.
char * SDDS_FindColumn(SDDS_DATASET *SDDS_dataset, int32_t mode,...)
Finds the first column in the SDDS dataset that matches the specified criteria.
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
#define SDDS_STRING
Identifier for the string data type.
#define SDDS_LONG
Identifier for the signed 32-bit integer data type.
void * trealloc(void *old_ptr, uint64_t size_of_block)
Reallocates a memory block to a new size.
void bomb(char *error, char *usage)
Reports error messages to the terminal and aborts the program.
char * cp_str(char **s, char *t)
Copies a string, allocating memory for storage.
double ipow(const double x, const int64_t p)
Compute x raised to the power p (x^p).
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.
double ChiSqrSigLevel(double ChiSquared0, long nu)
Computes the probability that a chi-squared variable exceeds a given value.
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.