/** * Create a function from an expression. * @param expr :: The input expression * @param parentAttributes :: An output map filled with the attribute name & values of the parent function * @return A pointer to the created function */ IFunction_sptr FunctionFactoryImpl::createSimple(const Expression& expr, std::map<std::string,std::string>& parentAttributes)const { if (expr.name() == "=" && expr.size() > 1) { return createFunction(expr.terms()[1].name()); } if (expr.name() != "," || expr.size() == 0) { inputError(expr.str()); } const std::vector<Expression>& terms = expr.terms(); std::vector<Expression>::const_iterator term = terms.begin(); if (term->name() != "=") inputError(expr.str()); if (term->terms()[0].name() != "name" && term->terms()[0].name() != "composite") { throw std::invalid_argument("Function name must be defined before its parameters"); } std::string fnName = term->terms()[1].name(); IFunction_sptr fun = createFunction(fnName); for(++term;term!=terms.end();++term) {// loop over function's parameters/attributes if (term->name() != "=") inputError(expr.str()); std::string parName = term->terms()[0].name(); std::string parValue = term->terms()[1].str(); if (fun->hasAttribute(parName)) {// set attribute if (parValue.size() > 1 && parValue[0] == '"') {// remove the double quotes parValue = parValue.substr(1,parValue.size()-2); } IFunction::Attribute att = fun->getAttribute(parName); att.fromString(parValue); fun->setAttribute(parName,att); } else if (parName.size() >= 10 && parName.substr(0,10) == "constraint") {// or it can be a list of constraints addConstraints(fun,(*term)[1]); } else if (parName == "ties") { addTies(fun,(*term)[1]); } else if (!parName.empty() && parName[0] == '$') { parName.erase(0,1); parentAttributes[parName] = parValue; } else {// set initial parameter value fun->setParameter(parName,atof(parValue.c_str())); } }// for term fun->applyTies(); return fun; }
void ChFun::setAttribute(const std::string& attName,const IFunction::Attribute& att) { IFunction1D::setAttribute( attName, att ); if ( attName == "n" ) { reset( att.asInt() ); } else if ( attName == "StartX" ) { set( n(), att.asDouble(), endX() ); } else if ( attName == "EndX" ) { set( n(), startX(), att.asDouble() ); } }
/** * Set a value to a "local" attribute, ie an attribute related to a member *function. * * The only attribute that can be set here is "domains" which defines the * indices of domains a particular function is applied to. Possible values are *(strings): * * 1) "All" : the function is applied to all domains defined for this *MultiDomainFunction. * 2) "i" : the function is applied to a single domain which index is *equal to the * function's index in this MultiDomainFunction. * 3) "non-negative integer" : a domain index. * 4) "a,b,c,..." : a list of domain indices (a,b,c,.. are non-negative *integers). * 5) "a - b" : a range of domain indices (a,b are non-negative integers a *<= b). * * To be used with Fit algorithm at least one of the member functions must have *"domains" value * of type 2), 3), 4) or 5) because these values can tell Fit how many domains *need to be created. * * @param i :: Index of a function for which the attribute is being set. * @param attName :: Name of an attribute. * @param att :: Value of the attribute to set. */ void MultiDomainFunction::setLocalAttribute(size_t i, const std::string &attName, const IFunction::Attribute &att) { if (attName != "domains") { throw std::invalid_argument("MultiDomainFunction does not have attribute " + attName); } if (i >= nFunctions()) { throw std::out_of_range("Function index is out of range."); } std::string value = att.asString(); auto it = m_domains.find(i); if (value == "All") { // fit to all domains if (it != m_domains.end()) { m_domains.erase(it); } return; } else if (value == "i") { // fit to domain with the same index as the function setDomainIndex(i, i); return; } else if (value.empty()) { // do not fit to any domain setDomainIndices(i, std::vector<size_t>()); return; } // fit to a selection of domains std::vector<size_t> indx; Expression list; list.parse(value); if (list.name() == "+") { if (list.size() != 2 || list.terms()[1].operator_name() != "-") { throw std::runtime_error("MultiDomainFunction: attribute \"domains\" " "expects two integers separated by a \"-\""); } // value looks like "a - b". a and b must be ints and define a range of // domain indices size_t start = boost::lexical_cast<size_t>(list.terms()[0].str()); size_t end = boost::lexical_cast<size_t>(list.terms()[1].str()) + 1; if (start >= end) { throw std::runtime_error( "MultiDomainFunction: attribute \"domains\": wrong range limits."); } indx.resize(end - start); for (size_t i = start; i < end; ++i) { indx[i - start] = i; } } else { // value must be either an int or a list of ints: "a,b,c,..." list.toList(); for (size_t k = 0; k < list.size(); ++k) { indx.push_back(boost::lexical_cast<size_t>(list[k].name())); } } setDomainIndices(i, indx); }
/// Perform a castom action when an attribute is set. void CrystalFieldPeaksBase::setAttribute(const std::string &name, const IFunction::Attribute &attr) { if (name == "Symmetry") { auto symmIter = SYMMETRY_MAP.find(attr.asString()); if (symmIter == SYMMETRY_MAP.end()) { throw std::runtime_error("Unknown symmetry passed to CrystalFieldPeaks."); } symmIter->second(*this); } IFunction::setAttribute(name, attr); }
/** * Set a value to attribute attName */ void MultiDomainFunction::setLocalAttribute(size_t i, const std::string& attName,const IFunction::Attribute& att) { if (attName != "domains") { throw std::invalid_argument("MultiDomainFunction does not have attribute " + attName); } if (i >= nFunctions()) { throw std::out_of_range("Function index is out of range."); } std::string value = att.asString(); auto it = m_domains.find(i); if (value == "All") {// fit to all domains if (it != m_domains.end()) { m_domains.erase(it); } return; } else if (value == "i") {// fit to domain with the same index as the function setDomainIndex(i,i); return; } else if (value.empty()) {// do not fit to any domain setDomainIndices(i,std::vector<size_t>()); } // fit to a selection of domains std::vector<size_t> indx; Expression list; list.parse(value); list.toList(); for(size_t k = 0; k < list.size(); ++k) { indx.push_back(boost::lexical_cast<size_t>(list[k].name())); } setDomainIndices(i,indx); }