diff --git a/Code/Mantid/Framework/SINQ/inc/MantidSINQ/PoldiCalculateSpectrum2D.h b/Code/Mantid/Framework/SINQ/inc/MantidSINQ/PoldiCalculateSpectrum2D.h index a279c0b500bf..6847906982c2 100644 --- a/Code/Mantid/Framework/SINQ/inc/MantidSINQ/PoldiCalculateSpectrum2D.h +++ b/Code/Mantid/Framework/SINQ/inc/MantidSINQ/PoldiCalculateSpectrum2D.h @@ -4,13 +4,12 @@ #include "MantidKernel/System.h" #include "MantidSINQ/DllConfig.h" #include "MantidAPI/Algorithm.h" -#include "MantidAPI/MultiDomainFunction.h" +#include "MantidAPI/IFunction.h" #include "MantidDataObjects/TableWorkspace.h" #include "MantidSINQ/PoldiUtilities/PoldiPeakCollection.h" #include "MantidSINQ/PoldiUtilities/PoldiTimeTransformer.h" #include "MantidSINQ/PoldiUtilities/Poldi2DFunction.h" - namespace Mantid { namespace Poldi @@ -64,10 +63,13 @@ class MANTID_SINQ_DLL PoldiCalculateSpectrum2D : public API::Algorithm PoldiPeakCollection_sptr getNormalizedPeakCollection(const PoldiPeakCollection_sptr &peakCollection) const; PoldiPeakCollection_sptr getCountPeakCollection(const PoldiPeakCollection_sptr &peakCollection) const; + PoldiPeakCollection_sptr getPeakCollectionFromFunction(const API::IFunction_sptr &fitFunction) const; boost::shared_ptr getFunctionFromPeakCollection(const PoldiPeakCollection_sptr &peakCollection) const; void addBackgroundTerms(boost::shared_ptr poldi2DFunction) const; - API::MatrixWorkspace_sptr calculateSpectrum(const PoldiPeakCollection_sptr &peakCollection, const API::MatrixWorkspace_sptr &matrixWorkspace); + API::IAlgorithm_sptr calculateSpectrum(const PoldiPeakCollection_sptr &peakCollection, const API::MatrixWorkspace_sptr &matrixWorkspace); + API::MatrixWorkspace_sptr getWorkspace(const API::IAlgorithm_sptr &fitAlgorithm) const; + API::IFunction_sptr getFunction(const API::IAlgorithm_sptr &fitAlgorithm) const; void setTimeTransformerFromInstrument(const PoldiInstrumentAdapter_sptr &poldiInstrument); void setTimeTransformer(const PoldiTimeTransformer_sptr &poldiTimeTransformer); diff --git a/Code/Mantid/Framework/SINQ/src/PoldiCalculateSpectrum2D.cpp b/Code/Mantid/Framework/SINQ/src/PoldiCalculateSpectrum2D.cpp index 6d59e6296915..fb8248dd9633 100644 --- a/Code/Mantid/Framework/SINQ/src/PoldiCalculateSpectrum2D.cpp +++ b/Code/Mantid/Framework/SINQ/src/PoldiCalculateSpectrum2D.cpp @@ -74,7 +74,53 @@ namespace Poldi declareProperty("FitLinearBackground", true, "Add a background term linear in 2theta to the fit."); declareProperty("LinearBackgroundParameter", 0.0, "Initial value of linear background."); + declareProperty("MaximumIterations", 0, "Maximum number of iterations for the fit. Use 0 to calculate 2D-spectrum without fitting."); + declareProperty(new WorkspaceProperty("OutputWorkspace","",Direction::Output), "Calculated POLDI 2D-spectrum"); + declareProperty(new WorkspaceProperty("RefinedPoldiPeakWorkspace", "", Direction::Output), "Table workspace with fitted 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 PoldiCalculateSpectrum2D::getPeakCollectionFromFunction(const IFunction_sptr &fitFunction) const + { + boost::shared_ptr poldi2DFunction = boost::dynamic_pointer_cast(fitFunction); + + if(!poldi2DFunction) { + throw std::invalid_argument("Cannot process function that is not a Poldi2DFunction."); + } + + PoldiPeakCollection_sptr normalizedPeaks = boost::make_shared(PoldiPeakCollection::Integral); + + for(size_t i = 0; i < poldi2DFunction->nFunctions(); ++i) { + boost::shared_ptr peakFunction = boost::dynamic_pointer_cast(poldi2DFunction->getFunction(i)); + + if(peakFunction) { + size_t dIndex = peakFunction->parameterIndex("Centre"); + UncertainValue d(peakFunction->getParameter(dIndex), peakFunction->getError(dIndex)); + + size_t iIndex = peakFunction->parameterIndex("Area"); + UncertainValue intensity(peakFunction->getParameter(iIndex), peakFunction->getError(iIndex)); + + size_t fIndex = peakFunction->parameterIndex("Fwhm"); + UncertainValue fwhm(peakFunction->getParameter(fIndex), peakFunction->getError(fIndex)); + + PoldiPeak_sptr peak = PoldiPeak::create(MillerIndices(), d, intensity, UncertainValue(1.0)); + peak->setFwhm(fwhm, PoldiPeak::FwhmRelation::AbsoluteD); + + normalizedPeaks->addPeak(peak); + } + } + + return normalizedPeaks; } /** @@ -124,7 +170,14 @@ namespace Poldi peakCollection->setProfileFunctionName(profileFunctionProperty->value()); } - setProperty("OutputWorkspace", calculateSpectrum(peakCollection, ws)); + IAlgorithm_sptr fitAlgorithm = calculateSpectrum(peakCollection, ws); + + IFunction_sptr fitFunction = getFunction(fitAlgorithm); + PoldiPeakCollection_sptr normalizedPeaks = getPeakCollectionFromFunction(fitFunction); + PoldiPeakCollection_sptr integralPeaks = getCountPeakCollection(normalizedPeaks); + + setProperty("OutputWorkspace", getWorkspace(fitAlgorithm)); + setProperty("RefinedPoldiPeakWorkspace", integralPeaks->asTableWorkspace()); } /** @@ -154,15 +207,17 @@ namespace Poldi } /** - * Calculates the 2D spectrum in a MatrixWorkspace + * Performs the fit and returns the fit algorithm * - * In this method the actual function calculation is performed using Fit. + * In this method the actual function fit/calculation is performed + * using the Fit algorithm. After execution the algorithm is returned for + * further processing. * * @param peakCollection :: PoldiPeakCollection * @param matrixWorkspace :: MatrixWorkspace with POLDI instrument and correct dimensions - * @return MatrixWorkspace with the calculated data + * @return Instance of Fit-algorithm, after execution */ - MatrixWorkspace_sptr PoldiCalculateSpectrum2D::calculateSpectrum(const PoldiPeakCollection_sptr &peakCollection, const MatrixWorkspace_sptr &matrixWorkspace) + IAlgorithm_sptr PoldiCalculateSpectrum2D::calculateSpectrum(const PoldiPeakCollection_sptr &peakCollection, const MatrixWorkspace_sptr &matrixWorkspace) { PoldiPeakCollection_sptr integratedPeaks = getIntegratedPeakCollection(peakCollection); PoldiPeakCollection_sptr normalizedPeakCollection = getNormalizedPeakCollection(integratedPeaks); @@ -180,14 +235,36 @@ namespace Poldi fit->setProperty("Function", boost::dynamic_pointer_cast(mdFunction)); fit->setProperty("InputWorkspace", matrixWorkspace); fit->setProperty("CreateOutput", true); - fit->setProperty("MaxIterations", 0); + + int maxIterations = getProperty("MaximumIterations"); + fit->setProperty("MaxIterations", maxIterations); + fit->setProperty("Minimizer", "Levenberg-MarquardtMD"); fit->execute(); - MatrixWorkspace_sptr outputWs = fit->getProperty("OutputWorkspace"); + return fit; + } + + /// Returns the output workspace stored in the Fit algorithm. + MatrixWorkspace_sptr PoldiCalculateSpectrum2D::getWorkspace(const IAlgorithm_sptr &fitAlgorithm) const + { + if(!fitAlgorithm) { + throw std::invalid_argument("Cannot extract workspace from null-algorithm."); + } + + MatrixWorkspace_sptr outputWorkspace = fitAlgorithm->getProperty("OutputWorkspace"); + return outputWorkspace; + } + + IFunction_sptr PoldiCalculateSpectrum2D::getFunction(const IAlgorithm_sptr &fitAlgorithm) const + { + if(!fitAlgorithm) { + throw std::invalid_argument("Cannot extract function from null-algorithm."); + } - return outputWs; + IFunction_sptr fitFunction = fitAlgorithm->getProperty("Function"); + return fitFunction; } /** diff --git a/Code/Mantid/Framework/SINQ/test/PoldiCalculateSpectrum2DTest.h b/Code/Mantid/Framework/SINQ/test/PoldiCalculateSpectrum2DTest.h index 9e6b76f9bc66..8137f6211bf2 100644 --- a/Code/Mantid/Framework/SINQ/test/PoldiCalculateSpectrum2DTest.h +++ b/Code/Mantid/Framework/SINQ/test/PoldiCalculateSpectrum2DTest.h @@ -202,6 +202,26 @@ class PoldiCalculateSpectrum2DTest : public CxxTest::TestSuite } } + void testGetPeakCollectionFromFunction() + { + TestablePoldiCalculateSpectrum2D spectrumCalculator; + PoldiPeakCollection_sptr peaks = PoldiPeakCollectionHelpers::createPoldiPeakCollectionNormalized(); + + IFunction_sptr poldi2DFunction = spectrumCalculator.getFunctionFromPeakCollection(peaks); + + PoldiPeakCollection_sptr peaksFromFunction = spectrumCalculator.getPeakCollectionFromFunction(poldi2DFunction); + + TS_ASSERT_EQUALS(peaksFromFunction->peakCount(), peaks->peakCount()); + for(size_t i = 0; i < peaksFromFunction->peakCount(); ++i) { + 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->intensity(), referencePeak->intensity()); + } + } + void testAddBackgroundFunctions() { TestablePoldiCalculateSpectrum2D spectrumCalculator;