SDDS ToolKit Programs and Libraries for C and Python
All Classes Files Functions Variables Macros Pages
sddsexpfit.c
Go to the documentation of this file.
1/**
2 * @file sddsexpfit.c
3 * @brief Performs exponential fitting for input data using the SDDS library.
4 *
5 * @details
6 * This program fits data to an exponential function of the form:
7 * ```
8 * y = a0 + a1 * exp(a2 * x)
9 * ```
10 * It reads input data, applies the fitting model, and writes the results to an output file. The program
11 * supports flexible configuration of input/output formats, fitting parameters, and other operational settings.
12 *
13 * @section Usage
14 * ```
15 * sddsexpfit [<inputfile>] [<outputfile>]
16 * [-pipe=[input][,output]]
17 * [-fulloutput]
18 * -columns=<x-name>,<y-name>[,ySigma=<name>]
19 * [-tolerance=<value>]
20 * [-verbosity=<integer>]
21 * [-clue={grows|decays}]
22 * [-guess=<constant>,<factor>,<rate>]
23 * [-startValues=[constant=<value>][,factor=<value>][,rate=<value>]]
24 * [-fixValue=[constant=<value>][,factor=<value>][,rate=<value>]]
25 * [-autoOffset]
26 * [-limits=[evaluations=<number>][,passes=<number>]]
27 * [-majorOrder=row|column]
28 * ```
29 *
30 * @section Options
31 * | Required | Description |
32 * |--------------------|----------------------------------------------------------------------------|
33 * | `-columns` | Specify column names for x, y, and optional ySigma. |
34 *
35 * | Optional | Description |
36 * |-------------------------------|----------------------------------------------------------|
37 * | `-pipe` | Use input/output pipes instead of files. |
38 * | `-fulloutput` | Include detailed results in the output. |
39 * | `-tolerance` | Set convergence tolerance for the fitting algorithm. |
40 * | `-verbosity` | Define verbosity level for logging. |
41 * | `-clue` | Provide a hint for exponential behavior. |
42 * | `-guess` | Initial guesses for parameters `a0`, `a1`, `a2`. |
43 * | `-startValues` | Set specific starting values for fit parameters. |
44 * | `-fixValue` | Fix certain fit parameters during optimization. |
45 * | `-autoOffset` | Automatically adjust offset for input data. |
46 * | `-limits` | Set algorithm limits (e.g., evaluations, passes). |
47 * | `-majorOrder` | Specify data processing order (row or column). |
48 *
49 * @subsection Incompatibilities
50 * - `-guess` is incompatible with:
51 * - `-startValues`
52 * - `-fixValue` and `-startValues` cannot be applied to the same parameter simultaneously.
53 *
54 * @copyright
55 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
56 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
57 *
58 * @license
59 * This file is distributed under the terms of the Software License Agreement
60 * found in the file LICENSE included with this distribution.
61 *
62 * @author
63 * M. Borland, C. Saunders, L. Emery, R. Soliday, H. Shang, N. Kuklev
64 */
65
66#include "mdb.h"
67#include "SDDS.h"
68#include "scan.h"
69
70/* Enumeration for option types */
71enum option_type {
72 SET_TOLERANCE,
73 SET_VERBOSITY,
74 SET_CLUE,
75 SET_GUESS,
76 SET_COLUMNS,
77 SET_FULLOUTPUT,
78 SET_PIPE,
79 SET_LIMITS,
80 SET_STARTVALUES,
81 SET_FIXVALUE,
82 SET_AUTOOFFSET,
83 SET_MAJOR_ORDER,
84 N_OPTIONS
85};
86
87char *option[N_OPTIONS] = {
88 "tolerance",
89 "verbosity",
90 "clue",
91 "guess",
92 "columns",
93 "fulloutput",
94 "pipe",
95 "limits",
96 "startvalues",
97 "fixvalue",
98 "autooffset",
99 "majorOrder",
100};
101
102static char *USAGE =
103 "sddsexpfit [<inputfile>] [<outputfile>]\n"
104 " [-pipe=[input][,output]]\n"
105 " [-fulloutput]\n"
106 " -columns=<x-name>,<y-name>[,ySigma=<name>]\n"
107 " [-tolerance=<value>]\n"
108 " [-verbosity=<integer>]\n"
109 " [-clue={grows|decays}]\n"
110 " [-guess=<constant>,<factor>,<rate>]\n"
111 " [-startValues=[constant=<value>][,factor=<value>][,rate=<value>]]\n"
112 " [-fixValue=[constant=<value>][,factor=<value>][,rate=<value>]]\n"
113 " [-autoOffset]\n"
114 " [-limits=[evaluations=<number>][,passes=<number>]]\n"
115 " [-majorOrder=row|column]\n\n"
116 "Performs an exponential fit of the form y = <constant> + <factor> * exp(<rate> * x).\n\n"
117 "Program by Michael Borland. (" __DATE__ " " __TIME__ ", SVN revision: " SVN_VERSION ")\n";
118
119static double *xData, *yData, *syData;
120static int64_t nData;
121static double yMin, yMax, xMin, xMax;
122static double fit[3];
123
124double fitFunction(double *a, long *invalid);
125void report(double res, double *a, long pass, long n_eval, long n_dimen);
126void setupOutputFile(SDDS_DATASET *OutputTable, long *xIndex, long *yIndex, long *fitIndex, long *residualIndex, char *output, long fullOutput, SDDS_DATASET *InputTable, char *xName, char *yName, short columnMajorOrder);
127char *makeInverseUnits(char *units);
128
129#define START_CONSTANT_GIVEN 0x0001
130#define FIX_CONSTANT_GIVEN (0x0001 << 3)
131#define START_FACTOR_GIVEN 0x0002
132#define FIX_FACTOR_GIVEN (0x0002 << 3)
133#define START_RATE_GIVEN 0x0004
134#define FIX_RATE_GIVEN (0x0004 << 3)
135
136#define CLUE_GROWS 0
137#define CLUE_DECAYS 1
138#define N_CLUE_TYPES 2
139char *clue_name[N_CLUE_TYPES] = {
140 "grows",
141 "decays"
142};
143
144long verbosity;
145
146int main(int argc, char **argv) {
147 double tolerance, result, chiSqr, sigLevel;
148 int32_t nEvalMax = 5000, nPassMax = 100;
149 double guess[3];
150 double a[3], da[3];
151 double alo[3], ahi[3];
152 long n_dimen = 3, guessGiven, startGiven;
153 SDDS_DATASET InputTable, OutputTable;
154 SCANNED_ARG *s_arg;
155 long i_arg, clue, fullOutput;
156 int64_t i;
157 char *input, *output, *xName, *yName, *syName;
158 long xIndex, yIndex, fitIndex, residualIndex, retval;
159 double *fitData, *residualData, rmsResidual;
160 unsigned long guessFlags, pipeFlags, dummyFlags, majorOrderFlag;
161 double constantStart, factorStart, rateStart;
162 short disable[3] = {0, 0, 0};
163 short autoOffset = 0;
164 short columnMajorOrder = -1;
165
167 argc = scanargs(&s_arg, argc, argv);
168 if (argc < 2 || argc > (2 + N_OPTIONS))
169 bomb(NULL, USAGE);
170
171 input = output = NULL;
172 tolerance = 1e-6;
173 verbosity = fullOutput = guessGiven = startGiven = 0;
174 clue = -1;
175 xName = yName = syName = NULL;
176 pipeFlags = guessFlags = 0;
177 constantStart = factorStart = rateStart = 0;
178
179 for (i_arg = 1; i_arg < argc; i_arg++) {
180 if (s_arg[i_arg].arg_type == OPTION) {
181 switch (match_string(s_arg[i_arg].list[0], option, N_OPTIONS, 0)) {
182 case SET_MAJOR_ORDER:
183 majorOrderFlag = 0;
184 s_arg[i_arg].n_items--;
185 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)))
186 SDDS_Bomb("invalid -majorOrder syntax/values");
187 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
188 columnMajorOrder = 1;
189 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
190 columnMajorOrder = 0;
191 break;
192 case SET_AUTOOFFSET:
193 autoOffset = 1;
194 break;
195 case SET_TOLERANCE:
196 if (s_arg[i_arg].n_items != 2 || sscanf(s_arg[i_arg].list[1], "%lf", &tolerance) != 1)
197 SDDS_Bomb("incorrect -tolerance syntax");
198 break;
199 case SET_VERBOSITY:
200 if (s_arg[i_arg].n_items != 2 || sscanf(s_arg[i_arg].list[1], "%ld", &verbosity) != 1)
201 SDDS_Bomb("incorrect -verbosity syntax");
202 break;
203 case SET_CLUE:
204 if (s_arg[i_arg].n_items != 2 || (clue = match_string(s_arg[i_arg].list[1], clue_name, N_CLUE_TYPES, 0)) < 0)
205 SDDS_Bomb("incorrect -clue syntax");
206 break;
207 case SET_GUESS:
208 if (startGiven)
209 SDDS_Bomb("can't have -startValues and -guess at once");
210 if (s_arg[i_arg].n_items != 4 || sscanf(s_arg[i_arg].list[1], "%lf", guess + 0) != 1 || sscanf(s_arg[i_arg].list[2], "%lf", guess + 1) != 1 || sscanf(s_arg[i_arg].list[3], "%lf", guess + 2) != 1)
211 SDDS_Bomb("invalid -guess syntax");
212 guessGiven = 1;
213 break;
214 case SET_STARTVALUES:
215 if (s_arg[i_arg].n_items < 2)
216 SDDS_Bomb("incorrect -startValues syntax");
217 if (guessGiven)
218 SDDS_Bomb("can't have -startValues and -guess at once");
219 s_arg[i_arg].n_items -= 1;
220 dummyFlags = guessFlags;
221 if (!scanItemList(&guessFlags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0, "constant", SDDS_DOUBLE, &constantStart, 1, START_CONSTANT_GIVEN, "factor", SDDS_DOUBLE, &factorStart, 1, START_FACTOR_GIVEN, "rate", SDDS_DOUBLE, &rateStart, 1, START_RATE_GIVEN, NULL))
222 SDDS_Bomb("invalid -fixValue syntax");
223 if ((dummyFlags >> 3) & (guessFlags))
224 SDDS_Bomb("can't have -fixValue and -startValue for the same item");
225 guessFlags |= dummyFlags;
226 startGiven = 1;
227 break;
228 case SET_FIXVALUE:
229 if (s_arg[i_arg].n_items < 2)
230 SDDS_Bomb("incorrect -fixValue syntax");
231 s_arg[i_arg].n_items -= 1;
232 dummyFlags = guessFlags;
233 if (!scanItemList(&guessFlags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0, "constant", SDDS_DOUBLE, &constantStart, 1, FIX_CONSTANT_GIVEN, "factor", SDDS_DOUBLE, &factorStart, 1, FIX_FACTOR_GIVEN, "rate", SDDS_DOUBLE, &rateStart, 1, FIX_RATE_GIVEN, NULL))
234 SDDS_Bomb("invalid -fixValue syntax");
235 if ((dummyFlags) & (guessFlags >> 3))
236 SDDS_Bomb("can't have -fixValue and -startValue for the same item");
237 guessFlags |= dummyFlags;
238 break;
239 case SET_COLUMNS:
240 if (s_arg[i_arg].n_items != 3 && s_arg[i_arg].n_items != 4)
241 SDDS_Bomb("invalid -columns syntax");
242 xName = s_arg[i_arg].list[1];
243 yName = s_arg[i_arg].list[2];
244 s_arg[i_arg].n_items -= 3;
245 if (!scanItemList(&dummyFlags, s_arg[i_arg].list + 3, &s_arg[i_arg].n_items, 0, "ysigma", SDDS_STRING, &syName, 1, 0, NULL))
246 SDDS_Bomb("invalid -columns syntax");
247 break;
248 case SET_FULLOUTPUT:
249 fullOutput = 1;
250 break;
251 case SET_PIPE:
252 if (!processPipeOption(s_arg[i_arg].list + 1, s_arg[i_arg].n_items - 1, &pipeFlags))
253 SDDS_Bomb("invalid -pipe syntax");
254 break;
255 case SET_LIMITS:
256 if (s_arg[i_arg].n_items < 2)
257 SDDS_Bomb("incorrect -limits syntax");
258 s_arg[i_arg].n_items -= 1;
259 if (!scanItemList(&dummyFlags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0, "evaluations", SDDS_LONG, &nEvalMax, 1, 0, "passes", SDDS_LONG, &nPassMax, 1, 0, NULL) || nEvalMax <= 0 || nPassMax <= 0)
260 SDDS_Bomb("invalid -limits syntax");
261 break;
262 default:
263 fprintf(stderr, "error: unknown/ambiguous option: %s\n", s_arg[i_arg].list[0]);
264 exit(EXIT_FAILURE);
265 break;
266 }
267 } else {
268 if (input == NULL)
269 input = s_arg[i_arg].list[0];
270 else if (output == NULL)
271 output = s_arg[i_arg].list[0];
272 else
273 SDDS_Bomb("too many filenames");
274 }
275 }
276
277 processFilenames("sddsexpfit", &input, &output, pipeFlags, 0, NULL);
278
279 for (i = 0; i < 3; i++) {
280 if ((guessFlags >> 3) & (1 << i)) {
281 disable[i] = 1;
282 }
283 }
284
285 if (!xName || !yName)
286 SDDS_Bomb("-columns option must be given");
287
288 if (!SDDS_InitializeInput(&InputTable, input) || SDDS_GetColumnIndex(&InputTable, xName) < 0 ||
289 SDDS_GetColumnIndex(&InputTable, yName) < 0 || (syName && SDDS_GetColumnIndex(&InputTable, syName) < 0))
290 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
291
292 setupOutputFile(&OutputTable, &xIndex, &yIndex, &fitIndex, &residualIndex, output, fullOutput, &InputTable, xName, yName, columnMajorOrder);
293
294 while ((retval = SDDS_ReadPage(&InputTable)) > 0) {
295 fitData = residualData = NULL;
296 xData = yData = syData = NULL;
297 if (!(xData = SDDS_GetColumnInDoubles(&InputTable, xName)) ||
298 !(yData = SDDS_GetColumnInDoubles(&InputTable, yName)) ||
299 (syName && !(syData = SDDS_GetColumnInDoubles(&InputTable, syName))))
300 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
301 if ((nData = SDDS_CountRowsOfInterest(&InputTable)) < 4)
302 continue;
303
304 if (xData[0] > xData[nData - 1])
305 fputs("warning: data reverse-ordered", stderr);
306
307 find_min_max(&yMin, &yMax, yData, nData);
308 find_min_max(&xMin, &xMax, xData, nData);
309 for (i = 0; i < nData; i++)
310 xData[i] -= xMin;
311
312 fill_double_array(alo, 3, -DBL_MAX / 2);
313 fill_double_array(ahi, 3, DBL_MAX / 2);
314
315 if (!guessGiven) {
316 if (clue == CLUE_GROWS) {
317 a[0] = 0.9 * yData[0];
318 a[1] = yData[nData - 1] - yData[0];
319 a[2] = 1 / (xData[nData - 1] - xData[0]);
320 alo[2] = 0;
321 if (a[1] > 0)
322 alo[1] = 0;
323 else
324 ahi[1] = 0;
325 } else if (clue == CLUE_DECAYS) {
326 a[0] = 0.9 * yData[nData - 1];
327 a[1] = yData[0] - yData[nData - 1];
328 a[2] = 0;
329 ahi[2] = 0;
330 if (a[1] > 0)
331 alo[1] = 0;
332 else
333 ahi[1] = 0;
334 } else {
335 a[0] = yMin * 0.9;
336 a[1] = yMax - yMin;
337 a[2] = 0;
338 }
339 } else {
340 a[0] = guess[0];
341 a[1] = guess[1];
342 a[2] = guess[2];
343 }
344
345 if (guessFlags & (START_CONSTANT_GIVEN + FIX_CONSTANT_GIVEN))
346 a[0] = constantStart;
347 if (guessFlags & (START_FACTOR_GIVEN + FIX_FACTOR_GIVEN))
348 a[1] = factorStart;
349 if (guessFlags & (START_RATE_GIVEN + FIX_RATE_GIVEN))
350 a[2] = rateStart;
351
352 da[0] = da[1] = fabs(a[1] - a[0]) / 20.0;
353 da[2] = 0.1 / (xData[nData - 1] - xData[0]);
354 if (verbosity > 3)
355 fprintf(stderr, "starting guess: %e, %e, %e\n", a[0], a[1], a[2]);
356
357 simplexMin(&result, a, da, alo, ahi, disable, n_dimen, -DBL_MAX, tolerance, fitFunction, (verbosity > 0 ? report : NULL), nEvalMax, nPassMax, 12, 3, 1.0, 0);
358
359 da[0] = a[0] / 10;
360 da[1] = a[1] / 10;
361 da[2] = a[2] / 10;
362 simplexMin(&result, a, da, alo, ahi, disable, n_dimen, -DBL_MAX, tolerance, fitFunction, (verbosity > 0 ? report : NULL), nEvalMax, nPassMax, 12, 3, 1.0, 0);
363
364 if (!autoOffset) {
365 /* user wants the coefficients with the offset removed */
366 a[1] *= exp(-a[2] * xMin);
367 for (i = 0; i < nData; i++)
368 xData[i] += xMin;
369 }
370
371 fitData = trealloc(fitData, sizeof(*fitData) * nData);
372 residualData = trealloc(residualData, sizeof(*residualData) * nData);
373 for (i = result = 0; i < nData; i++) {
374 fitData[i] = a[0] + a[1] * exp(a[2] * xData[i]);
375 residualData[i] = yData[i] - fitData[i];
376 result += sqr(residualData[i]);
377 }
378 rmsResidual = sqrt(result / nData);
379 if (syData) {
380 for (i = chiSqr = 0; i < nData; i++)
381 chiSqr += sqr(residualData[i] / syData[i]);
382 } else {
383 double sy2;
384 sy2 = result / (nData - 3);
385 for (i = chiSqr = 0; i < nData; i++)
386 chiSqr += sqr(residualData[i]) / sy2;
387 }
388 sigLevel = ChiSqrSigLevel(chiSqr, nData - 3);
389 if (verbosity > 1) {
390 fprintf(stderr, "RMS deviation: %.15e\n", rmsResidual);
391 fprintf(stderr, "(RMS deviation)/(largest value): %.15e\n", rmsResidual / MAX(fabs(yMin), fabs(yMax)));
392 if (syData)
393 fprintf(stderr, "Significance level: %.5e\n", sigLevel);
394 }
395 if (verbosity > 0) {
396 fprintf(stderr, "coefficients of fit to the form y = a0 + a1*exp(a2*x), a = \n");
397 for (i = 0; i < 3; i++)
398 fprintf(stderr, "%.8e ", a[i]);
399 fprintf(stderr, "\n");
400 }
401
402 if (!SDDS_StartPage(&OutputTable, nData) ||
403 !SDDS_CopyParameters(&OutputTable, &InputTable) ||
404 !SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, xData, nData, xIndex) ||
405 !SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, fitData, nData, fitIndex) ||
406 !SDDS_SetParameters(&OutputTable, SDDS_PASS_BY_VALUE | SDDS_SET_BY_NAME,
407 "expfitConstant", a[0],
408 "expfitFactor", a[1],
409 "expfitRate", a[2],
410 "expfitRmsResidual", rmsResidual,
411 "expfitSigLevel", sigLevel, NULL) ||
412 (fullOutput && (!SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, yData, nData, yIndex) ||
413 !SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, residualData, nData, residualIndex))) ||
414 !SDDS_WritePage(&OutputTable))
415 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
416 if (xData)
417 free(xData);
418 if (yData)
419 free(yData);
420 if (syData)
421 free(syData);
422 if (fitData)
423 free(fitData);
424 if (residualData)
425 free(residualData);
426 }
427 if (!SDDS_Terminate(&InputTable) || !SDDS_Terminate(&OutputTable)) {
428 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
429 exit(EXIT_FAILURE);
430 }
431 return EXIT_SUCCESS;
432}
433
434void setupOutputFile(SDDS_DATASET *OutputTable, long *xIndex, long *yIndex, long *fitIndex, long *residualIndex, char *output, long fullOutput, SDDS_DATASET *InputTable, char *xName, char *yName, short columnMajorOrder) {
435 char *name, *yUnits, *description, *xUnits, *inverse_xUnits;
436 int32_t typeValue = SDDS_DOUBLE;
437 static char *residualNamePart = "Residual";
438 static char *residualDescriptionPart = "Residual of exponential fit to ";
439
440 if (!SDDS_InitializeOutput(OutputTable, SDDS_BINARY, 0, NULL, "sddsexpfit output", output) ||
441 !SDDS_TransferColumnDefinition(OutputTable, InputTable, xName, NULL) ||
442 !SDDS_ChangeColumnInformation(OutputTable, "type", &typeValue, SDDS_BY_NAME, xName) ||
443 (*xIndex = SDDS_GetColumnIndex(OutputTable, xName)) < 0 ||
444 !SDDS_GetColumnInformation(InputTable, "units", &xUnits, SDDS_BY_NAME, xName) ||
445 !SDDS_GetColumnInformation(InputTable, "units", &yUnits, SDDS_BY_NAME, yName)) {
446 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
447 exit(EXIT_FAILURE);
448 }
449
450 if (columnMajorOrder != -1)
451 OutputTable->layout.data_mode.column_major = columnMajorOrder;
452 else
453 OutputTable->layout.data_mode.column_major = InputTable->layout.data_mode.column_major;
454
455 name = tmalloc(sizeof(*name) * (strlen(yName) + strlen(residualNamePart) + 1));
456 description = tmalloc(sizeof(*name) * (strlen(yName) + strlen(residualDescriptionPart) + 1));
457
458 if (fullOutput) {
459 if (!SDDS_TransferColumnDefinition(OutputTable, InputTable, yName, NULL) ||
460 !SDDS_ChangeColumnInformation(OutputTable, "type", &typeValue, SDDS_BY_NAME, yName) ||
461 (*yIndex = SDDS_GetColumnIndex(OutputTable, yName)) < 0)
462 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
463 sprintf(name, "%s%s", yName, residualNamePart);
464 sprintf(description, "%s%s", yName, residualDescriptionPart);
465 if ((*residualIndex = SDDS_DefineColumn(OutputTable, name, NULL, yUnits, description, NULL, SDDS_DOUBLE, 0)) < 0)
466 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
467 }
468
469 sprintf(name, "%sFit", yName);
470 sprintf(description, "Exponential fit to %s", yName);
471 if ((*fitIndex = SDDS_DefineColumn(OutputTable, name, NULL, yUnits, description, NULL, SDDS_DOUBLE, 0)) < 0)
472 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
473
474 inverse_xUnits = makeInverseUnits(xUnits);
475
476 if (SDDS_DefineParameter(OutputTable, "expfitConstant", NULL, yUnits, "Constant term from exponential fit",
477 NULL, SDDS_DOUBLE, 0) < 0 ||
478 SDDS_DefineParameter(OutputTable, "expfitFactor", NULL, yUnits, "Factor from exponential fit",
479 NULL, SDDS_DOUBLE, 0) < 0 ||
480 SDDS_DefineParameter(OutputTable, "expfitRate", NULL, inverse_xUnits, "Rate from exponential fit",
481 NULL, SDDS_DOUBLE, 0) < 0 ||
482 SDDS_DefineParameter(OutputTable, "expfitRmsResidual", NULL, yUnits, "RMS residual from exponential fit",
483 NULL, SDDS_DOUBLE, 0) < 0 ||
484 SDDS_DefineParameter(OutputTable, "expfitSigLevel", NULL, NULL, "Significance level from chi-squared test", NULL, SDDS_DOUBLE, 0) < 0 ||
485 !SDDS_TransferAllParameterDefinitions(OutputTable, InputTable, SDDS_TRANSFER_KEEPOLD) ||
486 !SDDS_WriteLayout(OutputTable))
487 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
488}
489
490char *makeInverseUnits(char *units) {
491 char *inverseUnits;
492
493 if (!units || SDDS_StringIsBlank(units))
494 return NULL;
495 inverseUnits = tmalloc(sizeof(*inverseUnits) * (strlen(units) + 5));
496
497 if (strncmp(units, "1/(", 3) == 0 && units[strlen(units) - 1] == ')') {
498 /* special case of "1/(<unit>)" */
499 strcpy(inverseUnits, units + 3);
500 inverseUnits[strlen(inverseUnits) - 1] = '\0';
501 } else if (!strchr(units, ' ')) {
502 /* special case of units string without spaces */
503 sprintf(inverseUnits, "1/%s", units);
504 } else {
505 /* general case */
506 sprintf(inverseUnits, "1/(%s)", units);
507 }
508
509 return inverseUnits;
510}
511
512double fitFunction(double *a, long *invalid) {
513 int64_t i;
514 double chi = 0.0, diff;
515 static double min_chi;
516
517 min_chi = DBL_MAX;
518
519 *invalid = 0;
520 for (i = 0; i < nData; i++) {
521 diff = yData[i] - (a[0] + a[1] * exp(a[2] * xData[i]));
522 if (syData)
523 diff /= syData[i];
524 chi += sqr(diff);
525 }
526 if (isnan(chi) || isinf(chi))
527 *invalid = 1;
528 if (verbosity > 3)
529 fprintf(stderr, "trial: a = %e, %e, %e --> chi = %e, invalid = %ld\n", a[0], a[1], a[2], chi, *invalid);
530 if (min_chi > chi) {
531 min_chi = chi;
532 fit[0] = a[0];
533 fit[1] = a[1];
534 fit[2] = a[2];
535 if (verbosity > 2)
536 fprintf(stderr, "new best chi = %e: a = %e, %e, %e\n", chi, fit[0], fit[1], fit[2]);
537 }
538 return chi;
539}
540
541void report(double y, double *x, long pass, long nEval, long n_dimen) {
542 long i;
543
544 fprintf(stderr, "Pass %ld, after %ld evaluations: result = %.16e\na = ", pass, nEval, y);
545 for (i = 0; i < n_dimen; i++)
546 fprintf(stderr, "%.8e ", x[i]);
547 fputc('\n', stderr);
548}
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.
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
int32_t SDDS_StringIsBlank(char *s)
Checks if a string is blank (contains only whitespace characters).
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
void fill_double_array(double *array, long n, double value)
Fills a double array with the specified value.
Definition fill_array.c:27
int find_min_max(double *min, double *max, double *list, int64_t n)
Finds the minimum and maximum values in a list of doubles.
Definition findMinMax.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
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