/** * Returns a Poldi2DFunction that encapsulates individual peaks * * This function takes all peaks from the supplied peak collection and * generates an IPeakFunction of the type given in the name parameter, wraps * them in a Poldi2DFunction and returns it. * * @param profileFunctionName :: Profile function name. * @param peakCollection :: Peak collection with peaks to be used in the fit. * @return :: A Poldi2DFunction with peak profile functions. */ Poldi2DFunction_sptr PoldiFitPeaks2D::getFunctionIndividualPeaks( std::string profileFunctionName, const PoldiPeakCollection_sptr &peakCollection) const { auto mdFunction = boost::make_shared<Poldi2DFunction>(); for (size_t i = 0; i < peakCollection->peakCount(); ++i) { PoldiPeak_sptr peak = peakCollection->peak(i); boost::shared_ptr<PoldiSpectrumDomainFunction> peakFunction = boost::dynamic_pointer_cast<PoldiSpectrumDomainFunction>( FunctionFactory::Instance().createFunction( "PoldiSpectrumDomainFunction")); if (!peakFunction) { throw std::invalid_argument( "Cannot process null pointer poldi function."); } peakFunction->setDecoratedFunction(profileFunctionName); IPeakFunction_sptr wrappedProfile = boost::dynamic_pointer_cast<IPeakFunction>( peakFunction->getProfileFunction()); if (wrappedProfile) { wrappedProfile->setCentre(peak->d()); wrappedProfile->setFwhm(peak->fwhm(PoldiPeak::AbsoluteD)); wrappedProfile->setIntensity(peak->intensity()); } mdFunction->addFunction(peakFunction); } return mdFunction; }
IFunction_sptr PoldiFitPeaks1D2::getPeakProfile(const PoldiPeak_sptr &poldiPeak) const { IPeakFunction_sptr clonedProfile = boost::dynamic_pointer_cast<IPeakFunction>( FunctionFactory::Instance().createFunction(m_profileTemplate)); clonedProfile->setCentre(poldiPeak->q()); clonedProfile->setFwhm(poldiPeak->fwhm(PoldiPeak::AbsoluteQ)); clonedProfile->setHeight(poldiPeak->intensity()); return clonedProfile; }
/** * Returns a Poldi2DFunction that encapsulates a PawleyFunction * * This function creates a PawleyFunction using the supplied profile function * name and the crystal system as well as initial cell from the input * properties of the algorithm and wraps it in a Poldi2DFunction. * * The cell is refined using LatticeFunction to get better starting values. * * Because the peak intensities are integral at this step but PawleyFunction * expects peak heights, a profile function is created and * setIntensity/height-methods are used to convert. * * @param profileFunctionName :: Profile function name for PawleyFunction. * @param peakCollection :: Peak collection with peaks to be used in the fit. * @return :: A Poldi2DFunction with a PawleyFunction. */ Poldi2DFunction_sptr PoldiFitPeaks2D::getFunctionPawley( std::string profileFunctionName, const PoldiPeakCollection_sptr &peakCollection) { auto mdFunction = boost::make_shared<Poldi2DFunction>(); boost::shared_ptr<PoldiSpectrumPawleyFunction> poldiPawleyFunction = boost::dynamic_pointer_cast<PoldiSpectrumPawleyFunction>( FunctionFactory::Instance().createFunction( "PoldiSpectrumPawleyFunction")); if (!poldiPawleyFunction) { throw std::invalid_argument("Could not create pawley function."); } poldiPawleyFunction->setDecoratedFunction("PawleyFunction"); IPawleyFunction_sptr pawleyFunction = poldiPawleyFunction->getPawleyFunction(); pawleyFunction->setProfileFunction(profileFunctionName); // Extract crystal system from peak collection PointGroup_sptr pointGroup = peakCollection->pointGroup(); if (!pointGroup) { throw std::invalid_argument("Can not initialize pawley function properly - " "peaks do not have point group."); } std::string latticeSystem = getLatticeSystemFromPointGroup(pointGroup); pawleyFunction->setLatticeSystem(latticeSystem); UnitCell cell = peakCollection->unitCell(); // Extract unit cell from peak collection pawleyFunction->setUnitCell(getRefinedStartingCell( unitCellToStr(cell), latticeSystem, peakCollection)); IPeakFunction_sptr pFun = boost::dynamic_pointer_cast<IPeakFunction>( FunctionFactory::Instance().createFunction(profileFunctionName)); for (size_t i = 0; i < peakCollection->peakCount(); ++i) { PoldiPeak_sptr peak = peakCollection->peak(i); pFun->setCentre(peak->d()); pFun->setFwhm(peak->fwhm(PoldiPeak::AbsoluteD)); pFun->setIntensity(peak->intensity()); pawleyFunction->addPeak(peak->hkl().asV3D(), peak->fwhm(PoldiPeak::AbsoluteD), pFun->height()); } pawleyFunction->fix(pawleyFunction->parameterIndex("f0.ZeroShift")); mdFunction->addFunction(poldiPawleyFunction); return mdFunction; }
/// Sets the profile function and replaces already existing functions in the /// internally stored CompositeFunction. void PawleyFunction::setProfileFunction(const std::string &profileFunction) { m_pawleyParameterFunction->setAttributeValue("ProfileFunction", profileFunction); /* At this point PawleyParameterFunction guarantees that it's an IPeakFunction * and all existing profile functions are replaced. */ for (size_t i = 0; i < m_peakProfileComposite->nFunctions(); ++i) { IPeakFunction_sptr oldFunction = boost::dynamic_pointer_cast<IPeakFunction>( m_peakProfileComposite->getFunction(i)); IPeakFunction_sptr newFunction = boost::dynamic_pointer_cast<IPeakFunction>( FunctionFactory::Instance().createFunction( m_pawleyParameterFunction->getProfileFunctionName())); newFunction->setCentre(oldFunction->centre()); try { newFunction->setFwhm(oldFunction->fwhm()); } catch (...) { // do nothing. } newFunction->setHeight(oldFunction->height()); m_peakProfileComposite->replaceFunction(i, newFunction); } // Update exposed parameters. m_compositeFunction->checkFunction(); }
/// Tries to extract and store the center parameter name from the function. void PawleyParameterFunction::setCenterParameterNameFromFunction( const IPeakFunction_sptr &profileFunction) { m_profileFunctionCenterParameterName.clear(); if (profileFunction) { m_profileFunctionCenterParameterName = profileFunction->getCentreParameterName(); } }
/// Creates a PoldiPeak from the given profile function/hkl pair. PoldiPeak_sptr PoldiFitPeaks2D::getPeakFromPeakFunction(IPeakFunction_sptr profileFunction, const V3D &hkl) { // Use EstimatePeakErrors to calculate errors of FWHM and so on IAlgorithm_sptr errorAlg = createChildAlgorithm("EstimatePeakErrors"); errorAlg->setProperty( "Function", boost::dynamic_pointer_cast<IFunction>(profileFunction)); errorAlg->setPropertyValue("OutputWorkspace", "Errors"); errorAlg->execute(); double centre = profileFunction->centre(); double fwhmValue = profileFunction->fwhm(); ITableWorkspace_sptr errorTable = errorAlg->getProperty("OutputWorkspace"); double centreError = errorTable->cell<double>(0, 2); double fwhmError = errorTable->cell<double>(2, 2); UncertainValue d(centre, centreError); UncertainValue fwhm(fwhmValue, fwhmError); UncertainValue intensity; bool useIntegratedIntensities = getProperty("OutputIntegratedIntensities"); if (useIntegratedIntensities) { double integratedIntensity = profileFunction->intensity(); double integratedIntensityError = errorTable->cell<double>(3, 2); intensity = UncertainValue(integratedIntensity, integratedIntensityError); } else { double height = profileFunction->height(); double heightError = errorTable->cell<double>(1, 2); intensity = UncertainValue(height, heightError); } // Create peak with extracted parameters and supplied hkl PoldiPeak_sptr peak = PoldiPeak::create(MillerIndices(hkl), d, intensity, UncertainValue(1.0)); peak->setFwhm(fwhm, PoldiPeak::FwhmRelation::AbsoluteD); return peak; }
IFunction_sptr PoldiFitPeaks1D::getPeakProfile(const PoldiPeak_sptr &poldiPeak) const { IPeakFunction_sptr clonedProfile = boost::dynamic_pointer_cast<IPeakFunction>( FunctionFactory::Instance().createFunction(m_profileTemplate)); clonedProfile->setCentre(poldiPeak->q()); clonedProfile->setFwhm(poldiPeak->fwhm(PoldiPeak::AbsoluteQ)); clonedProfile->setHeight(poldiPeak->intensity()); IFunction_sptr clonedBackground = m_backgroundTemplate->clone(); auto totalProfile = boost::make_shared<CompositeFunction>(); totalProfile->initialize(); totalProfile->addFunction(clonedProfile); totalProfile->addFunction(clonedBackground); if (!m_profileTies.empty()) { totalProfile->addTies(m_profileTies); } return totalProfile; }
/// Adds a peak with the supplied FWHM and height. void PawleyFunction::addPeak(const Kernel::V3D &hkl, double fwhm, double height) { m_hkls.push_back(hkl); IPeakFunction_sptr peak = boost::dynamic_pointer_cast<IPeakFunction>( FunctionFactory::Instance().createFunction( m_pawleyParameterFunction->getProfileFunctionName())); peak->fix(peak->parameterIndex( m_pawleyParameterFunction->getProfileFunctionCenterParameterName())); try { peak->setFwhm(fwhm); } catch (...) { // do nothing. } peak->setHeight(height); m_peakProfileComposite->addFunction(peak); m_compositeFunction->checkFunction(); }
void PoldiFitPeaks1D2::setValuesFromProfileFunction( PoldiPeak_sptr poldiPeak, const IFunction_sptr &fittedFunction) const { IPeakFunction_sptr peakFunction = boost::dynamic_pointer_cast<IPeakFunction>(fittedFunction); 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))); } }
/** * 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; }
/** * Return peak collection with integrated peaks * * This method takes a PoldiPeakCollection where the intensity is represented * by the maximum. Then it takes the profile function stored in the peak * collection, which must be the name of a registered * IPeakFunction-implementation. The parameters height and fwhm are assigned, * centre is set to 0 to avoid problems with the parameter transformation for * the integration from -inf to inf. The profiles are integrated using * a PeakFunctionIntegrator to the precision of 1e-10. * * The original peak collection is not modified, a new instance is created. * * @param rawPeakCollection :: PoldiPeakCollection * @return PoldiPeakCollection with integrated intensities */ PoldiPeakCollection_sptr PoldiFitPeaks2D::getIntegratedPeakCollection( const PoldiPeakCollection_sptr &rawPeakCollection) const { if (!rawPeakCollection) { throw std::invalid_argument( "Cannot proceed with invalid PoldiPeakCollection."); } if (!isValidDeltaT(m_deltaT)) { throw std::invalid_argument("Cannot proceed with invalid time bin size."); } if (!m_timeTransformer) { throw std::invalid_argument( "Cannot proceed with invalid PoldiTimeTransformer."); } if (rawPeakCollection->intensityType() == PoldiPeakCollection::Integral) { /* Intensities are integral already - don't need to do anything, * except cloning the collection, to make behavior consistent, since * integrating also results in a new peak collection. */ return rawPeakCollection->clone(); } /* If no profile function is specified, it's not possible to get integrated * intensities at all and we try to use the one specified by the user * instead. */ std::string profileFunctionName = rawPeakCollection->getProfileFunctionName(); if (!rawPeakCollection->hasProfileFunctionName()) { profileFunctionName = getPropertyValue("PeakProfileFunction"); } std::vector<std::string> allowedProfiles = FunctionFactory::Instance().getFunctionNames<IPeakFunction>(); if (std::find(allowedProfiles.begin(), allowedProfiles.end(), profileFunctionName) == allowedProfiles.end()) { throw std::runtime_error( "Cannot integrate peak profiles with invalid profile function."); } PoldiPeakCollection_sptr integratedPeakCollection = boost::make_shared<PoldiPeakCollection>(PoldiPeakCollection::Integral); integratedPeakCollection->setProfileFunctionName(profileFunctionName); // Preserve unit cell, point group assignCrystalData(integratedPeakCollection, rawPeakCollection); for (size_t i = 0; i < rawPeakCollection->peakCount(); ++i) { PoldiPeak_sptr peak = rawPeakCollection->peak(i); IPeakFunction_sptr profileFunction = boost::dynamic_pointer_cast<IPeakFunction>( FunctionFactory::Instance().createFunction(profileFunctionName)); profileFunction->setHeight(peak->intensity()); profileFunction->setFwhm(peak->fwhm(PoldiPeak::AbsoluteD)); PoldiPeak_sptr integratedPeak = peak->clone(); integratedPeak->setIntensity(UncertainValue(profileFunction->intensity())); integratedPeakCollection->addPeak(integratedPeak); } return integratedPeakCollection; }
/** Generate peaks in the given output workspace * @param functionmap :: map to contain the list of functions with key as their spectra * @param dataWS :: output matrix workspace */ void GeneratePeaks::generatePeaks(const std::map<specid_t, std::vector<std::pair<double, API::IFunction_sptr> > >& functionmap, API::MatrixWorkspace_sptr dataWS) { // Calcualte function std::map<specid_t, std::vector<std::pair<double, API::IFunction_sptr> > >::const_iterator mapiter; for (mapiter = functionmap.begin(); mapiter != functionmap.end(); ++mapiter) { // Get spec id and translated to wsindex in the output workspace specid_t specid = mapiter->first; specid_t wsindex; if (m_newWSFromParent) wsindex = specid; else wsindex = m_SpectrumMap[specid]; const std::vector<std::pair<double, API::IFunction_sptr> >& vec_centrefunc = mapiter->second; size_t numpeaksinspec = mapiter->second.size(); for (size_t ipeak = 0; ipeak < numpeaksinspec; ++ipeak) { const std::pair<double, API::IFunction_sptr>& centrefunc = vec_centrefunc[ipeak]; // Determine boundary API::IPeakFunction_sptr thispeak = getPeakFunction(centrefunc.second); double centre = centrefunc.first; double fwhm = thispeak->fwhm(); // const MantidVec& X = dataWS->dataX(wsindex); double leftbound = centre - m_numPeakWidth*fwhm; if (ipeak > 0) { // Not left most peak. API::IPeakFunction_sptr leftPeak = getPeakFunction(vec_centrefunc[ipeak-1].second); double middle = 0.5*(centre + leftPeak->centre()); if (leftbound < middle) leftbound = middle; } std::vector<double>::const_iterator left = std::lower_bound(X.begin(), X.end(), leftbound); if (left == X.end()) left = X.begin(); double rightbound = centre + m_numPeakWidth*fwhm; if (ipeak != numpeaksinspec-1) { // Not the rightmost peak IPeakFunction_sptr rightPeak = getPeakFunction(vec_centrefunc[ipeak+1].second); double middle = 0.5*(centre + rightPeak->centre()); if (rightbound > middle) rightbound = middle; } std::vector<double>::const_iterator right = std::lower_bound(left + 1, X.end(), rightbound); // Build domain & function API::FunctionDomain1DVector domain(left, right); //dataWS->dataX(wsindex)); // Evaluate the function API::FunctionValues values(domain); centrefunc.second->function(domain, values); // Put to output std::size_t offset = (left-X.begin()); std::size_t numY = values.size(); for (std::size_t i = 0; i < numY; i ++) { dataWS->dataY(wsindex)[i + offset] += values[i]; } } // ENDFOR(ipeak) } return; }
double PoldiFitPeaks1D::getFwhmWidthRelation(IPeakFunction_sptr peakFunction) const { return peakFunction->fwhm() / peakFunction->getParameter(2); }