Exemple #1
0
/** Fit GSL function wrapper
* @param x :: Input function parameters
* @param params :: Input data
* @param f :: Output function values = (y_cal-y_data)/sigma for each data point
* @return A GSL status information
*/
int gsl_f(const gsl_vector *x, void *params, gsl_vector *f) {

  struct GSL_FitData *p = (struct GSL_FitData *)params;

  // update function parameters
  if (x->data) {
    size_t ia = 0;
    for (size_t i = 0; i < p->function->nParams(); ++i) {
      if (p->function->isActive(i)) {
        p->function->setActiveParameter(i, x->data[ia]);
        ++ia;
      }
    }
  }
  p->function->applyTies();

  auto values = boost::dynamic_pointer_cast<API::FunctionValues>(
      p->costFunction->getValues());
  if (!values) {
    throw std::invalid_argument("FunctionValues expected");
  }
  p->function->function(*p->costFunction->getDomain(), *values);

  // Add penalty
  double penalty = 0.;
  for (size_t i = 0; i < p->function->nParams(); ++i) {
    API::IConstraint *c = p->function->getConstraint(i);
    if (c) {
      penalty += c->checkDeriv();
    }
  }

  size_t n = values->size() - 1;
  // add penalty to first and last point and every 10th point in between
  if (penalty != 0.0) {
    values->addToCalculated(0, penalty);
    values->addToCalculated(n, penalty);

    for (size_t i = 9; i < n; i += 10) {
      values->addToCalculated(i, penalty);
    }
  }

  // function() return calculated data values. Need to convert this values into
  // calculated-observed devided by error values used by GSL

  for (size_t i = 0; i < p->n; i++) {
    f->data[i] = (values->getCalculated(i) - values->getFitData(i)) *
                 values->getFitWeight(i);
    // std::cerr << values.getCalculated(i) << ' ' << values.getFitData(i) << '
    // ' << values.getFitWeight(i) << std::endl;
  }

  return GSL_SUCCESS;
}
/** Calculate the value and the first and second derivatives of the cost function
 *  @param evalFunction :: If false cost function isn't evaluated and returned value (0.0) should be ignored.
 *    It is for efficiency reasons.
 *  @param evalDeriv :: flag for evaluation of the first derivatives
 *  @param evalHessian :: flag for evaluation of the second derivatives
 */
double CostFuncLeastSquares::valDerivHessian(bool evalFunction, bool evalDeriv, bool evalHessian) const
{
  if (m_pushed || !evalDeriv)
  {
    return val();
  }

  if (!m_dirtyVal && !m_dirtyDeriv && !m_dirtyHessian) return m_value;
  if (m_dirtyVal) evalFunction = true;

  checkValidity();

  if (evalFunction)
  {
    m_value = 0.0;
  }
  if (evalDeriv)
  {
    m_der.resize(nParams());
    m_der.zero();
  }
  if (evalHessian)
  {
    m_hessian.resize(nParams(),nParams());
    m_hessian.zero();
  }

  auto seqDomain = boost::dynamic_pointer_cast<SeqDomain>(m_domain);

  if (seqDomain)
  {
    seqDomain->leastSquaresValDerivHessian(*this,evalFunction,evalDeriv,evalHessian);
  }
  else
  {
    auto simpleValues = boost::dynamic_pointer_cast<API::FunctionValues>(m_values);
    if (!simpleValues)
    {
      throw std::runtime_error("LeastSquares: unsupported IFunctionValues.");
    }
    addValDerivHessian(m_function,m_domain,simpleValues,evalFunction,evalDeriv,evalHessian);
  }

  // Add constraints penalty
  size_t np = m_function->nParams();
  if (evalFunction)
  {
    for(size_t i = 0; i < np; ++i)
    {
      API::IConstraint* c = m_function->getConstraint(i);
      if (c)
      {
        m_value += c->check();
      }
    }
    m_dirtyVal = false;
  }

  if (evalDeriv)
  {
    size_t i = 0;
    for(size_t ip = 0; ip < np; ++ip)
    {
      if ( !m_function->isActive(ip) ) continue;
      API::IConstraint* c = m_function->getConstraint(ip);
      if (c)
      {
        double d =  m_der.get(i) + c->checkDeriv();
        m_der.set(i,d);
      }
      ++i;
    }
    m_dirtyDeriv = false;
  }

  if (evalDeriv)
  {
    size_t i = 0;
    for(size_t ip = 0; ip < np; ++ip)
    {
      if ( !m_function->isActive(ip) ) continue;
      API::IConstraint* c = m_function->getConstraint(ip);
      if (c)
      {
        double d =  m_hessian.get(i,i) + c->checkDeriv2();
        m_hessian.set(i,i,d);
      }
      ++i;
    }
    // clear the dirty flag if hessian was actually calculated
    m_dirtyHessian = m_hessian.isEmpty();
  }

  return m_value;
}