183 {
184 double tolerance, result;
185 int32_t nEvalMax = 5000, nPassMax = 25;
186 double a[6], da[6];
187 double alo[6], ahi[6];
188 int64_t zeroes;
190 SCANNED_ARG *s_arg;
191 long i_arg, fullOutput;
192 int64_t i;
193 char *input, *output, *xName, *yName;
194 int32_t xIndex, yIndex, fitIndex, residualIndex;
195 long retval;
196 unsigned long guessFlags, dummyFlags, pipeFlags;
197 double constantGuess, factorGuess, freqGuess, phaseGuess, slopeGuess, rateGuess;
198 double firstZero, lastZero;
199 unsigned long simplexFlags = 0, majorOrderFlag;
200 short columnMajorOrder = -1;
201 short lockFreq = 0;
202
204 argc =
scanargs(&s_arg, argc, argv);
205 if (argc < 2 || argc > (2 + N_OPTIONS))
207
208 input = output = NULL;
209 tolerance = 1e-6;
210 verbosity = fullOutput = 0;
211 xName = yName = NULL;
212 guessFlags = 0;
213 pipeFlags = 0;
214 constantGuess = factorGuess = freqGuess = phaseGuess = slopeGuess = rateGuess = 0;
215
216 for (i_arg = 1; i_arg < argc; i_arg++) {
217 if (s_arg[i_arg].arg_type == OPTION) {
218 switch (
match_string(s_arg[i_arg].list[0], option, N_OPTIONS, 0)) {
219 case SET_MAJOR_ORDER:
220 majorOrderFlag = 0;
221 s_arg[i_arg].n_items--;
222 if (s_arg[i_arg].n_items > 0 &&
223 (!
scanItemList(&majorOrderFlag, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
224 "row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
225 "column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL)))
226 SDDS_Bomb(
"invalid -majorOrder syntax/values");
227 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
228 columnMajorOrder = 1;
229 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
230 columnMajorOrder = 0;
231 break;
232 case SET_TOLERANCE:
233 if (s_arg[i_arg].n_items != 2 || sscanf(s_arg[i_arg].list[1], "%lf", &tolerance) != 1)
234 SDDS_Bomb(
"incorrect -tolerance syntax");
235 break;
236 case SET_VERBOSITY:
237 if (s_arg[i_arg].n_items != 2 || sscanf(s_arg[i_arg].list[1], "%ld", &verbosity) != 1)
238 SDDS_Bomb(
"incorrect -verbosity syntax");
239 break;
240 case SET_GUESS:
241 if (s_arg[i_arg].n_items < 2)
243 s_arg[i_arg].n_items -= 1;
244 if (!
scanItemList(&guessFlags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
245 "constant",
SDDS_DOUBLE, &constantGuess, 1, GUESS_CONSTANT_GIVEN,
246 "factor",
SDDS_DOUBLE, &factorGuess, 1, GUESS_FACTOR_GIVEN,
247 "frequency",
SDDS_DOUBLE, &freqGuess, 1, GUESS_FREQ_GIVEN,
248 "phase",
SDDS_DOUBLE, &phaseGuess, 1, GUESS_PHASE_GIVEN,
249 "slope",
SDDS_DOUBLE, &slopeGuess, 1, GUESS_SLOPE_GIVEN,
250 "rate",
SDDS_DOUBLE, &rateGuess, 1, GUESS_RATE_GIVEN, NULL,
251 NULL))
253 break;
254 case SET_COLUMNS:
255 if (s_arg[i_arg].n_items != 3)
257 xName = s_arg[i_arg].list[1];
258 yName = s_arg[i_arg].list[2];
259 break;
260 case SET_FULLOUTPUT:
261 fullOutput = 1;
262 break;
263 case SET_LOCK_FREQ:
264 lockFreq = 1;
265 break;
266 case SET_ADD_SLOPE:
267 addSlope = 1;
268 break;
269 case SET_ADD_EXPONENTIAL:
270 if (s_arg[i_arg].n_items!=2)
271 SDDS_Bomb(
"incorrect -addExponential syntax");
272 switch (
match_string(s_arg[i_arg].list[1], expotentialOptions, EXPONENTIAL_OPTIONS, 0)) {
273 case EXPONENTIAL_DECAY:
274 addExponential = -1;
275 break;
276 case EXPONENTIAL_GROW:
277 addExponential = 1;
278 break;
279 default:
280 SDDS_Bomb(
"incorrect -addExponential syntax");
281 break;
282 }
283 break;
284 case SET_LIMITS:
285 if (s_arg[i_arg].n_items < 2)
287 s_arg[i_arg].n_items -= 1;
288 if (!
scanItemList(&dummyFlags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
289 "evaluations",
SDDS_LONG, &nEvalMax, 1, 0,
290 "passes",
SDDS_LONG, &nPassMax, 1, 0, NULL) ||
291 nEvalMax <= 0 || nPassMax <= 0)
293 break;
294 case SET_PIPE:
295 if (!
processPipeOption(s_arg[i_arg].list + 1, s_arg[i_arg].n_items - 1, &pipeFlags))
297 break;
298 default:
299 fprintf(stderr, "Error: Unknown or ambiguous option: %s\n", s_arg[i_arg].list[0]);
300 exit(EXIT_FAILURE);
301 break;
302 }
303 } else {
304 if (input == NULL)
305 input = s_arg[i_arg].list[0];
306 else if (output == NULL)
307 output = s_arg[i_arg].list[0];
308 else
309 SDDS_Bomb(
"Too many filenames provided.");
310 }
311 }
312
313 if (addSlope)
314 disable[4] = 0;
315 if (addExponential)
316 disable[5] = 0;
317
318 if ((guessFlags & GUESS_SLOPE_GIVEN) && !addSlope)
319 SDDS_Bomb(
"-guess=slope given but -addSlope not given");
320
321 if ((guessFlags & GUESS_RATE_GIVEN) && !addExponential)
322 SDDS_Bomb(
"-guess=rate given but -addExponential not given");
323
325
326 if (!xName || !yName)
327 SDDS_Bomb(
"-columns option must be specified.");
328
333
334 setupOutputFile(&OutputTable, &xIndex, &yIndex, &fitIndex, &residualIndex, output, fullOutput,
335 &InputTable, xName, yName, columnMajorOrder, addSlope, addExponential);
336
337 fitData = residualData = NULL;
338
339 alo[0] = -(ahi[0] = DBL_MAX);
340 alo[1] = alo[2] = 0;
341 ahi[1] = ahi[2] = DBL_MAX;
342 alo[3] = -(ahi[3] = PIx2);
343 if (addSlope)
344 alo[4] = -(ahi[4] = DBL_MAX);
345 if (addExponential)
346 alo[5] = -(ahi[5] = DBL_MAX);
347
348 firstZero = lastZero = 0;
349 if (verbosity>5) {
350 simplexFlags = SIMPLEX_VERBOSE_LEVEL1;
351 }
357 continue;
358
359 fitData =
SDDS_Realloc(fitData,
sizeof(*fitData) * nData);
360 residualData =
SDDS_Realloc(residualData,
sizeof(*residualData) * nData);
361
364 zeroes = 0;
365 for (i = 1; i < nData; i++)
366 if (yData[i] * yData[i - 1] <= 0) {
367 i++;
368 if (!zeroes)
369 firstZero = (xData[i] + xData[i - 1]) / 2;
370 else
371 lastZero = (xData[i] + xData[i - 1]) / 2;
372 zeroes++;
373 if (zeroes>5)
374 break;
375 }
376 a[0] = (yMin + yMax) / 2;
377 a[1] = (yMax - yMin) / 2;
378 if (!zeroes)
379 a[2] = 2 / fabs(xMax - xMin);
380 else
381 a[2] = zeroes / (2 * fabs(lastZero - firstZero));
382 a[3] = 0;
383 a[4] = 0;
384 a[5] = 0;
385 if (guessFlags & GUESS_CONSTANT_GIVEN)
386 a[0] = constantGuess;
387 if (guessFlags & GUESS_FACTOR_GIVEN)
388 a[1] = factorGuess;
389 if (guessFlags & GUESS_FREQ_GIVEN)
390 a[2] = freqGuess;
391 if (guessFlags & GUESS_PHASE_GIVEN)
392 a[3] = phaseGuess;
393 if (guessFlags & GUESS_SLOPE_GIVEN)
394 a[4] = slopeGuess;
395 if (guessFlags & GUESS_RATE_GIVEN)
396 a[5] = rateGuess;
397
398 alo[1] = a[1] / 2;
399 if (!(da[0] = a[0] * 0.1))
400 da[0] = 0.01;
401 if (!(da[1] = a[1] * 0.1))
402 da[1] = 0.01;
403 da[2] = a[2] * 0.25;
404 da[3] = 0.01;
405 if (addSlope)
406 da[4] = 0.01;
407 if (addExponential) {
408 if (a[5])
409 da[5] = a[5]*0.01;
410 else
411 da[5] = 0.001;
412 }
413
414 if (lockFreq) {
415 alo[2] = ahi[2] = a[2];
416 da[2] = 0;
417 disable[2] = 1;
418 }
419
420 simplexMin(&result, a, da, alo, ahi, disable, 6, -DBL_MAX, tolerance, fitFunction,
421 (verbosity > 0 ? report : NULL), nEvalMax, nPassMax, 12, 3, 1.0, simplexFlags);
422
423 for (i = result = 0; i < nData; i++)
424 result += sqr(residualData[i]);
425 rmsResidual = sqrt(result / nData);
426 if (verbosity > 1) {
427 fprintf(stderr, "RMS deviation: %.15e\n", rmsResidual);
428 fprintf(stderr, "(RMS deviation)/(largest value): %.15e\n", rmsResidual / MAX(fabs(yMin), fabs(yMax)));
429 }
430 if (verbosity > 0) {
431 if (addSlope) {
432 fprintf(stderr, "Coefficients of fit to the form y = a0 + a1*sin(2*PI*a2*x + a3) + a4*x, a = \n");
433 for (i = 0; i < 5; i++)
434 fprintf(stderr, "%.8e ", a[i]);
435 } else {
436 fprintf(stderr, "Coefficients of fit to the form y = a0 + a1*sin(2*PI*a2*x + a3), a = \n");
437 for (i = 0; i < 4; i++)
438 fprintf(stderr, "%.8e ", a[i]);
439 }
440 fprintf(stderr, "\n");
441 }
442
444 !
SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, xData, nData, xIndex) ||
445 !
SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, fitData, nData, fitIndex) ||
447 "sinefitConstant", a[0],
448 "sinefitFactor", a[1],
449 "sinefitFrequency", a[2],
450 "sinefitPhase", a[3],
451 "sinefitRmsResidual", rmsResidual,
452 NULL) ||
453 (addSlope &&
455 "sinefitSlope", a[4], NULL))) ||
456 (addExponential &&
458 "sinefitRate", a[5], NULL))) ||
459 (fullOutput && (!
SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, yData, nData, yIndex) ||
460 !
SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, residualData, nData, residualIndex))) ||
463 }
464
467 return EXIT_FAILURE;
468 }
471 return EXIT_FAILURE;
472 }
473
474 return EXIT_SUCCESS;
475}
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.
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.
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
void * SDDS_Realloc(void *old_ptr, size_t new_size)
Reallocates memory to a new size.
#define SDDS_LONG
Identifier for the signed 32-bit integer data type.
#define SDDS_DOUBLE
Identifier for the double data type.
void bomb(char *error, char *usage)
Reports error messages to the terminal and aborts the program.
int find_min_max(double *min, double *max, double *list, int64_t n)
Finds the minimum and maximum values in a list of doubles.
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)
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.
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.