161 {
162 double tolerance, result;
163 int32_t nEvalMax = 5000, nPassMax = 25;
164 double a[5], da[5];
165 double alo[5], ahi[5];
166 long n_dimen = 4;
167 int64_t zeroes;
169 SCANNED_ARG *s_arg;
170 long i_arg, fullOutput;
171 int64_t i;
172 char *input, *output, *xName, *yName;
173 int32_t xIndex, yIndex, fitIndex, residualIndex;
174 long retval;
175 double *fitData, *residualData, rmsResidual;
176 unsigned long guessFlags, dummyFlags, pipeFlags;
177 double constantGuess, factorGuess, freqGuess, phaseGuess, slopeGuess;
178 double firstZero, lastZero;
179 unsigned long simplexFlags = 0, majorOrderFlag;
180 short columnMajorOrder = -1;
181 short lockFreq = 0;
182 short addSlope = 0;
183
185 argc =
scanargs(&s_arg, argc, argv);
186 if (argc < 2 || argc > (2 + N_OPTIONS))
188
189 input = output = NULL;
190 tolerance = 1e-6;
191 verbosity = fullOutput = 0;
192 xName = yName = NULL;
193 guessFlags = 0;
194 pipeFlags = 0;
195
196 for (i_arg = 1; i_arg < argc; i_arg++) {
197 if (s_arg[i_arg].arg_type == OPTION) {
198 switch (
match_string(s_arg[i_arg].list[0], option, N_OPTIONS, 0)) {
199 case SET_MAJOR_ORDER:
200 majorOrderFlag = 0;
201 s_arg[i_arg].n_items--;
202 if (s_arg[i_arg].n_items > 0 &&
203 (!
scanItemList(&majorOrderFlag, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
204 "row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
205 "column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL)))
206 SDDS_Bomb(
"invalid -majorOrder syntax/values");
207 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
208 columnMajorOrder = 1;
209 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
210 columnMajorOrder = 0;
211 break;
212 case SET_TOLERANCE:
213 if (s_arg[i_arg].n_items != 2 || sscanf(s_arg[i_arg].list[1], "%lf", &tolerance) != 1)
214 SDDS_Bomb(
"incorrect -tolerance syntax");
215 break;
216 case SET_VERBOSITY:
217 if (s_arg[i_arg].n_items != 2 || sscanf(s_arg[i_arg].list[1], "%ld", &verbosity) != 1)
218 SDDS_Bomb(
"incorrect -verbosity syntax");
219 break;
220 case SET_GUESS:
221 if (s_arg[i_arg].n_items < 2)
223 s_arg[i_arg].n_items -= 1;
224 if (!
scanItemList(&guessFlags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
225 "constant",
SDDS_DOUBLE, &constantGuess, 1, GUESS_CONSTANT_GIVEN,
226 "factor",
SDDS_DOUBLE, &factorGuess, 1, GUESS_FACTOR_GIVEN,
227 "frequency",
SDDS_DOUBLE, &freqGuess, 1, GUESS_FREQ_GIVEN,
228 "phase",
SDDS_DOUBLE, &phaseGuess, 1, GUESS_PHASE_GIVEN,
229 "slope",
SDDS_DOUBLE, &slopeGuess, 1, GUESS_SLOPE_GIVEN, NULL))
231 break;
232 case SET_COLUMNS:
233 if (s_arg[i_arg].n_items != 3)
235 xName = s_arg[i_arg].list[1];
236 yName = s_arg[i_arg].list[2];
237 break;
238 case SET_FULLOUTPUT:
239 fullOutput = 1;
240 break;
241 case SET_LOCK_FREQ:
242 lockFreq = 1;
243 break;
244 case SET_ADD_SLOPE:
245 addSlope = 1;
246 n_dimen = 5;
247 break;
248 case SET_LIMITS:
249 if (s_arg[i_arg].n_items < 2)
251 s_arg[i_arg].n_items -= 1;
252 if (!
scanItemList(&dummyFlags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
253 "evaluations",
SDDS_LONG, &nEvalMax, 1, 0,
254 "passes",
SDDS_LONG, &nPassMax, 1, 0, NULL) ||
255 nEvalMax <= 0 || nPassMax <= 0)
257 break;
258 case SET_PIPE:
259 if (!
processPipeOption(s_arg[i_arg].list + 1, s_arg[i_arg].n_items - 1, &pipeFlags))
261 break;
262 default:
263 fprintf(stderr, "Error: Unknown or 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 provided.");
274 }
275 }
276
278
279 if (!xName || !yName)
280 SDDS_Bomb(
"-columns option must be specified.");
281
286
287 setupOutputFile(&OutputTable, &xIndex, &yIndex, &fitIndex, &residualIndex, output, fullOutput,
288 &InputTable, xName, yName, columnMajorOrder, addSlope);
289
290 fitData = residualData = NULL;
291
292 alo[0] = -(ahi[0] = DBL_MAX);
293 alo[1] = alo[2] = 0;
294 ahi[1] = ahi[2] = DBL_MAX;
295 alo[3] = -(ahi[3] = PIx2);
296 if (addSlope) {
297 alo[4] = -(ahi[4] = DBL_MAX);
298 }
299 firstZero = lastZero = 0;
305 continue;
306
309 zeroes = 0;
310 for (i = 1; i < nData; i++)
311 if (yData[i] * yData[i - 1] <= 0) {
312 i++;
313 if (!zeroes)
314 firstZero = (xData[i] + xData[i - 1]) / 2;
315 else
316 lastZero = (xData[i] + xData[i - 1]) / 2;
317 zeroes++;
318 }
319 a[0] = (yMin + yMax) / 2;
320 a[1] = (yMax - yMin) / 2;
321 if (!zeroes)
322 a[2] = 2 / fabs(xMax - xMin);
323 else
324 a[2] = zeroes / (2 * fabs(lastZero - firstZero));
325 a[3] = 0;
326 if (addSlope) {
327 a[4] = 0;
328 }
329 if (guessFlags & GUESS_CONSTANT_GIVEN)
330 a[0] = constantGuess;
331 if (guessFlags & GUESS_FACTOR_GIVEN)
332 a[1] = factorGuess;
333 if (guessFlags & GUESS_FREQ_GIVEN)
334 a[2] = freqGuess;
335 if (guessFlags & GUESS_PHASE_GIVEN)
336 a[3] = phaseGuess;
337 if (guessFlags & GUESS_SLOPE_GIVEN)
338 a[4] = slopeGuess;
339
340 alo[1] = a[1] / 2;
341 if (!(da[0] = a[0] * 0.1))
342 da[0] = 0.01;
343 if (!(da[1] = a[1] * 0.1))
344 da[1] = 0.01;
345 da[2] = a[2] * 0.25;
346 da[3] = 0.01;
347 if (addSlope) {
348 da[4] = 0.01;
349 }
350
351 if (lockFreq) {
352 alo[2] = ahi[2] = a[2];
353 da[2] = 0;
354 }
355
356 if (addSlope) {
357 simplexMin(&result, a, da, alo, ahi, NULL, n_dimen, -DBL_MAX, tolerance, fitFunctionWithSlope,
358 (verbosity > 0 ? report : NULL), nEvalMax, nPassMax, 12, 3, 1.0, simplexFlags);
359 } else {
360 simplexMin(&result, a, da, alo, ahi, NULL, n_dimen, -DBL_MAX, tolerance, fitFunction,
361 (verbosity > 0 ? report : NULL), nEvalMax, nPassMax, 12, 3, 1.0, simplexFlags);
362 }
363 fitData =
trealloc(fitData,
sizeof(*fitData) * nData);
364 residualData =
trealloc(residualData,
sizeof(*residualData) * nData);
365 if (addSlope) {
366 for (i = result = 0; i < nData; i++) {
367 fitData[i] = a[0] + a[1] * sin(PIx2 * a[2] * xData[i] + a[3]) + a[4] * xData[i];
368 residualData[i] = yData[i] - fitData[i];
369 result += sqr(residualData[i]);
370 }
371 } else {
372 for (i = result = 0; i < nData; i++) {
373 fitData[i] = a[0] + a[1] * sin(PIx2 * a[2] * xData[i] + a[3]);
374 residualData[i] = yData[i] - fitData[i];
375 result += sqr(residualData[i]);
376 }
377 }
378 rmsResidual = sqrt(result / nData);
379 if (verbosity > 1) {
380 fprintf(stderr, "RMS deviation: %.15e\n", rmsResidual);
381 fprintf(stderr, "(RMS deviation)/(largest value): %.15e\n", rmsResidual / MAX(fabs(yMin), fabs(yMax)));
382 }
383 if (verbosity > 0) {
384 if (addSlope) {
385 fprintf(stderr, "Coefficients of fit to the form y = a0 + a1*sin(2*PI*a2*x + a3) + a4*x, a = \n");
386 for (i = 0; i < 5; i++)
387 fprintf(stderr, "%.8e ", a[i]);
388 } else {
389 fprintf(stderr, "Coefficients of fit to the form y = a0 + a1*sin(2*PI*a2*x + a3), a = \n");
390 for (i = 0; i < 4; i++)
391 fprintf(stderr, "%.8e ", a[i]);
392 }
393 fprintf(stderr, "\n");
394 }
395
397 !
SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, xData, nData, xIndex) ||
398 !
SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, fitData, nData, fitIndex) ||
400 "sinefitConstant", a[0],
401 "sinefitFactor", a[1],
402 "sinefitFrequency", a[2],
403 "sinefitPhase", a[3],
404 "sinefitRmsResidual", rmsResidual,
405 NULL) ||
406 (addSlope &&
408 "sinefitSlope", a[4], NULL))) ||
409 (fullOutput && (!
SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, yData, nData, yIndex) ||
410 !
SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, residualData, nData, residualIndex))) ||
413 }
414
417 return EXIT_FAILURE;
418 }
421 return EXIT_FAILURE;
422 }
423
424 return EXIT_SUCCESS;
425}
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.
#define SDDS_LONG
Identifier for the signed 32-bit integer data type.
#define SDDS_DOUBLE
Identifier for the double data type.
void * trealloc(void *old_ptr, uint64_t size_of_block)
Reallocates a memory block to a new size.
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.