//---------------------------------------------------------------------------------------------- /// 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; } }
//---------------------------------------------------------------------------------------------- /// 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'; }