/**
 * Calculates the function values on the supplied domain
 *
 * This function is the core of PawleyFunction. It calculates the d-value for
 * each stored HKL from the unit cell that is the result of the parameters
 * stored in the internal PawleyParameterFunction and adds the ZeroShift
 * parameter. The value is set as center parameter on the internally stored
 * PeakFunctions.
 *
 * @param domain :: Function domain.
 * @param values :: Function values.
 */
void PawleyFunction::function(const FunctionDomain &domain,
                              FunctionValues &values) const {
  values.zeroCalculated();
  try {
    const FunctionDomain1D &domain1D =
        dynamic_cast<const FunctionDomain1D &>(domain);

    UnitCell cell = m_pawleyParameterFunction->getUnitCellFromParameters();
    double zeroShift = m_pawleyParameterFunction->getParameter("ZeroShift");
    std::string centreName =
        m_pawleyParameterFunction->getProfileFunctionCenterParameterName();

    setPeakPositions(centreName, zeroShift, cell);

    FunctionValues localValues;

    for (size_t i = 0; i < m_peakProfileComposite->nFunctions(); ++i) {
      IPeakFunction_sptr peak = boost::dynamic_pointer_cast<IPeakFunction>(
          m_peakProfileComposite->getFunction(i));

      try {
        size_t offset = calculateFunctionValues(peak, domain1D, localValues);
        values.addToCalculated(offset, localValues);
      } catch (const std::invalid_argument &) {
        // do nothing
      }
    }

    setPeakPositions(centreName, 0.0, cell);
  } catch (const std::bad_cast &) {
    // do nothing
  }
}
/** Function you want to fit to.
 *  @param domain :: An instance of FunctionDomain with the function arguments.
 *  @param values :: A FunctionValues instance for storing the calculated
 * values.
 */
void CompositeFunction::function(const FunctionDomain &domain,
                                 FunctionValues &values) const {
  FunctionValues tmp(domain);
  values.zeroCalculated();
  for (size_t iFun = 0; iFun < nFunctions(); ++iFun) {
    m_functions[iFun]->function(domain, tmp);
    values += tmp;
  }
}
  /// Function you want to fit to. 
  /// @param domain :: The buffer for writing the calculated values. Must be big enough to accept dataSize() values
  void MultiDomainFunction::function(const FunctionDomain& domain, FunctionValues& values)const
  {
    // works only on CompositeDomain
    if (!dynamic_cast<const CompositeDomain*>(&domain))
    {
      throw std::invalid_argument("Non-CompositeDomain passed to MultiDomainFunction.");
    }
    const CompositeDomain& cd = dynamic_cast<const CompositeDomain&>(domain);
    // domain must not have less parts than m_maxIndex
    if (cd.getNParts() <= m_maxIndex)
    {
      throw std::invalid_argument("CompositeDomain has too few parts (" 
        + boost::lexical_cast<std::string>(cd.getNParts()) +
        ") for MultiDomainFunction (max index " + boost::lexical_cast<std::string>(m_maxIndex) + ").");
    }
    // domain and values must be consistent
    if (cd.size() != values.size())
    {
      throw std::invalid_argument("MultiDomainFunction: domain and values have different sizes.");
    }

    countValueOffsets(cd);
    // evaluate member functions
    values.zeroCalculated();
    for(size_t iFun = 0; iFun < nFunctions(); ++iFun)
    {
      // find the domains member function must be applied to
      std::vector<size_t> domains;
      getFunctionDomains(iFun, cd, domains);

      for(auto i = domains.begin(); i != domains.end(); ++i)
      {
        const FunctionDomain& d = cd.getDomain(*i);
        FunctionValues tmp(d);
        getFunction(iFun)->function( d, tmp );
        values.addToCalculated(m_valueOffsets[*i],tmp);
      }
    }
  }