/// Derivatives of function with respect to active parameters void MultiDomainFunction::functionDeriv(const FunctionDomain &domain, Jacobian &jacobian) { // 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) + ")."); } countValueOffsets(cd); // evaluate member functions derivatives for (size_t iFun = 0; iFun < nFunctions(); ++iFun) { // find the domains member function must be applied to std::vector<size_t> domains; getDomainIndices(iFun, cd.getNParts(), domains); for (auto i = domains.begin(); i != domains.end(); ++i) { const FunctionDomain &d = cd.getDomain(*i); PartialJacobian J(&jacobian, m_valueOffsets[*i], paramOffset(iFun)); getFunction(iFun)->functionDeriv(d, J); } } }
/** * Initialize the function with the workspace(s). * @param function :: A function to initialize. */ void MultiDomainCreator::initFunction(API::IFunction_sptr function) { auto mdFunction = boost::dynamic_pointer_cast<API::MultiDomainFunction>(function); if (mdFunction) { // loop over member functions and init them for (size_t iFun = 0; iFun < mdFunction->nFunctions(); ++iFun) { std::vector<size_t> domainIndices; // get domain indices for this function mdFunction->getDomainIndices(iFun, m_creators.size(), domainIndices); if (!domainIndices.empty()) { /* if ( domainIndices.size() != 1 ) { std::stringstream msg; msg << "Function #" << iFun << " applies to multiple domains.\n" << "Only one of the domains is used to set workspace."; g_log.warning(msg.str()); } */ size_t index = domainIndices[0]; if (index >= m_creators.size()) { std::stringstream msg; msg << "Domain index is out of range. (Function #" << iFun << ")"; throw std::runtime_error(msg.str()); } m_creators[index]->initFunction(mdFunction->getFunction(iFun)); } else { g_log.warning() << "Function #" << iFun << " doesn't apply to any domain" << std::endl; } } } else { IDomainCreator::initFunction(function); } }
/** * Split this function into independent functions. The number of functions in * the * returned vector must be equal to the number * of domains. The result of evaluation of the i-th function on the i-th domain * must be * the same as if this MultiDomainFunction was evaluated. */ std::vector<IFunction_sptr> MultiDomainFunction::createEquivalentFunctions() const { size_t nDomains = m_maxIndex + 1; std::vector<CompositeFunction_sptr> compositeFunctions(nDomains); for (size_t iFun = 0; iFun < nFunctions(); ++iFun) { // find the domains member function must be applied to std::vector<size_t> domains; getDomainIndices(iFun, nDomains, domains); for (auto i = domains.begin(); i != domains.end(); ++i) { size_t j = *i; CompositeFunction_sptr cf = compositeFunctions[j]; if (!cf) { // create a composite function for each domain cf = CompositeFunction_sptr(new CompositeFunction()); compositeFunctions[j] = cf; } // add copies of all functions applied to j-th domain to a single // compositefunction cf->addFunction(FunctionFactory::Instance().createInitialized( getFunction(iFun)->asString())); } } std::vector<IFunction_sptr> outFunctions(nDomains); // fill in the output vector // check functions containing a single member and take it out of the composite for (size_t i = 0; i < compositeFunctions.size(); ++i) { auto fun = compositeFunctions[i]; if (!fun || fun->nFunctions() == 0) { throw std::runtime_error("There is no function for domain " + boost::lexical_cast<std::string>(i)); } if (fun->nFunctions() > 1) { outFunctions[i] = fun; } else { outFunctions[i] = fun->getFunction(0); } } return outFunctions; }
/// 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; getDomainIndices(iFun, cd.getNParts(), 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); } } }