TEST(FunctionFactoryTest, CreateCompositeFunctionTest) { std::string ini = "CompositeFunction(" "FunctionFactoryTestFunction(A=10,B=20)," "FunctionFactoryTestFunction(A=30,B=40)" ")"; IFunction_sptr fun = FunctionFactory::instance().createFitFunction(ini); EXPECT_TRUE( fun.get() != nullptr ); CompositeFunction_sptr cf = boost::dynamic_pointer_cast<CompositeFunction>(fun); EXPECT_TRUE( cf.get() != nullptr ); EXPECT_EQ( cf->nFunctions(), 2 ); auto f1 = cf->getFunction(0); auto f2 = cf->getFunction(1); EXPECT_EQ(f1->getParameter("A"),10); EXPECT_EQ(f1->getParameter("B"),20); EXPECT_EQ(f2->getParameter("A"),30); EXPECT_EQ(f2->getParameter("B"),40); EXPECT_EQ(cf->getParameter("f0.A"),10); EXPECT_EQ(cf->getParameter("f0.B"),20); EXPECT_EQ(cf->getParameter("f1.A"),30); EXPECT_EQ(cf->getParameter("f1.B"),40); std::cerr << '\n' << fun->asString(true) << '\n' << std::endl; IFunction_sptr fun1 = FunctionFactory::instance().createFitFunction(ini); EXPECT_TRUE( fun1.get() != nullptr ); cf = boost::dynamic_pointer_cast<CompositeFunction>(fun1); EXPECT_TRUE( cf.get() != nullptr ); EXPECT_EQ( cf->nFunctions(), 2 ); EXPECT_EQ(cf->getParameter("f0.A"),10); EXPECT_EQ(cf->getParameter("f0.B"),20); EXPECT_EQ(cf->getParameter("f1.A"),30); EXPECT_EQ(cf->getParameter("f1.B"),40); }
void IqtFit::plotGuess(QtProperty *) { // Do nothing if there is no sample data curve if (!m_uiForm.ppPlot->hasCurve("Sample")) return; CompositeFunction_sptr function = createFunction(true); // Create the double* array from the input workspace const size_t binIndxLow = m_ffInputWS->binIndexOf(m_ffRangeManager->value(m_properties["StartX"])); const size_t binIndxHigh = m_ffInputWS->binIndexOf(m_ffRangeManager->value(m_properties["EndX"])); const size_t nData = binIndxHigh - binIndxLow; std::vector<double> inputXData(nData); const Mantid::MantidVec &XValues = m_ffInputWS->readX(0); const bool isHistogram = m_ffInputWS->isHistogramData(); for (size_t i = 0; i < nData; i++) { if (isHistogram) inputXData[i] = 0.5 * (XValues[binIndxLow + i] + XValues[binIndxLow + i + 1]); else inputXData[i] = XValues[binIndxLow + i]; } FunctionDomain1DVector domain(inputXData); FunctionValues outputData(domain); function->function(domain, outputData); QVector<double> dataX; QVector<double> dataY; for (size_t i = 0; i < nData; i++) { dataX.append(inputXData[i]); dataY.append(outputData.getCalculated(i)); } IAlgorithm_sptr createWsAlg = AlgorithmManager::Instance().create("CreateWorkspace"); createWsAlg->initialize(); createWsAlg->setChild(true); createWsAlg->setLogging(false); createWsAlg->setProperty("OutputWorkspace", "__GuessAnon"); createWsAlg->setProperty("NSpec", 1); createWsAlg->setProperty("DataX", dataX.toStdVector()); createWsAlg->setProperty("DataY", dataY.toStdVector()); createWsAlg->execute(); MatrixWorkspace_sptr guessWs = createWsAlg->getProperty("OutputWorkspace"); m_uiForm.ppPlot->addSpectrum("Guess", guessWs, 0, Qt::green); }
/// Returns a TableWorkspace with refined cell parameters and error. ITableWorkspace_sptr PoldiFitPeaks2D::getRefinedCellParameters( const IFunction_sptr &fitFunction) const { Poldi2DFunction_sptr poldi2DFunction = boost::dynamic_pointer_cast<Poldi2DFunction>(fitFunction); if (!poldi2DFunction || poldi2DFunction->nFunctions() < 1) { throw std::invalid_argument( "Cannot process function that is not a Poldi2DFunction."); } // Create a new table for lattice parameters ITableWorkspace_sptr latticeParameterTable = WorkspaceFactory::Instance().createTable(); latticeParameterTable->addColumn("str", "Parameter"); latticeParameterTable->addColumn("double", "Value"); latticeParameterTable->addColumn("double", "Error"); // The first function should be PoldiSpectrumPawleyFunction boost::shared_ptr<PoldiSpectrumPawleyFunction> poldiPawleyFunction = boost::dynamic_pointer_cast<PoldiSpectrumPawleyFunction>( poldi2DFunction->getFunction(0)); if (!poldiPawleyFunction) { throw std::invalid_argument("First function in Poldi2DFunction is not " "PoldiSpectrumPawleyFunction."); } // Get the actual PawleyFunction to extract parameters. IPawleyFunction_sptr pawleyFunction = boost::dynamic_pointer_cast<IPawleyFunction>( poldiPawleyFunction->getDecoratedFunction()); if (pawleyFunction) { CompositeFunction_sptr pawleyParts = boost::dynamic_pointer_cast<CompositeFunction>( pawleyFunction->getDecoratedFunction()); // The first function in PawleyFunction contains the parameters IFunction_sptr pawleyParameters = pawleyParts->getFunction(0); for (size_t i = 0; i < pawleyParameters->nParams(); ++i) { TableRow newRow = latticeParameterTable->appendRow(); newRow << pawleyParameters->parameterName(i) << pawleyParameters->getParameter(i) << pawleyParameters->getError(i); } } return latticeParameterTable; }
/** Makes sure that the function is consistent. */ void CompositeFunction::checkFunction() { m_nParams = 0; m_paramOffsets.clear(); m_IFunction.clear(); std::vector<IFunction_sptr> functions(m_functions.begin(), m_functions.end()); m_functions.clear(); for (auto &f : functions) { CompositeFunction_sptr cf = boost::dynamic_pointer_cast<CompositeFunction>(f); if (cf) cf->checkFunction(); addFunction(f); } }
void PoldiFitPeaks1D::setValuesFromProfileFunction( PoldiPeak_sptr poldiPeak, const IFunction_sptr &fittedFunction) const { CompositeFunction_sptr totalFunction = boost::dynamic_pointer_cast<CompositeFunction>(fittedFunction); if (totalFunction) { IPeakFunction_sptr peakFunction = boost::dynamic_pointer_cast<IPeakFunction>( totalFunction->getFunction(0)); if (peakFunction) { poldiPeak->setIntensity( UncertainValue(peakFunction->height(), peakFunction->getError(0))); poldiPeak->setQ( UncertainValue(peakFunction->centre(), peakFunction->getError(1))); poldiPeak->setFwhm(UncertainValue(peakFunction->fwhm(), getFwhmWidthRelation(peakFunction) * peakFunction->getError(2))); } } }
/** * 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; }
PoldiPeakCollection_sptr PoldiFitPeaks1D2::fitPeaks(const PoldiPeakCollection_sptr &peaks) { g_log.information() << "Peaks to fit: " << peaks->peakCount() << std::endl; std::vector<RefinedRange_sptr> rawRanges = getRefinedRanges(peaks); std::vector<RefinedRange_sptr> reducedRanges = getReducedRanges(rawRanges); g_log.information() << "Ranges used for fitting: " << reducedRanges.size() << std::endl; Workspace2D_sptr dataWorkspace = getProperty("InputWorkspace"); m_fitplots->removeAll(); for (size_t i = 0; i < reducedRanges.size(); ++i) { RefinedRange_sptr currentRange = reducedRanges[i]; int nMin = getBestChebyshevPolynomialDegree(dataWorkspace, currentRange); if (nMin > -1) { IAlgorithm_sptr fit = getFitAlgorithm(dataWorkspace, currentRange, nMin); fit->execute(); IFunction_sptr fitFunction = fit->getProperty("Function"); CompositeFunction_sptr composite = boost::dynamic_pointer_cast<CompositeFunction>(fitFunction); if (!composite) { throw std::runtime_error("Not a composite function!"); } std::vector<PoldiPeak_sptr> peaks = currentRange->getPeaks(); for (size_t i = 0; i < peaks.size(); ++i) { setValuesFromProfileFunction(peaks[i], composite->getFunction(i)); MatrixWorkspace_sptr fpg = fit->getProperty("OutputWorkspace"); m_fitplots->addWorkspace(fpg); } } } return getReducedPeakCollection(peaks); }
/** * Construct a PoldiPeakCollection from a Poldi2DFunction * * This method performs the opposite operation of *getFunctionFromPeakCollection. * It takes a function, checks if it's of the proper type and turns the * information into a PoldiPeakCollection. * * @param Poldi2DFunction with one PoldiSpectrumDomainFunction per peak * @return PoldiPeakCollection containing peaks with normalized intensities */ PoldiPeakCollection_sptr PoldiFitPeaks2D::getPeakCollectionFromFunction( const IFunction_sptr &fitFunction) { Poldi2DFunction_sptr poldi2DFunction = boost::dynamic_pointer_cast<Poldi2DFunction>(fitFunction); if (!poldi2DFunction) { throw std::invalid_argument( "Cannot process function that is not a Poldi2DFunction."); } PoldiPeakCollection_sptr normalizedPeaks = boost::make_shared<PoldiPeakCollection>(PoldiPeakCollection::Integral); boost::shared_ptr<const Kernel::DblMatrix> covarianceMatrix = poldi2DFunction->getCovarianceMatrix(); size_t offset = 0; for (size_t i = 0; i < poldi2DFunction->nFunctions(); ++i) { boost::shared_ptr<PoldiSpectrumPawleyFunction> poldiPawleyFunction = boost::dynamic_pointer_cast<PoldiSpectrumPawleyFunction>( poldi2DFunction->getFunction(i)); // If it's a Pawley function, there are several peaks in one function. if (poldiPawleyFunction) { IPawleyFunction_sptr pawleyFunction = poldiPawleyFunction->getPawleyFunction(); if (pawleyFunction) { CompositeFunction_sptr decoratedFunction = boost::dynamic_pointer_cast<CompositeFunction>( pawleyFunction->getDecoratedFunction()); offset = decoratedFunction->getFunction(0)->nParams(); for (size_t j = 0; j < pawleyFunction->getPeakCount(); ++j) { IPeakFunction_sptr profileFunction = pawleyFunction->getPeakFunction(j); size_t nLocalParams = profileFunction->nParams(); boost::shared_ptr<Kernel::DblMatrix> localCov = getLocalCovarianceMatrix(covarianceMatrix, offset, nLocalParams); profileFunction->setCovarianceMatrix(localCov); // Increment offset for next function offset += nLocalParams; V3D peakHKL = pawleyFunction->getPeakHKL(j); PoldiPeak_sptr peak = getPeakFromPeakFunction(profileFunction, peakHKL); normalizedPeaks->addPeak(peak); } } break; } // Otherwise, it's just one peak in this function. boost::shared_ptr<PoldiSpectrumDomainFunction> peakFunction = boost::dynamic_pointer_cast<PoldiSpectrumDomainFunction>( poldi2DFunction->getFunction(i)); if (peakFunction) { IPeakFunction_sptr profileFunction = boost::dynamic_pointer_cast<IPeakFunction>( peakFunction->getProfileFunction()); // Get local covariance matrix size_t nLocalParams = profileFunction->nParams(); boost::shared_ptr<Kernel::DblMatrix> localCov = getLocalCovarianceMatrix(covarianceMatrix, offset, nLocalParams); profileFunction->setCovarianceMatrix(localCov); // Increment offset for next function offset += nLocalParams; PoldiPeak_sptr peak = getPeakFromPeakFunction(profileFunction, V3D(0, 0, 0)); normalizedPeaks->addPeak(peak); } } return normalizedPeaks; }
/** * Create a composite 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 */ CompositeFunction_sptr FunctionFactoryImpl::createComposite( const Expression &expr, std::map<std::string, std::string> &parentAttributes) const { if (expr.name() != ";") inputError(expr.str()); if (expr.size() == 0) { return CompositeFunction_sptr(); } const std::vector<Expression> &terms = expr.terms(); auto it = terms.cbegin(); const Expression &term = it->bracketsRemoved(); CompositeFunction_sptr cfun; if (term.name() == "=") { if (term.terms()[0].name() == "composite") { cfun = boost::dynamic_pointer_cast<CompositeFunction>( createFunction(term.terms()[1].name())); if (!cfun) inputError(expr.str()); ++it; } else if (term.terms()[0].name() == "name") { cfun = boost::dynamic_pointer_cast<CompositeFunction>( createFunction("CompositeFunction")); if (!cfun) inputError(expr.str()); } else { inputError(expr.str()); } } else if (term.name() == ",") { auto firstTerm = term.terms().cbegin(); if (firstTerm->name() == "=") { if (firstTerm->terms()[0].name() == "composite") { cfun = boost::dynamic_pointer_cast<CompositeFunction>( createSimple(term, parentAttributes)); if (!cfun) inputError(expr.str()); ++it; } else if (firstTerm->terms()[0].name() == "name") { cfun = boost::dynamic_pointer_cast<CompositeFunction>( createFunction("CompositeFunction")); if (!cfun) inputError(expr.str()); } else { inputError(expr.str()); } } } else if (term.name() == ";") { cfun = boost::dynamic_pointer_cast<CompositeFunction>( createFunction("CompositeFunction")); if (!cfun) inputError(expr.str()); } else { inputError(expr.str()); } if (!cfun) inputError(expr.str()); for (; it != terms.end(); ++it) { const Expression &term = it->bracketsRemoved(); IFunction_sptr fun; std::map<std::string, std::string> pAttributes; if (term.name() == ";") { fun = createComposite(term, pAttributes); if (!fun) continue; } else { std::string parName = term[0].name(); if (parName.size() >= 10 && parName.substr(0, 10) == "constraint") { addConstraints(cfun, term[1]); continue; } else if (parName == "ties") { addTies(cfun, term[1]); continue; } else { fun = createSimple(term, pAttributes); } } cfun->addFunction(fun); size_t i = cfun->nFunctions() - 1; for (auto &pAttribute : pAttributes) { // Apply parent attributes of the child function to this function. If this // function doesn't have those attributes, they get passed up the chain to // this function's parent. if (cfun->hasLocalAttribute(pAttribute.first)) { cfun->setLocalAttributeValue(i, pAttribute.first, pAttribute.second); } else { parentAttributes[pAttribute.first] = pAttribute.second; } } } if (cfun) { cfun->applyTies(); } return cfun; }
void IqtFit::constrainIntensities(CompositeFunction_sptr func) { std::string paramName = "f1.Intensity"; size_t index = func->parameterIndex(paramName); switch (m_uiForm.cbFitType->currentIndex()) { case 0: // 1 Exp case 2: // 1 Str if (!func->isFixed(index)) { func->tie(paramName, "1-f0.A0"); } else { std::string paramValue = boost::lexical_cast<std::string>(func->getParameter(paramName)); func->tie(paramName, paramValue); func->tie("f0.A0", "1-" + paramName); } break; case 1: // 2 Exp case 3: // 1 Exp & 1 Str if (!func->isFixed(index)) { func->tie(paramName, "1-f2.Intensity-f0.A0"); } else { std::string paramValue = boost::lexical_cast<std::string>(func->getParameter(paramName)); func->tie(paramName, "1-f2.Intensity-f0.A0"); func->tie(paramName, paramValue); } break; } }
/** * Create a composite 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 */ CompositeFunction_sptr FunctionFactoryImpl::createComposite(const Expression& expr, std::map<std::string,std::string>& parentAttributes)const { if (expr.name() != ";") inputError(expr.str()); if (expr.size() == 0) { return CompositeFunction_sptr(); } const std::vector<Expression>& terms = expr.terms(); std::vector<Expression>::const_iterator it = terms.begin(); const Expression& term = it->bracketsRemoved(); CompositeFunction_sptr cfun; if (term.name() == "=") { if (term.terms()[0].name() == "composite") { cfun = boost::dynamic_pointer_cast<CompositeFunction>(createFunction(term.terms()[1].name())); if (!cfun) inputError(expr.str()); ++it; } else if (term.terms()[0].name() == "name") { cfun = boost::dynamic_pointer_cast<CompositeFunction>(createFunction("CompositeFunction")); if (!cfun) inputError(expr.str()); } else { inputError(expr.str()); } } else if (term.name() == ",") { std::vector<Expression>::const_iterator firstTerm = term.terms().begin(); if (firstTerm->name() == "=") { if (firstTerm->terms()[0].name() == "composite") { cfun = boost::dynamic_pointer_cast<CompositeFunction>(createSimple(term,parentAttributes)); if (!cfun) inputError(expr.str()); ++it; } else if (firstTerm->terms()[0].name() == "name") { cfun = boost::dynamic_pointer_cast<CompositeFunction>(createFunction("CompositeFunction")); if (!cfun) inputError(expr.str()); } else { inputError(expr.str()); } } } else if (term.name() == ";") { cfun = boost::dynamic_pointer_cast<CompositeFunction>(createFunction("CompositeFunction")); if (!cfun) inputError(expr.str()); } else { inputError(expr.str()); } for(;it!=terms.end();++it) { const Expression& term = it->bracketsRemoved(); IFunction_sptr fun; std::map<std::string,std::string> pAttributes; if (term.name() == ";") { fun = createComposite(term,pAttributes); if (!fun) continue; } else { std::string parName = term[0].name(); if (parName.size() >= 10 && parName.substr(0,10) == "constraint") { addConstraints(cfun,term[1]); continue; } else if (parName == "ties") { addTies(cfun,term[1]); continue; } else { fun = createSimple(term,pAttributes); } } cfun->addFunction(fun); size_t i = cfun->nFunctions() - 1; for(auto att = pAttributes.begin(); att != pAttributes.end(); ++att) { cfun->setLocalAttributeValue(i,att->first,att->second); } } cfun->applyTies(); return cfun; }