//----------------------------------------------------------------------------------------------
/// 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;
}
Esempio n. 3
0
// 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);
}
Esempio n. 4
0
// 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");
}
Esempio n. 5
0
 /**
  * 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';
}