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