SDDS ToolKit Programs and Libraries for C and Python
All Classes Files Functions Variables Macros Pages
sddslorentzianfit.c
Go to the documentation of this file.
1/**
2 * @file sddslorentzianfit.c
3 * @brief Perform a Lorentzian fit on data using the SDDS library.
4 *
5 * @details
6 * This program reads data from an SDDS file, performs a Lorentzian fit, and writes the
7 * results to an SDDS file. The fitting function is:
8 * \f[
9 * y(x) = baseline + height \cdot \frac{\gamma^2}{\gamma^2 + (x - center)^2}
10 * \f]
11 * Various options allow the user to customize the fit, including specifying fitting ranges,
12 * initial parameter guesses, and verbosity levels.
13 *
14 * @section Usage
15 * ```
16 * sddslorentzianfit [<inputfile>] [<outputfile>]
17 * [-pipe=[input][,output]]
18 * -columns=<x-name>,<y-name>[,ySigma=<sy-name>]
19 * [-fitRange=<lower>|@<parameter-name>,<upper>|@<parameter-name>]
20 * [-fullOutput]
21 * [-verbosity=<integer>]
22 * [-stepSize=<factor>]
23 * [-tolerance=<value>]
24 * [-guesses=[baseline=<value>|@<parameter-name>][,center=<value>|@<parameter-name>][,height=<value>|@<parameter-name>][,gamma=<value>|@<parameter-name>]]
25 * [-fixValue=[baseline=<value>|@<parameter-name>][,center=<value>|@<parameter-name>][,height=<value>|@<parameter-name>][,gamma=<value>|@<parameter-name>]]
26 * [-limits=[evaluations=<number>][,passes=<number>]]
27 * [-majorOrder=row|column]
28 * ```
29 *
30 * @section Options
31 * | Required | Description |
32 * |---------------------------------------|---------------------------------------------------------|
33 * | `-columns` | Specify x and y column names, and optionally y sigma. |
34 *
35 * | Optional | Description |
36 * |-------------------------|---------------------------------------------------------------------------------------------|
37 * | `-pipe` | Use standard input/output pipes. |
38 * | `-fitRange` | Define fitting range with bounds, which can be constants or parameters. |
39 * | `-fullOutput` | Enable detailed output including residuals. |
40 * | `-verbosity` | Set verbosity level. |
41 * | `-stepSize` | Step size factor for fitting algorithm. |
42 * | `-tolerance` | Tolerance for convergence. |
43 * | `-guesses` | Provide initial guesses for parameters (baseline, center, height, gamma). |
44 * | `-fixValue` | Fix specific parameters to provided values. |
45 * | `-limits` | Set limits on evaluations and passes. |
46 * | `-majorOrder` | Specify major order for data storage (row or column). |
47 *
48 * @subsection Incompatibilities
49 * - `-fixValue` is incompatible with `-guesses` for the same parameter.
50 *
51 * @subsection Requirements
52 * - For `-fitRange`:
53 * - Both lower and upper bounds are required.
54 * - For `-limits`:
55 * - Must specify `evaluations` or `passes` or both.
56 *
57 * @copyright
58 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
59 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
60 *
61 * @license
62 * This file is distributed under the terms of the Software License Agreement
63 * found in the file LICENSE included with this distribution.
64 *
65 * @author
66 * M. Borland
67 */
68
69#include "mdb.h"
70#include "SDDS.h"
71#include "scan.h"
72
73/* Enumeration for option types */
74enum option_type {
75 SET_FITRANGE,
76 SET_GUESSES,
77 SET_VERBOSITY,
78 SET_COLUMNS,
79 SET_TOLERANCE,
80 SET_FULLOUTPUT,
81 SET_STEPSIZE,
82 SET_LIMITS,
83 SET_PIPE,
84 SET_FIXVALUE,
85 SET_MAJOR_ORDER,
86 N_OPTIONS
87};
88
89char *option[N_OPTIONS] = {
90 "fitrange",
91 "guesses",
92 "verbosity",
93 "columns",
94 "tolerance",
95 "fulloutput",
96 "stepsize",
97 "limits",
98 "pipe",
99 "fixvalue",
100 "majorOrder",
101};
102
103static char *USAGE =
104 "Usage: sddslorentzianfit [<inputfile>] [<outputfile>]\n"
105 " [-pipe=[input][,output]]\n"
106 " -columns=<x-name>,<y-name>[,ySigma=<sy-name>]\n"
107 " [-fitRange=<lower>|@<parameter-name>,<upper>|@<parameter-name>]\n"
108 " [-fullOutput]\n"
109 " [-verbosity=<integer>] \n"
110 " [-stepSize=<factor>] \n"
111 " [-tolerance=<value>]\n"
112 " [-guesses=[baseline=<value>|@<parameter-name>][,center=<value>|@<parameter-name>]\n"
113 " [,height=<value>|@<parameter-name>][,gamma=<value>|@<parameter-name>]] \n"
114 " [-fixValue=[baseline=<value>|@<parameter-name>][,center=<value>|@<parameter-name>]\n"
115 " [,height=<value>|@<parameter-name>][,gamma=<value>|@<parameter-name>]]\n"
116 " [-limits=[evaluations=<number>][,passes=<number>]] \n"
117 " [-majorOrder=row|column] \n"
118 "\nOptions:\n"
119 " -pipe=<input>,<output> Use standard input/output pipes.\n"
120 " -columns=<x-name>,<y-name>[,ySigma=<sy-name>]\n"
121 " Specify the names of the x and y data columns,\n"
122 " and optionally the y sigma column.\n"
123 " -fitRange=<lower>|@<param>,<upper>|@<param>\n"
124 " Define the fitting range with lower and upper bounds.\n"
125 " Values can be direct or parameter references.\n"
126 " -guesses=<baseline|@param>,<center|@param>,<height|@param>,<gamma|@param>\n"
127 " Provide initial guesses for the fit parameters.\n"
128 " -fixValue=<baseline|@param>,<center|@param>,<height|@param>,<gamma|@param>\n"
129 " Fix specific fit parameters to given values or parameters.\n"
130 " -verbosity=<integer> Set verbosity level (higher for more detail).\n"
131 " -stepSize=<factor> Define the step size factor for the fitting algorithm.\n"
132 " -tolerance=<value> Set the tolerance for convergence of the fit.\n"
133 " -limits=<evaluations>,<passes> Set maximum number of evaluations and passes.\n"
134 " -majorOrder=row|column Specify the major order for data storage.\n"
135 " -fullOutput Enable detailed output including residuals.\n"
136 "\nDescription:\n"
137 " Performs a Lorentzian fit of the form:\n"
138 " y = baseline + height * gamma^2 / (gamma^2 + (x - center)^2)\n"
139 "\nAuthor:\n"
140 " Michael Borland\n"
141 " (" __DATE__ " " __TIME__ ", SVN revision: " SVN_VERSION ")\n";
142
143void report(double res, double *a, long pass, long n_eval, long n_dimen);
144void setupOutputFile(SDDS_DATASET *OutputTable, long *xIndex, long *yIndex, long *syIndex, long *fitIndex,
145 long *residualIndex, long fullOutput, char *output, SDDS_DATASET *InputTable,
146 char *xName, char *yName, char *syName, short columnMajorOrder);
147long computeStartingPoint(double *a, double *da, double *x, double *y, int64_t n, unsigned long guessFlags,
148 double gammaGuess, double centerGuess, double baselineGuess, double heightGuess,
149 double stepSize);
150double fitFunction(double *a, long *invalid);
151int64_t makeFilteredCopy(double **xFit, double **yFit, double **syFit, double *x, double *y, double *sy,
152 int64_t n, double lower, double upper);
153
154static double *xDataFit = NULL, *yDataFit = NULL, *syDataFit = NULL;
155static int64_t nDataFit = 0;
156
157#define GUESS_BASELINE_GIVEN 0x0001
158#define FIX_BASELINE_GIVEN (0x0001 << 4)
159#define GUESS_HEIGHT_GIVEN 0x0002
160#define FIX_HEIGHT_GIVEN (0x0002 << 4)
161#define GUESS_CENTER_GIVEN 0x0004
162#define FIX_CENTER_GIVEN (0x0004 << 4)
163#define GUESS_GAMMA_GIVEN 0x0008
164#define FIX_GAMMA_GIVEN (0x0008 << 4)
165
166#define BASELINE_INDEX 0
167#define HEIGHT_INDEX 1
168#define CENTER_INDEX 2
169#define GAMMA_INDEX 3
170
171int main(int argc, char **argv) {
172 double *xData = NULL, *yData = NULL, *syData = NULL;
173 int64_t nData = 0;
174 SDDS_DATASET InputTable, OutputTable;
175 SCANNED_ARG *s_arg;
176 long i_arg;
177 char *input, *output, *xName, *yName, *syName;
178 long xIndex, yIndex, fitIndex, residualIndex, syIndex_col, retval;
179 double *fitData, *residualData, rmsResidual, chiSqr, sigLevel;
180 unsigned long guessFlags, dummyFlags, pipeFlags, majorOrderFlag;
181 double gammaGuess, centerGuess, baselineGuess, heightGuess;
182 double tolerance, stepSize;
183 double a[4], da[4], lower, upper, result;
184 double aLow[4], aHigh[4];
185 short disable[4] = {0, 0, 0, 0};
186 int32_t nEvalMax = 5000, nPassMax = 100;
187 long nEval, verbosity, fullOutput = 0;
188 int64_t i;
189 short columnMajorOrder = -1;
190 char *lowerPar, *upperPar, *baselineGuessPar, *gammaGuessPar, *centerGuessPar, *heightGuessPar;
191
193 argc = scanargs(&s_arg, argc, argv);
194 if (argc < 2 || argc > (2 + N_OPTIONS)) {
195 fprintf(stderr, "%s", USAGE);
196 exit(EXIT_FAILURE);
197 }
198
199 for (i = 0; i < 4; i++)
200 aLow[i] = -(aHigh[i] = DBL_MAX);
201 aLow[GAMMA_INDEX] = 0;
202 input = output = NULL;
203 stepSize = 1e-2;
204 tolerance = 1e-8;
205 verbosity = 0;
206 guessFlags = gammaGuess = heightGuess = baselineGuess = centerGuess = pipeFlags = 0;
207 xName = yName = syName = NULL;
208 lower = upper = 0;
209 lowerPar = upperPar = gammaGuessPar = heightGuessPar = baselineGuessPar = centerGuessPar = NULL;
210 for (i_arg = 1; i_arg < argc; i_arg++) {
211 if (s_arg[i_arg].arg_type == OPTION) {
212 switch (match_string(s_arg[i_arg].list[0], option, N_OPTIONS, 0)) {
213 case SET_MAJOR_ORDER:
214 majorOrderFlag = 0;
215 s_arg[i_arg].n_items--;
216 if (s_arg[i_arg].n_items > 0 && (!scanItemList(&majorOrderFlag, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0, "row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER, "column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL)))
217 SDDS_Bomb("invalid -majorOrder syntax/values");
218 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
219 columnMajorOrder = 1;
220 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
221 columnMajorOrder = 0;
222 break;
223 case SET_FITRANGE:
224 if (s_arg[i_arg].n_items != 3)
225 SDDS_Bomb("incorrect -fitRange syntax");
226 if (s_arg[i_arg].list[1][0] == '@') {
227 cp_str(&lowerPar, s_arg[i_arg].list[1] + 1);
228 } else if (sscanf(s_arg[i_arg].list[1], "%lf", &lower) != 1)
229 SDDS_Bomb("invalid fitRange lower value provided");
230 if (s_arg[i_arg].list[2][0] == '@') {
231 cp_str(&upperPar, s_arg[i_arg].list[2] + 1);
232 } else if (sscanf(s_arg[i_arg].list[2], "%lf", &upper) != 1)
233 SDDS_Bomb("invalid fitRange upper value provided");
234 break;
235 case SET_TOLERANCE:
236 if (s_arg[i_arg].n_items != 2 || sscanf(s_arg[i_arg].list[1], "%lf", &tolerance) != 1 || tolerance <= 0)
237 SDDS_Bomb("incorrect -tolerance syntax");
238 break;
239 case SET_STEPSIZE:
240 if (s_arg[i_arg].n_items != 2 || sscanf(s_arg[i_arg].list[1], "%lf", &stepSize) != 1 || stepSize <= 0)
241 SDDS_Bomb("incorrect -stepSize syntax");
242 break;
243 case SET_VERBOSITY:
244 if (s_arg[i_arg].n_items != 2 || sscanf(s_arg[i_arg].list[1], "%ld", &verbosity) != 1)
245 SDDS_Bomb("incorrect -verbosity syntax");
246 break;
247 case SET_GUESSES:
248 if (s_arg[i_arg].n_items < 2)
249 SDDS_Bomb("incorrect -guesses syntax");
250 s_arg[i_arg].n_items -= 1;
251 dummyFlags = guessFlags;
252 if (!scanItemList(&guessFlags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
253 "baseline", SDDS_STRING, &baselineGuessPar, 1, GUESS_BASELINE_GIVEN,
254 "height", SDDS_STRING, &heightGuessPar, 1, GUESS_HEIGHT_GIVEN,
255 "center", SDDS_STRING, &centerGuessPar, 1, GUESS_CENTER_GIVEN,
256 "gamma", SDDS_STRING, &gammaGuessPar, 1, GUESS_GAMMA_GIVEN, NULL))
257 SDDS_Bomb("invalid -guesses syntax");
258 if (baselineGuessPar) {
259 if (baselineGuessPar[0] == '@') {
260 baselineGuessPar++;
261 } else {
262 if (sscanf(baselineGuessPar, "%lf", &baselineGuess) != 1)
263 SDDS_Bomb("Invalid baseline guess value provided.");
264 free(baselineGuessPar);
265 baselineGuessPar = NULL;
266 }
267 }
268 if (heightGuessPar) {
269 if (heightGuessPar[0] == '@') {
270 heightGuessPar++;
271 } else {
272 if (sscanf(heightGuessPar, "%lf", &heightGuess) != 1)
273 SDDS_Bomb("Invalid height guess value provided.");
274 free(heightGuessPar);
275 heightGuessPar = NULL;
276 }
277 }
278 if (centerGuessPar) {
279 if (centerGuessPar[0] == '@') {
280 centerGuessPar++;
281 } else {
282 if (sscanf(centerGuessPar, "%lf", &centerGuess) != 1)
283 SDDS_Bomb("Invalid center guess value provided.");
284 free(centerGuessPar);
285 centerGuessPar = NULL;
286 }
287 }
288 if (gammaGuessPar) {
289 if (gammaGuessPar[0] == '@') {
290 gammaGuessPar++;
291 } else {
292 if (sscanf(gammaGuessPar, "%lf", &gammaGuess) != 1)
293 SDDS_Bomb("Invalid gamma guess value provided.");
294 free(gammaGuessPar);
295 gammaGuessPar = NULL;
296 }
297 }
298 if ((dummyFlags >> 4) & guessFlags)
299 SDDS_Bomb("can't have -fixValue and -guesses for the same item");
300 guessFlags |= dummyFlags;
301 break;
302 case SET_FIXVALUE:
303 if (s_arg[i_arg].n_items < 2)
304 SDDS_Bomb("incorrect -fixValue syntax");
305 s_arg[i_arg].n_items -= 1;
306 dummyFlags = guessFlags;
307 if (!scanItemList(&guessFlags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
308 "baseline", SDDS_STRING, &baselineGuessPar, 1, FIX_BASELINE_GIVEN,
309 "height", SDDS_STRING, &heightGuessPar, 1, FIX_HEIGHT_GIVEN,
310 "center", SDDS_STRING, &centerGuessPar, 1, FIX_CENTER_GIVEN,
311 "gamma", SDDS_STRING, &gammaGuessPar, 1, FIX_GAMMA_GIVEN, NULL))
312 SDDS_Bomb("invalid -fixValue syntax");
313 if (dummyFlags & (guessFlags >> 4))
314 SDDS_Bomb("can't have -fixValue and -guesses for the same item");
315 guessFlags |= dummyFlags;
316 if (baselineGuessPar) {
317 if (baselineGuessPar[0] == '@') {
318 baselineGuessPar++;
319 } else {
320 if (sscanf(baselineGuessPar, "%lf", &baselineGuess) != 1)
321 SDDS_Bomb("Invalid baseline guess value provided.");
322 free(baselineGuessPar);
323 baselineGuessPar = NULL;
324 }
325 }
326 if (heightGuessPar) {
327 if (heightGuessPar[0] == '@') {
328 heightGuessPar++;
329 } else {
330 if (sscanf(heightGuessPar, "%lf", &heightGuess) != 1)
331 SDDS_Bomb("Invalid height guess value provided.");
332 free(heightGuessPar);
333 heightGuessPar = NULL;
334 }
335 }
336 if (centerGuessPar) {
337 if (centerGuessPar[0] == '@') {
338 centerGuessPar++;
339 } else {
340 if (sscanf(centerGuessPar, "%lf", &centerGuess) != 1)
341 SDDS_Bomb("Invalid center guess value provided.");
342 free(centerGuessPar);
343 centerGuessPar = NULL;
344 }
345 }
346 if (gammaGuessPar) {
347 if (gammaGuessPar[0] == '@') {
348 gammaGuessPar++;
349 } else {
350 if (sscanf(gammaGuessPar, "%lf", &gammaGuess) != 1)
351 SDDS_Bomb("Invalid gamma guess value provided.");
352 free(gammaGuessPar);
353 gammaGuessPar = NULL;
354 }
355 }
356 break;
357 case SET_COLUMNS:
358 if (s_arg[i_arg].n_items != 3 && s_arg[i_arg].n_items != 4)
359 SDDS_Bomb("invalid -columns syntax");
360 xName = s_arg[i_arg].list[1];
361 yName = s_arg[i_arg].list[2];
362 s_arg[i_arg].n_items -= 3;
363 if (!scanItemList(&dummyFlags, s_arg[i_arg].list + 3, &s_arg[i_arg].n_items, 0,
364 "ysigma", SDDS_STRING, &syName, 1, 0, NULL))
365 SDDS_Bomb("invalid -columns syntax");
366 break;
367 case SET_FULLOUTPUT:
368 fullOutput = 1;
369 break;
370 case SET_LIMITS:
371 if (s_arg[i_arg].n_items < 2)
372 SDDS_Bomb("incorrect -limits syntax");
373 s_arg[i_arg].n_items -= 1;
374 if (!scanItemList(&dummyFlags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
375 "evaluations", SDDS_LONG, &nEvalMax, 1, 0,
376 "passes", SDDS_LONG, &nPassMax, 1, 0, NULL) ||
377 nEvalMax <= 0 || nPassMax <= 0)
378 SDDS_Bomb("invalid -limits syntax");
379 break;
380 case SET_PIPE:
381 if (!processPipeOption(s_arg[i_arg].list + 1, s_arg[i_arg].n_items - 1, &pipeFlags))
382 SDDS_Bomb("invalid -pipe syntax");
383 break;
384 default:
385 fprintf(stderr, "Error: Unknown or ambiguous option: %s\n", s_arg[i_arg].list[0]);
386 fprintf(stderr, "%s", USAGE);
387 exit(EXIT_FAILURE);
388 break;
389 }
390 } else {
391 if (input == NULL)
392 input = s_arg[i_arg].list[0];
393 else if (output == NULL)
394 output = s_arg[i_arg].list[0];
395 else
396 SDDS_Bomb("too many filenames");
397 }
398 }
399
400 processFilenames("sddslorentzianfit", &input, &output, pipeFlags, 0, NULL);
401
402 for (i = 0; i < 4; i++) {
403 if ((guessFlags >> 4) & (1 << i)) {
404 disable[i] = 1;
405 }
406 }
407
408 if (!xName || !yName) {
409 fprintf(stderr, "Error: -columns option must be specified.\n");
410 fprintf(stderr, "%s", USAGE);
411 exit(EXIT_FAILURE);
412 }
413
414 if (!SDDS_InitializeInput(&InputTable, input))
415 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
416 if (!SDDS_FindColumn(&InputTable, FIND_NUMERIC_TYPE, xName, NULL) ||
417 !SDDS_FindColumn(&InputTable, FIND_NUMERIC_TYPE, yName, NULL) ||
418 (syName && !SDDS_FindColumn(&InputTable, FIND_NUMERIC_TYPE, syName, NULL)))
419 SDDS_Bomb("One or more of the specified data columns do not exist or are non-numeric.");
420
421 setupOutputFile(&OutputTable, &xIndex, &yIndex, &syIndex_col, &fitIndex, &residualIndex,
422 fullOutput, output, &InputTable, xName, yName, syName, columnMajorOrder);
423
424 while ((retval = SDDS_ReadPage(&InputTable)) > 0) {
425 xData = yData = syData = NULL;
426 fitData = residualData = NULL;
427 if (!(xData = SDDS_GetColumnInDoubles(&InputTable, xName)) ||
428 !(yData = SDDS_GetColumnInDoubles(&InputTable, yName)))
429 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
430 if (syName && !(syData = SDDS_GetColumnInDoubles(&InputTable, syName)))
431 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
432 if (lowerPar && !SDDS_GetParameterAsDouble(&InputTable, lowerPar, &lower))
433 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
434 if (upperPar && !SDDS_GetParameterAsDouble(&InputTable, upperPar, &upper))
435 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
436 if (baselineGuessPar && !SDDS_GetParameterAsDouble(&InputTable, baselineGuessPar, &baselineGuess))
437 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
438 if (heightGuessPar && !SDDS_GetParameterAsDouble(&InputTable, heightGuessPar, &heightGuess))
439 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
440 if (centerGuessPar && !SDDS_GetParameterAsDouble(&InputTable, centerGuessPar, &centerGuess))
441 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
442 if (gammaGuessPar && !SDDS_GetParameterAsDouble(&InputTable, gammaGuessPar, &gammaGuess))
443 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
444
445 if ((nData = SDDS_CountRowsOfInterest(&InputTable)) < 5)
446 continue;
447 if (lower < upper) {
448 if ((nDataFit = makeFilteredCopy(&xDataFit, &yDataFit, &syDataFit, xData, yData, syData, nData, lower, upper)) < 5)
449 continue;
450 } else {
451 xDataFit = xData;
452 yDataFit = yData;
453 syDataFit = syData;
454 nDataFit = nData;
455 }
456
457 if (!computeStartingPoint(a, da, xDataFit, yDataFit, nDataFit, guessFlags, gammaGuess, centerGuess, baselineGuess, heightGuess, stepSize)) {
458 fprintf(stderr, "Error: Couldn't compute starting point for page %ld--skipping\n", retval);
459 continue;
460 }
461 if (verbosity > 2)
462 fprintf(stderr, "Starting values: gamma=%.6e center=%.6e baseline=%.6e height=%.6e\n", a[GAMMA_INDEX], a[CENTER_INDEX], a[BASELINE_INDEX], a[HEIGHT_INDEX]);
463 if (verbosity > 3)
464 fprintf(stderr, "Starting steps: gamma=%.6e center=%.6e baseline=%.6e height=%.6e\n", da[GAMMA_INDEX], da[CENTER_INDEX], da[BASELINE_INDEX], da[HEIGHT_INDEX]);
465
466 nEval = simplexMin(&result, a, da, aLow, aHigh, disable, 4, -DBL_MAX, tolerance, fitFunction, (verbosity > 0 ? report : NULL), nEvalMax, nPassMax, 12, 3, 1.0, 0);
467 if (xData != xDataFit) {
468 free(xDataFit);
469 free(yDataFit);
470 if (syDataFit)
471 free(syDataFit);
472 }
473
474 if (verbosity > 3)
475 fprintf(stderr, "%ld evaluations of fit function required, giving result %e\n", nEval, result);
476
477 fitData = trealloc(fitData, sizeof(*fitData) * nData);
478 residualData = trealloc(residualData, sizeof(*residualData) * nData);
479 for (i = result = 0; i < nData; i++) {
480 fitData[i] = a[BASELINE_INDEX] + a[HEIGHT_INDEX] / (1 + sqr((xDataFit[i] - a[CENTER_INDEX]) / a[GAMMA_INDEX]));
481 residualData[i] = yData[i] - fitData[i];
482 result += sqr(residualData[i]);
483 }
484 rmsResidual = sqrt(result / nData);
485 if (syData) {
486 for (i = chiSqr = 0; i < nData; i++)
487 chiSqr += sqr(residualData[i] / syData[i]);
488 } else {
489 double sy2;
490 sy2 = result / (nData - 4);
491 for (i = chiSqr = 0; i < nData; i++)
492 chiSqr += sqr(residualData[i]) / sy2;
493 }
494 sigLevel = ChiSqrSigLevel(chiSqr, nData - 4);
495 if (verbosity > 0) {
496 fprintf(stderr, "gamma: %.15e\ncenter: %.15e\nbaseline: %.15e\nheight: %.15e\n", a[GAMMA_INDEX], a[CENTER_INDEX], a[BASELINE_INDEX], a[HEIGHT_INDEX]);
497 }
498 if (verbosity > 1) {
499 if (syData)
500 fprintf(stderr, "Significance level: %.5e\n", sigLevel);
501 fprintf(stderr, "RMS deviation: %.15e\n", rmsResidual);
502 }
503
504 if (!SDDS_StartPage(&OutputTable, nData) ||
505 !SDDS_CopyParameters(&OutputTable, &InputTable) ||
506 !SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, xData, nData, xIndex) ||
507 !SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, fitData, nData, fitIndex) ||
508 !SDDS_SetParameters(&OutputTable, SDDS_PASS_BY_VALUE | SDDS_SET_BY_NAME,
509 "lorentzianfitGamma", a[GAMMA_INDEX],
510 "lorentzianfitCenter", a[CENTER_INDEX],
511 "lorentzianfitBaseline", a[BASELINE_INDEX],
512 "lorentzianfitHeight", a[HEIGHT_INDEX],
513 "lorentzianfitRmsResidual", rmsResidual,
514 "lorentzianfitSigLevel", sigLevel, NULL) ||
515 (fullOutput &&
516 (!SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, yData, nData, yIndex) ||
517 !SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, residualData, nData, residualIndex) ||
518 (syName && !SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, syData, nData, syIndex_col)))) ||
519 !SDDS_WritePage(&OutputTable))
520 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
521 if (xData)
522 free(xData);
523 if (yData)
524 free(yData);
525 if (syData)
526 free(syData);
527 if (fitData)
528 free(fitData);
529 if (residualData)
530 free(residualData);
531 }
532 if (!SDDS_Terminate(&InputTable) || !SDDS_Terminate(&OutputTable)) {
533 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
534 exit(EXIT_FAILURE);
535 }
536 if (lowerPar)
537 free(lowerPar);
538 if (upperPar)
539 free(upperPar);
540 if (baselineGuessPar)
541 free(baselineGuessPar);
542 if (heightGuessPar)
543 free(heightGuessPar);
544 if (gammaGuessPar)
545 free(gammaGuessPar);
546 free_scanargs(&s_arg, argc);
547 return EXIT_SUCCESS;
548}
549
550void setupOutputFile(SDDS_DATASET *OutputTable, long *xIndex, long *yIndex, long *syIndex, long *fitIndex,
551 long *residualIndex, long fullOutput, char *output, SDDS_DATASET *InputTable,
552 char *xName, char *yName, char *syName, short columnMajorOrder) {
553 char *name, *yUnits, *description, *xUnits;
554 int32_t typeValue = SDDS_DOUBLE;
555 static char *residualNamePart = "Residual";
556 static char *residualDescriptionPart = "Residual of Lorentzian fit to ";
557
558 if (!SDDS_InitializeOutput(OutputTable, SDDS_BINARY, 0, NULL, "sddslorentzianfit output", output) ||
559 !SDDS_TransferColumnDefinition(OutputTable, InputTable, xName, NULL) ||
560 !SDDS_ChangeColumnInformation(OutputTable, "type", &typeValue, SDDS_BY_NAME, xName) ||
561 (*xIndex = SDDS_GetColumnIndex(OutputTable, xName)) < 0 ||
562 !SDDS_GetColumnInformation(InputTable, "units", &xUnits, SDDS_BY_NAME, xName) ||
563 !SDDS_GetColumnInformation(InputTable, "units", &yUnits, SDDS_BY_NAME, yName))
564 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
565 if (columnMajorOrder != -1)
566 OutputTable->layout.data_mode.column_major = columnMajorOrder;
567 else
568 OutputTable->layout.data_mode.column_major = InputTable->layout.data_mode.column_major;
569 name = tmalloc(sizeof(*name) * (strlen(yName) + strlen(residualNamePart) + 1));
570 description = tmalloc(sizeof(*description) * (strlen(yName) + strlen(residualDescriptionPart) + 1));
571
572 if (fullOutput) {
573 if (!SDDS_TransferColumnDefinition(OutputTable, InputTable, yName, NULL) ||
574 !SDDS_ChangeColumnInformation(OutputTable, "type", &typeValue, SDDS_BY_NAME, yName) ||
575 (*yIndex = SDDS_GetColumnIndex(OutputTable, yName)) < 0)
576 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
577 if (syName && (!SDDS_TransferColumnDefinition(OutputTable, InputTable, syName, NULL) ||
578 !SDDS_ChangeColumnInformation(OutputTable, "type", &typeValue, SDDS_BY_NAME, syName) ||
579 (*syIndex = SDDS_GetColumnIndex(OutputTable, syName)) < 0))
580 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
581 sprintf(name, "%s%s", yName, residualNamePart);
582 sprintf(description, "%s%s", yName, residualDescriptionPart);
583 if ((*residualIndex = SDDS_DefineColumn(OutputTable, name, NULL, yUnits, description, NULL, SDDS_DOUBLE, 0)) < 0)
584 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
585 }
586
587 sprintf(name, "%sFit", yName);
588 sprintf(description, "Lorentzian fit to %s", yName);
589 if ((*fitIndex = SDDS_DefineColumn(OutputTable, name, NULL, yUnits, description, NULL, SDDS_DOUBLE, 0)) < 0)
590 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
591
592 if (SDDS_DefineParameter(OutputTable, "lorentzianfitBaseline", NULL, yUnits, "Baseline from Lorentzian fit",
593 NULL, SDDS_DOUBLE, 0) < 0 ||
594 SDDS_DefineParameter(OutputTable, "lorentzianfitHeight", NULL, yUnits, "Height from Lorentzian fit",
595 NULL, SDDS_DOUBLE, 0) < 0 ||
596 SDDS_DefineParameter(OutputTable, "lorentzianfitCenter", NULL, xUnits, "Center from Lorentzian fit",
597 NULL, SDDS_DOUBLE, 0) < 0 ||
598 SDDS_DefineParameter(OutputTable, "lorentzianfitGamma", NULL, xUnits, "Gamma from Lorentzian fit",
599 NULL, SDDS_DOUBLE, 0) < 0 ||
600 SDDS_DefineParameter(OutputTable, "lorentzianfitRmsResidual", NULL, yUnits, "RMS residual from Lorentzian fit",
601 NULL, SDDS_DOUBLE, 0) < 0 ||
602 SDDS_DefineParameter(OutputTable, "lorentzianfitSigLevel", NULL, NULL, "Significance level from chi-squared test",
603 NULL, SDDS_DOUBLE, 0) < 0 ||
604 !SDDS_TransferAllParameterDefinitions(OutputTable, InputTable, SDDS_TRANSFER_KEEPOLD) ||
605 !SDDS_WriteLayout(OutputTable))
606 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
607}
608
609double fitFunction(double *a, long *invalid) {
610 double sum, tmp, center, gamma, base, norm;
611 int64_t i;
612
613 *invalid = 0;
614 gamma = a[GAMMA_INDEX];
615 center = a[CENTER_INDEX];
616 base = a[BASELINE_INDEX];
617 norm = a[HEIGHT_INDEX];
618
619 if (!syDataFit) {
620 for (i = sum = 0; i < nDataFit; i++) {
621 tmp = (xDataFit[i] - center) / gamma;
622 tmp = norm / (1 + sqr(tmp)) + base;
623 sum += sqr(tmp - yDataFit[i]);
624 }
625 return (sum / nDataFit);
626 } else {
627 for (i = sum = 0; i < nDataFit; i++) {
628 tmp = (xDataFit[i] - center) / gamma;
629 tmp = norm / (1 + sqr(tmp)) + base;
630 sum += sqr((tmp - yDataFit[i]) / syDataFit[i]);
631 }
632 return (sum / nDataFit);
633 }
634}
635
636void report(double y, double *x, long pass, long nEval, long n_dimen) {
637 long i;
638
639 fprintf(stderr, "Pass %ld, after %ld evaluations: result = %.16e\na = ", pass, nEval, y);
640 for (i = 0; i < n_dimen; i++)
641 fprintf(stderr, "%.8e ", x[i]);
642 fputc('\n', stderr);
643}
644
645long computeStartingPoint(double *a, double *da, double *x, double *y, int64_t n, unsigned long guessFlags,
646 double gammaGuess, double centerGuess, double baselineGuess, double heightGuess,
647 double stepSize) {
648 double xhalf, dhalf, ymin, ymax, xcenter, tmp, xmax, xmin;
649 int64_t i;
650
651 if (n < 5)
652 return 0;
653
654 /* First find maximum y value and corresponding x value, plus max x */
655 xcenter = 0;
656 ymax = xmax = -DBL_MAX;
657 ymin = xmin = DBL_MAX;
658 for (i = 0; i < n; i++) {
659 if (xmax < (tmp = fabs(x[i])))
660 xmax = tmp;
661 if (xmin < tmp)
662 xmin = tmp;
663 if (ymax < y[i]) {
664 ymax = y[i];
665 xcenter = x[i];
666 }
667 if (ymin > y[i])
668 ymin = y[i];
669 }
670
671 /* Now find approximate half-max point */
672 xhalf = 0;
673 dhalf = DBL_MAX;
674 for (i = 0; i < n; i++) {
675 tmp = fabs(fabs(y[i] - ymax) / (ymax - ymin) - 0.5);
676 if (tmp < dhalf) {
677 xhalf = x[i];
678 dhalf = tmp;
679 }
680 }
681 if (dhalf != DBL_MAX)
682 a[GAMMA_INDEX] = fabs(xhalf - xcenter) / 1.177; /* Starting gamma */
683 else
684 a[GAMMA_INDEX] = xmax - xmin;
685 a[CENTER_INDEX] = xcenter; /* Starting center */
686 a[BASELINE_INDEX] = ymin; /* Starting baseline */
687 a[HEIGHT_INDEX] = ymax - ymin; /* Starting height */
688
689 if (guessFlags & (GUESS_GAMMA_GIVEN + FIX_GAMMA_GIVEN))
690 a[GAMMA_INDEX] = gammaGuess;
691 if (guessFlags & (GUESS_CENTER_GIVEN + FIX_CENTER_GIVEN))
692 a[CENTER_INDEX] = centerGuess;
693 if (guessFlags & (GUESS_BASELINE_GIVEN + FIX_BASELINE_GIVEN))
694 a[BASELINE_INDEX] = baselineGuess;
695 if (guessFlags & (GUESS_HEIGHT_GIVEN + FIX_HEIGHT_GIVEN))
696 a[HEIGHT_INDEX] = heightGuess;
697
698 /* Step sizes */
699 for (i = 0; i < 4; i++)
700 if (!(da[i] = a[i] * stepSize))
701 da[i] = stepSize;
702
703 return 1;
704}
705
706int64_t makeFilteredCopy(double **xFit, double **yFit, double **syFit, double *x, double *y,
707 double *sy, int64_t n, double lower, double upper) {
708 int64_t i, j;
709
710 if (!(*xFit = (double *)malloc(sizeof(**xFit) * n)) ||
711 !(*yFit = (double *)malloc(sizeof(**yFit) * n)) ||
712 (sy && !(*syFit = (double *)malloc(sizeof(**syFit) * n))))
713 return 0;
714
715 for (i = j = 0; i < n; i++) {
716 if (x[i] < lower || x[i] > upper)
717 continue;
718 (*xFit)[j] = x[i];
719 (*yFit)[j] = y[i];
720 if (sy)
721 (*syFit)[j] = sy[i];
722 j++;
723 }
724 return j;
725}
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
char * cp_str(char **s, char *t)
Copies a string, allocating memory for storage.
Definition cp_str.c:28
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