NumeRe v1.1.4
NumeRe: Framework für Numerische Rechnungen
fitting.cpp
Go to the documentation of this file.
1/*****************************************************************************
2 NumeRe: Framework fuer Numerische Rechnungen
3 Copyright (C) 2019 Erik Haenel et al.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17******************************************************************************/
18
19#include "parser_functions.hpp"
20#include "../../kernel.hpp"
21#include "fitcontroller.hpp"
22#include "../interval.hpp"
23
24// This structure combines all main fitting
25// parameter and storage objects to simplify
26// the interaction between the main routine and
27// the (file static) helper routines
29{
30 std::vector<double> vx;
31 std::vector<double> vy;
32 std::vector<double> vy_w;
33 std::vector<std::vector<double> > vz;
34 std::vector<std::vector<double> > vz_w;
35
37 bool restricted[3];
38
39 size_t nDim;
40 size_t nFitVars;
45 double dPrecision;
47
48 std::string sFitFunction;
49 std::string sRestrictions;
50 std::string sParams;
51 std::string sChiMap;
52 std::string sChiMap_Vars[2];
53};
54
55// These are the prototypes of the file static helper routines
56static std::vector<double> evaluateFittingParams(FittingData& fitData, std::string& sCmd, Indices& _idx, std::string& sTeXExportFile, bool& bTeXExport, bool& bMaskDialog);
57static mu::varmap_type getFittingParameters(FittingData& fitData, const mu::varmap_type& varMap, const std::string& sCmd);
58static int getDataForFit(const std::string& sCmd, std::string& sDimsForFitLog, FittingData& fitData);
59static void removeObsoleteParentheses(std::string& sFunction);
60static bool calculateChiMap(std::string sFunctionDefString, const std::string& sFuncDisplay, Indices& _idx, mu::varmap_type& varMap, mu::varmap_type& paramsMap, FittingData& fitData, std::vector<double> vInitialVals);
61static std::string applyFitAlgorithm(Fitcontroller& _fControl, FittingData& fitData, mu::varmap_type& paramsMap, const std::string& sFuncDisplay, const std::string& sCmd);
62static void calculateCovarianceData(FittingData& fitData, double dChisq, size_t paramsMapSize);
63static std::string getFitOptionsTable(Fitcontroller& _fControl, FittingData& fitData, const std::string& sFuncDisplay, const std::string& sFittedFunction, const std::string& sDimsForFitLog, double dChisq, const mu::varmap_type& paramsMap, size_t nSize, bool forFitLog);
64static std::string getParameterTable(FittingData& fitData, mu::varmap_type& paramsMap, const std::vector<double>& vInitialVals, size_t windowSize, const std::string& sPMSign, bool forFitLog);
65static std::string constructCovarianceMatrix(FittingData& fitData, size_t paramsMapSize, bool forFitLog);
66static double calculatePercentageAvgAndCreateParserVariables(FittingData& fitData, mu::varmap_type& paramsMap, double dChisq);
67static std::string getFitAnalysis(Fitcontroller& _fControl, FittingData& fitData, double dNormChisq, double dAverageErrorPercentage, bool noOverfitting);
68static void createTeXExport(Fitcontroller& _fControl, const std::string& sTeXExportFile, const std::string& sCmd, mu::varmap_type& paramsMap, FittingData& fitData, const std::vector<double>& vInitialVals, size_t nSize, const std::string& sFitAnalysis, const std::string& sFuncDisplay, const std::string& sFittedFunction, double dChisq);
69
70using namespace std;
71
72// This is the fitting main routine
73bool fitDataSet(string& sCmd, Parser& _parser, MemoryManager& _data, FunctionDefinitionManager& _functions, const Settings& _option)
74{
75 // Declare the FittingData object first
76 FittingData fitData;
77
78 vector<double> vInitialVals;
79 vector<double> vInterVal;
80 double dChisq = 0.0;
81 Indices _idx;
82
83 ofstream oFitLog;
84 string sFitLog = "<savepath>/numerefit.log";
85 sFitLog = _data.ValidFileName(sFitLog, ".log");
86
87 bool bMaskDialog = false;
88 bool bTeXExport = false;
89 string sTeXExportFile = "<savepath>/fit.tex";
90 string sDimsForFitLog;
91 string sFunctionDefString = "";
92 string sFuncDisplay = "";
93
94 // Prepare the default values in the FittingData
95 // object for the further calculation
96 fitData.ivl.intervals.resize(3);
97 fitData.restricted[0] = false;
98 fitData.restricted[1] = false;
99 fitData.restricted[2] = false;
100
101 fitData.nDim = 1;
102 fitData.nFitVars = 0;
103 fitData.bUseErrors = false;
104 fitData.bSaveErrors = false;
105 fitData.bNoParams = false;
106 fitData.b1DChiMap = false;
107 fitData.dPrecision = 1e-4;
108 fitData.nMaxIterations = 500;
109 fitData.sChiMap_Vars[0].clear();
110 fitData.sChiMap_Vars[1].clear();
111 fitData.sFitFunction = sCmd;
112 fitData.sRestrictions = "";
113
114 if (findCommand(sCmd, "fit").sString == "fitw")
115 fitData.bUseErrors = true;
116
117 // Ensure that data is available
118 if (!_data.containsTablesOrClusters(sCmd))
120
121 // Evaluate all passed parameters in this file static
122 // function and return the initial fitting parameter
123 // values
124 vInterVal = evaluateFittingParams(fitData, sCmd, _idx, sTeXExportFile, bTeXExport, bMaskDialog);
125
126 fitData.sFitFunction = " " + fitData.sFitFunction + " ";
127 _parser.SetExpr(fitData.sFitFunction);
128 _parser.Eval();
129 mu::varmap_type varMap = _parser.GetUsedVar();
130
131 // Get the map containing all the fitting parameters,
132 // which will be used by the fit
133 mu::varmap_type paramsMap = getFittingParameters(fitData, varMap, sCmd);
134
135 fitData.sParams.clear();
136
137 // Determine the number of fitting variables
138 if (varMap.find("x") != varMap.end())
139 fitData.nFitVars += 1;
140
141 if (varMap.find("y") != varMap.end())
142 fitData.nFitVars += 2;
143
144 if (varMap.find("z") != varMap.end())
145 fitData.nFitVars += 4;
146
147 // If a chi^2 map shall be calculated, ensure that its
148 // fitting parameter names are set correctly
149 if (fitData.sChiMap.length())
150 {
151 if (fitData.sChiMap_Vars[0] == "x" || fitData.sChiMap_Vars[1] == "x")
153
154 if (fitData.sChiMap_Vars[0] == "y" || fitData.sChiMap_Vars[1] == "y")
156
157 if (varMap.find(fitData.sChiMap_Vars[0]) == varMap.end())
159
160 if (varMap.find(fitData.sChiMap_Vars[1]) == varMap.end())
161 fitData.b1DChiMap = true;
162 }
163
164 // Ensure that "x" is present in the function, if the fit
165 // is along a single dimension
166 if (!fitData.nFitVars || !(fitData.nFitVars & 1))
168
169 // Validate the parameters in the parameter map. If the
170 // parameter map contains one of the variables x,y,z, then
171 // throw an error. Also ensure that all passed fitting
172 // parameters are also part of the fit function
173 for (auto pItem = paramsMap.begin(); pItem != paramsMap.end(); ++pItem)
174 {
175 if (pItem->first == "x" || pItem->first == "y" || pItem->first == "z")
177
178 if (varMap.find(pItem->first) == varMap.end())
180 }
181
182 // Remove the parameters of the chi^2 map from the usual
183 // fitting parameters, because we'll set their values
184 // elsewhere
185 if (fitData.sChiMap.length())
186 {
187 paramsMap.erase(fitData.sChiMap_Vars[0]);
188
189 if (!fitData.b1DChiMap)
190 paramsMap.erase(fitData.sChiMap_Vars[1]);
191 }
192
193 // Ensure that at least a single parameter is available
194 if (!paramsMap.size())
196
197 sFuncDisplay = fitData.sFitFunction;
198
199 sCmd.erase(0, findCommand(sCmd).nPos + findCommand(sCmd).sString.length());
200 StripSpaces(sCmd);
201
202 // Get the necessary data for the fitting routine. This is done
203 // in the following file static routine. It will also return the
204 // actual fitting dimension
205 fitData.nDim = getDataForFit(sCmd, sDimsForFitLog, fitData);
206
207 // Ensure that we're not trying to use more paramters than values
208 if (paramsMap.size() > fitData.vy.size())
210
211 if (paramsMap.size() > fitData.vx.size())
213
214 if ((fitData.nFitVars & 2)
215 && (paramsMap.size() > fitData.vz.size() || paramsMap.size() > fitData.vz[0].size()))
217
218 // Remove obsolete parentheses in the function displaying
219 // string and the actual fitting function
220 removeObsoleteParentheses(sFuncDisplay);
222
223 if (_option.systemPrints())
224 NumeReKernel::printPreFmt(LineBreak("|-> " + _lang.get("PARSERFUNCS_FIT_FITTING", sFuncDisplay) + " ", _option, 0));
225
226 for (auto iter = paramsMap.begin(); iter != paramsMap.end(); ++iter)
227 {
228 vInitialVals.push_back((*(iter->second)).real());
229 }
230
231 // If the user desires a chi^2 map, then it is calculated in the
232 // following static function and the code returns after the map
233 // has been calculated
234 if (fitData.sChiMap.length())
235 return calculateChiMap(sFunctionDefString, sFuncDisplay, _idx, varMap, paramsMap, fitData, vInitialVals);
236
237 // Create a fitcontroller object
238 Fitcontroller _fControl(&_parser);
239
240 // Apply the fitting algorithm to data and fitting function.
241 // This will update the parameter values and return all necessary
242 // values for evaluating the fitting result.
243 sFunctionDefString = applyFitAlgorithm(_fControl, fitData, paramsMap, sFuncDisplay, sCmd);
244
245 // DONE. We're finished with fitting. The following lines have the
246 // single purpose to display the results in the logfiles and in the
247 // terminal, if necessary.
248 //
249 // Overwrite the z-weighting field with the parameter
250 // covariance matrix as we don't need the weighting field any more
251 fitData.vz_w = _fControl.getCovarianceMatrix();
252 dChisq = _fControl.getFitChi();
253
254 // Calculate the data for the covariance matrix. This includes multiplying
255 // the matrix elements with the chi^2 value depending on the type of the
256 // fit
257 calculateCovarianceData(fitData, dChisq, paramsMap.size());
258 size_t nSize = ((fitData.vz.size()) ? (fitData.vz.size() * fitData.vz[0].size()) : fitData.vx.size());
259
260 // Reduce the file size of the fit log, if necessary
261 if (!bMaskDialog && _option.systemPrints())
262 reduceLogFilesize(sFitLog);
263
264 string sFittedFunction = _fControl.getFitFunction();
265
266 // Open the fitting log file stream
267 oFitLog.open(sFitLog.c_str(), ios_base::ate | ios_base::app);
268
269 // If the we could not open the file stream
270 // abort and inform the user
271 if (oFitLog.fail())
272 {
273 oFitLog.close();
276 }
277
278 // Write the headline to the fitting logfile
279 oFitLog << std::setw(156) << std::setfill('=') << '=' << endl;
280 oFitLog << toUpperCase(_lang.get("PARSERFUNCS_FIT_HEADLINE")) << ": " << getTimeStamp(false) << endl;
281 oFitLog << std::setw(156) << std::setfill('=') << '=' << endl;
282
283 // Write the fitting options table to the log file
284 oFitLog << getFitOptionsTable(_fControl, fitData, sFuncDisplay, sFittedFunction, sDimsForFitLog, dChisq, paramsMap, nSize, true) << endl;
285
286 string sPMSign = " ";
287 sPMSign[0] = (char)177;
288
289 // Prepare the headline for the fitting parameter table
290 if (fitData.bUseErrors)
291 oFitLog << _lang.get("PARSERFUNCS_FIT_LOG_TABLEHEAD1") << endl;
292 else
293 oFitLog << _lang.get("PARSERFUNCS_FIT_LOG_TABLEHEAD2") << endl;
294
295 // Write the fitting parameter table to the logfile
296 oFitLog << std::setw(156) << std::setfill('-') << '-' << endl;
297 oFitLog << getParameterTable(fitData, paramsMap, vInitialVals, 160, sPMSign, true);
298 oFitLog << std::setw(156) << std::setfill('-') << '-' << endl;
299
300
301 if (_option.systemPrints())
302 NumeReKernel::printPreFmt(_lang.get("COMMON_SUCCESS") + ".\n");
303
304 if (_option.systemPrints() && !bMaskDialog)
305 {
307 make_hline();
308 NumeReKernel::print(toSystemCodePage("NUMERE: " + toUpperCase(_lang.get("PARSERFUNCS_FIT_HEADLINE"))));
309 make_hline();
310
311 // Write the fitting options table to the terminal screen
312 NumeReKernel::printPreFmt("|-> " + getFitOptionsTable(_fControl, fitData, sFuncDisplay, sFittedFunction, sDimsForFitLog, dChisq, paramsMap, nSize, false));
314
315 // Prepare the headline for the fitting parameter table
316 // displayed in the terminal
317 if (fitData.bUseErrors)
318 {
319 NumeReKernel::print(_lang.get("PARSERFUNCS_FIT_PARAM")
320 + strfill(_lang.get("PARSERFUNCS_FIT_INITIAL"), (_option.getWindow() - 32) / 2 + _option.getWindow() % 2 - 5 + 9 - _lang.get("PARSERFUNCS_FIT_PARAM").length())
321 + strfill(_lang.get("PARSERFUNCS_FIT_FITTED"), (_option.getWindow() - 50) / 2)
322 + strfill(_lang.get("PARSERFUNCS_FIT_PARAM_DEV"), 33));
323 }
324 else
325 {
326 NumeReKernel::print(_lang.get("PARSERFUNCS_FIT_PARAM")
327 + strfill(_lang.get("PARSERFUNCS_FIT_INITIAL"), (_option.getWindow() - 32) / 2 + _option.getWindow() % 2 - 5 + 9 - _lang.get("PARSERFUNCS_FIT_PARAM").length())
328 + strfill(_lang.get("PARSERFUNCS_FIT_FITTED"), (_option.getWindow() - 50) / 2)
329 + strfill(_lang.get("PARSERFUNCS_FIT_ASYMPTOTIC_ERROR"), 33));
330 }
331
332 // Write the fitting parameter table to the terminal
333 NumeReKernel::printPreFmt("| " + strfill("-", _option.getWindow() - 4, '-') + "\n");
334 NumeReKernel::printPreFmt(getParameterTable(fitData, paramsMap, vInitialVals, _option.getWindow(), sPMSign, false));
335 NumeReKernel::printPreFmt("| " + strfill("-", _option.getWindow() - 4, '-') + "\n");
336 }
337
338 // Calculate the average of the percentual errors, which will be used to
339 // derive a fitting analysis and create the variable to store the individual
340 // fitting error values needed for further calulations (error propagation, etc.)
341 double dAverageErrorPercentage = calculatePercentageAvgAndCreateParserVariables(fitData, paramsMap, dChisq);
342
343 // Write the correlation matrix to the log file and the terminal
344 if (paramsMap.size() > 1 && paramsMap.size() != nSize)
345 {
346 oFitLog << endl;
347 oFitLog << _lang.get("PARSERFUNCS_FIT_CORRELMAT_HEAD") << ":" << endl;
348 oFitLog << endl;
349 oFitLog << constructCovarianceMatrix(fitData, paramsMap.size(), true) << endl;
350
351 if (_option.systemPrints() && !bMaskDialog)
352 {
353 NumeReKernel::printPreFmt("|\n|-> " + toSystemCodePage(_lang.get("PARSERFUNCS_FIT_CORRELMAT_HEAD")) + ":\n|\n");
354 NumeReKernel::printPreFmt(constructCovarianceMatrix(fitData, paramsMap.size(), false));
355 }
356 }
357
358 if (fitData.nFitVars & 2)
359 nSize *= nSize;
360
361 // Get the fitting analysis as a string. The fitting analysis is
362 // calculated from the average of the percentual errors and the
363 // value of the reduced chi^2
364 string sFitAnalysis = getFitAnalysis(_fControl, fitData, dChisq / (double)(nSize - paramsMap.size()), dAverageErrorPercentage, nSize != paramsMap.size());
365
366 // Write the fitting analysis to the logfile and to the terminal
367 oFitLog << _lang.get("PARSERFUNCS_FIT_ANALYSIS") << ":" << endl;
368 oFitLog << sFitAnalysis << endl;
369 oFitLog.close();
370
371 if (_option.systemPrints() && !bMaskDialog)
372 {
373 NumeReKernel::printPreFmt("|\n|-> " + _lang.get("PARSERFUNCS_FIT_ANALYSIS") + ":\n");
374 NumeReKernel::print(sFitAnalysis);
376 make_hline();
377 }
378
379 // If the user requested an export of the fitting results to
380 // a TeX file, this is done here
381 if (bTeXExport)
382 createTeXExport(_fControl, sTeXExportFile, sCmd, paramsMap, fitData, vInitialVals, nSize, sFitAnalysis, sFuncDisplay, sFittedFunction, dChisq);
383
384 // Update the function definition of the automatically created
385 // Fit(x) or Fitw(x) function
386 bool bDefinitionSuccess = false;
387
388 if (!_functions.isDefined(sFunctionDefString))
389 bDefinitionSuccess = _functions.defineFunc(sFunctionDefString);
390 else if (_functions.getDefinitionString(_functions.getFunctionIndex(sFunctionDefString)) != sFunctionDefString)
391 bDefinitionSuccess = _functions.defineFunc(sFunctionDefString, true);
392 else if (_functions.getDefinitionString(_functions.getFunctionIndex(sFunctionDefString)) == sFunctionDefString)
393 return true;
394
395 if (bDefinitionSuccess)
396 NumeReKernel::print(_lang.get("DEFINE_SUCCESS"), _option.systemPrints());
397 else
398 NumeReKernel::issueWarning(_lang.get("DEFINE_FAILURE"));
399
400 return true;
401}
402
403
404// This static function evaluates the passed
405// parameters of the fitting routine
406static vector<double> evaluateFittingParams(FittingData& fitData, string& sCmd, Indices& _idx, string& sTeXExportFile, bool& bTeXExport, bool& bMaskDialog)
407{
412
413 vector<double> vInterVal;
414 static const string sBADFUNCTIONS = "ascii(),char(),findfile(),findparam(),gauss(),getopt(),is_string(),rand(),replace(),replaceall(),split(),strfnd(),string_cast(),strrfnd(),strlen(),time(),to_char(),to_cmd(),to_string(),to_value()";
415
416 // Evaluate the chi^2 map option
417 if (findParameter(sCmd, "chimap", '='))
418 {
419 fitData.sChiMap = getArgAtPos(sCmd, findParameter(sCmd, "chimap", '=') + 6);
420 eraseToken(sCmd, "chimap", true);
421
422 if (fitData.sChiMap.length())
423 {
424 getIndices(fitData.sChiMap, _idx, _parser, _data, _option);
425
426 if (!isValidIndexSet(_idx))
428
429 if (_idx.col.size() < 2)
431
432 evaluateIndices(fitData.sChiMap, _idx, _data);
433 fitData.sChiMap.erase(fitData.sChiMap.find('('));
434 fitData.sChiMap_Vars[0] = _data.getHeadLineElement(_idx.col[0], fitData.sChiMap);
435 fitData.sChiMap_Vars[1] = _data.getHeadLineElement(_idx.col[1], fitData.sChiMap);
436 }
437 }
438
439 // Does the user want to export the results into a TeX file?
440 if (findParameter(sCmd, "export", '='))
441 {
442 bTeXExport = true;
443 sTeXExportFile = getArgAtPos(sCmd, findParameter(sCmd, "export", '=') + 6);
444 eraseToken(sCmd, "export", true);
445 }
446 else if (findParameter(sCmd, "export"))
447 {
448 bTeXExport = true;
449 eraseToken(sCmd, "export", false);
450 }
451
452 // Ensure that the file name for the TeX file is valid
453 if (bTeXExport)
454 {
455 sTeXExportFile = _data.ValidFileName(sTeXExportFile, ".tex");
456
457 if (sTeXExportFile.substr(sTeXExportFile.rfind('.')) != ".tex")
458 sTeXExportFile.replace(sTeXExportFile.rfind('.'), string::npos, ".tex");
459 }
460
461 // Separate expression from the command line option list
462 for (unsigned int i = 0; i < sCmd.length(); i++)
463 {
464 if (sCmd[i] == '(')
465 i += getMatchingParenthesis(sCmd.substr(i));
466
467 if (sCmd[i] == '-')
468 {
469 sCmd.erase(0, i);
470 break;
471 }
472 }
473
474 // Decode possible interval definitions in the command
475 // line option list
476 vInterVal = readAndParseIntervals(sCmd, _parser, _data, _functions, _option, true);
477
478 // Evaluate the contents of the parsed interval definitions
479 for (size_t i = 0; i < vInterVal.size(); i += 2)
480 {
481 fitData.ivl[i / 2].reset(vInterVal[i], vInterVal[i+1]);
482 fitData.restricted[i / 2] = true;
483 }
484
485 // Insert the command line option list after the intervals
486 // were parsed into the original command line
487 for (unsigned int i = 0; i < fitData.sFitFunction.length(); i++)
488 {
489 if (fitData.sFitFunction[i] == '(')
490 i += getMatchingParenthesis(fitData.sFitFunction.substr(i));
491
492 if (fitData.sFitFunction[i] == '-')
493 {
494 fitData.sFitFunction.replace(i, string::npos, sCmd.substr(sCmd.find('-')));
495 break;
496 }
497 }
498
499 sCmd = fitData.sFitFunction;
500
501 // Because it's quite likely that one misspells the option value
502 // "saverr", whe accept also the spelling "saveer" as an alternative
503 if (findParameter(fitData.sFitFunction, "saverr"))
504 {
505 fitData.bSaveErrors = true;
506 fitData.sFitFunction.erase(findParameter(fitData.sFitFunction, "saverr") - 1, 6);
507 sCmd.erase(findParameter(sCmd, "saverr") - 1, 6);
508 }
509
510 if (findParameter(fitData.sFitFunction, "saveer"))
511 {
512 fitData.bSaveErrors = true;
513 fitData.sFitFunction.erase(findParameter(fitData.sFitFunction, "saveer") - 1, 6);
514 sCmd.erase(findParameter(sCmd, "saveer") - 1, 6);
515 }
516
517 // The masking paramter
518 if (findParameter(fitData.sFitFunction, "mask"))
519 {
520 bMaskDialog = true;
521 fitData.sFitFunction.erase(findParameter(fitData.sFitFunction, "mask") - 1, 6);
522 sCmd.erase(findParameter(sCmd, "mask") - 1, 6);
523 }
524
525 // Ensure that a fitting function was defined
526 if (!findParameter(fitData.sFitFunction, "with", '='))
528
529 // Changes to the tolerance
530 if (findParameter(fitData.sFitFunction, "tol", '='))
531 {
532 _parser.SetExpr(getArgAtPos(fitData.sFitFunction, findParameter(fitData.sFitFunction, "tol", '=') + 3));
533 eraseToken(sCmd, "tol", true);
534 eraseToken(fitData.sFitFunction, "tol", true);
535 fitData.dPrecision = fabs(_parser.Eval());
536
537 if (isnan(fitData.dPrecision) || isinf(fitData.dPrecision) || fitData.dPrecision == 0)
538 fitData.dPrecision = 1e-4;
539 }
540
541 // Changes to the maximal number of iterations
542 if (findParameter(fitData.sFitFunction, "iter", '='))
543 {
544 _parser.SetExpr(getArgAtPos(fitData.sFitFunction, findParameter(fitData.sFitFunction, "iter", '=') + 4));
545 eraseToken(sCmd, "iter", true);
546 eraseToken(fitData.sFitFunction, "iter", true);
547 fitData.nMaxIterations = abs(rint(_parser.Eval()).real());
548
549 if (!fitData.nMaxIterations)
550 fitData.nMaxIterations = 500;
551 }
552
553 // Fitting parameter restrictions
554 if (findParameter(fitData.sFitFunction, "restrict", '='))
555 {
556 fitData.sRestrictions = getArgAtPos(fitData.sFitFunction, findParameter(fitData.sFitFunction, "restrict", '=') + 8);
557 eraseToken(sCmd, "restrict", true);
558 eraseToken(fitData.sFitFunction, "restrict", true);
559
560 if (fitData.sRestrictions.length() && fitData.sRestrictions.front() == '[' && fitData.sRestrictions.back() == ']')
561 {
562 fitData.sRestrictions.erase(0, 1);
563 fitData.sRestrictions.pop_back();
564 }
565
566 StripSpaces(fitData.sRestrictions);
567
568 if (fitData.sRestrictions.length())
569 {
570 if (fitData.sRestrictions.front() == ',')
571 fitData.sRestrictions.erase(0, 1);
572
573 if (fitData.sRestrictions.back() == ',')
574 fitData.sRestrictions.pop_back();
575
576 _parser.SetExpr(fitData.sRestrictions);
577 _parser.Eval();
578 }
579 }
580
581 // The fitting parameter list including their possible
582 // starting values
583 if (!findParameter(fitData.sFitFunction, "params", '='))
584 {
585 fitData.bNoParams = true;
586 fitData.sFitFunction = fitData.sFitFunction.substr(findParameter(fitData.sFitFunction, "with", '=') + 4);
587 sCmd.erase(findParameter(sCmd, "with", '=') - 1);
588 }
589 else if (findParameter(fitData.sFitFunction, "with", '=') < findParameter(fitData.sFitFunction, "params", '='))
590 {
591 fitData.sParams = fitData.sFitFunction.substr(findParameter(fitData.sFitFunction, "params", '=') + 6);
592 fitData.sFitFunction = fitData.sFitFunction.substr(findParameter(fitData.sFitFunction, "with", '=') + 4, findParameter(fitData.sFitFunction, "params", '=') - 1 - findParameter(fitData.sFitFunction, "with", '=') - 4);
593 sCmd = sCmd.substr(0, findParameter(sCmd, "with", '=') - 1);
594 }
595 else
596 {
597 fitData.sParams = fitData.sFitFunction.substr(findParameter(fitData.sFitFunction, "params", '=') + 6, findParameter(fitData.sFitFunction, "with", '=') - 1 - findParameter(fitData.sFitFunction, "params", '=') - 6);
598 fitData.sFitFunction = fitData.sFitFunction.substr(findParameter(fitData.sFitFunction, "with", '=') + 4);
599 sCmd = sCmd.substr(0, findParameter(sCmd, "params", '=') - 1);
600 }
601
602 // Remove surrounding brackets from the parameter list
603 if (fitData.sParams.find('[') != string::npos)
604 fitData.sParams = fitData.sParams.substr(fitData.sParams.find('[') + 1);
605
606 if (fitData.sParams.find(']') != string::npos)
607 fitData.sParams = fitData.sParams.substr(0, fitData.sParams.find(']'));
608
609 StripSpaces(fitData.sFitFunction);
610
611 // Remove the possible trailing minus character
612 if (fitData.sFitFunction.back() == '-')
613 {
614 fitData.sFitFunction.back() = ' ';
615 StripSpaces(fitData.sFitFunction);
616 }
617
618 // Evaluate the defined paramters and their initial values
619 if (!fitData.bNoParams)
620 {
621 StripSpaces(fitData.sParams);
622
623 if (fitData.sParams.back() == '-')
624 {
625 fitData.sParams.back() = ' ';
626 StripSpaces(fitData.sParams);
627 }
628
629 if (!_functions.call(fitData.sParams))
630 throw SyntaxError(SyntaxError::FUNCTION_ERROR, sCmd,fitData. sParams, fitData.sParams);
631
632 if (_data.containsTablesOrClusters(fitData.sParams))
633 {
634 getDataElements(fitData.sParams, _parser, _data, _option);
635 }
636
637 if (fitData.sParams.find("{") != string::npos && NumeReKernel::getInstance()->getStringParser().isStringExpression(fitData.sParams))
638 convertVectorToExpression(fitData.sParams, _option);
639 }
640
641 StripSpaces(sCmd);
642
643 // Evaluate function definition calls
644 if (!_functions.call(fitData.sFitFunction))
646
647 // Get values from a references data object
648 if (_data.containsTablesOrClusters(fitData.sFitFunction))
649 {
650 getDataElements(fitData.sFitFunction, _parser, _data, _option);
651 }
652
653 // Expand remaining vectors
654 if (fitData.sFitFunction.find("{") != string::npos)
655 convertVectorToExpression(fitData.sFitFunction, _option);
656
657 size_t nPos = 0;
658
659 // Ensure that the fitting function does not contain any of the
660 // functions from the bad fitting functions list (a list of functions,
661 // which cannot be used to solve the optimisation problem)
662 while (sBADFUNCTIONS.find(',', nPos) != string::npos)
663 {
664 if (fitData.sFitFunction.find(sBADFUNCTIONS.substr(nPos, sBADFUNCTIONS.find(',', nPos) - nPos - 1)) != string::npos)
665 {
666 throw SyntaxError(SyntaxError::FUNCTION_CANNOT_BE_FITTED, sCmd, SyntaxError::invalid_position, sBADFUNCTIONS.substr(nPos, sBADFUNCTIONS.find(',', nPos) - nPos));
667 }
668 else
669 nPos = sBADFUNCTIONS.find(',', nPos) + 1;
670
671 if (nPos >= sBADFUNCTIONS.length())
672 break;
673 }
674
675 return vInterVal;
676}
677
678
679// This static function returns a map of all
680// fitting paramters used in the fitting algorithm
681static mu::varmap_type getFittingParameters(FittingData& fitData, const mu::varmap_type& varMap, const string& sCmd)
682{
683 mu::varmap_type paramsMap;
685
686 // If the user did not provide his own fitting parameters,
687 // we'll create our own list depending on the found variables
688 // in the fitting expression
689 if (fitData.bNoParams)
690 {
691 // Get the variable map
692 paramsMap = varMap;
693
694 // Remove x and y variables
695 if (paramsMap.find("x") != paramsMap.end())
696 paramsMap.erase(paramsMap.find("x"));
697
698 if (paramsMap.find("y") != paramsMap.end())
699 paramsMap.erase(paramsMap.find("y"));
700
701 if (!paramsMap.size())
703 }
704 else
705 {
706 // Evaluate the fitting parameters provided
707 // by the user
708 _parser.SetExpr(fitData.sParams);
709 _parser.Eval();
710
711 // Remove the values from the expression, to avoid
712 // that they would be mis-identified as fitting
713 // parameters
714 if (fitData.sParams.find('=') != string::npos)
715 {
716 for (size_t i = 0; i < fitData.sParams.length(); i++)
717 {
718 if (fitData.sParams[i] == '=')
719 {
720 for (size_t j = i; j < fitData.sParams.length(); j++)
721 {
722 if (fitData.sParams[j] == '(')
723 j += getMatchingParenthesis(fitData.sParams.substr(j));
724
725 if (fitData.sParams[j] == ',')
726 {
727 fitData.sParams.erase(i, j - i);
728 break;
729 }
730
731 if (j == fitData.sParams.length() - 1)
732 fitData.sParams.erase(i);
733 }
734 }
735 }
736
737 _parser.SetExpr(fitData.sParams);
738 _parser.Eval();
739 }
740
741 paramsMap = _parser.GetUsedVar();
742 }
743
744 return paramsMap;
745}
746
747
748// This static function obtains the data needed for
749// the fitting algorithm and stores it in the vector
750// members in the FittingData object
751static int getDataForFit(const string& sCmd, string& sDimsForFitLog, FittingData& fitData)
752{
754 vector<double> vTempZ;
755 string sDataTable = "";
756 Indices _idx;
757 int nColumns = 0;
758 bool openEnd = false;
759 bool isCluster = false;
760 sDataTable = "data";
761 int nDim = 0;
762
763 _idx = getIndicesForPlotAndFit(sCmd, sDataTable, nColumns, openEnd, isCluster);
764
765
766 if (_idx.row.isOpenEnd())
767 {
768 if (!isCluster)
769 _idx.row.setRange(0, _data.getLines(sDataTable, false)-1);
770 else
771 _idx.row.setRange(0, _data.getCluster(sDataTable).size()-1);
772 }
773
774 if (!isCluster && _idx.col.isOpenEnd())
775 {
776 _idx.col.setRange(0, _data.getCols(sDataTable, false)-1);
777 }
778
779 if (!isCluster)
780 {
781 if (_idx.row.back() > _data.getLines(sDataTable, false))
782 _idx.row.setRange(0, _data.getLines(sDataTable, false)-1);
783
784 if (_idx.col.back() > _data.getCols(sDataTable))
785 _idx.col.setRange(0, _data.getCols(sDataTable)-1);
786 }
787 else
788 {
789 if (_idx.row.back() > (int)_data.getCluster(sDataTable).size())
790 _idx.row.setRange(0, _data.getCluster(sDataTable).size()-1);
791 }
792
793 /* --> Bestimmen wir die "Dimension" des zu fittenden Datensatzes. Dabei ist es auch
794 * von Bedeutung, ob Fehlerwerte verwendet werden sollen <--
795 */
796 nDim = 0;
797
798 if (nColumns == 1 && fitData.bUseErrors && _idx.col.size() < 3)
800
801 if (nColumns == 1)
802 nDim = 2;
803 else if (nColumns == 2)
804 {
805 if (!fitData.bUseErrors)
806 {
807 if (!(fitData.nFitVars & 2))
808 {
809 nDim = 2;
810
811 if (_idx.col.size() < 2)
813 }
814 else
815 {
816 nDim = 3;
817
818 if (_idx.col.size() < _data.num(sDataTable, _idx.row, _idx.col.subidx(1, 1)).real() + 2)
820 }
821 }
822 else
823 {
824 if (!(fitData.nFitVars & 2))
825 {
826 nDim = 4;
827
828 if (_idx.col.size() < 3)
830 }
831 else
832 {
833 nDim = 5;
834
835 if (_idx.col.size() < 3 * _data.num(sDataTable, _idx.row, _idx.col.subidx(1, 1)).real() + 2)
837 }
838 }
839 }
840 else
841 {
842 nDim = _idx.col.size();
843 }
844
845 if (isnan(fitData.ivl[0].front()))
846 {
847 fitData.ivl[0].reset(_data.min(sDataTable, _idx.row, VectorIndex(_idx.col.front())).real(),
848 _data.max(sDataTable, _idx.row, VectorIndex(_idx.col.front())).real());
849 }
850
851 if (isnan(fitData.ivl[1].front()) && !isCluster)
852 {
853 bool useLast = _idx.col.isExpanded() && nDim == 2;
854
855 fitData.ivl[1].reset(_data.min(sDataTable, _idx.row, VectorIndex(useLast ? _idx.col.last() : _idx.col[1])).real(),
856 _data.max(sDataTable, _idx.row, VectorIndex(useLast ? _idx.col.last() : _idx.col[1])).real());
857 }
858
859 if (fitData.nFitVars & 2 && !isCluster && isnan(fitData.ivl[2].front()))
860 {
861 fitData.ivl[2].reset(_data.min(sDataTable, _idx.row, _idx.col.subidx(2)).real(),
862 _data.max(sDataTable, _idx.row, _idx.col.subidx(2)).real());
863 }
864
865 if (nDim == 2 || isCluster)
866 {
867 for (size_t i = 0; i < _idx.row.size(); i++)
868 {
869 if (nColumns == 1)
870 {
871 mu::value_type val = getDataFromObject(sDataTable, _idx.row[i], _idx.col.front(), isCluster);
872 if (isValidValue(val.real()) && fitData.ivl[0].isInside(val))
873 {
874 fitData.vx.push_back(_idx.row[i] + 1);
875 fitData.vy.push_back(getDataFromObject(sDataTable, _idx.row[i], _idx.col.front(), isCluster).real());
876 }
877 }
878 else
879 {
880 if (_data.isValidElement(_idx.row[i], _idx.col.front(), sDataTable)
881 && _data.isValidElement(_idx.row[i], _idx.col.last(), sDataTable))
882 {
883 if (!fitData.ivl[0].isInside(_data.getElement(_idx.row[i], _idx.col.front(), sDataTable))
884 || !fitData.ivl[1].isInside(_data.getElement(_idx.row[i], _idx.col.last(), sDataTable)))
885 continue;
886
887 fitData.vx.push_back(_data.getElement(_idx.row[i], _idx.col.front(), sDataTable).real());
888 fitData.vy.push_back(_data.getElement(_idx.row[i], _idx.col.last(), sDataTable).real());
889 }
890 }
891 }
892 }
893 else if (nDim == 4)
894 {
895 int nErrorCols = 2;
896
897 if (nColumns == 2)
898 {
899 if (abs(_idx.col[1] - _idx.col[0]) == 2)
900 nErrorCols = 1;
901 }
902 else if (nColumns == 4)
903 nErrorCols = 2;
904
905 for (size_t i = 0; i < _idx.row.size(); i++)
906 {
907 if (nColumns == 2)
908 {
909 if (_data.isValidElement(_idx.row[i], _idx.col[0], sDataTable)
910 && _data.isValidElement(_idx.row[i], _idx.col[1], sDataTable))
911 {
912 if (!fitData.ivl[0].isInside(_data.getElement(_idx.row[i], _idx.col[0], sDataTable))
913 || !fitData.ivl[1].isInside(_data.getElement(_idx.row[i], _idx.col[1], sDataTable)))
914 continue;
915
916 fitData.vx.push_back(_data.getElement(_idx.row[i], _idx.col[0], sDataTable).real());
917 fitData.vy.push_back(_data.getElement(_idx.row[i], _idx.col[1], sDataTable).real());
918
919 if (nErrorCols == 1)
920 {
921 if (_data.isValidElement(_idx.row[i], _idx.col[2], sDataTable))
922 fitData.vy_w.push_back(fabs(_data.getElement(_idx.row[i], _idx.col[2], sDataTable).real()));
923 else
924 fitData.vy_w.push_back(0.0);
925 }
926 else
927 {
928 if (_data.isValidElement(_idx.row[i], _idx.col[2], sDataTable)
929 && _data.isValidElement(_idx.row[i], _idx.col[3], sDataTable)
930 && (_data.getElement(_idx.row[i], _idx.col[2], sDataTable).real()
931 && _data.getElement(_idx.row[i], _idx.col[3], sDataTable).real()))
932 fitData.vy_w.push_back(sqrt(fabs(_data.getElement(_idx.row[i], _idx.col[2], sDataTable).real()) * fabs(_data.getElement(_idx.row[i], _idx.col[3], sDataTable).real())));
933 else if (_data.isValidElement(_idx.row[i], _idx.col[2], sDataTable) && _data.getElement(_idx.row[i], _idx.col[2], sDataTable).real())
934 fitData.vy_w.push_back(fabs(_data.getElement(_idx.row[i], _idx.col[2], sDataTable).real()));
935 else if (_data.isValidElement(_idx.row[i], _idx.col[3], sDataTable) && _data.getElement(_idx.row[i], _idx.col[3], sDataTable).real())
936 fitData.vy_w.push_back(fabs(_data.getElement(_idx.row[i], _idx.col[3], sDataTable).real()));
937 else
938 fitData.vy_w.push_back(0.0);
939 }
940 }
941 }
942 else
943 {
944 if (_data.isValidElement(_idx.row[i], _idx.col[0], sDataTable) && _data.isValidElement(_idx.row[i], _idx.col[1], sDataTable))
945 {
946 if (!fitData.ivl[0].isInside(_data.getElement(_idx.row[i], _idx.col[0], sDataTable))
947 || !fitData.ivl[1].isInside(_data.getElement(_idx.row[i], _idx.col[1], sDataTable)))
948 continue;
949
950 fitData.vx.push_back(_data.getElement(_idx.row[i], _idx.col[0], sDataTable).real());
951 fitData.vy.push_back(_data.getElement(_idx.row[i], _idx.col[1], sDataTable).real());
952
953 if (_data.isValidElement(_idx.row[i], _idx.col[2], sDataTable)
954 && _data.isValidElement(_idx.row[i], _idx.col[3], sDataTable)
955 && (_data.getElement(_idx.row[i], _idx.col[2], sDataTable).real()
956 && _data.getElement(_idx.row[i], _idx.col[3], sDataTable).real()))
957 fitData.vy_w.push_back(sqrt(fabs(_data.getElement(_idx.row[i], _idx.col[2], sDataTable).real()) * fabs(_data.getElement(i, _idx.col[3], sDataTable).real())));
958 else if (_data.isValidElement(_idx.row[i], _idx.col[2], sDataTable) && _data.getElement(_idx.row[i], _idx.col[2], sDataTable).real())
959 fitData.vy_w.push_back(fabs(_data.getElement(_idx.row[i], _idx.col[2], sDataTable).real()));
960 else if (_data.isValidElement(_idx.row[i], _idx.col[3], sDataTable) && _data.getElement(_idx.row[i], _idx.col[3], sDataTable).real())
961 fitData.vy_w.push_back(fabs(_data.getElement(_idx.row[i], _idx.col[3], sDataTable).real()));
962 else
963 fitData.vy_w.push_back(0.0);
964 }
965 }
966 }
967 }
968 else if (!isCluster && (fitData.nFitVars & 2))
969 {
970 for (size_t i = 0; i < _idx.row.size(); i++)
971 {
972 if (!_data.isValidElement(_idx.row[i], _idx.col[1], sDataTable)
973 || !fitData.ivl[1].isInside(_data.getElement(_idx.row[i], _idx.col[1], sDataTable)))
974 continue;
975 else
976 fitData.vy.push_back(_data.getElement(_idx.row[i], _idx.col[1], sDataTable).real());
977
978 if (!_data.isValidElement(_idx.row[i], _idx.col[0], sDataTable)
979 || !fitData.ivl[0].isInside(_data.getElement(_idx.row[i], _idx.col[0], sDataTable)))
980 continue;
981 else
982 fitData.vx.push_back(_data.getElement(_idx.row[i], _idx.col[0], sDataTable).real());
983
984 for (size_t k = 2; k < _idx.col.size(); k++)
985 {
986 if (nColumns > 3 && k == _idx.row.size() + 2)
987 break;
988
989 if (!_data.isValidElement(_idx.row[k-2], _idx.col[1], sDataTable)
990 || !fitData.ivl[1].isInside(_data.getElement(_idx.row[k-2], _idx.col[1], sDataTable)))
991 continue;
992 else if (!fitData.ivl[2].isInside(_data.getElement(_idx.row[i], _idx.col[k], sDataTable)))
993 {
994 vTempZ.push_back(NAN);
995
996 if (fitData.bUseErrors)
997 fitData.vy_w.push_back(0.0);
998 }
999 else
1000 {
1001 vTempZ.push_back(_data.getElement(_idx.row[i], _idx.col[k], sDataTable).real());
1002
1003 if (fitData.bUseErrors)
1004 {
1005 if (_data.isValidElement(_idx.row[i], _idx.col[k + _idx.row.size()], sDataTable))
1006 fitData.vy_w.push_back(fabs(_data.getElement(_idx.row[i], _idx.col[k + _idx.row.size()], sDataTable).real()));
1007 else
1008 fitData.vy_w.push_back(0.0);
1009 }
1010 }
1011 }
1012
1013 fitData.vz.push_back(vTempZ);
1014 vTempZ.clear();
1015
1016 if (fitData.vy_w.size() && fitData.bUseErrors)
1017 {
1018 fitData.vz_w.push_back(fitData.vy_w);
1019 fitData.vy_w.clear();
1020 }
1021 }
1022 }
1023 else
1024 {
1025 for (unsigned int i = 0; i < _idx.row.size(); i++)
1026 {
1027 if (_data.isValidElement(_idx.row[i], _idx.col[0], sDataTable)
1028 && _data.isValidElement(_idx.row[i], _idx.col[1], sDataTable))
1029 {
1030 if (!fitData.ivl[0].isInside(_data.getElement(_idx.row[i], _idx.col[0], sDataTable))
1031 || !fitData.ivl[1].isInside(_data.getElement(_idx.row[i], _idx.col[1], sDataTable)))
1032 continue;
1033
1034 fitData.vx.push_back(_data.getElement(_idx.row[i], _idx.col[0], sDataTable).real());
1035 fitData.vy.push_back(_data.getElement(_idx.row[i], _idx.col[1], sDataTable).real());
1036
1037 if (_data.isValidElement(_idx.row[i], _idx.col[2], sDataTable))
1038 fitData.vy_w.push_back(fabs(_data.getElement(_idx.row[i], _idx.col[2], sDataTable).real()));
1039 else
1040 fitData.vy_w.push_back(0.0);
1041 }
1042 }
1043 }
1044
1045 sDimsForFitLog.clear();
1046
1047 if (nDim == 2)
1048 {
1049 sDimsForFitLog += toString(_idx.col.front()+1);
1050
1051 if (nColumns == 2)
1052 {
1053 sDimsForFitLog += ", " + toString(_idx.col.last() + 1);
1054 }
1055 }
1056 else if (nDim == 4)
1057 {
1058 int nErrorCols = 2;
1059
1060 if (nColumns == 2)
1061 {
1062 if (_idx.col.size() == 3)
1063 nErrorCols = 1;
1064 }
1065 else if (nColumns == 4)
1066 nErrorCols = 2;
1067
1068 if (nColumns == 2)
1069 {
1070 sDimsForFitLog += toString(_idx.col[0] + 1) + ", " + toString(_idx.col[1] + 1) + ", " + toString(_idx.col[2] + 1);
1071
1072 if (nErrorCols == 2)
1073 sDimsForFitLog += ", " + toString(_idx.col[3] + 1);
1074 }
1075 else
1076 {
1077 sDimsForFitLog += toString(_idx.col[0] + 1) + ", " + toString(_idx.col[1] + 1) + ", " + toString(_idx.col[2] + 1) + ", " + toString(_idx.col[3] + 1);
1078 }
1079 }
1080 else if ((fitData.nFitVars & 2))
1081 {
1082 if (nColumns == 2)
1083 {
1084 sDimsForFitLog += toString(_idx.col[0] + 1) + ", " + toString(_idx.col[1] + 1) + ", " + toString(_idx.col[2] + 1) + "-" + toString(_idx.col.last()+1);
1085
1086 if (fitData.bUseErrors)
1087 sDimsForFitLog += ", " + toString(_idx.col[2] + 2 + _idx.row.size()) + "-" + toString(_idx.col[2] + 2 + 2 * _idx.row.size());
1088 }
1089 else
1090 {
1091 sDimsForFitLog += toString(_idx.col[0] + 1) + ", " + toString(_idx.col[1] + 1) + ", " + toString(_idx.col[2] + 1) + "-" + toString(_idx.col[2] + _idx.row.size());
1092
1093 if (fitData.bUseErrors)
1094 {
1095 if (nColumns > 3)
1096 sDimsForFitLog += ", " + toString(_idx.col[3] + 1) + "-" + toString(_idx.col[3] + _idx.row.size());
1097 else
1098 sDimsForFitLog += ", " + toString(_idx.col[2] + _idx.row.size() + 1) + "-" + toString(_idx.col[0] + 2 * (_idx.row.size()));
1099 }
1100 }
1101 }
1102 else
1103 {
1104 for (int k = 0; k < (int)nDim; k++)
1105 {
1106 sDimsForFitLog += toString(_idx.col[k] + 1);
1107
1108 if (k + 1 < (int)nDim)
1109 sDimsForFitLog += ", ";
1110 }
1111 }
1112
1113 sDimsForFitLog += " " + _lang.get("PARSERFUNCS_FIT_FROM") + " " + _data.getDataFileName(sDataTable);
1114
1115 return nDim;
1116}
1117
1118
1119// This static function removes obsolete surrounding
1120// parentheses in function strings
1121static void removeObsoleteParentheses(string& sFunction)
1122{
1123 StripSpaces(sFunction);
1124
1125 // As long as the first character is an opening
1126 // parenthesis, search the closing one and remove both,
1127 // if it is the last character of the function
1128 while (sFunction.front() == '(')
1129 {
1130 if (getMatchingParenthesis(sFunction) == sFunction.length() - 1 && getMatchingParenthesis(sFunction) != string::npos)
1131 {
1132 sFunction.erase(0, 1);
1133 sFunction.pop_back();
1134 StripSpaces(sFunction);
1135 }
1136 else
1137 break;
1138 }
1139}
1140
1141
1142// This static function calculates the chi^2 map instead
1143// of applying the single fit
1144static bool calculateChiMap(string sFunctionDefString, const string& sFuncDisplay, Indices& _idx, mu::varmap_type& varMap, mu::varmap_type& paramsMap, FittingData& fitData, vector<double> vInitialVals)
1145{
1150
1151 Fitcontroller _fControl(&_parser);
1152
1153 for (size_t i = 0; i < _idx.row.size(); i++)
1154 {
1155 for (size_t j = 0; j <= (_idx.row.size() - 1) * (!fitData.b1DChiMap); j++)
1156 {
1157 auto iter = paramsMap.begin();
1158
1159 for (unsigned int n = 0; n < vInitialVals.size(); n++)
1160 {
1161 *(iter->second) = vInitialVals[n];
1162 ++iter;
1163 }
1164
1165 if (!_data.isValidElement(_idx.row[i], _idx.col[0], fitData.sChiMap))
1166 continue;
1167
1168 *(varMap.at(fitData.sChiMap_Vars[0])) = _data.getElement(_idx.row[i], _idx.col[0], fitData.sChiMap);
1169
1170 if (!fitData.b1DChiMap)
1171 {
1172 if (!_data.isValidElement(_idx.row[j], _idx.col[1], fitData.sChiMap))
1173 continue;
1174
1175 *(varMap.at(fitData.sChiMap_Vars[1])) = _data.getElement(_idx.row[j], _idx.col[1], fitData.sChiMap);
1176 }
1177
1178 if (fitData.nDim >= 2 && fitData.nFitVars == 1)
1179 {
1180 if (!fitData.bUseErrors)
1181 {
1182 if (!_fControl.fit(fitData.vx, fitData.vy, fitData.sFitFunction, fitData.sRestrictions, paramsMap, fitData.dPrecision, fitData.nMaxIterations))
1183 {
1184 if (_option.systemPrints())
1185 NumeReKernel::printPreFmt(_lang.get("COMMON_FAILURE") + "!\n");
1186
1187 return false;
1188 }
1189
1190 sFunctionDefString = "Fit(x) := " + sFuncDisplay + " " + _lang.get("PARSERFUNCS_FIT_DEFINECOMMENT");
1191 }
1192 else
1193 {
1194 if (!_fControl.fit(fitData.vx, fitData.vy, fitData.vy_w, fitData.sFitFunction, fitData.sRestrictions, paramsMap, fitData.dPrecision, fitData.nMaxIterations))
1195 {
1196 if (_option.systemPrints())
1197 NumeReKernel::printPreFmt(_lang.get("COMMON_FAILURE") + "!\n");
1198
1199 return false;
1200 }
1201
1202 sFunctionDefString = "Fitw(x) := " + sFuncDisplay + " " + _lang.get("PARSERFUNCS_FIT_DEFINECOMMENT");
1203 }
1204 }
1205 else if (fitData.nDim == 3)
1206 {
1207 if (!_fControl.fit(fitData.vx, fitData.vy, fitData.vz, fitData.sFitFunction, fitData.sRestrictions, paramsMap, fitData.dPrecision, fitData.nMaxIterations))
1208 {
1209 if (_option.systemPrints())
1210 NumeReKernel::printPreFmt(_lang.get("COMMON_FAILURE") + "!\n");
1211
1212 return false;
1213 }
1214
1215 sFunctionDefString = "Fit(x,y) := " + sFuncDisplay + " " + _lang.get("PARSERFUNCS_FIT_DEFINECOMMENT");
1216 }
1217 else if (fitData.nDim == 5)
1218 {
1219 if (!_fControl.fit(fitData.vx, fitData.vy, fitData.vz, fitData.vz_w, fitData.sFitFunction, fitData.sRestrictions, paramsMap, fitData.dPrecision, fitData.nMaxIterations))
1220 {
1221 if (_option.systemPrints())
1222 NumeReKernel::printPreFmt(_lang.get("COMMON_FAILURE") + "!\n");
1223
1224 return false;
1225 }
1226
1227 sFunctionDefString = "Fitw(x,y) := " + sFuncDisplay + " " + _lang.get("PARSERFUNCS_FIT_DEFINECOMMENT");
1228 }
1229
1230 _data.writeToTable(_idx.row[i], _idx.col[1 + (!fitData.b1DChiMap) * (j + 1)], fitData.sChiMap, _fControl.getFitChi());
1231
1232 if (!i && !fitData.b1DChiMap)
1233 _data.setHeadLineElement(_idx.col[1 + (!fitData.b1DChiMap) * (j + 1)], fitData.sChiMap, "chi^2(" + toString(j + 1) + ")");
1234 else if (!i)
1235 _data.setHeadLineElement(_idx.col[1 + (!fitData.b1DChiMap) * (j + 1)], fitData.sChiMap, "chi^2");
1236
1237 }
1238 }
1239
1240 auto iter = paramsMap.begin();
1241
1242 for (unsigned int n = 0; n < vInitialVals.size(); n++)
1243 {
1244 *(iter->second) = vInitialVals[n];
1245 ++iter;
1246 }
1247
1248 if (_option.systemPrints())
1249 {
1250 NumeReKernel::printPreFmt(_lang.get("COMMON_SUCCESS") + ".\n");
1251 NumeReKernel::print(LineBreak(_lang.get("PARSERFUNCS_FIT_CHIMAPLOCATION", fitData.sChiMap), _option));
1252 }
1253
1254 bool bDefinitionSuccess = false;
1255
1256 if (!_functions.isDefined(sFunctionDefString))
1257 bDefinitionSuccess = _functions.defineFunc(sFunctionDefString);
1258 else if (_functions.getDefinitionString(_functions.getFunctionIndex(sFunctionDefString)) != sFunctionDefString)
1259 bDefinitionSuccess = _functions.defineFunc(sFunctionDefString, true);
1260 else if (_functions.getDefinitionString(_functions.getFunctionIndex(sFunctionDefString)) == sFunctionDefString)
1261 return true;
1262
1263 if (bDefinitionSuccess)
1264 NumeReKernel::print(_lang.get("DEFINE_SUCCESS"), _option.systemPrints());
1265 else
1266 NumeReKernel::issueWarning(_lang.get("DEFINE_FAILURE"));
1267
1268 return true;
1269
1270}
1271
1272
1273// This static function applies the fitting algorithm to
1274// the obtained data and the prepared fitting function. It
1275// returns the function definition string for the autmatically
1276// created fitting function
1277static string applyFitAlgorithm(Fitcontroller& _fControl, FittingData& fitData, mu::varmap_type& paramsMap, const string& sFuncDisplay, const std::string& sCmd)
1278{
1279 string sFunctionDefString;
1281
1282 if (fitData.nDim >= 2 && fitData.nFitVars == 1)
1283 {
1284 if (!fitData.bUseErrors)
1285 {
1286 if (!_fControl.fit(fitData.vx, fitData.vy, fitData.sFitFunction, fitData.sRestrictions, paramsMap, fitData.dPrecision, fitData.nMaxIterations))
1287 {
1288 if (_option.systemPrints())
1289 NumeReKernel::printPreFmt(_lang.get("COMMON_FAILURE") + "!\n");
1290
1291 throw SyntaxError(SyntaxError::FUNCTION_CANNOT_BE_FITTED, sFuncDisplay, sFuncDisplay, sFuncDisplay);
1292 }
1293
1294 sFunctionDefString = "Fit(x) := " + sFuncDisplay + " " + _lang.get("PARSERFUNCS_FIT_DEFINECOMMENT");
1295 }
1296 else
1297 {
1298 if (!_fControl.fit(fitData.vx, fitData.vy, fitData.vy_w, fitData.sFitFunction, fitData.sRestrictions, paramsMap, fitData.dPrecision, fitData.nMaxIterations))
1299 {
1300 if (_option.systemPrints())
1301 NumeReKernel::printPreFmt(_lang.get("COMMON_FAILURE") + "!\n");
1302
1303 throw SyntaxError(SyntaxError::FUNCTION_CANNOT_BE_FITTED, sFuncDisplay, sFuncDisplay, sFuncDisplay);
1304 }
1305
1306 sFunctionDefString = "Fitw(x) := " + sFuncDisplay + " " + _lang.get("PARSERFUNCS_FIT_DEFINECOMMENT");
1307 }
1308 }
1309 else if (fitData.nDim == 3)
1310 {
1311 if (!_fControl.fit(fitData.vx, fitData.vy, fitData.vz, fitData.sFitFunction, fitData.sRestrictions, paramsMap, fitData.dPrecision, fitData.nMaxIterations))
1312 {
1313 if (_option.systemPrints())
1314 NumeReKernel::printPreFmt(_lang.get("COMMON_FAILURE") + "!\n");
1315
1316 throw SyntaxError(SyntaxError::FUNCTION_CANNOT_BE_FITTED, sFuncDisplay, sFuncDisplay, sFuncDisplay);
1317 }
1318
1319 sFunctionDefString = "Fit(x,y) := " + sFuncDisplay + " " + _lang.get("PARSERFUNCS_FIT_DEFINECOMMENT");
1320 }
1321 else if (fitData.nDim == 5)
1322 {
1323 if (!_fControl.fit(fitData.vx, fitData.vy, fitData.vz, fitData.vz_w, fitData.sFitFunction, fitData.sRestrictions, paramsMap, fitData.dPrecision, fitData.nMaxIterations))
1324 {
1325 if (_option.systemPrints())
1326 NumeReKernel::printPreFmt(_lang.get("COMMON_FAILURE") + "!\n");
1327
1328 throw SyntaxError(SyntaxError::FUNCTION_CANNOT_BE_FITTED, sFuncDisplay, sFuncDisplay, sFuncDisplay);
1329 }
1330
1331 sFunctionDefString = "Fitw(x,y) := " + sFuncDisplay + " " + _lang.get("PARSERFUNCS_FIT_DEFINECOMMENT");
1332 }
1333
1334 return sFunctionDefString;
1335}
1336
1337
1338// This static function multiplies the elements in the covariance
1339// matrix with the "correct" reduced chi^2 value (this depends
1340// upon whether fitting weights shall be used for fitting)
1341static void calculateCovarianceData(FittingData& fitData, double dChisq, size_t paramsMapSize)
1342{
1343 // Do nothing, if fitting weights have been used
1344 if (fitData.bUseErrors)
1345 return;
1346
1347 double dSize = (fitData.vz.size()) ? (fitData.vz.size() * fitData.vz[0].size()) : fitData.vx.size();
1348 double dFactor = dChisq;
1349
1350 // Calculate the factor depending on the number of fitting dimensions
1351 if (!(fitData.nFitVars & 2))
1352 dFactor /= dSize - paramsMapSize;
1353 else
1354 dFactor /= dSize*dSize - paramsMapSize;
1355
1356 // SCale all elements in the covariance matrix with the
1357 // calculated factor
1358 for (unsigned int i = 0; i < fitData.vz_w.size(); i++)
1359 {
1360 for (unsigned int j = 0; j < fitData.vz_w[0].size(); j++)
1361 {
1362 fitData.vz_w[i][j] *= dFactor;
1363 }
1364 }
1365
1366}
1367
1368
1369// This static function returns a string containing the whole fitting
1370// options (algorithm parameters, etc.)
1371static string getFitOptionsTable(Fitcontroller& _fControl, FittingData& fitData, const string& sFuncDisplay, const string& sFittedFunction, const string& sDimsForFitLog, double dChisq, const mu::varmap_type& paramsMap, size_t nSize, bool forFitLog)
1372{
1373 string sFitParameterTable;
1374 string sPrefix;
1375
1376 if (forFitLog)
1377 {
1378 sFitParameterTable += _lang.get("PARSERFUNCS_FIT_FUNCTION", sFuncDisplay) + "\n";
1379 sFitParameterTable += _lang.get("PARSERFUNCS_FIT_FITTED_FUNC", sFittedFunction) + "\n";
1380 sFitParameterTable += _lang.get("PARSERFUNCS_FIT_DATASET") + " " + sDimsForFitLog + "\n";
1381 }
1382 else
1383 {
1384 sFitParameterTable += _lang.get("PARSERFUNCS_FIT_FUNCTION", sFittedFunction) + "\n";
1385 sPrefix = "|-> ";
1386 }
1387
1388 if (fitData.bUseErrors)
1389 sFitParameterTable += sPrefix + _lang.get("PARSERFUNCS_FIT_POINTS_W_ERR", toString((int)nSize)) + "\n";
1390 else
1391 sFitParameterTable += sPrefix + _lang.get("PARSERFUNCS_FIT_POINTS_WO_ERR", toString((int)nSize)) + "\n";
1392
1393 if (fitData.restricted[0])
1394 sFitParameterTable += sPrefix + _lang.get("PARSERFUNCS_FIT_COORD_RESTRICTS", "x", toString(fitData.ivl[0].min(), 5), toString(fitData.ivl[0].max(), 5)) + "\n";
1395
1396 if (fitData.restricted[1])
1397 sFitParameterTable += sPrefix + _lang.get("PARSERFUNCS_FIT_COORD_RESTRICTS", "y", toString(fitData.ivl[1].min(), 5), toString(fitData.ivl[1].max(), 5)) + "\n";
1398
1399 if (fitData.restricted[2])
1400 sFitParameterTable += sPrefix + _lang.get("PARSERFUNCS_FIT_COORD_RESTRICTS", "z", toString(fitData.ivl[2].min(), 5), toString(fitData.ivl[2].max(), 5)) + "\n";
1401
1402
1403 if (fitData.sRestrictions.length())
1404 sFitParameterTable += sPrefix + _lang.get("PARSERFUNCS_FIT_PARAM_RESTRICTS", fitData.sRestrictions) + "\n";
1405
1406 sFitParameterTable += sPrefix + _lang.get("PARSERFUNCS_FIT_FREEDOMS", toString((int)nSize - paramsMap.size())) + "\n";
1407 sFitParameterTable += sPrefix + _lang.get("PARSERFUNCS_FIT_ALGORITHM_SETTINGS", toString(fitData.dPrecision, 5), toString(fitData.nMaxIterations)) + "\n";
1408 sFitParameterTable += sPrefix + _lang.get("PARSERFUNCS_FIT_ITERATIONS", toString(_fControl.getIterations())) + "\n";
1409
1410 if (nSize != paramsMap.size() && !(fitData.nFitVars & 2))
1411 {
1412 sFitParameterTable += sPrefix + _lang.get("PARSERFUNCS_FIT_CHI2", toString(dChisq, 7)) + "\n";
1413 sFitParameterTable += sPrefix + _lang.get("PARSERFUNCS_FIT_RED_CHI2", toString(dChisq / (double) (nSize - paramsMap.size()), 7)) + "\n";
1414 sFitParameterTable += sPrefix + _lang.get("PARSERFUNCS_FIT_STD_DEV", toString(sqrt(_fControl.getFitChi() / (double)(nSize - paramsMap.size())), 7)) + "\n";
1415 }
1416 else if (fitData.nFitVars & 2 && nSize != paramsMap.size() )
1417 {
1418 sFitParameterTable += sPrefix + _lang.get("PARSERFUNCS_FIT_CHI2", toString(dChisq, 7)) + "\n";
1419 sFitParameterTable += sPrefix + _lang.get("PARSERFUNCS_FIT_RED_CHI2", toString(dChisq / (double) (nSize - paramsMap.size()), 7)) + "\n";
1420 sFitParameterTable += sPrefix + _lang.get("PARSERFUNCS_FIT_STD_DEV", toString(sqrt(_fControl.getFitChi() / (double)(nSize - paramsMap.size())), 7)) + "\n";
1421 }
1422
1423 return sFitParameterTable;
1424}
1425
1426
1427// This static function returns the layouted covariance matrix
1428// as a string for printing in file and to terminal
1429static string constructCovarianceMatrix(FittingData& fitData, size_t paramsMapSize, bool forFitLog)
1430{
1431 string sCovMatrix;
1432
1433 // Construct the whole matrix as a string
1434 for (unsigned int n = 0; n < paramsMapSize; n++)
1435 {
1436 // The terminal requires some indentation
1437 if (!forFitLog)
1438 sCovMatrix += "| ";
1439
1440 // Append the part of the opening parenthesis
1441 if (!n)
1442 sCovMatrix += "/";
1443 else if (n + 1 == paramsMapSize)
1444 sCovMatrix += "\\";
1445 else
1446 sCovMatrix += "|";
1447
1448 // Write the current matrix line
1449 for (unsigned int k = 0; k < paramsMapSize; k++)
1450 {
1451 sCovMatrix += " " + strfill(toString(fitData.vz_w[n][k] / sqrt(fabs(fitData.vz_w[n][n] * fitData.vz_w[k][k])), 3), 10);
1452 }
1453
1454 // Append the part of the closing parenthesis
1455 if (!n)
1456 sCovMatrix += " \\\n";
1457 else if (n + 1 == paramsMapSize)
1458 sCovMatrix += " /\n";
1459 else
1460 sCovMatrix += " |\n";
1461 }
1462
1463 return sCovMatrix;
1464}
1465
1466
1467// This static function returns the fitting paramters including
1468// their initial and final values as a string
1469static string getParameterTable(FittingData& fitData, mu::varmap_type& paramsMap, const vector<double>& vInitialVals, size_t windowSize, const string& sPMSign, bool forFitLog)
1470{
1472 auto pItem = paramsMap.begin();
1473 string sParameterTable;
1474
1475 // Construct the fitting parameter table as a single string
1476 for (size_t n = 0; n < paramsMap.size(); n++)
1477 {
1478 if (pItem == paramsMap.end())
1479 break;
1480
1481 // The terminal requires some indentation
1482 if (!forFitLog)
1483 sParameterTable += "| ";
1484
1485 // Write the single fitting parameter line including
1486 // parameter name, initial and final value and errors
1487 sParameterTable += pItem->first + " "
1488 + strfill(toString(vInitialVals[n], _option), (pItem->first.length() > (windowSize - 32) / 2 + windowSize % 2 ? 0u : (windowSize - 32) / 2 + windowSize % 2 - pItem->first.length()))
1489 + strfill(toString(*(pItem->second), _option.getPrecision()), (windowSize - 50) / 2)
1490 + strfill(sPMSign + " " + toString(sqrt(abs(fitData.vz_w[n][n])), 5), 16);
1491
1492 // Append the percentage of error compared to the final
1493 // value if the final value does exist
1494 if (fitData.vz_w[n][n])
1495 // Changed the position of the sqrt as it contained the parameter itself
1496 sParameterTable += " " + strfill("(" + toString(abs(sqrt(abs(fitData.vz_w[n][n])) / (*(pItem->second)) * 100.0), 4) + "%)", 16) + "\n";
1497 else
1498 sParameterTable += "\n";
1499
1500 ++pItem;
1501 }
1502
1503 return sParameterTable;
1504}
1505
1506
1507// This static function calculates the average of the percentual
1508// fitting errors and creates the variables for storing the
1509// fitting errors for each parameter for further calculations
1510static double calculatePercentageAvgAndCreateParserVariables(FittingData& fitData, mu::varmap_type& paramsMap, double dChisq)
1511{
1513 string sErrors = "";
1514 auto pItem = paramsMap.begin();
1515 double dAverageErrorPercentage = 0.0;
1516
1517 // Go through all fitting parameters and summarize the
1518 // percentual errors and construct error variables, if the
1519 // user required them
1520 for (unsigned int n = 0; n < paramsMap.size(); n++)
1521 {
1522 if (pItem == paramsMap.end())
1523 break;
1524
1525 // Add the percentage value
1526 if (fitData.vz_w[n][n])
1527 {
1528 dAverageErrorPercentage += abs(sqrt(abs(fitData.vz_w[n][n] / (*(pItem->second)))) * 100.0);
1529 }
1530
1531 // Add a constructed variable containing the error value
1532 if (fitData.bSaveErrors)
1533 {
1534 sErrors += pItem->first + "_error = " + toCmdString(sqrt(abs(fitData.vz_w[n][n]))) + ",";
1535 }
1536
1537 ++pItem;
1538 }
1539
1540 // Devide the sum to obtain the average value
1541 dAverageErrorPercentage /= (double)paramsMap.size();
1542
1543 // Create the error variables and the chi variable
1544 if (fitData.bSaveErrors)
1545 {
1546 sErrors.pop_back();
1547 _parser.SetExpr(sErrors);
1548 _parser.Eval();
1549 }
1550
1551 _parser.SetExpr("chi = " + toCmdString(sqrt(dChisq)));
1552 _parser.Eval();
1553
1554 return dAverageErrorPercentage;
1555}
1556
1557
1558// This static function returns the fitting analysis depending
1559// upon the chi^2 value and the sum of the percentual errors
1560static string getFitAnalysis(Fitcontroller& _fControl, FittingData& fitData, double dNormChisq, double dAverageErrorPercentage, bool noOverfitting)
1561{
1562 if (fitData.nFitVars & 2)
1563 dNormChisq = sqrt(dNormChisq);
1564
1565 if (_fControl.getIterations() == fitData.nMaxIterations)
1566 {
1567 return _lang.get("PARSERFUNCS_FIT_MAXITER_REACHED");
1568 }
1569 else
1570 {
1571 if (noOverfitting)
1572 {
1573 if (fitData.bUseErrors)
1574 {
1575 if (log10(dNormChisq) > -1.0 && log10(dNormChisq) < 0.5 && dAverageErrorPercentage < 50.0)
1576 return _lang.get("PARSERFUNCS_FIT_GOOD_W_ERROR");
1577 else if (log10(dNormChisq) <= -1.0 && dAverageErrorPercentage < 20.0)
1578 return _lang.get("PARSERFUNCS_FIT_BETTER_W_ERROR");
1579 else if (log10(dNormChisq) >= 0.5 && log10(dNormChisq) < 1.5 && dAverageErrorPercentage < 100.0)
1580 return _lang.get("PARSERFUNCS_FIT_NOT_GOOD_W_ERROR");
1581 else
1582 return _lang.get("PARSERFUNCS_FIT_BAD_W_ERROR");
1583 }
1584 else
1585 {
1586 if (log10(dNormChisq) < -3.0 && dAverageErrorPercentage < 20.0)
1587 return _lang.get("PARSERFUNCS_FIT_GOOD_WO_ERROR");
1588 else if (log10(dNormChisq) < 0.0 && dAverageErrorPercentage < 50.0)
1589 return _lang.get("PARSERFUNCS_FIT_IMPROVABLE_WO_ERROR");
1590 else if (log10(dNormChisq) >= 0.0 && log10(dNormChisq) < 0.5 && dAverageErrorPercentage < 100.0)
1591 return _lang.get("PARSERFUNCS_FIT_NOT_GOOD_WO_ERROR");
1592 else
1593 return _lang.get("PARSERFUNCS_FIT_BAD_WO_ERROR");
1594 }
1595 }
1596 else
1597 {
1598 return _lang.get("PARSERFUNCS_FIT_OVERFITTING");
1599 }
1600 }
1601
1602 return "";
1603}
1604
1605
1606// This static function writes the contents of the logfile to
1607// a TeX file, if the used requested this option
1608static void createTeXExport(Fitcontroller& _fControl, const string& sTeXExportFile, const string& sCmd, mu::varmap_type& paramsMap, FittingData& fitData, const vector<double>& vInitialVals, size_t nSize, const string& sFitAnalysis, const string& sFuncDisplay, const string& sFittedFunction, double dChisq)
1609{
1610 ofstream oTeXExport;
1611
1612 oTeXExport.open(sTeXExportFile.c_str(), ios_base::trunc);
1613
1614 // Ensure that the file stream can be opened
1615 if (oTeXExport.fail())
1616 {
1617 oTeXExport.close();
1620 }
1621
1622 // Write the headline to the TeX file
1623 oTeXExport << "%\n% " << _lang.get("OUTPUT_PRINTLEGAL_TEX") << "\n%" << endl;
1624 oTeXExport << "\\section{" << _lang.get("PARSERFUNCS_FIT_HEADLINE") << ": " << getTimeStamp(false) << "}" << endl;
1625 oTeXExport << "\\begin{itemize}" << endl;
1626 oTeXExport << "\t\\item " << _lang.get("PARSERFUNCS_FIT_FUNCTION", "$" + replaceToTeX(sFuncDisplay, true) + "$") << endl;
1627 oTeXExport << "\t\\item " << _lang.get("PARSERFUNCS_FIT_FITTED_FUNC", "$" + replaceToTeX(sFittedFunction, true) + "$") << endl;
1628
1629 if (fitData.bUseErrors)
1630 oTeXExport << "\t\\item " << _lang.get("PARSERFUNCS_FIT_POINTS_W_ERR", toString((int)nSize)) << endl;
1631 else
1632 oTeXExport << "\t\\item " << _lang.get("PARSERFUNCS_FIT_POINTS_WO_ERR", toString((int)nSize)) << endl;
1633
1634 if (fitData.restricted[0])
1635 oTeXExport << "\t\\item " << _lang.get("PARSERFUNCS_FIT_COORD_RESTRICTS", "x", toString(fitData.ivl[0].min(), 5), toString(fitData.ivl[0].max(), 5)) << endl;
1636
1637 if (fitData.restricted[1])
1638 oTeXExport << "\t\\item " << _lang.get("PARSERFUNCS_FIT_COORD_RESTRICTS", "y", toString(fitData.ivl[1].min(), 5), toString(fitData.ivl[1].max(), 5)) << endl;
1639
1640 if (fitData.restricted[2])
1641 oTeXExport << "\t\\item " << _lang.get("PARSERFUNCS_FIT_COORD_RESTRICTS", "z", toString(fitData.ivl[2].min(), 5), toString(fitData.ivl[2].max(), 5)) << endl;
1642
1643 if (fitData.sRestrictions.length())
1644 oTeXExport << "\t\\item " << _lang.get("PARSERFUNCS_FIT_PARAM_RESTRICTS", "$" + replaceToTeX(fitData.sRestrictions, true) + "$") << endl;
1645
1646 oTeXExport << "\t\\item " << _lang.get("PARSERFUNCS_FIT_FREEDOMS", toString((int)nSize - paramsMap.size())) << endl;
1647 oTeXExport << "\t\\item " << _lang.get("PARSERFUNCS_FIT_ALGORITHM_SETTINGS", toString(fitData.dPrecision, 5), toString(fitData.nMaxIterations)) << endl;
1648 oTeXExport << "\t\\item " << _lang.get("PARSERFUNCS_FIT_ITERATIONS", toString(_fControl.getIterations())) << endl;
1649
1650 // Write the calculated fitting result values to the TeX file
1651 if (nSize != paramsMap.size() && !(fitData.nFitVars & 2))
1652 {
1653 string sChiReplace = _lang.get("PARSERFUNCS_FIT_CHI2", toString(dChisq, 7));
1654 sChiReplace.replace(sChiReplace.find("chi^2"), 5, "$\\chi^2$");
1655 oTeXExport << "\t\\item " << sChiReplace << endl;
1656 sChiReplace = _lang.get("PARSERFUNCS_FIT_RED_CHI2", toString(dChisq / (double) (nSize - paramsMap.size()), 7));
1657 sChiReplace.replace(sChiReplace.find("chi^2"), 5, "$\\chi^2$");
1658 oTeXExport << "\t\\item " << sChiReplace << endl;
1659 oTeXExport << "\t\\item " << _lang.get("PARSERFUNCS_FIT_STD_DEV", toString(sqrt(_fControl.getFitChi() / (double)(nSize - paramsMap.size())), 7)) << endl;
1660 }
1661 else if (fitData.nFitVars & 2 && nSize != paramsMap.size())
1662 {
1663 string sChiReplace = _lang.get("PARSERFUNCS_FIT_CHI2", toString(dChisq, 7));
1664 sChiReplace.replace(sChiReplace.find("chi^2"), 5, "$\\chi^2$");
1665 oTeXExport << "\t\\item " << sChiReplace << endl;
1666 sChiReplace = _lang.get("PARSERFUNCS_FIT_RED_CHI2", toString(dChisq / (double) (nSize - paramsMap.size()), 7));
1667 sChiReplace.replace(sChiReplace.find("chi^2"), 5, "$\\chi^2$");
1668 oTeXExport << "\t\\item " << sChiReplace << endl;
1669 oTeXExport << "\t\\item " << _lang.get("PARSERFUNCS_FIT_STD_DEV", toString(sqrt(_fControl.getFitChi() / (double)(nSize - paramsMap.size())), 7)) << endl;
1670 }
1671
1672 // Start the table for the fitting parameters
1673 oTeXExport << "\\end{itemize}" << endl << "\\begin{table}[htb]" << endl << "\t\\centering\n\t\\begin{tabular}{cccc}" << endl << "\t\t\\toprule" << endl;
1674
1675 // Write the headline for the fitting parameters
1676 if (fitData.bUseErrors)
1677 oTeXExport << "\t\t" << _lang.get("PARSERFUNCS_FIT_PARAM") << " & "
1678 << _lang.get("PARSERFUNCS_FIT_INITIAL") << " & "
1679 << _lang.get("PARSERFUNCS_FIT_FITTED") << " & "
1680 << _lang.get("PARSERFUNCS_FIT_PARAM_DEV") << "\\\\" << endl;
1681 else
1682 oTeXExport << "\t\t" << _lang.get("PARSERFUNCS_FIT_PARAM") << " & "
1683 << _lang.get("PARSERFUNCS_FIT_INITIAL") << " & "
1684 << _lang.get("PARSERFUNCS_FIT_FITTED") << " & "
1685 << _lang.get("PARSERFUNCS_FIT_ASYMPTOTIC_ERROR") << "\\\\" << endl;
1686
1687 oTeXExport << "\t\t\\midrule" << endl;
1688
1689 auto pItem = paramsMap.begin();
1690 string sErrors = "";
1691 string sPMSign = " ";
1692
1693 // Write the fitting parameters linewise to the table
1694 for (unsigned int n = 0; n < paramsMap.size(); n++)
1695 {
1696 if (pItem == paramsMap.end())
1697 break;
1698
1699 oTeXExport << "\t\t$" << replaceToTeX(pItem->first, true) << "$ & $"
1700 << vInitialVals[n] << "$ & $"
1701 << *(pItem->second) << "$ & $\\pm"
1702 << sqrt(abs(fitData.vz_w[n][n]));
1703
1704 // Append the percentual error value, if the current parameter
1705 // is non-zero.
1706 if (fitData.vz_w[n][n])
1707 {
1708 oTeXExport << " \\quad (" + toString(abs(sqrt(abs(fitData.vz_w[n][n] / (*(pItem->second)))) * 100.0), 4) + "\\%)$\\\\" << endl;
1709 }
1710 else
1711 oTeXExport << "$\\\\" << endl;
1712
1713 ++pItem;
1714 }
1715
1716 // Close the fitting parameter table
1717 oTeXExport << "\t\t\\bottomrule" << endl << "\t\\end{tabular}" << endl << "\\end{table}" << endl;
1718
1719 // Write the correlation matrix
1720 if (paramsMap.size() > 1 && paramsMap.size() != nSize)
1721 {
1722 oTeXExport << endl << "\\subsection{" << _lang.get("PARSERFUNCS_FIT_CORRELMAT_HEAD") << "}" << endl;
1723 oTeXExport << "\\[" << endl << "\t\\begin{pmatrix}" << endl;
1724
1725 for (unsigned int n = 0; n < paramsMap.size(); n++)
1726 {
1727 oTeXExport << "\t\t";
1728
1729 for (unsigned int k = 0; k < paramsMap.size(); k++)
1730 {
1731 oTeXExport << fitData.vz_w[n][k] / sqrt(fabs(fitData.vz_w[n][n]*fitData.vz_w[k][k]));
1732
1733 if (k + 1 < paramsMap.size())
1734 oTeXExport << " & ";
1735 }
1736
1737 oTeXExport << "\\\\" << endl;
1738 }
1739
1740 oTeXExport << "\t\\end{pmatrix}" << endl << "\\]" << endl;
1741
1742 }
1743
1744 oTeXExport << endl;
1745 oTeXExport << "\\subsection{" << _lang.get("PARSERFUNCS_FIT_ANALYSIS") << "}" << endl;
1746 oTeXExport << sFitAnalysis << endl;
1747 oTeXExport.close();
1748}
1749
1750
std::string ValidFileName(std::string _sFileName, const std::string sExtension=".dat", bool checkExtension=true, bool doCleanPath=true) const
This member function evaluates, whether the passed filename is a valid filename. One may supply a pre...
Definition: filesystem.cpp:280
This class contains the internal fit logic and the interface to the GSL fitting module.
bool fit(FitVector &vx, FitVector &vy, const std::string &__sExpr, const std::string &__sRestrictions, mu::varmap_type &mParamsMap, double __dPrecision=1e-4, int nMaxIterations=500)
Calculate an unweighted 1D-fit.
int getIterations() const
Return the number of needed iterations.
FitMatrix getCovarianceMatrix() const
Returns the covariance matrix of the performed fit.
double getFitChi() const
Return the weighted sum of the residuals.
std::string getFitFunction()
Returns the fit function, where each parameter is replaced with its value converted to a string.
This class implements the function definition managing instance.
Definition: define.hpp:74
std::string getDefinitionString(size_t _i) const
Returns the definition string of the ith defined custom function.
Definition: define.cpp:964
bool defineFunc(const std::string &sExpr, bool bRedefine=false, bool bFallback=false)
This function defines a custom function, by passing it to a new FunctionDefinition class instance.
Definition: define.cpp:655
bool call(std::string &sExpr, int nRecursion=0)
This function searches for known custom definitions in the passed expression and replaces them with t...
Definition: define.cpp:801
bool isDefined(const std::string &sFunc)
This method checks, whether the passed function is already defined.
Definition: define.cpp:625
size_t getFunctionIndex(const std::string &sFuncName)
Returns the numerical index of the selected custom defined functions.
Definition: define.hpp:179
std::string get(const std::string &sMessage, const std::vector< std::string > &vTokens) const
This member function returns the language string for the passed language identifier and replaces all ...
Definition: language.cpp:292
This class represents the central memory managing instance. It will handle all tables and clusters,...
mu::value_type getElement(int _nLine, int _nCol, const std::string &_sTable) const
bool isValidElement(long long int _nLine, long long int _nCol, const std::string &_sTable) const
std::vector< mu::value_type > min(const std::string &sTable, std::string sDir) const
int getLines(StringView sTable, bool _bFull=false) const
std::vector< mu::value_type > num(const std::string &sTable, std::string sDir) const
std::string getHeadLineElement(int _i, const std::string &_sTable) const
std::vector< mu::value_type > max(const std::string &sTable, std::string sDir) const
bool containsTablesOrClusters(const std::string &sCmdLine)
This member function evaluates, whether the passed command line contains tables or clusters.
void writeToTable(int _nLine, int _nCol, const std::string &_sCache, const mu::value_type &_dData)
bool setHeadLineElement(int _i, const std::string &_sTable, std::string _sHead)
int getCols(StringView sTable, bool _bFull=false) const
size_t size() const
This member function returns the size of the internal memory buffer as items.
Definition: cluster.cpp:356
Cluster & getCluster(StringView sCluster)
This member function returns a reference to the cluster indicated by the passed cluster identifier.
Definition: cluster.cpp:2077
std::string getDataFileName(const std::string &sTable) const
This member function will return the file name of the selected table. Will default to the table name.
virtual bool isStringExpression(const std::string &sExpression) override
Returns true, if the passed expression is an expression containing strings, string variables or strin...
static NumeReKernel * getInstance()
This static member function returns a a pointer to the singleton instance of the kernel.
Definition: kernel.hpp:221
NumeRe::StringParser & getStringParser()
Definition: kernel.hpp:286
static void printPreFmt(const std::string &__sLine, bool printingEnabled=true)
This member function appends the pre- formatted string to the buffer and informs the terminal that we...
Definition: kernel.cpp:2683
mu::Parser & getParser()
Definition: kernel.hpp:281
MemoryManager & getMemoryManager()
Definition: kernel.hpp:263
static void print(const std::string &__sLine, bool printingEnabled=true)
This member function appends the passed string as a new output line to the buffer and informs the ter...
Definition: kernel.cpp:2636
FunctionDefinitionManager & getDefinitions()
Definition: kernel.hpp:291
static void issueWarning(std::string sWarningMessage)
This static function may be used to issue a warning to the user. The warning will be printed by the t...
Definition: kernel.cpp:2833
static void toggleTableStatus()
Toggles the table writing status, which will reduce the number or events send to the terminal.
Definition: kernel.cpp:3671
Settings & getSettings()
Definition: kernel.hpp:296
This class manages the setting values of the internal (kernel) settings of this application.
Definition: settings.hpp:663
bool systemPrints() const
Returns, whether system messages shall be printed to the terminal.
Definition: settings.hpp:1140
size_t getPrecision() const
Returns the precision for displaying floating numbers in the terminal. This value determines the numb...
Definition: settings.hpp:1000
size_t getWindow(int nWindow=0) const
Returns the current window size of the terminal.
Definition: settings.hpp:1101
Common exception class for all exceptions thrown in NumeRe.
Definition: error.hpp:32
@ NO_PARAMS_FOR_FIT
Definition: error.hpp:178
@ CANNOT_BE_A_FITTING_PARAM
INSERT HERE.
Definition: error.hpp:51
@ FUNCTION_CANNOT_BE_FITTED
Definition: error.hpp:109
@ CANNOT_OPEN_TARGET
Definition: error.hpp:73
@ FUNCTION_ERROR
Definition: error.hpp:110
@ TOO_FEW_COLS
Definition: error.hpp:213
@ CANNOT_OPEN_FITLOG
Definition: error.hpp:70
@ OVERFITTING_ERROR
Definition: error.hpp:187
@ FITFUNC_NOT_CONTAINS
Definition: error.hpp:106
@ NO_FUNCTION_FOR_FIT
Definition: error.hpp:170
@ INVALID_INDEX
Definition: error.hpp:129
@ NO_DATA_FOR_FIT
Definition: error.hpp:161
static size_t invalid_position
Definition: error.hpp:235
This class abstracts all the index logics, i.e. the logical differences between single indices and in...
Definition: structures.hpp:42
VectorIndex subidx(size_t pos, size_t nLen=std::string::npos) const
This member function returns a subset of the internal stored index just like the std::string::substr(...
Definition: structures.hpp:238
int last() const
This member function returns the last index value, which can be reached by the values stored internal...
Definition: structures.hpp:693
size_t size() const
This member function returns the size of the indices stored in this class.
Definition: structures.hpp:314
bool isOpenEnd() const
This member function determines, whether the internal index set has an open end.
Definition: structures.hpp:614
void setRange(int nMin, int nMax)
This member function can be used to force the indices stored internally to be in a defined interval....
Definition: structures.hpp:712
std::string to_string() const
This member function converts the vector indexes contents into a human-readable string representation...
Definition: structures.hpp:770
int & back()
This member function returns a reference to the final index value stored internally.
Definition: structures.hpp:653
bool isExpanded() const
This member function determines, whether the indices are calculated or actual vectorial indices.
Definition: structures.hpp:377
int & front()
This member function returns a reference to the first index value stored internally.
Definition: structures.hpp:640
void SetExpr(StringView a_sExpr)
Set the expression. Triggers first time calculation thus the creation of the bytecode and scanning of...
value_type Eval()
Single-value wrapper around the vectorized overload of this member function.
const varmap_type & GetUsedVar()
Return a map containing the used variables only.
Mathematical expressions parser.
Definition: muParser.h:51
mu::value_type getDataFromObject(const std::string &sObject, long long int i, long long int j, bool isCluster)
This function returns the data from the selected object and switches automatically between tables and...
string getDataElements(string &sLine, Parser &_parser, MemoryManager &_data, const Settings &_option, int options)
Searches the passed string for calls to any table or cluster and replaces them with internal vectors ...
Definition: dataaccess.cpp:276
Indices getIndicesForPlotAndFit(const string &sExpression, string &sDataTable, int &nColumns, bool &openEnd, bool &isCluster)
This function will calculate the indices from the passed data expression and return them optimized fo...
Indices getIndices(StringView sCmd, mu::Parser &_parser, MemoryManager &_data, const Settings &_option)
Wrapper for the new getIndices function interface.
Definition: indices.cpp:49
bool isValidIndexSet(const Indices &_idx)
Definition: dataaccess.hpp:81
Language _lang
Definition: kernel.cpp:39
std::string toSystemCodePage(std::string)
Converts an internal to an external string. Does nothing currently.
static void createTeXExport(Fitcontroller &_fControl, const std::string &sTeXExportFile, const std::string &sCmd, mu::varmap_type &paramsMap, FittingData &fitData, const std::vector< double > &vInitialVals, size_t nSize, const std::string &sFitAnalysis, const std::string &sFuncDisplay, const std::string &sFittedFunction, double dChisq)
Definition: fitting.cpp:1608
static std::vector< double > evaluateFittingParams(FittingData &fitData, std::string &sCmd, Indices &_idx, std::string &sTeXExportFile, bool &bTeXExport, bool &bMaskDialog)
Definition: fitting.cpp:406
bool fitDataSet(string &sCmd, Parser &_parser, MemoryManager &_data, FunctionDefinitionManager &_functions, const Settings &_option)
Definition: fitting.cpp:73
static int getDataForFit(const std::string &sCmd, std::string &sDimsForFitLog, FittingData &fitData)
Definition: fitting.cpp:751
static mu::varmap_type getFittingParameters(FittingData &fitData, const mu::varmap_type &varMap, const std::string &sCmd)
Definition: fitting.cpp:681
static std::string applyFitAlgorithm(Fitcontroller &_fControl, FittingData &fitData, mu::varmap_type &paramsMap, const std::string &sFuncDisplay, const std::string &sCmd)
Definition: fitting.cpp:1277
static double calculatePercentageAvgAndCreateParserVariables(FittingData &fitData, mu::varmap_type &paramsMap, double dChisq)
Definition: fitting.cpp:1510
static std::string getFitAnalysis(Fitcontroller &_fControl, FittingData &fitData, double dNormChisq, double dAverageErrorPercentage, bool noOverfitting)
Definition: fitting.cpp:1560
static bool calculateChiMap(std::string sFunctionDefString, const std::string &sFuncDisplay, Indices &_idx, mu::varmap_type &varMap, mu::varmap_type &paramsMap, FittingData &fitData, std::vector< double > vInitialVals)
Definition: fitting.cpp:1144
static std::string getFitOptionsTable(Fitcontroller &_fControl, FittingData &fitData, const std::string &sFuncDisplay, const std::string &sFittedFunction, const std::string &sDimsForFitLog, double dChisq, const mu::varmap_type &paramsMap, size_t nSize, bool forFitLog)
Definition: fitting.cpp:1371
static void removeObsoleteParentheses(std::string &sFunction)
Definition: fitting.cpp:1121
static std::string constructCovarianceMatrix(FittingData &fitData, size_t paramsMapSize, bool forFitLog)
Definition: fitting.cpp:1429
static void calculateCovarianceData(FittingData &fitData, double dChisq, size_t paramsMapSize)
Definition: fitting.cpp:1341
static std::string getParameterTable(FittingData &fitData, mu::varmap_type &paramsMap, const std::vector< double > &vInitialVals, size_t windowSize, const std::string &sPMSign, bool forFitLog)
Definition: fitting.cpp:1469
std::string strfill(const std::string &sString, unsigned int nWidth, char cFill=' ', bool limit=false)
This function fills the passed string up to the width nWidth with the characters cFill....
Definition: kernel.hpp:408
unsigned int getMatchingParenthesis(const StringView &)
Returns the position of the closing parenthesis.
Definition: tools.cpp:414
CONSTCD11 std::enable_if<!std::chrono::treat_as_floating_point< T >::value, T >::type trunc(T t) NOEXCEPT
Definition: date.h:1113
CONSTCD11 std::chrono::duration< Rep, Period > abs(std::chrono::duration< Rep, Period > d)
Definition: date.h:1317
MUP_BASETYPE value_type
The numeric datatype used by the parser.
Definition: muParserDef.h:251
bool isnan(const value_type &v)
Definition: muParserDef.h:379
bool isinf(const value_type &v)
Definition: muParserDef.h:374
std::map< string_type, value_type * > varmap_type
Type used for storing variables.
Definition: muParserDef.h:273
value_type rint(value_type v)
bool evaluateIndices(const string &sCache, Indices &_idx, MemoryManager &_data)
This function will evaluate the passed indices, so that they match the dimensions of the passed cache...
void convertVectorToExpression(string &sLine, const Settings &_option)
This function replaces vector expressions with their corresponding multi- expression equation.
vector< double > readAndParseIntervals(string &sExpr, Parser &_parser, MemoryManager &_data, FunctionDefinitionManager &_functions, const Settings &_option, bool bEraseInterval)
This function will read the interval syntax in commands and return their values in a single vector.
void StripSpaces(std::string &)
Removes leading and trailing white spaces and tabulator characters.
int findParameter(const std::string &sCmd, const std::string &sParam, const char cFollowing)
This function searches the passed parameter in the passed command string. If something is found,...
Definition: tools.cpp:113
std::string toUpperCase(const std::string &sLowerCase)
Converts lowercase letters to uppercase ones.
std::string toCmdString(double dNumber)
Converts a numerical value into a "full" precision string.
std::string getTimeStamp(bool bGetStamp)
This function simple returns the current time as a default timestamp.
std::string sRestrictions
Definition: fitting.cpp:49
std::string sParams
Definition: fitting.cpp:50
std::vector< double > vy
Definition: fitting.cpp:31
std::string sFitFunction
Definition: fitting.cpp:48
std::vector< std::vector< double > > vz_w
Definition: fitting.cpp:34
bool restricted[3]
Definition: fitting.cpp:37
size_t nFitVars
Definition: fitting.cpp:40
bool bNoParams
Definition: fitting.cpp:43
IntervalSet ivl
Definition: fitting.cpp:36
double dPrecision
Definition: fitting.cpp:45
std::vector< double > vy_w
Definition: fitting.cpp:32
std::vector< std::vector< double > > vz
Definition: fitting.cpp:33
bool bUseErrors
Definition: fitting.cpp:41
std::vector< double > vx
Definition: fitting.cpp:30
int nMaxIterations
Definition: fitting.cpp:46
bool b1DChiMap
Definition: fitting.cpp:44
std::string sChiMap_Vars[2]
Definition: fitting.cpp:52
size_t nDim
Definition: fitting.cpp:39
bool bSaveErrors
Definition: fitting.cpp:42
std::string sChiMap
Definition: fitting.cpp:51
This structure is central for managing the indices of a table or cluster read or write data access....
VectorIndex col
VectorIndex row
This class represents a set of intervals used together for calculations and simulations.
Definition: interval.hpp:84
std::vector< Interval > intervals
Definition: interval.hpp:85
std::string toString(int)
Converts an integer to a string without the Settings bloat.
Match findCommand(StringView sCmd, const std::string &sCommand)
This function is very important for the command handler.
Definition: tools.cpp:1275
string getArgAtPos(const string &sCmd, unsigned int nPos, int extraction)
Extracts a options value at the selected position and applies automatic parsing, if necessary.
Definition: tools.cpp:1598
std::string replaceToTeX(const std::string &sString, bool replaceForTeXFile)
Replace the special tokens with their TeX counterparts, so that they can be handled by a LaTeX interp...
Definition: tools.cpp:753
void reduceLogFilesize(const string &sFileName)
This function is used to reduce the log file size from >= 100.000 to 20.000 lines to reduce the neede...
Definition: tools.cpp:2998
std::string LineBreak(std::string sOutput, const Settings &_option, bool bAllowDashBreaks, int nFirstIndent, int nIndent)
This function takes a string, splits it into multiple lines if it is too long and returns the result.
Definition: tools.cpp:2205
void eraseToken(string &sExpr, const string &sToken, bool bTokenHasValue)
This function erases option tokens including their possible value from a parameter string.
Definition: tools.cpp:2527
void make_hline(int nLength=-1)
This function prints a horizontal line to the terminal using either minus or equal signs.
Definition: kernel.cpp:3720
bool isValidValue(double d)
Definition: tools.hpp:84