SDDSlib
Loading...
Searching...
No Matches
sddsgfit.c
Go to the documentation of this file.
1/**
2 * @file sddsgfit.c
3 * @brief Performs a Gaussian fit on input data.
4 *
5 * This program fits the data to the Gaussian function:
6 *
7 * y(n) = baseline + height * exp(-0.5 * (x(n) - mean)^2 / sigma^2)
8 *
9 * The program supports various options for specifying fit ranges, initial guesses,
10 * verbosity levels, output formats, and more. It processes input data from a file
11 * or via a pipe and outputs the fitted results to a file or pipe.
12 *
13 * @section usage Usage
14 *
15 * To execute the Gaussian fitting program, use the following command structure:
16 *
17 * @code
18 * sddsgfit [<inputfile>] [<outputfile>] [options]
19 * @endcode
20 *
21 * @section options Options
22 *
23 * The program accepts the following command-line options:
24 *
25 * -pipe=[input][,output]
26 * -columns=<x-name>,<y-name>[,ySigma=<sy-name>]
27 * -fitRange=<lower>|@<parameter-name>,<upper>|@<parameter-name>
28 * -fullOutput
29 * -verbosity=<integer>
30 * -stepSize=<factor>
31 * -tolerance=<value>
32 * -guesses=[baseline=<value>|@<parameter-name>][,mean=<value>|@<parameter-name>][,height=<value>|@<parameter-name>][,sigma=<value>|@<parameter-name>]
33 * -fixValue=[baseline=<value>|@<parameter-name>][,mean=<value>|@<parameter-name>][,height=<value>|@<parameter-name>][,sigma=<value>|@<parameter-name>]
34 * -limits=[evaluations=<number>][,passes=<number>]
35 * -majorOrder=row|column
36 *
37 * @copyright
38 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
39 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
40 *
41 * @license
42 * This file is distributed under the terms of the Software License Agreement
43 * found in the file LICENSE included with this distribution.
44 *
45 * @author M. Borland, C. Saunders, R. Soliday, H. Shang
46 */
47
48#include "mdb.h"
49#include "SDDS.h"
50#include "scan.h"
51
52/* Enumeration for option types */
53enum option_type {
54 SET_FITRANGE,
55 SET_GUESSES,
56 SET_VERBOSITY,
57 SET_COLUMNS,
58 SET_TOLERANCE,
59 SET_FULLOUTPUT,
60 SET_STEPSIZE,
61 SET_LIMITS,
62 SET_PIPE,
63 SET_FIXVALUE,
64 SET_MAJOR_ORDER,
65 N_OPTIONS
66};
67
68char *option[N_OPTIONS] = {
69 "fitrange",
70 "guesses",
71 "verbosity",
72 "columns",
73 "tolerance",
74 "fulloutput",
75 "stepsize",
76 "limits",
77 "pipe",
78 "fixvalue",
79 "majorOrder",
80};
81
82static char *USAGE =
83 "Usage: sddsgfit [<inputfile>] [<outputfile>] [-pipe=[input][,output]]\n"
84 " -columns=<x-name>,<y-name>[,ySigma=<sy-name>]\n"
85 " -fitRange=<lower>|@<parameter-name>,<upper>|@<parameter-name>\n"
86 " -fullOutput\n"
87 " -verbosity=<integer>\n"
88 " -stepSize=<factor>\n"
89 " -tolerance=<value>\n"
90 " -guesses=[baseline=<value>|@<parameter-name>][,mean=<value>|@<parameter-name>]"
91 "[,height=<value>|@<parameter-name>][,sigma=<value>|@<parameter-name>]\n"
92 " -fixValue=[baseline=<value>|@<parameter-name>][,mean=<value>|@<parameter-name>]"
93 "[,height=<value>|@<parameter-name>][,sigma=<value>|@<parameter-name>]\n"
94 " -limits=[evaluations=<number>][,passes=<number>]\n"
95 " -majorOrder=row|column\n\n"
96 "Performs a Gaussian fit of the form:\n"
97 " y = <baseline> + <height> * exp(-0.5 * (x - <mean>)^2 / <sigma>^2)\n"
98 "Program by Michael Borland. (" __DATE__ " " __TIME__ ", SVN revision: " SVN_VERSION ")\n";
99
100void report(double res, double *a, long pass, long n_eval, long n_dimen);
101void setupOutputFile(SDDS_DATASET *OutputTable, long *xIndex, long *yIndex, long *syIndex, long *fitIndex,
102 long *residualIndex, long fullOutput, char *output, SDDS_DATASET *InputTable,
103 char *xName, char *yName, char *syName, short columnMajorOrder);
104long computeStartingPoint(double *a, double *da, double *x, double *y, int64_t n, unsigned long guessFlags,
105 double sigmaGuess, double meanGuess, double baselineGuess, double heightGuess,
106 double stepSize);
107double fitFunction(double *a, long *invalid);
108int64_t makeFilteredCopy(double **xFit, double **yFit, double **syFit, double *x, double *y, double *sy,
109 int64_t n, double lower, double upper);
110
111static double *xDataFit = NULL, *yDataFit = NULL, *syDataFit = NULL;
112static int64_t nDataFit = 0;
113
114#define GUESS_BASELINE_GIVEN 0x0001
115#define FIX_BASELINE_GIVEN (0x0001 << 4)
116#define GUESS_HEIGHT_GIVEN 0x0002
117#define FIX_HEIGHT_GIVEN (0x0002 << 4)
118#define GUESS_MEAN_GIVEN 0x0004
119#define FIX_MEAN_GIVEN (0x0004 << 4)
120#define GUESS_SIGMA_GIVEN 0x0008
121#define FIX_SIGMA_GIVEN (0x0008 << 4)
122
123#define BASELINE_INDEX 0
124#define HEIGHT_INDEX 1
125#define MEAN_INDEX 2
126#define SIGMA_INDEX 3
127
128int main(int argc, char **argv) {
129 double *xData = NULL, *yData = NULL, *syData = NULL;
130 int64_t nData = 0;
131 SDDS_DATASET InputTable, OutputTable;
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)) {
152 bomb(NULL, USAGE);
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) {
188 SDDS_Bomb("incorrect -fitRange syntax");
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) {
214 SDDS_Bomb("incorrect -stepSize syntax");
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) {
227 SDDS_Bomb("incorrect -guesses syntax");
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)) {
236 SDDS_Bomb("invalid -guesses syntax");
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) {
290 SDDS_Bomb("incorrect -fixValue syntax");
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)) {
299 SDDS_Bomb("invalid -fixValue syntax");
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) {
353 SDDS_Bomb("invalid -columns syntax");
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,
359 "ysigma", SDDS_STRING, &syName, 1, 0, NULL)) {
360 SDDS_Bomb("invalid -columns syntax");
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) {
370 SDDS_Bomb("incorrect -limits syntax");
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) {
377 SDDS_Bomb("invalid -limits syntax");
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)) {
383 SDDS_Bomb("invalid -pipe syntax");
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 {
398 SDDS_Bomb("too many filenames");
399 }
400 }
401 }
402
403 processFilenames("sddsgfit", &input, &output, pipeFlags, 0, NULL);
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
415 if (!SDDS_InitializeInput(&InputTable, input)) {
416 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
417 }
418 if (!SDDS_FindColumn(&InputTable, FIND_NUMERIC_TYPE, xName, NULL) ||
419 !SDDS_FindColumn(&InputTable, FIND_NUMERIC_TYPE, yName, NULL) ||
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
427 while ((retval = SDDS_ReadPage(&InputTable)) > 0) {
428 xData = yData = syData = NULL;
429 fitData = residualData = NULL;
430 if (!(xData = SDDS_GetColumnInDoubles(&InputTable, xName)) ||
431 !(yData = SDDS_GetColumnInDoubles(&InputTable, yName))) {
432 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
433 }
434 if (syName && !(syData = SDDS_GetColumnInDoubles(&InputTable, syName))) {
435 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
436 }
437 if (lowerPar && !SDDS_GetParameterAsDouble(&InputTable, lowerPar, &lower)) {
438 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
439 }
440 if (upperPar && !SDDS_GetParameterAsDouble(&InputTable, upperPar, &upper)) {
441 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
442 }
443 if (baselineGuessPar && !SDDS_GetParameterAsDouble(&InputTable, baselineGuessPar, &baselineGuess)) {
444 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
445 }
446 if (heightGuessPar && !SDDS_GetParameterAsDouble(&InputTable, heightGuessPar, &heightGuess)) {
447 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
448 }
449 if (meanGuessPar && !SDDS_GetParameterAsDouble(&InputTable, meanGuessPar, &meanGuess)) {
450 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
451 }
452 if (sigmaGuessPar && !SDDS_GetParameterAsDouble(&InputTable, sigmaGuessPar, &sigmaGuess)) {
453 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
454 }
455
456 if ((nData = SDDS_CountRowsOfInterest(&InputTable)) < 5) {
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 }
517 sigLevel = ChiSqrSigLevel(chiSqr, nData - 4);
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
529 if (!SDDS_StartPage(&OutputTable, nData) ||
530 !SDDS_CopyParameters(&OutputTable, &InputTable) ||
531 !SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, xData, nData, xIndex) ||
532 !SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, fitData, nData, fitIndex) ||
533 !SDDS_SetParameters(&OutputTable, SDDS_PASS_BY_VALUE | SDDS_SET_BY_NAME,
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)))) ||
544 !SDDS_WritePage(&OutputTable)) {
545 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
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
565 if (!SDDS_Terminate(&InputTable) || !SDDS_Terminate(&OutputTable)) {
566 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
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 }
584 free_scanargs(&s_arg, argc);
585 return EXIT_SUCCESS;
586}
587
588void setupOutputFile(SDDS_DATASET *OutputTable, long *xIndex, long *yIndex, long *syIndex, long *fitIndex,
589 long *residualIndex, long fullOutput, char *output, SDDS_DATASET *InputTable,
590 char *xName, char *yName, char *syName, short columnMajorOrder) {
591 char *name, *yUnits, *description, *xUnits;
592 int32_t typeValue = SDDS_DOUBLE;
593 static char *residualNamePart = "Residual";
594 static char *residualDescriptionPart = "Residual of Gaussian fit to ";
595
596 if (!SDDS_InitializeOutput(OutputTable, SDDS_BINARY, 0, NULL, "sddsgfit output", output) ||
597 !SDDS_TransferColumnDefinition(OutputTable, InputTable, xName, NULL) ||
598 !SDDS_ChangeColumnInformation(OutputTable, "type", &typeValue, SDDS_BY_NAME, xName) ||
599 (*xIndex = SDDS_GetColumnIndex(OutputTable, xName)) < 0 ||
600 !SDDS_GetColumnInformation(InputTable, "units", &xUnits, SDDS_BY_NAME, xName) ||
601 !SDDS_GetColumnInformation(InputTable, "units", &yUnits, SDDS_BY_NAME, yName)) {
602 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
603 }
604
605 if (columnMajorOrder != -1) {
606 OutputTable->layout.data_mode.column_major = columnMajorOrder;
607 } else {
608 OutputTable->layout.data_mode.column_major = InputTable->layout.data_mode.column_major;
609 }
610
611 name = tmalloc(sizeof(*name) * (strlen(yName) + strlen(residualNamePart) + 1));
612 description = tmalloc(sizeof(*description) * (strlen(yName) + strlen(residualDescriptionPart) + 1));
613
614 if (fullOutput) {
615 if (!SDDS_TransferColumnDefinition(OutputTable, InputTable, yName, NULL) ||
616 !SDDS_ChangeColumnInformation(OutputTable, "type", &typeValue, SDDS_BY_NAME, yName) ||
617 (*yIndex = SDDS_GetColumnIndex(OutputTable, yName)) < 0) {
618 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
619 }
620 if (syName && (!SDDS_TransferColumnDefinition(OutputTable, InputTable, syName, NULL) ||
621 !SDDS_ChangeColumnInformation(OutputTable, "type", &typeValue, SDDS_BY_NAME, syName) ||
622 (*syIndex = SDDS_GetColumnIndex(OutputTable, syName)) < 0)) {
623 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
624 }
625 sprintf(name, "%s%s", yName, residualNamePart);
626 sprintf(description, "%s%s", yName, residualDescriptionPart);
627 if ((*residualIndex = SDDS_DefineColumn(OutputTable, name, NULL, yUnits, description, NULL, SDDS_DOUBLE, 0)) < 0) {
628 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
629 }
630 }
631
632 sprintf(name, "%sFit", yName);
633 sprintf(description, "Gaussian fit to %s", yName);
634 if ((*fitIndex = SDDS_DefineColumn(OutputTable, name, NULL, yUnits, description, NULL, SDDS_DOUBLE, 0)) < 0) {
635 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
636 }
637
638 if (SDDS_DefineParameter(OutputTable, "gfitBaseline", NULL, yUnits, "Baseline from Gaussian fit",
639 NULL, SDDS_DOUBLE, 0) < 0 ||
640 SDDS_DefineParameter(OutputTable, "gfitHeight", NULL, yUnits, "Height from Gaussian fit",
641 NULL, SDDS_DOUBLE, 0) < 0 ||
642 SDDS_DefineParameter(OutputTable, "gfitMean", "$gm$r", xUnits, "Mean from Gaussian fit",
643 NULL, SDDS_DOUBLE, 0) < 0 ||
644 SDDS_DefineParameter(OutputTable, "gfitSigma", "$gs$r", xUnits, "Sigma from Gaussian fit",
645 NULL, SDDS_DOUBLE, 0) < 0 ||
646 SDDS_DefineParameter(OutputTable, "gfitRmsResidual", NULL, yUnits, "RMS residual from Gaussian fit",
647 NULL, SDDS_DOUBLE, 0) < 0 ||
648 SDDS_DefineParameter(OutputTable, "gfitSigLevel", NULL, NULL, "Significance level from chi-squared test",
649 NULL, SDDS_DOUBLE, 0) < 0 ||
650 !SDDS_TransferAllParameterDefinitions(OutputTable, InputTable, SDDS_TRANSFER_KEEPOLD) ||
651 !SDDS_WriteLayout(OutputTable)) {
652 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
653 }
654
655 free(name);
656 free(description);
657}
658
659double fitFunction(double *a, long *invalid) {
660 double sum, tmp, mean, sigma, base, norm;
661 int64_t i;
662
663 *invalid = 0;
664 sigma = a[SIGMA_INDEX];
665 mean = a[MEAN_INDEX];
666 base = a[BASELINE_INDEX];
667 norm = a[HEIGHT_INDEX];
668
669 if (!syDataFit) {
670 for (i = sum = 0; i < nDataFit; i++) {
671 tmp = (xDataFit[i] - mean) / sigma;
672 tmp = yDataFit[i] - base - norm * exp(-sqr(tmp) / 2);
673 sum += sqr(tmp);
674 }
675 return (sum / nDataFit);
676 } else {
677 for (i = sum = 0; i < nDataFit; i++) {
678 tmp = (xDataFit[i] - mean) / sigma;
679 tmp = (yDataFit[i] - base - norm * exp(-sqr(tmp) / 2)) / syDataFit[i];
680 sum += sqr(tmp);
681 }
682 return (sum / nDataFit);
683 }
684}
685
686void report(double y, double *x, long pass, long nEval, long n_dimen) {
687 long i;
688
689 fprintf(stderr, "pass %ld, after %ld evaluations: result = %.16e\na = ", pass, nEval, y);
690 for (i = 0; i < n_dimen; i++) {
691 fprintf(stderr, "%.8e ", x[i]);
692 }
693 fputc('\n', stderr);
694}
695
696long computeStartingPoint(double *a, double *da, double *x, double *y, int64_t n, unsigned long guessFlags,
697 double sigmaGuess, double meanGuess, double baselineGuess, double heightGuess,
698 double stepSize) {
699 double xhalf, dhalf, ymin, ymax, xcenter, tmp, xmax, xmin;
700 int64_t i;
701
702 if (n < 5) {
703 return 0;
704 }
705
706 /* first find maximum y value and corresponding x value, plus max x */
707 xcenter = 0;
708 ymax = xmax = -DBL_MAX;
709 ymin = xmin = DBL_MAX;
710 for (i = 0; i < n; i++) {
711 if (xmax < fabs(x[i])) {
712 xmax = fabs(x[i]);
713 }
714 if (xmin > fabs(x[i])) { /* Corrected comparison from < to > */
715 xmin = fabs(x[i]);
716 }
717 if (ymax < y[i]) {
718 ymax = y[i];
719 xcenter = x[i];
720 }
721 if (ymin > y[i]) {
722 ymin = y[i];
723 }
724 }
725
726 /* now find approximate half-max point */
727 xhalf = 0;
728 dhalf = DBL_MAX;
729 for (i = 0; i < n; i++) {
730 tmp = fabs((fabs(y[i] - ymax) / (ymax - ymin)) - 0.5);
731 if (tmp < dhalf) {
732 xhalf = x[i];
733 dhalf = tmp;
734 }
735 }
736 if (dhalf != DBL_MAX) {
737 a[SIGMA_INDEX] = fabs(xhalf - xcenter) / 1.177; /* starting sigma */
738 } else {
739 a[SIGMA_INDEX] = xmax - xmin;
740 }
741 a[MEAN_INDEX] = xcenter; /* starting mean */
742 a[BASELINE_INDEX] = ymin; /* starting baseline */
743 a[HEIGHT_INDEX] = ymax - ymin; /* starting height */
744
745 if (guessFlags & (GUESS_SIGMA_GIVEN + FIX_SIGMA_GIVEN)) {
746 a[SIGMA_INDEX] = sigmaGuess;
747 }
748 if (guessFlags & (GUESS_MEAN_GIVEN + FIX_MEAN_GIVEN)) {
749 a[MEAN_INDEX] = meanGuess;
750 }
751 if (guessFlags & (GUESS_BASELINE_GIVEN + FIX_BASELINE_GIVEN)) {
752 a[BASELINE_INDEX] = baselineGuess;
753 }
754 if (guessFlags & (GUESS_HEIGHT_GIVEN + FIX_HEIGHT_GIVEN)) {
755 a[HEIGHT_INDEX] = heightGuess;
756 }
757
758 /* step sizes */
759 for (i = 0; i < 4; i++) {
760 if (!(da[i] = a[i] * stepSize))
761 da[i] = stepSize;
762 }
763
764 return 1;
765}
766
767int64_t makeFilteredCopy(double **xFit, double **yFit, double **syFit, double *x, double *y,
768 double *sy, int64_t n, double lower, double upper) {
769 int64_t i, j;
770
771 if (!(*xFit = (double *)malloc(sizeof(**xFit) * n)) ||
772 !(*yFit = (double *)malloc(sizeof(**yFit) * n)) ||
773 (sy && !(*syFit = (double *)malloc(sizeof(**syFit) * n)))) {
774 return 0;
775 }
776
777 for (i = j = 0; i < n; i++) {
778 if (x[i] < lower || x[i] > upper) {
779 continue;
780 }
781 (*xFit)[j] = x[i];
782 (*yFit)[j] = y[i];
783 if (sy) {
784 (*syFit)[j] = sy[i];
785 }
786 j++;
787 }
788 return j;
789}
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
int32_t SDDS_CopyParameters(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source)
Definition SDDS_copy.c:286
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.
double * SDDS_GetParameterAsDouble(SDDS_DATASET *SDDS_dataset, char *parameter_name, double *memory)
Retrieves the value of a specified parameter as a double from the current data table of an SDDS datas...
int64_t SDDS_CountRowsOfInterest(SDDS_DATASET *SDDS_dataset)
Counts the number of rows marked as "of interest" in the current data table.
double * SDDS_GetColumnInDoubles(SDDS_DATASET *SDDS_dataset, char *column_name)
Retrieves the data of a specified numerical column as an array of doubles, considering only rows mark...
int32_t SDDS_ChangeColumnInformation(SDDS_DATASET *SDDS_dataset, char *field_name, void *memory, int32_t mode,...)
Modifies a specific field in a column definition within the SDDS dataset.
Definition SDDS_info.c:364
int32_t SDDS_GetColumnInformation(SDDS_DATASET *SDDS_dataset, char *field_name, void *memory, int32_t mode,...)
Retrieves information about a specified column in the SDDS dataset.
Definition SDDS_info.c:41
int32_t SDDS_InitializeInput(SDDS_DATASET *SDDS_dataset, char *filename)
Definition SDDS_input.c:49
int32_t SDDS_Terminate(SDDS_DATASET *SDDS_dataset)
int32_t SDDS_ReadPage(SDDS_DATASET *SDDS_dataset)
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_DefineColumn(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, int32_t field_length)
Defines a data column within the SDDS dataset.
int32_t SDDS_WriteLayout(SDDS_DATASET *SDDS_dataset)
Writes the SDDS layout header to the output file.
int32_t SDDS_DefineParameter(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, char *fixed_value)
Defines a data parameter with a fixed string value.
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.
int32_t SDDS_GetColumnIndex(SDDS_DATASET *SDDS_dataset, char *name)
Retrieves the index of a named column in the SDDS dataset.
void SDDS_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
Definition SDDS_utils.c:432
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
Definition SDDS_utils.c:288
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.
Definition SDDS_utils.c:342
#define SDDS_STRING
Identifier for the string data type.
Definition SDDStypes.h:85
#define SDDS_LONG
Identifier for the signed 32-bit integer data type.
Definition SDDStypes.h:61
#define SDDS_DOUBLE
Identifier for the double data type.
Definition SDDStypes.h:37
void * trealloc(void *old_ptr, uint64_t size_of_block)
Reallocates a memory block to a new size.
Definition array.c:181
void * tmalloc(uint64_t size_of_block)
Allocates a memory block of the specified size with zero initialization.
Definition array.c:59
void bomb(char *error, char *usage)
Reports error messages to the terminal and aborts the program.
Definition bomb.c:26
char * cp_str(char **s, char *t)
Copies a string, allocating memory for storage.
Definition cp_str.c:28
double ipow(const double x, const int64_t p)
Compute x raised to the power p (x^p).
Definition ipow.c:33
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)
Definition scanargs.c:36
long processPipeOption(char **item, long items, unsigned long *flags)
Definition scanargs.c:356
void processFilenames(char *programName, char **input, char **output, unsigned long pipeFlags, long noWarnings, long *tmpOutputUsed)
Definition scanargs.c:390
void free_scanargs(SCANNED_ARG **scanned, int argc)
Definition scanargs.c:584
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.
Definition sigLevel.c:64
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.
Definition simplex.c:472