112 {
113 double tolerance, result;
114 int32_t nEvalMax = 5000, nPassMax = 25;
115 double a[5], da[5];
116 double alo[5], ahi[5];
117 long n_dimen = 4;
118 int64_t zeroes;
120 SCANNED_ARG *s_arg;
121 long i_arg, fullOutput;
122 int64_t i;
123 char *input, *output, *xName, *yName;
124 int32_t xIndex, yIndex, fitIndex, residualIndex;
125 long retval;
126 double *fitData, *residualData, rmsResidual;
127 unsigned long guessFlags, dummyFlags, pipeFlags;
128 double constantGuess, factorGuess, freqGuess, phaseGuess, slopeGuess;
129 double firstZero, lastZero;
130 unsigned long simplexFlags = 0, majorOrderFlag;
131 short columnMajorOrder = -1;
132 short lockFreq = 0;
133 short addSlope = 0;
134
136 argc =
scanargs(&s_arg, argc, argv);
137 if (argc < 2 || argc > (2 + N_OPTIONS))
139
140 input = output = NULL;
141 tolerance = 1e-6;
142 verbosity = fullOutput = 0;
143 xName = yName = NULL;
144 guessFlags = 0;
145 pipeFlags = 0;
146
147 for (i_arg = 1; i_arg < argc; i_arg++) {
148 if (s_arg[i_arg].arg_type == OPTION) {
149 switch (
match_string(s_arg[i_arg].list[0], option, N_OPTIONS, 0)) {
150 case SET_MAJOR_ORDER:
151 majorOrderFlag = 0;
152 s_arg[i_arg].n_items--;
153 if (s_arg[i_arg].n_items > 0 &&
154 (!
scanItemList(&majorOrderFlag, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
155 "row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
156 "column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL)))
157 SDDS_Bomb(
"invalid -majorOrder syntax/values");
158 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
159 columnMajorOrder = 1;
160 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
161 columnMajorOrder = 0;
162 break;
163 case SET_TOLERANCE:
164 if (s_arg[i_arg].n_items != 2 || sscanf(s_arg[i_arg].list[1], "%lf", &tolerance) != 1)
165 SDDS_Bomb(
"incorrect -tolerance syntax");
166 break;
167 case SET_VERBOSITY:
168 if (s_arg[i_arg].n_items != 2 || sscanf(s_arg[i_arg].list[1], "%ld", &verbosity) != 1)
169 SDDS_Bomb(
"incorrect -verbosity syntax");
170 break;
171 case SET_GUESS:
172 if (s_arg[i_arg].n_items < 2)
174 s_arg[i_arg].n_items -= 1;
175 if (!
scanItemList(&guessFlags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
176 "constant",
SDDS_DOUBLE, &constantGuess, 1, GUESS_CONSTANT_GIVEN,
177 "factor",
SDDS_DOUBLE, &factorGuess, 1, GUESS_FACTOR_GIVEN,
178 "frequency",
SDDS_DOUBLE, &freqGuess, 1, GUESS_FREQ_GIVEN,
179 "phase",
SDDS_DOUBLE, &phaseGuess, 1, GUESS_PHASE_GIVEN,
180 "slope",
SDDS_DOUBLE, &slopeGuess, 1, GUESS_SLOPE_GIVEN, NULL))
182 break;
183 case SET_COLUMNS:
184 if (s_arg[i_arg].n_items != 3)
186 xName = s_arg[i_arg].list[1];
187 yName = s_arg[i_arg].list[2];
188 break;
189 case SET_FULLOUTPUT:
190 fullOutput = 1;
191 break;
192 case SET_LOCK_FREQ:
193 lockFreq = 1;
194 break;
195 case SET_ADD_SLOPE:
196 addSlope = 1;
197 n_dimen = 5;
198 break;
199 case SET_LIMITS:
200 if (s_arg[i_arg].n_items < 2)
202 s_arg[i_arg].n_items -= 1;
203 if (!
scanItemList(&dummyFlags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
204 "evaluations",
SDDS_LONG, &nEvalMax, 1, 0,
205 "passes",
SDDS_LONG, &nPassMax, 1, 0, NULL) ||
206 nEvalMax <= 0 || nPassMax <= 0)
208 break;
209 case SET_PIPE:
210 if (!
processPipeOption(s_arg[i_arg].list + 1, s_arg[i_arg].n_items - 1, &pipeFlags))
212 break;
213 default:
214 fprintf(stderr, "Error: Unknown or ambiguous option: %s\n", s_arg[i_arg].list[0]);
215 exit(EXIT_FAILURE);
216 break;
217 }
218 } else {
219 if (input == NULL)
220 input = s_arg[i_arg].list[0];
221 else if (output == NULL)
222 output = s_arg[i_arg].list[0];
223 else
224 SDDS_Bomb(
"Too many filenames provided.");
225 }
226 }
227
229
230 if (!xName || !yName)
231 SDDS_Bomb(
"-columns option must be specified.");
232
237
238 setupOutputFile(&OutputTable, &xIndex, &yIndex, &fitIndex, &residualIndex, output, fullOutput,
239 &InputTable, xName, yName, columnMajorOrder, addSlope);
240
241 fitData = residualData = NULL;
242
243 alo[0] = -(ahi[0] = DBL_MAX);
244 alo[1] = alo[2] = 0;
245 ahi[1] = ahi[2] = DBL_MAX;
246 alo[3] = -(ahi[3] = PIx2);
247 if (addSlope) {
248 alo[4] = -(ahi[4] = DBL_MAX);
249 }
250 firstZero = lastZero = 0;
256 continue;
257
260 zeroes = 0;
261 for (i = 1; i < nData; i++)
262 if (yData[i] * yData[i - 1] <= 0) {
263 i++;
264 if (!zeroes)
265 firstZero = (xData[i] + xData[i - 1]) / 2;
266 else
267 lastZero = (xData[i] + xData[i - 1]) / 2;
268 zeroes++;
269 }
270 a[0] = (yMin + yMax) / 2;
271 a[1] = (yMax - yMin) / 2;
272 if (!zeroes)
273 a[2] = 2 / fabs(xMax - xMin);
274 else
275 a[2] = zeroes / (2 * fabs(lastZero - firstZero));
276 a[3] = 0;
277 if (addSlope) {
278 a[4] = 0;
279 }
280 if (guessFlags & GUESS_CONSTANT_GIVEN)
281 a[0] = constantGuess;
282 if (guessFlags & GUESS_FACTOR_GIVEN)
283 a[1] = factorGuess;
284 if (guessFlags & GUESS_FREQ_GIVEN)
285 a[2] = freqGuess;
286 if (guessFlags & GUESS_PHASE_GIVEN)
287 a[3] = phaseGuess;
288 if (guessFlags & GUESS_SLOPE_GIVEN)
289 a[4] = slopeGuess;
290
291 alo[1] = a[1] / 2;
292 if (!(da[0] = a[0] * 0.1))
293 da[0] = 0.01;
294 if (!(da[1] = a[1] * 0.1))
295 da[1] = 0.01;
296 da[2] = a[2] * 0.25;
297 da[3] = 0.01;
298 if (addSlope) {
299 da[4] = 0.01;
300 }
301
302 if (lockFreq) {
303 alo[2] = ahi[2] = a[2];
304 da[2] = 0;
305 }
306
307 if (addSlope) {
308 simplexMin(&result, a, da, alo, ahi, NULL, n_dimen, -DBL_MAX, tolerance, fitFunctionWithSlope,
309 (verbosity > 0 ? report : NULL), nEvalMax, nPassMax, 12, 3, 1.0, simplexFlags);
310 } else {
311 simplexMin(&result, a, da, alo, ahi, NULL, n_dimen, -DBL_MAX, tolerance, fitFunction,
312 (verbosity > 0 ? report : NULL), nEvalMax, nPassMax, 12, 3, 1.0, simplexFlags);
313 }
314 fitData =
trealloc(fitData,
sizeof(*fitData) * nData);
315 residualData =
trealloc(residualData,
sizeof(*residualData) * nData);
316 if (addSlope) {
317 for (i = result = 0; i < nData; i++) {
318 fitData[i] = a[0] + a[1] * sin(PIx2 * a[2] * xData[i] + a[3]) + a[4] * xData[i];
319 residualData[i] = yData[i] - fitData[i];
320 result += sqr(residualData[i]);
321 }
322 } else {
323 for (i = result = 0; i < nData; i++) {
324 fitData[i] = a[0] + a[1] * sin(PIx2 * a[2] * xData[i] + a[3]);
325 residualData[i] = yData[i] - fitData[i];
326 result += sqr(residualData[i]);
327 }
328 }
329 rmsResidual = sqrt(result / nData);
330 if (verbosity > 1) {
331 fprintf(stderr, "RMS deviation: %.15e\n", rmsResidual);
332 fprintf(stderr, "(RMS deviation)/(largest value): %.15e\n", rmsResidual / MAX(fabs(yMin), fabs(yMax)));
333 }
334 if (verbosity > 0) {
335 if (addSlope) {
336 fprintf(stderr, "Coefficients of fit to the form y = a0 + a1*sin(2*PI*a2*x + a3) + a4*x, a = \n");
337 for (i = 0; i < 5; i++)
338 fprintf(stderr, "%.8e ", a[i]);
339 } else {
340 fprintf(stderr, "Coefficients of fit to the form y = a0 + a1*sin(2*PI*a2*x + a3), a = \n");
341 for (i = 0; i < 4; i++)
342 fprintf(stderr, "%.8e ", a[i]);
343 }
344 fprintf(stderr, "\n");
345 }
346
348 !
SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, xData, nData, xIndex) ||
349 !
SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, fitData, nData, fitIndex) ||
351 "sinefitConstant", a[0],
352 "sinefitFactor", a[1],
353 "sinefitFrequency", a[2],
354 "sinefitPhase", a[3],
355 "sinefitRmsResidual", rmsResidual,
356 NULL) ||
357 (addSlope &&
359 "sinefitSlope", a[4], NULL))) ||
360 (fullOutput && (!
SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, yData, nData, yIndex) ||
361 !
SDDS_SetColumn(&OutputTable, SDDS_SET_BY_INDEX, residualData, nData, residualIndex))) ||
364 }
365
368 return EXIT_FAILURE;
369 }
372 return EXIT_FAILURE;
373 }
374
375 return EXIT_SUCCESS;
376}
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.