Пример #1
0
 /// Create a domain from the input workspace
 void MultiDomainCreator::createDomain(
   boost::shared_ptr<API::FunctionDomain>& domain, 
   boost::shared_ptr<API::IFunctionValues>& ivalues, size_t i0)
 {
   if (m_workspacePropertyNames.size() != m_creators.size())
   {
     throw std::runtime_error("Cannot create JointDomain: number of workspaces does not match "
       "the number of creators");
   }
   auto jointDomain = new API::JointDomain;
   API::IFunctionValues_sptr values;
   i0 = 0;
   for(auto c = m_creators.begin(); c != m_creators.end(); ++c)
   {
     if (!(*c))
     {
       throw std::runtime_error("Missing domain creator");
     }
     API::FunctionDomain_sptr domain;
     (**c).createDomain(domain,values,i0);
     jointDomain->addDomain(domain);
     i0 += domain->size();
   }
   domain.reset(jointDomain);
   ivalues = values;
 }
Пример #2
0
/** Set fitting function, domain it will operate on, and container for values.
 * @param function :: The fitting function.
 * @param domain :: The domain for the function.
 * @param values :: The FunctionValues object which receives the calculated
 * values and
 *  also contains the data to fit to and the fitting weights (reciprocal
 * errors).
 */
void CostFuncFitting::setFittingFunction(API::IFunction_sptr function,
                                         API::FunctionDomain_sptr domain,
                                         API::FunctionValues_sptr values) {
  if (domain->size() != values->size()) {
    throw std::runtime_error(
        "Function domain and values objects are incompatible.");
  }
  m_function = function;
  m_domain = domain;
  m_values = values;
  m_indexMap.clear();
  for (size_t i = 0; i < m_function->nParams(); ++i) {
    if (m_function->isActive(i)) {
      m_indexMap.push_back(i);
    }
    API::IConstraint *c = m_function->getConstraint(i);
    if (c) {
      c->setParamToSatisfyConstraint();
    }
  }
}
Пример #3
0
/** Executes the algorithm
*
*  @throw runtime_error Thrown if algorithm cannot execute
*/
void Fit::execConcrete() {

  std::string ties = getPropertyValue("Ties");
  if (!ties.empty()) {
    m_function->addTies(ties);
  }
  std::string contstraints = getPropertyValue("Constraints");
  if (!contstraints.empty()) {
    m_function->addConstraints(contstraints);
  }

  // prepare the function for a fit
  m_function->setUpForFit();

  API::FunctionDomain_sptr domain;
  API::FunctionValues_sptr values;
  m_domainCreator->createDomain(domain, values);

  // do something with the function which may depend on workspace
  m_domainCreator->initFunction(m_function);

  // get the minimizer
  std::string minimizerName = getPropertyValue("Minimizer");
  API::IFuncMinimizer_sptr minimizer =
      API::FuncMinimizerFactory::Instance().createMinimizer(minimizerName);

  // Try to retrieve optional properties
  int intMaxIterations = getProperty("MaxIterations");
  const size_t maxIterations = static_cast<size_t>(intMaxIterations);

  // get the cost function which must be a CostFuncFitting
  boost::shared_ptr<CostFuncFitting> costFunc =
      boost::dynamic_pointer_cast<CostFuncFitting>(
          API::CostFunctionFactory::Instance().create(
              getPropertyValue("CostFunction")));

  costFunc->setFittingFunction(m_function, domain, values);
  minimizer->initialize(costFunc, maxIterations);

  const int64_t nsteps = maxIterations * m_function->estimateNoProgressCalls();
  API::Progress prog(this, 0.0, 1.0, nsteps);
  m_function->setProgressReporter(&prog);

  // do the fitting until success or iteration limit is reached
  size_t iter = 0;
  bool success = false;
  std::string errorString;
  g_log.debug("Starting minimizer iteration\n");
  while (iter < maxIterations) {
    g_log.debug() << "Starting iteration " << iter << "\n";
    m_function->iterationStarting();
    if (!minimizer->iterate(iter)) {
      errorString = minimizer->getError();
      g_log.debug() << "Iteration stopped. Minimizer status string="
                    << errorString << "\n";

      success = errorString.empty() || errorString == "success";
      if (success) {
        errorString = "success";
      }
      break;
    }
    prog.report();
    m_function->iterationFinished();
    ++iter;
  }
  g_log.debug() << "Number of minimizer iterations=" << iter << "\n";

  minimizer->finalize();

  if (iter >= maxIterations) {
    if (!errorString.empty()) {
      errorString += '\n';
    }
    errorString += "Failed to converge after " +
                   boost::lexical_cast<std::string>(maxIterations) +
                   " iterations.";
  }

  // return the status flag
  setPropertyValue("OutputStatus", errorString);

  // degrees of freedom
  size_t dof = domain->size() - costFunc->nParams();
  if (dof == 0)
    dof = 1;
  double rawcostfuncval = minimizer->costFunctionVal();
  double finalCostFuncVal = rawcostfuncval / double(dof);

  setProperty("OutputChi2overDoF", finalCostFuncVal);

  // fit ended, creating output

  // get the workspace
  API::Workspace_const_sptr ws = getProperty("InputWorkspace");

  bool doCreateOutput = getProperty("CreateOutput");
  std::string baseName = getPropertyValue("Output");
  if (!baseName.empty()) {
    doCreateOutput = true;
  }
  bool doCalcErrors = getProperty("CalcErrors");
  if (doCreateOutput) {
    doCalcErrors = true;
  }
  if (costFunc->nParams() == 0) {
    doCalcErrors = false;
  }

  GSLMatrix covar;
  if (doCalcErrors) {
    // Calculate the covariance matrix and the errors.
    costFunc->calCovarianceMatrix(covar);
    costFunc->calFittingErrors(covar, rawcostfuncval);
  }

  if (doCreateOutput) {
    copyMinimizerOutput(*minimizer);

    if (baseName.empty()) {
      baseName = ws->name();
      if (baseName.empty()) {
        baseName = "Output";
      }
    }
    baseName += "_";

    declareProperty(
        new API::WorkspaceProperty<API::ITableWorkspace>(
            "OutputNormalisedCovarianceMatrix", "", Kernel::Direction::Output),
        "The name of the TableWorkspace in which to store the final covariance "
        "matrix");
    setPropertyValue("OutputNormalisedCovarianceMatrix",
                     baseName + "NormalisedCovarianceMatrix");

    Mantid::API::ITableWorkspace_sptr covariance =
        Mantid::API::WorkspaceFactory::Instance().createTable("TableWorkspace");
    covariance->addColumn("str", "Name");
    // set plot type to Label = 6
    covariance->getColumn(covariance->columnCount() - 1)->setPlotType(6);
    // std::vector<std::string> paramThatAreFitted; // used for populating 1st
    // "name" column
    for (size_t i = 0; i < m_function->nParams(); i++) {
      if (m_function->isActive(i)) {
        covariance->addColumn("double", m_function->parameterName(i));
        // paramThatAreFitted.push_back(m_function->parameterName(i));
      }
    }

    size_t np = m_function->nParams();
    size_t ia = 0;
    for (size_t i = 0; i < np; i++) {
      if (m_function->isFixed(i))
        continue;
      Mantid::API::TableRow row = covariance->appendRow();
      row << m_function->parameterName(i);
      size_t ja = 0;
      for (size_t j = 0; j < np; j++) {
        if (m_function->isFixed(j))
          continue;
        if (j == i)
          row << 100.0;
        else {
          if (!covar.gsl()) {
            throw std::runtime_error(
                "There was an error while allocating the (GSL) covariance "
                "matrix "
                "which is needed to produce fitting error results.");
          }
          row << 100.0 * covar.get(ia, ja) /
                     sqrt(covar.get(ia, ia) * covar.get(ja, ja));
        }
        ++ja;
      }
      ++ia;
    }

    setProperty("OutputNormalisedCovarianceMatrix", covariance);

    // create output parameter table workspace to store final fit parameters
    // including error estimates if derivative of fitting function defined

    declareProperty(new API::WorkspaceProperty<API::ITableWorkspace>(
                        "OutputParameters", "", Kernel::Direction::Output),
                    "The name of the TableWorkspace in which to store the "
                    "final fit parameters");

    setPropertyValue("OutputParameters", baseName + "Parameters");

    Mantid::API::ITableWorkspace_sptr result =
        Mantid::API::WorkspaceFactory::Instance().createTable("TableWorkspace");
    result->addColumn("str", "Name");
    // set plot type to Label = 6
    result->getColumn(result->columnCount() - 1)->setPlotType(6);
    result->addColumn("double", "Value");
    result->addColumn("double", "Error");
    // yErr = 5
    result->getColumn(result->columnCount() - 1)->setPlotType(5);

    for (size_t i = 0; i < m_function->nParams(); i++) {
      Mantid::API::TableRow row = result->appendRow();
      row << m_function->parameterName(i) << m_function->getParameter(i)
          << m_function->getError(i);
    }
    // Add chi-squared value at the end of parameter table
    Mantid::API::TableRow row = result->appendRow();
#if 1
    std::string costfuncname = getPropertyValue("CostFunction");
    if (costfuncname == "Rwp")
      row << "Cost function value" << rawcostfuncval;
    else
      row << "Cost function value" << finalCostFuncVal;
    setProperty("OutputParameters", result);
#else
    row << "Cost function value" << finalCostFuncVal;
    Mantid::API::TableRow row2 = result->appendRow();
    std::string name(getPropertyValue("CostFunction"));
    name += " value";
    row2 << name << rawcostfuncval;
#endif

    setProperty("OutputParameters", result);

    bool outputParametersOnly = getProperty("OutputParametersOnly");

    if (!outputParametersOnly) {
      const bool unrollComposites = getProperty("OutputCompositeMembers");
      bool convolveMembers = existsProperty("ConvolveMembers");
      if (convolveMembers) {
        convolveMembers = getProperty("ConvolveMembers");
      }
      m_domainCreator->separateCompositeMembersInOutput(unrollComposites,
                                                        convolveMembers);
      m_domainCreator->createOutputWorkspace(baseName, m_function, domain,
                                             values);
    }
  }

  progress(1.0);
}
Пример #4
0
/**
 * Update the cost function, derivatives and hessian by adding values calculated
 * on a domain.
 * @param function :: Function to use to calculate the value and the derivatives
 * @param domain :: The domain.
 * @param values :: The fit function values
 * @param evalFunction :: Flag to evaluate the function
 * @param evalDeriv :: Flag to evaluate the derivatives
 * @param evalHessian :: Flag to evaluate the Hessian
 */
void CostFuncLeastSquares::addValDerivHessian(
  API::IFunction_sptr function,
  API::FunctionDomain_sptr domain,
  API::FunctionValues_sptr values,
  bool evalFunction , bool evalDeriv, bool evalHessian) const
{
  UNUSED_ARG(evalDeriv);
  size_t np = function->nParams();  // number of parameters 
  size_t ny = domain->size(); // number of data points
  Jacobian jacobian(ny,np);
  if (evalFunction)
  {
    function->function(*domain,*values);
  }
  function->functionDeriv(*domain,jacobian);

  size_t iActiveP = 0;
  double fVal = 0.0;
  if (debug)
  {
    std::cerr << "Jacobian:\n";
    for(size_t i = 0; i < ny; ++i)
    {
      for(size_t ip = 0; ip < np; ++ip)
      {
        if ( !m_function->isActive(ip) ) continue;
        std::cerr << jacobian.get(i,ip) << ' ';
      }
      std::cerr << std::endl;
    }
  }
  for(size_t ip = 0; ip < np; ++ip)
  {
    if ( !function->isActive(ip) ) continue;
    double d = 0.0;
    for(size_t i = 0; i < ny; ++i)
    {
      double calc = values->getCalculated(i);
      double obs = values->getFitData(i);
      double w = values->getFitWeight(i);
      double y = ( calc - obs ) * w;
      d += y * jacobian.get(i,ip) * w;
      if (iActiveP == 0 && evalFunction)
      {
        fVal += y * y;
      }
    }
    PARALLEL_CRITICAL(der_set)
    {
      double der = m_der.get(iActiveP);
      m_der.set(iActiveP, der + d);
    }
    //std::cerr << "der " << ip << ' ' << der[iActiveP] << std::endl;
    ++iActiveP;
  }

  if (evalFunction)
  {
    PARALLEL_ATOMIC
    m_value += 0.5 * fVal;
  }

  if (!evalHessian) return;

  //size_t na = m_der.size(); // number of active parameters

  size_t i1 = 0; // active parameter index
  for(size_t i = 0; i < np; ++i) // over parameters
  {
    if ( !function->isActive(i) ) continue;
    size_t i2 = 0; // active parameter index
    for(size_t j = 0; j <= i; ++j) // over ~ half of parameters
    {
      if ( !function->isActive(j) ) continue;
      double d = 0.0;
      for(size_t k = 0; k < ny; ++k) // over fitting data
      {
        double w = values->getFitWeight(k);
        d += jacobian.get(k,i) * jacobian.get(k,j) * w * w;
      }
      PARALLEL_CRITICAL(hessian_set)
      {
        double h = m_hessian.get(i1,i2);
        m_hessian.set(i1,i2, h + d);
        //std::cerr << "hess " << i1 << ' ' << i2 << std::endl;
        if (i1 != i2)
        {
          m_hessian.set(i2,i1,h + d);
        }
      }
      ++i2;
    }
    ++i1;
  }
}