171 {
172 double *xData = NULL, *yData = NULL, *syData = NULL;
173 int64_t nData = 0;
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)
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)
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)
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, ¢erGuessPar, 1, GUESS_CENTER_GIVEN,
256 "gamma",
SDDS_STRING, &gammaGuessPar, 1, GUESS_GAMMA_GIVEN, NULL))
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", ¢erGuess) != 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)
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, ¢erGuessPar, 1, FIX_CENTER_GIVEN,
311 "gamma",
SDDS_STRING, &gammaGuessPar, 1, FIX_GAMMA_GIVEN, NULL))
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", ¢erGuess) != 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)
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,
366 break;
367 case SET_FULLOUTPUT:
368 fullOutput = 1;
369 break;
370 case SET_LIMITS:
371 if (s_arg[i_arg].n_items < 2)
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)
379 break;
380 case SET_PIPE:
381 if (!
processPipeOption(s_arg[i_arg].list + 1, s_arg[i_arg].n_items - 1, &pipeFlags))
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
397 }
398 }
399
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
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
425 xData = yData = syData = NULL;
426 fitData = residualData = NULL;
444
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 }
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
506 !
SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, xData, nData, xIndex) ||
507 !
SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, fitData, nData, fitIndex) ||
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)))) ||
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 }
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);
547 return EXIT_SUCCESS;
548}
int32_t SDDS_CopyParameters(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source)
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.
int32_t SDDS_WritePage(SDDS_DATASET *SDDS_dataset)
Writes the current data table to the output file.
void SDDS_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
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.
#define SDDS_STRING
Identifier for the string data type.
#define SDDS_LONG
Identifier for the signed 32-bit integer data type.
void * trealloc(void *old_ptr, uint64_t size_of_block)
Reallocates a memory block to a new size.
char * cp_str(char **s, char *t)
Copies a string, allocating memory for storage.
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)
long processPipeOption(char **item, long items, unsigned long *flags)
void processFilenames(char *programName, char **input, char **output, unsigned long pipeFlags, long noWarnings, long *tmpOutputUsed)
void free_scanargs(SCANNED_ARG **scanned, int argc)
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.
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.