SDDS ToolKit Programs and Libraries for C and Python
All Classes Files Functions Variables Macros Pages
sddsgfit.c
Go to the documentation of this file.
1/**
2 * @file sddsgfit.c
3 * @brief A program for performing Gaussian fitting on input data.
4 *
5 * This program fits input data to a Gaussian function using customizable options. It reads data
6 * from SDDS (Self Describing Data Set) files, processes input columns, and generates fitted results.
7 * Users can specify fit ranges, initial parameter guesses, verbosity levels, and output formats.
8 *
9 * @section Usage
10 * ```
11 * sddsgfit [<inputfile>] [<outputfile>]
12 * [-pipe=[input][,output]]
13 * -columns=<x-name>,<y-name>[,ySigma=<sy-name>]
14 * [-fitRange=<lower>|@<parameter-name>,<upper>|@<parameter-name>]
15 * [-fullOutput]
16 * [-verbosity=<integer>]
17 * [-stepSize=<factor>]
18 * [-tolerance=<value>]
19 * [-guesses=[baseline=<value>|@<parameter-name>][,mean=<value>|@<parameter-name>][,height=<value>|@<parameter-name>][,sigma=<value>|@<parameter-name>]]
20 * [-fixValue=[baseline=<value>|@<parameter-name>][,mean=<value>|@<parameter-name>][,height=<value>|@<parameter-name>][,sigma=<value>|@<parameter-name>]]
21 * [-limits=[evaluations=<number>][,passes=<number>]]
22 * [-majorOrder=row|column]
23 * ```
24 *
25 * @section Options
26 * | Required | Description |
27 * |-----------------------------------------|----------------------------------------------------------------------------------------|
28 * | `-columns` | Specifies the column names for x and y data. |
29 *
30 * | Optional | Description |
31 * |-----------------------------------------|----------------------------------------------------------------------------------------|
32 * | `-pipe` | Specifies input/output via pipes. |
33 * | `-fitRange` | Sets the range for fitting. |
34 * | `-fullOutput` | Enables full output, including residuals. |
35 * | `-verbosity` | Controls verbosity level (higher values give more detailed logs). |
36 * | `-stepSize` | Sets the optimization step size. |
37 * | `-tolerance` | Specifies the convergence tolerance. |
38 * | `-guesses` | Provides initial parameter guesses (baseline, mean, height, sigma). |
39 * | `-fixValue` | Fixes specific parameter values during fitting. |
40 * | `-limits` | Sets limits for evaluations and passes. |
41 * | `-majorOrder` | Defines the data order for output (row or column major). |
42 *
43 * @subsection Incompatibilities
44 * - `-fixValue` is incompatible with `-guesses` for the same parameter.
45 *
46 * @details
47 * The program fits data to the Gaussian function:
48 * ```
49 * y(n) = baseline + height * exp(-0.5 * (x(n) - mean)^2 / sigma^2)
50 * ```
51 * @copyright
52 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
53 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
54 *
55 * @license
56 * This file is distributed under the terms of the Software License Agreement
57 * found in the file LICENSE included with this distribution.
58 *
59 * @author
60 * M. Borland, C. Saunders, R. Soliday, H. Shang
61 */
62
63#include "mdb.h"
64#include "SDDS.h"
65#include "scan.h"
66
67/* Enumeration for option types */
68enum option_type {
69 SET_FITRANGE,
70 SET_GUESSES,
71 SET_VERBOSITY,
72 SET_COLUMNS,
73 SET_TOLERANCE,
74 SET_FULLOUTPUT,
75 SET_STEPSIZE,
76 SET_LIMITS,
77 SET_PIPE,
78 SET_FIXVALUE,
79 SET_MAJOR_ORDER,
80 N_OPTIONS
81};
82
83char *option[N_OPTIONS] = {
84 "fitrange",
85 "guesses",
86 "verbosity",
87 "columns",
88 "tolerance",
89 "fulloutput",
90 "stepsize",
91 "limits",
92 "pipe",
93 "fixvalue",
94 "majorOrder",
95};
96
97static char *USAGE =
98 "sddsgfit [<inputfile>] [<outputfile>] [-pipe=[input][,output]]\n"
99 " -columns=<x-name>,<y-name>[,ySigma=<sy-name>]\n"
100 " -fitRange=<lower>|@<parameter-name>,<upper>|@<parameter-name>\n"
101 " -fullOutput\n"
102 " -verbosity=<integer>\n"
103 " -stepSize=<factor>\n"
104 " -tolerance=<value>\n"
105 " -guesses=[baseline=<value>|@<parameter-name>][,mean=<value>|@<parameter-name>]"
106 "[,height=<value>|@<parameter-name>][,sigma=<value>|@<parameter-name>]\n"
107 " -fixValue=[baseline=<value>|@<parameter-name>][,mean=<value>|@<parameter-name>]"
108 "[,height=<value>|@<parameter-name>][,sigma=<value>|@<parameter-name>]\n"
109 " -limits=[evaluations=<number>][,passes=<number>]\n"
110 " -majorOrder=row|column\n\n"
111 "Performs a Gaussian fit of the form:\n"
112 " y = <baseline> + <height> * exp(-0.5 * (x - <mean>)^2 / <sigma>^2)\n"
113 "Program by Michael Borland. (" __DATE__ " " __TIME__ ", SVN revision: " SVN_VERSION ")\n";
114
115void report(double res, double *a, long pass, long n_eval, long n_dimen);
116void setupOutputFile(SDDS_DATASET *OutputTable, long *xIndex, long *yIndex, long *syIndex, long *fitIndex,
117 long *residualIndex, long fullOutput, char *output, SDDS_DATASET *InputTable,
118 char *xName, char *yName, char *syName, short columnMajorOrder);
119long computeStartingPoint(double *a, double *da, double *x, double *y, int64_t n, unsigned long guessFlags,
120 double sigmaGuess, double meanGuess, double baselineGuess, double heightGuess,
121 double stepSize);
122double fitFunction(double *a, long *invalid);
123int64_t makeFilteredCopy(double **xFit, double **yFit, double **syFit, double *x, double *y, double *sy,
124 int64_t n, double lower, double upper);
125
126static double *xDataFit = NULL, *yDataFit = NULL, *syDataFit = NULL;
127static int64_t nDataFit = 0;
128
129#define GUESS_BASELINE_GIVEN 0x0001
130#define FIX_BASELINE_GIVEN (0x0001 << 4)
131#define GUESS_HEIGHT_GIVEN 0x0002
132#define FIX_HEIGHT_GIVEN (0x0002 << 4)
133#define GUESS_MEAN_GIVEN 0x0004
134#define FIX_MEAN_GIVEN (0x0004 << 4)
135#define GUESS_SIGMA_GIVEN 0x0008
136#define FIX_SIGMA_GIVEN (0x0008 << 4)
137
138#define BASELINE_INDEX 0
139#define HEIGHT_INDEX 1
140#define MEAN_INDEX 2
141#define SIGMA_INDEX 3
142
143int main(int argc, char **argv) {
144 double *xData = NULL, *yData = NULL, *syData = NULL;
145 int64_t nData = 0;
146 SDDS_DATASET InputTable, OutputTable;
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)) {
167 bomb(NULL, USAGE);
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) {
203 SDDS_Bomb("incorrect -fitRange syntax");
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) {
229 SDDS_Bomb("incorrect -stepSize syntax");
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) {
242 SDDS_Bomb("incorrect -guesses syntax");
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)) {
251 SDDS_Bomb("invalid -guesses syntax");
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) {
305 SDDS_Bomb("incorrect -fixValue syntax");
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)) {
314 SDDS_Bomb("invalid -fixValue syntax");
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) {
368 SDDS_Bomb("invalid -columns syntax");
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,
374 "ysigma", SDDS_STRING, &syName, 1, 0, NULL)) {
375 SDDS_Bomb("invalid -columns syntax");
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) {
385 SDDS_Bomb("incorrect -limits syntax");
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) {
392 SDDS_Bomb("invalid -limits syntax");
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)) {
398 SDDS_Bomb("invalid -pipe syntax");
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 {
413 SDDS_Bomb("too many filenames");
414 }
415 }
416 }
417
418 processFilenames("sddsgfit", &input, &output, pipeFlags, 0, NULL);
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
430 if (!SDDS_InitializeInput(&InputTable, input)) {
431 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
432 }
433 if (!SDDS_FindColumn(&InputTable, FIND_NUMERIC_TYPE, xName, NULL) ||
434 !SDDS_FindColumn(&InputTable, FIND_NUMERIC_TYPE, yName, NULL) ||
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
442 while ((retval = SDDS_ReadPage(&InputTable)) > 0) {
443 xData = yData = syData = NULL;
444 fitData = residualData = NULL;
445 if (!(xData = SDDS_GetColumnInDoubles(&InputTable, xName)) ||
446 !(yData = SDDS_GetColumnInDoubles(&InputTable, yName))) {
447 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
448 }
449 if (syName && !(syData = SDDS_GetColumnInDoubles(&InputTable, syName))) {
450 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
451 }
452 if (lowerPar && !SDDS_GetParameterAsDouble(&InputTable, lowerPar, &lower)) {
453 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
454 }
455 if (upperPar && !SDDS_GetParameterAsDouble(&InputTable, upperPar, &upper)) {
456 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
457 }
458 if (baselineGuessPar && !SDDS_GetParameterAsDouble(&InputTable, baselineGuessPar, &baselineGuess)) {
459 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
460 }
461 if (heightGuessPar && !SDDS_GetParameterAsDouble(&InputTable, heightGuessPar, &heightGuess)) {
462 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
463 }
464 if (meanGuessPar && !SDDS_GetParameterAsDouble(&InputTable, meanGuessPar, &meanGuess)) {
465 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
466 }
467 if (sigmaGuessPar && !SDDS_GetParameterAsDouble(&InputTable, sigmaGuessPar, &sigmaGuess)) {
468 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
469 }
470
471 if ((nData = SDDS_CountRowsOfInterest(&InputTable)) < 5) {
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 }
532 sigLevel = ChiSqrSigLevel(chiSqr, nData - 4);
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
544 if (!SDDS_StartPage(&OutputTable, nData) ||
545 !SDDS_CopyParameters(&OutputTable, &InputTable) ||
546 !SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, xData, nData, xIndex) ||
547 !SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, fitData, nData, fitIndex) ||
548 !SDDS_SetParameters(&OutputTable, SDDS_PASS_BY_VALUE | SDDS_SET_BY_NAME,
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)))) ||
559 !SDDS_WritePage(&OutputTable)) {
560 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
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
580 if (!SDDS_Terminate(&InputTable) || !SDDS_Terminate(&OutputTable)) {
581 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
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 }
599 free_scanargs(&s_arg, argc);
600 return EXIT_SUCCESS;
601}
602
603void setupOutputFile(SDDS_DATASET *OutputTable, long *xIndex, long *yIndex, long *syIndex, long *fitIndex,
604 long *residualIndex, long fullOutput, char *output, SDDS_DATASET *InputTable,
605 char *xName, char *yName, char *syName, short columnMajorOrder) {
606 char *name, *yUnits, *description, *xUnits;
607 int32_t typeValue = SDDS_DOUBLE;
608 static char *residualNamePart = "Residual";
609 static char *residualDescriptionPart = "Residual of Gaussian fit to ";
610
611 if (!SDDS_InitializeOutput(OutputTable, SDDS_BINARY, 0, NULL, "sddsgfit output", output) ||
612 !SDDS_TransferColumnDefinition(OutputTable, InputTable, xName, NULL) ||
613 !SDDS_ChangeColumnInformation(OutputTable, "type", &typeValue, SDDS_BY_NAME, xName) ||
614 (*xIndex = SDDS_GetColumnIndex(OutputTable, xName)) < 0 ||
615 !SDDS_GetColumnInformation(InputTable, "units", &xUnits, SDDS_BY_NAME, xName) ||
616 !SDDS_GetColumnInformation(InputTable, "units", &yUnits, SDDS_BY_NAME, yName)) {
617 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
618 }
619
620 if (columnMajorOrder != -1) {
621 OutputTable->layout.data_mode.column_major = columnMajorOrder;
622 } else {
623 OutputTable->layout.data_mode.column_major = InputTable->layout.data_mode.column_major;
624 }
625
626 name = tmalloc(sizeof(*name) * (strlen(yName) + strlen(residualNamePart) + 1));
627 description = tmalloc(sizeof(*description) * (strlen(yName) + strlen(residualDescriptionPart) + 1));
628
629 if (fullOutput) {
630 if (!SDDS_TransferColumnDefinition(OutputTable, InputTable, yName, NULL) ||
631 !SDDS_ChangeColumnInformation(OutputTable, "type", &typeValue, SDDS_BY_NAME, yName) ||
632 (*yIndex = SDDS_GetColumnIndex(OutputTable, yName)) < 0) {
633 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
634 }
635 if (syName && (!SDDS_TransferColumnDefinition(OutputTable, InputTable, syName, NULL) ||
636 !SDDS_ChangeColumnInformation(OutputTable, "type", &typeValue, SDDS_BY_NAME, syName) ||
637 (*syIndex = SDDS_GetColumnIndex(OutputTable, syName)) < 0)) {
638 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
639 }
640 sprintf(name, "%s%s", yName, residualNamePart);
641 sprintf(description, "%s%s", yName, residualDescriptionPart);
642 if ((*residualIndex = SDDS_DefineColumn(OutputTable, name, NULL, yUnits, description, NULL, SDDS_DOUBLE, 0)) < 0) {
643 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
644 }
645 }
646
647 sprintf(name, "%sFit", yName);
648 sprintf(description, "Gaussian fit to %s", yName);
649 if ((*fitIndex = SDDS_DefineColumn(OutputTable, name, NULL, yUnits, description, NULL, SDDS_DOUBLE, 0)) < 0) {
650 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
651 }
652
653 if (SDDS_DefineParameter(OutputTable, "gfitBaseline", NULL, yUnits, "Baseline from Gaussian fit",
654 NULL, SDDS_DOUBLE, 0) < 0 ||
655 SDDS_DefineParameter(OutputTable, "gfitHeight", NULL, yUnits, "Height from Gaussian fit",
656 NULL, SDDS_DOUBLE, 0) < 0 ||
657 SDDS_DefineParameter(OutputTable, "gfitMean", "$gm$r", xUnits, "Mean from Gaussian fit",
658 NULL, SDDS_DOUBLE, 0) < 0 ||
659 SDDS_DefineParameter(OutputTable, "gfitSigma", "$gs$r", xUnits, "Sigma from Gaussian fit",
660 NULL, SDDS_DOUBLE, 0) < 0 ||
661 SDDS_DefineParameter(OutputTable, "gfitRmsResidual", NULL, yUnits, "RMS residual from Gaussian fit",
662 NULL, SDDS_DOUBLE, 0) < 0 ||
663 SDDS_DefineParameter(OutputTable, "gfitSigLevel", NULL, NULL, "Significance level from chi-squared test",
664 NULL, SDDS_DOUBLE, 0) < 0 ||
665 !SDDS_TransferAllParameterDefinitions(OutputTable, InputTable, SDDS_TRANSFER_KEEPOLD) ||
666 !SDDS_WriteLayout(OutputTable)) {
667 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
668 }
669
670 free(name);
671 free(description);
672}
673
674double fitFunction(double *a, long *invalid) {
675 double sum, tmp, mean, sigma, base, norm;
676 int64_t i;
677
678 *invalid = 0;
679 sigma = a[SIGMA_INDEX];
680 mean = a[MEAN_INDEX];
681 base = a[BASELINE_INDEX];
682 norm = a[HEIGHT_INDEX];
683
684 if (!syDataFit) {
685 for (i = sum = 0; i < nDataFit; i++) {
686 tmp = (xDataFit[i] - mean) / sigma;
687 tmp = yDataFit[i] - base - norm * exp(-sqr(tmp) / 2);
688 sum += sqr(tmp);
689 }
690 return (sum / nDataFit);
691 } else {
692 for (i = sum = 0; i < nDataFit; i++) {
693 tmp = (xDataFit[i] - mean) / sigma;
694 tmp = (yDataFit[i] - base - norm * exp(-sqr(tmp) / 2)) / syDataFit[i];
695 sum += sqr(tmp);
696 }
697 return (sum / nDataFit);
698 }
699}
700
701void report(double y, double *x, long pass, long nEval, long n_dimen) {
702 long i;
703
704 fprintf(stderr, "pass %ld, after %ld evaluations: result = %.16e\na = ", pass, nEval, y);
705 for (i = 0; i < n_dimen; i++) {
706 fprintf(stderr, "%.8e ", x[i]);
707 }
708 fputc('\n', stderr);
709}
710
711long computeStartingPoint(double *a, double *da, double *x, double *y, int64_t n, unsigned long guessFlags,
712 double sigmaGuess, double meanGuess, double baselineGuess, double heightGuess,
713 double stepSize) {
714 double xhalf, dhalf, ymin, ymax, xcenter, tmp, xmax, xmin;
715 int64_t i;
716
717 if (n < 5) {
718 return 0;
719 }
720
721 /* first find maximum y value and corresponding x value, plus max x */
722 xcenter = 0;
723 ymax = xmax = -DBL_MAX;
724 ymin = xmin = DBL_MAX;
725 for (i = 0; i < n; i++) {
726 if (xmax < fabs(x[i])) {
727 xmax = fabs(x[i]);
728 }
729 if (xmin > fabs(x[i])) { /* Corrected comparison from < to > */
730 xmin = fabs(x[i]);
731 }
732 if (ymax < y[i]) {
733 ymax = y[i];
734 xcenter = x[i];
735 }
736 if (ymin > y[i]) {
737 ymin = y[i];
738 }
739 }
740
741 /* now find approximate half-max point */
742 xhalf = 0;
743 dhalf = DBL_MAX;
744 for (i = 0; i < n; i++) {
745 tmp = fabs((fabs(y[i] - ymax) / (ymax - ymin)) - 0.5);
746 if (tmp < dhalf) {
747 xhalf = x[i];
748 dhalf = tmp;
749 }
750 }
751 if (dhalf != DBL_MAX) {
752 a[SIGMA_INDEX] = fabs(xhalf - xcenter) / 1.177; /* starting sigma */
753 } else {
754 a[SIGMA_INDEX] = xmax - xmin;
755 }
756 a[MEAN_INDEX] = xcenter; /* starting mean */
757 a[BASELINE_INDEX] = ymin; /* starting baseline */
758 a[HEIGHT_INDEX] = ymax - ymin; /* starting height */
759
760 if (guessFlags & (GUESS_SIGMA_GIVEN + FIX_SIGMA_GIVEN)) {
761 a[SIGMA_INDEX] = sigmaGuess;
762 }
763 if (guessFlags & (GUESS_MEAN_GIVEN + FIX_MEAN_GIVEN)) {
764 a[MEAN_INDEX] = meanGuess;
765 }
766 if (guessFlags & (GUESS_BASELINE_GIVEN + FIX_BASELINE_GIVEN)) {
767 a[BASELINE_INDEX] = baselineGuess;
768 }
769 if (guessFlags & (GUESS_HEIGHT_GIVEN + FIX_HEIGHT_GIVEN)) {
770 a[HEIGHT_INDEX] = heightGuess;
771 }
772
773 /* step sizes */
774 for (i = 0; i < 4; i++) {
775 if (!(da[i] = a[i] * stepSize))
776 da[i] = stepSize;
777 }
778
779 return 1;
780}
781
782int64_t makeFilteredCopy(double **xFit, double **yFit, double **syFit, double *x, double *y,
783 double *sy, int64_t n, double lower, double upper) {
784 int64_t i, j;
785
786 if (!(*xFit = (double *)malloc(sizeof(**xFit) * n)) ||
787 !(*yFit = (double *)malloc(sizeof(**yFit) * n)) ||
788 (sy && !(*syFit = (double *)malloc(sizeof(**syFit) * n)))) {
789 return 0;
790 }
791
792 for (i = j = 0; i < n; i++) {
793 if (x[i] < lower || x[i] > upper) {
794 continue;
795 }
796 (*xFit)[j] = x[i];
797 (*yFit)[j] = y[i];
798 if (sy) {
799 (*syFit)[j] = sy[i];
800 }
801 j++;
802 }
803 return j;
804}
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