128 {
129 double *xData = NULL, *yData = NULL, *syData = NULL;
130 int64_t nData = 0;
132 SCANNED_ARG *s_arg;
133 long i_arg;
134 char *input, *output, *xName, *yName, *syName;
135 long xIndex, yIndex, fitIndex, residualIndex, syIndex_out, retval;
136 double *fitData, *residualData, rmsResidual, chiSqr, sigLevel;
137 unsigned long guessFlags, dummyFlags, pipeFlags, majorOrderFlag;
138 double sigmaGuess, meanGuess, baselineGuess, heightGuess;
139 double tolerance, stepSize;
140 double a[4], da[4], lower, upper, result;
141 double aLow[4], aHigh[4];
142 short disable[4] = {0, 0, 0, 0};
143 int32_t nEvalMax = 5000, nPassMax = 100;
144 long nEval, verbosity, fullOutput = 0;
145 int64_t i;
146 short columnMajorOrder = -1;
147 char *lowerPar, *upperPar, *baselineGuessPar, *sigmaGuessPar, *meanGuessPar, *heightGuessPar;
148
150 argc =
scanargs(&s_arg, argc, argv);
151 if (argc < 2 || argc > (2 + N_OPTIONS)) {
153 }
154
155 for (i = 0; i < 4; i++) {
156 aLow[i] = -(aHigh[i] = DBL_MAX);
157 }
158 aLow[SIGMA_INDEX] = 0;
159 input = output = NULL;
160 stepSize = 1e-2;
161 tolerance = 1e-8;
162 verbosity = 0;
163 guessFlags = sigmaGuess = heightGuess = baselineGuess = meanGuess = pipeFlags = 0;
164 xName = yName = syName = NULL;
165 lower = upper = 0;
166 lowerPar = upperPar = sigmaGuessPar = heightGuessPar = baselineGuessPar = meanGuessPar = NULL;
167
168 for (i_arg = 1; i_arg < argc; i_arg++) {
169 if (s_arg[i_arg].arg_type == OPTION) {
170 switch (
match_string(s_arg[i_arg].list[0], option, N_OPTIONS, 0)) {
171 case SET_MAJOR_ORDER:
172 majorOrderFlag = 0;
173 s_arg[i_arg].n_items--;
174 if (s_arg[i_arg].n_items > 0 && (!
scanItemList(&majorOrderFlag, s_arg[i_arg].list + 1,
175 &s_arg[i_arg].n_items, 0, "row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
176 "column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL))) {
177 SDDS_Bomb(
"invalid -majorOrder syntax/values");
178 }
179 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER) {
180 columnMajorOrder = 1;
181 } else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER) {
182 columnMajorOrder = 0;
183 }
184 break;
185
186 case SET_FITRANGE:
187 if (s_arg[i_arg].n_items != 3) {
189 }
190 if (s_arg[i_arg].list[1][0] == '@') {
191 cp_str(&lowerPar, s_arg[i_arg].list[1] + 1);
192 } else if (sscanf(s_arg[i_arg].list[1], "%lf", &lower) != 1) {
193 SDDS_Bomb(
"invalid fitRange lower value provided");
194 }
195 if (s_arg[i_arg].list[2][0] == '@') {
196 cp_str(&upperPar, s_arg[i_arg].list[2] + 1);
197 } else if (sscanf(s_arg[i_arg].list[2], "%lf", &upper) != 1) {
198 SDDS_Bomb(
"invalid fitRange upper value provided");
199 }
200 break;
201
202 case SET_TOLERANCE:
203 if (s_arg[i_arg].n_items != 2 ||
204 sscanf(s_arg[i_arg].list[1], "%lf", &tolerance) != 1 ||
205 tolerance <= 0) {
206 SDDS_Bomb(
"incorrect -tolerance syntax");
207 }
208 break;
209
210 case SET_STEPSIZE:
211 if (s_arg[i_arg].n_items != 2 ||
212 sscanf(s_arg[i_arg].list[1], "%lf", &stepSize) != 1 ||
213 stepSize <= 0) {
215 }
216 break;
217
218 case SET_VERBOSITY:
219 if (s_arg[i_arg].n_items != 2 ||
220 sscanf(s_arg[i_arg].list[1], "%ld", &verbosity) != 1) {
221 SDDS_Bomb(
"incorrect -verbosity syntax");
222 }
223 break;
224
225 case SET_GUESSES:
226 if (s_arg[i_arg].n_items < 2) {
228 }
229 s_arg[i_arg].n_items -= 1;
230 dummyFlags = guessFlags;
231 if (!
scanItemList(&guessFlags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
232 "baseline",
SDDS_STRING, &baselineGuessPar, 1, GUESS_BASELINE_GIVEN,
233 "height",
SDDS_STRING, &heightGuessPar, 1, GUESS_HEIGHT_GIVEN,
234 "mean",
SDDS_STRING, &meanGuessPar, 1, GUESS_MEAN_GIVEN,
235 "sigma",
SDDS_STRING, &sigmaGuessPar, 1, GUESS_SIGMA_GIVEN, NULL)) {
237 }
238 if (baselineGuessPar) {
239 if (baselineGuessPar[0] == '@') {
240 baselineGuessPar++;
241 } else {
242 if (sscanf(baselineGuessPar, "%lf", &baselineGuess) != 1) {
243 SDDS_Bomb(
"Invalid baseline guess value provided.");
244 }
245 free(baselineGuessPar);
246 baselineGuessPar = NULL;
247 }
248 }
249 if (heightGuessPar) {
250 if (heightGuessPar[0] == '@') {
251 heightGuessPar++;
252 } else {
253 if (sscanf(heightGuessPar, "%lf", &heightGuess) != 1) {
254 SDDS_Bomb(
"Invalid height guess value provided.");
255 }
256 free(heightGuessPar);
257 heightGuessPar = NULL;
258 }
259 }
260 if (meanGuessPar) {
261 if (meanGuessPar[0] == '@') {
262 meanGuessPar++;
263 } else {
264 if (sscanf(meanGuessPar, "%lf", &meanGuess) != 1) {
265 SDDS_Bomb(
"Invalid mean guess value provided.");
266 }
267 free(meanGuessPar);
268 meanGuessPar = NULL;
269 }
270 }
271 if (sigmaGuessPar) {
272 if (sigmaGuessPar[0] == '@') {
273 sigmaGuessPar++;
274 } else {
275 if (sscanf(sigmaGuessPar, "%lf", &sigmaGuess) != 1) {
276 SDDS_Bomb(
"Invalid sigma guess value provided.");
277 }
278 free(sigmaGuessPar);
279 sigmaGuessPar = NULL;
280 }
281 }
282 if ((dummyFlags >> 4) & guessFlags) {
283 SDDS_Bomb(
"can't have -fixedValue and -guesses for the same item");
284 }
285 guessFlags |= dummyFlags;
286 break;
287
288 case SET_FIXVALUE:
289 if (s_arg[i_arg].n_items < 2) {
291 }
292 s_arg[i_arg].n_items -= 1;
293 dummyFlags = guessFlags;
294 if (!
scanItemList(&guessFlags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
295 "baseline",
SDDS_STRING, &baselineGuessPar, 1, FIX_BASELINE_GIVEN,
296 "height",
SDDS_STRING, &heightGuessPar, 1, FIX_HEIGHT_GIVEN,
297 "mean",
SDDS_STRING, &meanGuessPar, 1, FIX_MEAN_GIVEN,
298 "sigma",
SDDS_STRING, &sigmaGuessPar, 1, FIX_SIGMA_GIVEN, NULL)) {
300 }
301 if (dummyFlags & (guessFlags >> 4)) {
302 SDDS_Bomb(
"can't have -fixValue and -guesses for the same item");
303 }
304 guessFlags |= dummyFlags;
305 if (baselineGuessPar) {
306 if (baselineGuessPar[0] == '@') {
307 baselineGuessPar++;
308 } else {
309 if (sscanf(baselineGuessPar, "%lf", &baselineGuess) != 1) {
310 SDDS_Bomb(
"Invalid baseline guess value provided.");
311 }
312 free(baselineGuessPar);
313 baselineGuessPar = NULL;
314 }
315 }
316 if (heightGuessPar) {
317 if (heightGuessPar[0] == '@') {
318 heightGuessPar++;
319 } else {
320 if (sscanf(heightGuessPar, "%lf", &heightGuess) != 1) {
321 SDDS_Bomb(
"Invalid height guess value provided.");
322 }
323 free(heightGuessPar);
324 heightGuessPar = NULL;
325 }
326 }
327 if (meanGuessPar) {
328 if (meanGuessPar[0] == '@') {
329 meanGuessPar++;
330 } else {
331 if (sscanf(meanGuessPar, "%lf", &meanGuess) != 1) {
332 SDDS_Bomb(
"Invalid mean guess value provided.");
333 }
334 free(meanGuessPar);
335 meanGuessPar = NULL;
336 }
337 }
338 if (sigmaGuessPar) {
339 if (sigmaGuessPar[0] == '@') {
340 sigmaGuessPar++;
341 } else {
342 if (sscanf(sigmaGuessPar, "%lf", &sigmaGuess) != 1) {
343 SDDS_Bomb(
"Invalid sigma guess value provided.");
344 }
345 free(sigmaGuessPar);
346 sigmaGuessPar = NULL;
347 }
348 }
349 break;
350
351 case SET_COLUMNS:
352 if (s_arg[i_arg].n_items != 3 && s_arg[i_arg].n_items != 4) {
354 }
355 xName = s_arg[i_arg].list[1];
356 yName = s_arg[i_arg].list[2];
357 s_arg[i_arg].n_items -= 3;
358 if (!
scanItemList(&dummyFlags, s_arg[i_arg].list + 3, &s_arg[i_arg].n_items, 0,
361 }
362 break;
363
364 case SET_FULLOUTPUT:
365 fullOutput = 1;
366 break;
367
368 case SET_LIMITS:
369 if (s_arg[i_arg].n_items < 2) {
371 }
372 s_arg[i_arg].n_items -= 1;
373 if (!
scanItemList(&dummyFlags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
374 "evaluations",
SDDS_LONG, &nEvalMax, 1, 0,
375 "passes",
SDDS_LONG, &nPassMax, 1, 0, NULL) ||
376 nEvalMax <= 0 || nPassMax <= 0) {
378 }
379 break;
380
381 case SET_PIPE:
382 if (!
processPipeOption(s_arg[i_arg].list + 1, s_arg[i_arg].n_items - 1, &pipeFlags)) {
384 }
385 break;
386
387 default:
388 fprintf(stderr, "error: unknown/ambiguous option: %s\n", s_arg[i_arg].list[0]);
389 exit(EXIT_FAILURE);
390 break;
391 }
392 } else {
393 if (input == NULL) {
394 input = s_arg[i_arg].list[0];
395 } else if (output == NULL) {
396 output = s_arg[i_arg].list[0];
397 } else {
399 }
400 }
401 }
402
404
405 for (i = 0; i < 4; i++) {
406 if ((guessFlags >> 4) & (1 << i)) {
407 disable[i] = 1;
408 }
409 }
410
411 if (!xName || !yName) {
412 SDDS_Bomb(
"-columns option must be given");
413 }
414
417 }
420 (syName && !
SDDS_FindColumn(&InputTable, FIND_NUMERIC_TYPE, syName, NULL))) {
421 SDDS_Bomb(
"one or more of the given data columns is nonexistent or nonnumeric");
422 }
423
424 setupOutputFile(&OutputTable, &xIndex, &yIndex, &syIndex_out, &fitIndex, &residualIndex,
425 fullOutput, output, &InputTable, xName, yName, syName, columnMajorOrder);
426
428 xData = yData = syData = NULL;
429 fitData = residualData = NULL;
433 }
436 }
439 }
442 }
445 }
448 }
451 }
454 }
455
457 continue;
458 }
459 if (lower < upper) {
460 if ((nDataFit = makeFilteredCopy(&xDataFit, &yDataFit, &syDataFit, xData, yData, syData, nData, lower, upper)) < 5) {
461 continue;
462 }
463 } else {
464 xDataFit = xData;
465 yDataFit = yData;
466 syDataFit = syData;
467 nDataFit = nData;
468 }
469
470 if (!computeStartingPoint(a, da, xDataFit, yDataFit, nDataFit, guessFlags, sigmaGuess, meanGuess,
471 baselineGuess, heightGuess, stepSize)) {
472 fprintf(stderr, "error: couldn't compute starting point for page %ld--skipping\n", retval);
473 continue;
474 }
475 if (verbosity > 2) {
476 fprintf(stderr, "starting values: sigma=%.6e mean=%.6e baseline=%.6e height=%.6e\n",
477 a[SIGMA_INDEX], a[MEAN_INDEX], a[BASELINE_INDEX], a[HEIGHT_INDEX]);
478 }
479 if (verbosity > 3) {
480 fprintf(stderr, "starting steps: sigma=%.6e mean=%.6e baseline=%.6e height=%.6e\n",
481 da[SIGMA_INDEX], da[MEAN_INDEX], da[BASELINE_INDEX], da[HEIGHT_INDEX]);
482 }
483
484 nEval =
simplexMin(&result, a, da, aLow, aHigh, disable, 4, -DBL_MAX, tolerance,
485 fitFunction, (verbosity > 0 ? report : NULL),
486 nEvalMax, nPassMax, 12, 3, 1.0, 0);
487 if (xData != xDataFit) {
488 free(xDataFit);
489 free(yDataFit);
490 if (syDataFit) {
491 free(syDataFit);
492 }
493 }
494
495 if (verbosity > 3) {
496 fprintf(stderr, "%ld evaluations of fit function required, giving result %e\n", nEval, result);
497 }
498
499 fitData =
trealloc(fitData,
sizeof(*fitData) * nData);
500 residualData =
trealloc(residualData,
sizeof(*residualData) * nData);
501 for (i = 0, result = 0; i < nData; i++) {
502 fitData[i] = a[BASELINE_INDEX] + a[HEIGHT_INDEX] * exp(-
ipow((xData[i] - a[MEAN_INDEX]) / a[SIGMA_INDEX], 2) / 2);
503 residualData[i] = yData[i] - fitData[i];
504 result += sqr(residualData[i]);
505 }
506 rmsResidual = sqrt(result / nData);
507 if (syData) {
508 for (i = 0, chiSqr = 0; i < nData; i++) {
509 chiSqr += sqr(residualData[i] / syData[i]);
510 }
511 } else {
512 double sy2 = result / (nData - 4);
513 for (i = 0, chiSqr = 0; i < nData; i++) {
514 chiSqr += sqr(residualData[i]) / sy2;
515 }
516 }
518 if (verbosity > 0) {
519 fprintf(stderr, "sigma: %.15e\nmean: %.15e\nbaseline: %.15e\nheight: %.15e\n",
520 a[SIGMA_INDEX], a[MEAN_INDEX], a[BASELINE_INDEX], a[HEIGHT_INDEX]);
521 }
522 if (verbosity > 1) {
523 if (syData) {
524 fprintf(stderr, "Significance level: %.5e\n", sigLevel);
525 }
526 fprintf(stderr, "RMS deviation: %.15e\n", rmsResidual);
527 }
528
531 !
SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, xData, nData, xIndex) ||
532 !
SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, fitData, nData, fitIndex) ||
534 "gfitSigma", a[SIGMA_INDEX],
535 "gfitMean", a[MEAN_INDEX],
536 "gfitBaseline", a[BASELINE_INDEX],
537 "gfitHeight", a[HEIGHT_INDEX],
538 "gfitRmsResidual", rmsResidual,
539 "gfitSigLevel", sigLevel, NULL) ||
540 (fullOutput &&
541 (!
SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, yData, nData, yIndex) ||
542 !
SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, residualData, nData, residualIndex) ||
543 (syName && !
SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, syData, nData, syIndex_out)))) ||
546 }
547
548 if (xData) {
549 free(xData);
550 }
551 if (yData) {
552 free(yData);
553 }
554 if (syData) {
555 free(syData);
556 }
557 if (fitData) {
558 free(fitData);
559 }
560 if (residualData) {
561 free(residualData);
562 }
563 }
564
567 exit(EXIT_FAILURE);
568 }
569 if (lowerPar) {
570 free(lowerPar);
571 }
572 if (upperPar) {
573 free(upperPar);
574 }
575 if (baselineGuessPar) {
576 free(baselineGuessPar);
577 }
578 if (heightGuessPar) {
579 free(heightGuessPar);
580 }
581 if (sigmaGuessPar) {
582 free(sigmaGuessPar);
583 }
585 return EXIT_SUCCESS;
586}
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.