diff --git a/Code/Mantid/Framework/SINQ/inc/MantidSINQ/PoldiFitPeaks2D.h b/Code/Mantid/Framework/SINQ/inc/MantidSINQ/PoldiFitPeaks2D.h index dc2d381822e324b24fffd5f45d4f864a9865e578..165df2ca7c0bb74e5922db6f39b58832342b1ed5 100644 --- a/Code/Mantid/Framework/SINQ/inc/MantidSINQ/PoldiFitPeaks2D.h +++ b/Code/Mantid/Framework/SINQ/inc/MantidSINQ/PoldiFitPeaks2D.h @@ -5,6 +5,10 @@ #include "MantidSINQ/DllConfig.h" #include "MantidAPI/Algorithm.h" #include "MantidAPI/IFunction.h" +#include "MantidAPI/IPeakFunction.h" + +#include "MantidKernel/Matrix.h" + #include "MantidDataObjects/TableWorkspace.h" #include "MantidSINQ/PoldiUtilities/PoldiPeakCollection.h" #include "MantidSINQ/PoldiUtilities/PoldiTimeTransformer.h" @@ -58,6 +62,10 @@ public: virtual const std::string summary() const; + boost::shared_ptr<Kernel::DblMatrix> getLocalCovarianceMatrix( + const boost::shared_ptr<const Kernel::DblMatrix> &covarianceMatrix, + size_t parameterOffset, size_t nParams) const; + protected: PoldiPeakCollection_sptr getPeakCollection(const DataObjects::TableWorkspace_sptr &peakTable) const; @@ -72,7 +80,7 @@ protected: PoldiPeakCollection_sptr &to) const; PoldiPeakCollection_sptr - getPeakCollectionFromFunction(const API::IFunction_sptr &fitFunction) const; + getPeakCollectionFromFunction(const API::IFunction_sptr &fitFunction); Poldi2DFunction_sptr getFunctionFromPeakCollection( const PoldiPeakCollection_sptr &peakCollection) const; void addBackgroundTerms(Poldi2DFunction_sptr poldi2DFunction) const; diff --git a/Code/Mantid/Framework/SINQ/src/PoldiFitPeaks2D.cpp b/Code/Mantid/Framework/SINQ/src/PoldiFitPeaks2D.cpp index 735094834f0288d4e726c83a446d37d785719773..ce552fe18c6fa3c9f00dc5b70fd85ea99ce4f156 100644 --- a/Code/Mantid/Framework/SINQ/src/PoldiFitPeaks2D.cpp +++ b/Code/Mantid/Framework/SINQ/src/PoldiFitPeaks2D.cpp @@ -50,9 +50,7 @@ const std::string PoldiFitPeaks2D::name() const { return "PoldiFitPeaks2D"; } int PoldiFitPeaks2D::version() const { return 1; } /// Algorithm's category for identification. @see Algorithm::category -const std::string PoldiFitPeaks2D::category() const { - return "SINQ\\Poldi"; -} +const std::string PoldiFitPeaks2D::category() const { return "SINQ\\Poldi"; } /// Very short algorithm summary. @see Algorith::summary const std::string PoldiFitPeaks2D::summary() const { @@ -102,6 +100,37 @@ void PoldiFitPeaks2D::init() { "Table workspace with fitted peaks."); } +/** + * Extracts the covariance matrix for the supplied function + * + * This method extracts the covariance matrix for a sub-function from + * the global covariance matrix. If no matrix is given, a zero-matrix is + * returned. + * + * @param covarianceMatrix :: Global covariance matrix. + * @param parameterOffset :: Offset for the parameters of profileFunction. + * @param nParams :: Number of parameters of the local function. + * @return + */ +boost::shared_ptr<DblMatrix> PoldiFitPeaks2D::getLocalCovarianceMatrix( + const boost::shared_ptr<const Kernel::DblMatrix> &covarianceMatrix, + size_t parameterOffset, size_t nParams) const { + if (covarianceMatrix) { + boost::shared_ptr<Kernel::DblMatrix> localCov = + boost::make_shared<Kernel::DblMatrix>(nParams, nParams, false); + for (size_t j = 0; j < nParams; ++j) { + for (size_t k = 0; k < nParams; ++k) { + (*localCov)[j][k] = + (*covarianceMatrix)[parameterOffset + j][parameterOffset + k]; + } + } + + return localCov; + } + + return boost::make_shared<Kernel::DblMatrix>(nParams, nParams, false); +} + /** * Construct a PoldiPeakCollection from a Poldi2DFunction * @@ -114,7 +143,7 @@ void PoldiFitPeaks2D::init() { * @return PoldiPeakCollection containing peaks with normalized intensities */ PoldiPeakCollection_sptr PoldiFitPeaks2D::getPeakCollectionFromFunction( - const IFunction_sptr &fitFunction) const { + const IFunction_sptr &fitFunction) { Poldi2DFunction_sptr poldi2DFunction = boost::dynamic_pointer_cast<Poldi2DFunction>(fitFunction); @@ -126,6 +155,11 @@ PoldiPeakCollection_sptr PoldiFitPeaks2D::getPeakCollectionFromFunction( 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<PoldiSpectrumDomainFunction> peakFunction = boost::dynamic_pointer_cast<PoldiSpectrumDomainFunction>( @@ -136,36 +170,35 @@ PoldiPeakCollection_sptr PoldiFitPeaks2D::getPeakCollectionFromFunction( 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; + + 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 height = profileFunction->height(); + double fwhmValue = profileFunction->fwhm(); - size_t dIndex = 0; - size_t iIndex = 0; - size_t fIndex = 0; - - for (size_t j = 0; j < profileFunction->nParams(); ++j) { - if (profileFunction->getParameter(j) == centre) { - dIndex = j; - } else if (profileFunction->getParameter(j) == height) { - iIndex = j; - } else { - fIndex = j; - } - } - - // size_t dIndex = peakFunction->parameterIndex("Centre"); - UncertainValue d(peakFunction->getParameter(dIndex), - peakFunction->getError(dIndex)); + ITableWorkspace_sptr errorTable = + errorAlg->getProperty("OutputWorkspace"); - // size_t iIndex = peakFunction->parameterIndex("Area"); - UncertainValue intensity(peakFunction->getParameter(iIndex), - peakFunction->getError(iIndex)); + double centreError = errorTable->cell<double>(0, 2); + double heightError = errorTable->cell<double>(1, 2); + double fwhmError = errorTable->cell<double>(2, 2); - // size_t fIndex = peakFunction->parameterIndex("Sigma"); - double fwhmValue = profileFunction->fwhm(); - UncertainValue fwhm(fwhmValue, fwhmValue / - peakFunction->getParameter(fIndex) * - peakFunction->getError(fIndex)); + UncertainValue d(centre, centreError); + UncertainValue intensity(height, heightError); + UncertainValue fwhm(fwhmValue, fwhmError); PoldiPeak_sptr peak = PoldiPeak::create(MillerIndices(), d, intensity, UncertainValue(1.0)); diff --git a/Code/Mantid/Framework/SINQ/test/PoldiFitPeaks2DTest.h b/Code/Mantid/Framework/SINQ/test/PoldiFitPeaks2DTest.h index 9c18d599c85b0f0833c8ea46ca5a989824390667..1ac7a69edaaf3814ff1e7001da18d7d75adc1249 100644 --- a/Code/Mantid/Framework/SINQ/test/PoldiFitPeaks2DTest.h +++ b/Code/Mantid/Framework/SINQ/test/PoldiFitPeaks2DTest.h @@ -6,6 +6,8 @@ #include "MantidAPI/FrameworkManager.h" #include "MantidAPI/AlgorithmManager.h" +#include "MantidKernel/Matrix.h" + #include "MantidSINQ/PoldiFitPeaks2D.h" #include "MantidSINQ/PoldiUtilities/PoldiSpectrumDomainFunction.h" #include "MantidSINQ/PoldiUtilities/PoldiMockInstrumentHelpers.h" @@ -14,6 +16,7 @@ using namespace Mantid::Poldi; using namespace Mantid::API; using namespace Mantid::DataObjects; +using namespace Mantid::Kernel; class PoldiFitPeaks2DTest : public CxxTest::TestSuite { @@ -234,6 +237,18 @@ public: PoldiPeakCollection_sptr peaks = PoldiPeakCollectionHelpers::createPoldiPeakCollectionNormalized(); IFunction_sptr poldi2DFunction = spectrumCalculator.getFunctionFromPeakCollection(peaks); + size_t nParams = poldi2DFunction->nParams(); + + // Make a matrix with diagonal elements = 0.05 and set as covariance matrix + boost::shared_ptr<DblMatrix> matrix = boost::make_shared<DblMatrix>(nParams, nParams, true); + matrix->operator *=(0.05); + poldi2DFunction->setCovarianceMatrix(matrix); + + // Also set errors for old behavior + for(size_t i = 0; i < nParams; ++i) { + poldi2DFunction->setError(i, sqrt(0.05)); + } + PoldiPeakCollection_sptr peaksFromFunction = spectrumCalculator.getPeakCollectionFromFunction(poldi2DFunction); TS_ASSERT_EQUALS(peaksFromFunction->peakCount(), peaks->peakCount()); @@ -241,8 +256,11 @@ public: PoldiPeak_sptr functionPeak = peaksFromFunction->peak(i); PoldiPeak_sptr referencePeak = peaks->peak(i); - TS_ASSERT_EQUALS(functionPeak->d(), referencePeak->d()); - TS_ASSERT_EQUALS(functionPeak->fwhm(), referencePeak->fwhm()); + TS_ASSERT_EQUALS(functionPeak->d().value(), referencePeak->d().value()); + TS_ASSERT_EQUALS(functionPeak->fwhm().value(), referencePeak->fwhm().value()); + TS_ASSERT_DELTA(functionPeak->d().error(), sqrt(0.05), 1e-6); + TS_ASSERT_DELTA(functionPeak->fwhm(PoldiPeak::AbsoluteD).error(), sqrt(0.05) * (2.0 * sqrt(2.0 * log(2.0))), 1e-6); + } }