//---------------------------------------------------------------------------------------------- /// Set initial values to a function if it needs to. /// @param function :: A fitting function. /// @param fun :: A smooth approximation of the fitting data. /// @param der1 :: The first derivative of the fitting data. /// @param der2 :: The second derivative of the fitting data. void setValues(API::IFunction &function, const SimpleChebfun &fun, const SimpleChebfun &der1, const SimpleChebfun &der2) { if (auto cf = dynamic_cast<const API::CompositeFunction *>(&function)) { for (size_t i = 0; i < cf->nFunctions(); ++i) { setValues(*cf->getFunction(i), fun, der1, der2); } return; } switch (whichFunction(function)) { case Gaussian: { double width = getPeakWidth(function.getParameter("PeakCentre"), der2); function.setParameter("Sigma", width); break; } case Lorentzian: { double width = getPeakWidth(function.getParameter("PeakCentre"), der2); function.setParameter("FWHM", width); break; } case BackToBackExponential: { setBackToBackExponential(function, fun, der1, der2); break; } default: break; } }
/// Return a function code for a function if it needs setting values or None /// otherwise. Function whichFunction(const API::IFunction &function) { const FunctionMapType &functionMap = getFunctionMapType(); auto index = functionMap.find(function.name()); if (index != functionMap.end()) { if (!function.isExplicitlySet(index->second.first)) return index->second.second; } return None; }
// Set symmetry C2v, D2 or D2h void setSymmetryC2v(API::IFunction &fun) { fun.clearTies(); fun.unfixParameter("B20"); fun.unfixParameter("B40"); fun.unfixParameter("B60"); fixx(fun, "B21"); free(fun, "B22", real); fixx(fun, "B41"); free(fun, "B42", real); fixx(fun, "B43"); free(fun, "B44", real); fixx(fun, "B61"); free(fun, "B62", real); fixx(fun, "B63"); free(fun, "B64", real); fixx(fun, "B65"); free(fun, "B66", real); }
// Set symmetry T, Td, Th, O, or Oh void setSymmetryT(API::IFunction &fun) { fun.clearTies(); fun.setParameter("B20", 0.0); fun.fixParameter("B20"); fun.unfixParameter("B40"); fun.unfixParameter("B60"); fixx(fun, "B21"); fixx(fun, "B22"); fixx(fun, "B41"); fixx(fun, "B42"); fixx(fun, "B43"); free(fun, "B44", real); fixx(fun, "B61"); fixx(fun, "B62"); fixx(fun, "B63"); free(fun, "B64", real); fixx(fun, "B65"); fixx(fun, "B66"); fun.tie("B44", "5*B40"); fun.tie("B64", "-21*B60"); }
/** * Set a reference to the convolved fitting function. Required as we need a default constructor for the factory * @param fittingFunction :: This object has access to the current value of the model parameters */ void ForegroundModel::setFunctionUnderMinimization(const API::IFunction & fittingFunction) { m_fittingFunction = &fittingFunction; m_parOffset = fittingFunction.nParams(); }
//---------------------------------------------------------------------------------------------- /// Set initial values to a BackToBackExponential. /// @param function :: A fitting BackToBackExponential function. /// @param fun :: A smooth approximation of the fitting data. /// @param der1 :: The first derivative of the fitting data. /// @param der2 :: The second derivative of the fitting data. void setBackToBackExponential(API::IFunction &function, const SimpleChebfun &fun, const SimpleChebfun &der1, const SimpleChebfun &der2) { // Find the actual peak centre and gaussian component of the width auto centre = getPeakCentre(function.getParameter("X0"), der1); double sigma = getPeakWidth(centre, der2); if (sigma == 0.0) sigma = 1e-06; function.setParameter("S", sigma); g_log.debug() << "Estimating parameters of BackToBackExponential\n"; g_log.debug() << "centre= " << centre << '\n'; g_log.debug() << "sigma = " << sigma << '\n'; // Estimate the background level auto xlr = getPeakLeftRightExtent(centre, der2); g_log.debug() << "extent: " << xlr.first - centre << ' ' << xlr.second - centre << '\n'; double yl = fun(xlr.first); double yr = fun(xlr.second); double slope = (yr - yl) / (xlr.second - xlr.first); double background = yl + slope * (centre - xlr.first); double height = fun(centre) - background; g_log.debug() << "height= " << height << '\n'; g_log.debug() << "background= " << background << '\n'; g_log.debug() << "slope= " << slope << '\n'; // Remove the background as it affects A and B parameters. LinearFunction bg(-yl + slope * xlr.first, -slope); SimpleChebfun fun1(fun); fun1 += bg; // Find left and right "HWHM". auto hwhm = getPeakHWHM(centre, height, fun1); g_log.debug() << "HWHM: " << hwhm.first << ' ' << hwhm.second << '\n'; // Find the extent of the default fitting function (with new S set) // to be able to make an approximation with a SimpleChebfun. function.setParameter("I", 1.0); double x0 = function.getParameter("X0"); double leftX = 1.0 / function.getParameter("A"); if (leftX < 3 * sigma) { leftX = 3 * sigma; } leftX = x0 - leftX; double rightX = 1.0 / function.getParameter("B"); if (rightX < 3 * sigma) { rightX = 3 * sigma; } rightX = x0 + rightX; // Find corrections to the default A and B parameters. // A and B are responsible for differences in the widths. { SimpleChebfun b2b(fun.order(), function, leftX, rightX); auto b2b_d1 = b2b.derivative(); auto centre1 = getPeakCentre(x0, b2b_d1); double height1 = b2b(centre1); auto hwhm1 = getPeakHWHM(centre1, height1, b2b); g_log.debug() << "new HWHM: " << hwhm1.first << ' ' << hwhm1.second << '\n'; double denom = hwhm.first + sigma; double aCorr = denom > 0 ? (hwhm1.first + sigma) / denom : 100.0; if (aCorr < 0) { aCorr = 100.0; function.fix(2); } denom = hwhm.second - sigma; double bCorr = denom > 0 ? (hwhm1.second - sigma) / denom : 100.0; if (bCorr < 0) { bCorr = 100.0; function.fix(3); } g_log.debug() << "corrections: " << aCorr << ' ' << bCorr << '\n'; double a = function.getParameter("A") * aCorr; double b = function.getParameter("B") * bCorr; function.setParameter("A", a); function.setParameter("B", b); } // After all shape parameters are set (S, A and B) shift X0 // and scale I. { SimpleChebfun b2b(fun.order(), function, leftX, rightX); auto b2b_d1 = b2b.derivative(); double centre1 = getPeakCentre(x0, b2b_d1); double height1 = b2b(centre1); x0 += centre - centre1; function.setParameter("X0", x0); function.setParameter("I", height / height1); } g_log.debug() << "Parameters:\n"; g_log.debug() << "I " << function.getParameter("I") << '\n'; g_log.debug() << "X0 " << function.getParameter("X0") << '\n'; g_log.debug() << "A " << function.getParameter("A") << '\n'; g_log.debug() << "B " << function.getParameter("B") << '\n'; g_log.debug() << "S " << function.getParameter("S") << '\n'; }