From cbebfee4fe7e3502d0b6b257f38e8fd2102c2a5e Mon Sep 17 00:00:00 2001 From: Michael Wedel Date: Wed, 18 Feb 2015 10:37:31 +0100 Subject: [PATCH 01/18] Refs #11104. Moving PeakFunctionIntegrator to API PeakFunctionIntegrator was moved from MantidSINQ to MantidAPI. PoldiFitPeaks2D had to be changed to use the correct header file. --- Code/Mantid/Framework/API/CMakeLists.txt | 3 + .../inc/MantidAPI}/PeakFunctionIntegrator.h | 22 +-- .../src}/PeakFunctionIntegrator.cpp | 8 +- .../test/PeakFunctionIntegratorTest.h | 21 +- .../PoldiBatchFitIndividualPeaks.py | 181 ++++++++++++++++++ Code/Mantid/Framework/SINQ/CMakeLists.txt | 3 - .../Framework/SINQ/src/PoldiFitPeaks2D.cpp | 2 +- .../SINQ/src/PoldiIndexKnownCompounds.cpp | 1 - 8 files changed, 211 insertions(+), 30 deletions(-) rename Code/Mantid/Framework/{SINQ/inc/MantidSINQ/PoldiUtilities => API/inc/MantidAPI}/PeakFunctionIntegrator.h (74%) rename Code/Mantid/Framework/{SINQ/src/PoldiUtilities => API/src}/PeakFunctionIntegrator.cpp (97%) rename Code/Mantid/Framework/{SINQ => API}/test/PeakFunctionIntegratorTest.h (92%) create mode 100644 Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/PoldiBatchFitIndividualPeaks.py diff --git a/Code/Mantid/Framework/API/CMakeLists.txt b/Code/Mantid/Framework/API/CMakeLists.txt index cc62a6115e29..c59fd55a43a5 100644 --- a/Code/Mantid/Framework/API/CMakeLists.txt +++ b/Code/Mantid/Framework/API/CMakeLists.txt @@ -93,6 +93,7 @@ set ( SRC_FILES src/ParamFunction.cpp src/ParameterReference.cpp src/ParameterTie.cpp + src/PeakFunctionIntegrator.cpp src/PeakTransform.cpp src/PeakTransformHKL.cpp src/PeakTransformQLab.cpp @@ -252,6 +253,7 @@ set ( INC_FILES inc/MantidAPI/ParamFunction.h inc/MantidAPI/ParameterReference.h inc/MantidAPI/ParameterTie.h + inc/MantidAPI/PeakFunctionIntegrator.h inc/MantidAPI/PeakTransform.h inc/MantidAPI/PeakTransformFactory.h inc/MantidAPI/PeakTransformHKL.h @@ -348,6 +350,7 @@ set ( TEST_FILES ParamFunctionAttributeHolderTest.h ParameterReferenceTest.h ParameterTieTest.h + PeakFunctionIntegratorTest.h PeakTransformHKLTest.h PeakTransformQLabTest.h PeakTransformQSampleTest.h diff --git a/Code/Mantid/Framework/SINQ/inc/MantidSINQ/PoldiUtilities/PeakFunctionIntegrator.h b/Code/Mantid/Framework/API/inc/MantidAPI/PeakFunctionIntegrator.h similarity index 74% rename from Code/Mantid/Framework/SINQ/inc/MantidSINQ/PoldiUtilities/PeakFunctionIntegrator.h rename to Code/Mantid/Framework/API/inc/MantidAPI/PeakFunctionIntegrator.h index c287ca1bf842..a191dd280707 100644 --- a/Code/Mantid/Framework/SINQ/inc/MantidSINQ/PoldiUtilities/PeakFunctionIntegrator.h +++ b/Code/Mantid/Framework/API/inc/MantidAPI/PeakFunctionIntegrator.h @@ -1,12 +1,12 @@ #ifndef PEAKFUNCTIONINTEGRATOR_H #define PEAKFUNCTIONINTEGRATOR_H -#include "MantidSINQ/DllConfig.h" +#include "MantidAPI/DllConfig.h" #include "MantidAPI/IPeakFunction.h" #include "gsl/gsl_integration.h" namespace Mantid { -namespace Poldi { +namespace API { /** PeakFunctionIntegrator : * @@ -37,7 +37,7 @@ namespace Poldi { Code Documentation is available at: */ -struct MANTID_SINQ_DLL IntegrationResult { +struct MANTID_API_DLL IntegrationResult { double result; double error; size_t intervals; @@ -46,7 +46,7 @@ struct MANTID_SINQ_DLL IntegrationResult { bool success; }; -class MANTID_SINQ_DLL PeakFunctionIntegrator { +class MANTID_API_DLL PeakFunctionIntegrator { public: PeakFunctionIntegrator(double requiredRelativePrecision = 1e-8); virtual ~PeakFunctionIntegrator(); @@ -55,27 +55,27 @@ class MANTID_SINQ_DLL PeakFunctionIntegrator { double requiredRelativePrecision() const; IntegrationResult - integrateInfinity(API::IPeakFunction_const_sptr peakFunction) const; + integrateInfinity(IPeakFunction_const_sptr peakFunction) const; IntegrationResult - integratePositiveInfinity(API::IPeakFunction_const_sptr peakFunction, + integratePositiveInfinity(IPeakFunction_const_sptr peakFunction, double lowerLimit) const; IntegrationResult - integrateNegativeInfinity(API::IPeakFunction_const_sptr peakFunction, + integrateNegativeInfinity(IPeakFunction_const_sptr peakFunction, double upperLimit) const; - IntegrationResult integrate(API::IPeakFunction_const_sptr peakFunction, + IntegrationResult integrate(IPeakFunction_const_sptr peakFunction, double lowerLimit, double upperLimit) const; protected: - gsl_function getGSLFunction(API::IPeakFunction_const_sptr peakFunction) const; - void throwIfInvalid(API::IPeakFunction_const_sptr peakFunction) const; + gsl_function getGSLFunction(IPeakFunction_const_sptr peakFunction) const; + void throwIfInvalid(IPeakFunction_const_sptr peakFunction) const; gsl_integration_workspace *m_integrationWorkspace; double m_relativePrecision; }; -double MANTID_SINQ_DLL gsl_peak_wrapper(double x, void *parameters); +double MANTID_API_DLL gsl_peak_wrapper(double x, void *parameters); } } diff --git a/Code/Mantid/Framework/SINQ/src/PoldiUtilities/PeakFunctionIntegrator.cpp b/Code/Mantid/Framework/API/src/PeakFunctionIntegrator.cpp similarity index 97% rename from Code/Mantid/Framework/SINQ/src/PoldiUtilities/PeakFunctionIntegrator.cpp rename to Code/Mantid/Framework/API/src/PeakFunctionIntegrator.cpp index 620b41e9237a..056af5b73fe9 100644 --- a/Code/Mantid/Framework/SINQ/src/PoldiUtilities/PeakFunctionIntegrator.cpp +++ b/Code/Mantid/Framework/API/src/PeakFunctionIntegrator.cpp @@ -1,4 +1,4 @@ -#include "MantidSINQ/PoldiUtilities/PeakFunctionIntegrator.h" +#include "MantidAPI/PeakFunctionIntegrator.h" #include "MantidAPI/FunctionDomain1D.h" #include "gsl/gsl_errno.h" @@ -6,9 +6,7 @@ #include namespace Mantid { -namespace Poldi { - -using namespace API; +namespace API { /** Constructor with required relative precision argument. The default is 1e-8. * See also PeakFunctionIntegrator::setRequiredRelativePrecision. @@ -153,7 +151,7 @@ PeakFunctionIntegrator::integrate(IPeakFunction_const_sptr peakFunction, gsl_function PeakFunctionIntegrator::getGSLFunction( IPeakFunction_const_sptr peakFunction) const { gsl_function f; - f.function = &Mantid::Poldi::gsl_peak_wrapper; + f.function = &Mantid::API::gsl_peak_wrapper; f.params = &peakFunction; return f; diff --git a/Code/Mantid/Framework/SINQ/test/PeakFunctionIntegratorTest.h b/Code/Mantid/Framework/API/test/PeakFunctionIntegratorTest.h similarity index 92% rename from Code/Mantid/Framework/SINQ/test/PeakFunctionIntegratorTest.h rename to Code/Mantid/Framework/API/test/PeakFunctionIntegratorTest.h index 59b641d58fb3..96162318a7be 100644 --- a/Code/Mantid/Framework/SINQ/test/PeakFunctionIntegratorTest.h +++ b/Code/Mantid/Framework/API/test/PeakFunctionIntegratorTest.h @@ -2,14 +2,12 @@ #define PEAKFUNCTIONINTEGRATORTEST_H #include -#include "MantidSINQ/PoldiUtilities/PeakFunctionIntegrator.h" - -#include "MantidCurveFitting/Gaussian.h" -#include "MantidCurveFitting/Lorentzian.h" +#include "MantidAPI/PeakFunctionIntegrator.h" +#include "MantidAPI/FrameworkManager.h" +#include "MantidAPI/FunctionFactory.h" #include "gsl/gsl_errno.h" -using namespace Mantid::Poldi; using namespace Mantid::API; using namespace Mantid::CurveFitting; @@ -30,10 +28,15 @@ class TestablePeakFunctionIntegrator : public PeakFunctionIntegrator class PeakFunctionIntegratorTest : public CxxTest::TestSuite { private: + PeakFunctionIntegratorTest() + { + FrameworkManager::Instance(); + } + IPeakFunction_sptr getGaussian(double center, double fwhm, double height) { - IPeakFunction_sptr gaussian(new Gaussian); - gaussian->initialize(); + IPeakFunction_sptr gaussian = boost::dynamic_pointer_cast( + FunctionFactory::Instance().createFunction("Gaussian")); gaussian->setCentre(center); gaussian->setFwhm(fwhm); gaussian->setHeight(height); @@ -48,8 +51,8 @@ class PeakFunctionIntegratorTest : public CxxTest::TestSuite IPeakFunction_sptr getLorentzian(double center, double fwhm, double height) { - IPeakFunction_sptr lorentzian(new Lorentzian); - lorentzian->initialize(); + IPeakFunction_sptr lorentzian = boost::dynamic_pointer_cast( + FunctionFactory::Instance().createFunction("Lorentzian")); lorentzian->setCentre(center); lorentzian->setFwhm(fwhm); lorentzian->setHeight(height); diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/PoldiBatchFitIndividualPeaks.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/PoldiBatchFitIndividualPeaks.py new file mode 100644 index 000000000000..b77beeb9d17c --- /dev/null +++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/PoldiBatchFitIndividualPeaks.py @@ -0,0 +1,181 @@ +from mantid.api import * +from mantid.kernel import * +from mantid.simpleapi import * +import os +import math +import sys + +class PoldiSample: + def __init__(self, initString): + self._name, self._runList = self.parseInitString(initString) + + def name(self): + return self._name + + def runList(self): + return self._runList + + def runNames(self): + return [x[0] for x in self._runList] + + def parseInitString(self, initString): + parts = initString.split(':') + + if not len(parts) == 2: + raise RuntimeError("Unable to parse init string.") + + sampleName = parts[0] + runDict = self.parseRunDictString(parts[1]) + + return (sampleName, runDict) + + def parseRunDictString(self, runDictString): + runRanges = filter(bool, runDictString.strip().split(';')) + + newRunList = [] + for runRange in runRanges: + runPoints = self.parseRunRangeString(runRange) + newRunList += runPoints + + return newRunList + + def parseRunRangeString(self, runRangeString): + runRangeParameters = [int(x) for x in runRangeString.split(',')] + + if not len(runRangeParameters) == 3: + raise RuntimeError("Unable to parse run range string.") + + begin, end, step = runRangeParameters + + runList = [] + for i in range(begin, end + 1, step): + runList.append((i + step - 1, [str(x) for x in range(i, i + step)])) + + print runList + + return runList + +class PoldiProject: + def __init__(self, projectName, sampleListFile): + self._name = projectName + self._sampleList = self.parseSampleListFile(sampleListFile) + + def sampleList(self): + return self._sampleList + + def name(self): + return self._name + + def parseSampleListFile(self, sampleListFile): + fh = open(sampleListFile, 'r') + + sampleList = [] + for line in fh: + if len(line.strip()) > 0 and not line.strip()[0] == '#': + sampleList.append(PoldiSample(line)) + + return sampleList + +class PoldiBatchFitIndividualPeaks(PythonAlgorithm): + prefixes = {'raw': 'raw_', + 'data': 'data_'} + + suffixes = {'correlation': '_correlation', + 'raw_peaks': '_peaks_raw', + 'fit_peaks_1d': '_peaks_fit_1d', + 'fit_peaks_2d': '_peaks_fit_2d', + 'calculated_2d': '_spectrum_fitted_2d', + 'residuals': '_residuals'} + + def category(self): + return "Workflow\\Poldi" + + def name(self): + return "PoldiBatchFitIndividualPeaks" + + def summary(self): + return "Load a file with instructions for batch processing POLDI fits." + + def PyInit(self): + self.declareProperty("ProjectName", "", "Project name to use for labeling") + self.declareProperty(FileProperty(name="SampleListFile", defaultValue="", + action=FileAction.Load)) + self.declareProperty(FileProperty(name="OutputDirectory", defaultValue="", + action=FileAction.OptionalDirectory)) + self.declareProperty(FileProperty(name="CrystalStructures", + defaultValue="", + action=FileAction.OptionalLoad)) + self.declareProperty("PeakNumber", 10, "Number of peaks to fit.") + + def PyExec(self): + poldiProject = PoldiProject(self.getProperty("ProjectName"), + self.getProperty("SampleListFile").valueAsStr) + + sampleCount = len(poldiProject.sampleList()) + progress = Progress(self, start=0.0, end=1.0, nreports=sampleCount) + + for i, sample in enumerate(poldiProject.sampleList()): + self.processSample(sample) + progress.report("Processed sample " + str(i + 1) + " of " + str(sampleCount)) + + def processSample(self, poldiSample): + sampleList = poldiSample.runList() + + for dataPoint in sampleList: + self.processDataPoint(dataPoint) + + def processDataPoint(self, dataPointTuple): + self.loadDataPoint(dataPointTuple) + self.runPoldiAnalysis(dataPointTuple[0]) + + def loadDataPoint(self, dataPointTuple): + dataWorkspaceName = self.prefixes['data'] + str(dataPointTuple[0]) + + rawWorkspaceNames = [ + self.prefixes['raw'] + str(x) for x in dataPointTuple[1]] + + for numor,rawWsName in zip(dataPointTuple[1], rawWorkspaceNames): + LoadSINQ(Instrument="POLDI", Year=2014, + Numor=numor, OutputWorkspace=rawWsName) + LoadInstrument(rawWsName, InstrumentName="POLDI") + + if len(dataPointTuple[1]) > 1: + PoldiMerge(rawWorkspaceNames, OutputWorkspace=dataWorkspaceName) + + for ws in rawWorkspaceNames: + DeleteWorkspace(ws) + + else: + RenameWorkspace(rawWorkspaceNames[0], OutputWorkspace=dataWorkspaceName) + + return dataWorkspaceName + + def runPoldiAnalysis(self, dataPointName): + dataWorkspaceName = self.prefixes['data'] + str(dataPointName) + + correlationWsName = dataWorkspaceName + self.suffixes['correlation'] + PoldiAutoCorrelation(dataWorkspaceName, wlenmin=1.1, wlenmax=5.0, + OutputWorkspace=correlationWsName) + + peakSearchWsName = dataWorkspaceName + self.suffixes['raw_peaks'] + PoldiPeakSearch(correlationWsName, OutputWorkspace=peakSearchWsName) + + DeleteTableRows(peakSearchWsName, + self.getProperty("PeakNumber").valueAsStr + '-30') + + peakFit1DWsName = dataWorkspaceName + self.suffixes['fit_peaks_1d'] + PoldiFitPeaks1D(correlationWsName, PoldiPeakTable=peakSearchWsName, + OutputWorkspace=peakFit1DWsName) + + peakFit2DWsName = dataWorkspaceName + self.suffixes['fit_peaks_2d'] + spectrum2DCalc = dataWorkspaceName + self.suffixes['calculated_2d'] + PoldiFitPeaks2D(dataWorkspaceName, PoldiPeakWorkspace=peakFit1DWsName, + MaximumIterations=100, OutputWorkspace=spectrum2DCalc, + RefinedPoldiPeakWorkspace=peakFit2DWsName) + + residualsWsName = dataWorkspaceName + self.suffixes['residuals'] + PoldiAnalyseResiduals(dataWorkspaceName, spectrum2DCalc, + OutputWorkspace=residualsWsName, + MaxIterations=5) + +AlgorithmFactory.subscribe(PoldiBatchFitIndividualPeaks) \ No newline at end of file diff --git a/Code/Mantid/Framework/SINQ/CMakeLists.txt b/Code/Mantid/Framework/SINQ/CMakeLists.txt index c308ea296586..2cf113c7486f 100644 --- a/Code/Mantid/Framework/SINQ/CMakeLists.txt +++ b/Code/Mantid/Framework/SINQ/CMakeLists.txt @@ -20,7 +20,6 @@ set ( SRC_FILES src/PoldiTruncateData.cpp src/PoldiUtilities/IPoldiFunction1D.cpp src/PoldiUtilities/MillerIndices.cpp - src/PoldiUtilities/PeakFunctionIntegrator.cpp src/PoldiUtilities/Poldi2DFunction.cpp src/PoldiUtilities/PoldiAutoCorrelationCore.cpp src/PoldiUtilities/PoldiBasicChopper.cpp @@ -71,7 +70,6 @@ set ( INC_FILES inc/MantidSINQ/PoldiUtilities/IPoldiFunction1D.h inc/MantidSINQ/PoldiUtilities/MillerIndices.h inc/MantidSINQ/PoldiUtilities/MillerIndicesIO.h - inc/MantidSINQ/PoldiUtilities/PeakFunctionIntegrator.h inc/MantidSINQ/PoldiUtilities/Poldi2DFunction.h inc/MantidSINQ/PoldiUtilities/PoldiAbstractChopper.h inc/MantidSINQ/PoldiUtilities/PoldiAbstractDetector.h @@ -107,7 +105,6 @@ set ( TEST_FILES MDHistoToWorkspace2DTest.h MillerIndicesIOTest.h MillerIndicesTest.h - PeakFunctionIntegratorTest.h Poldi2DFunctionTest.h PoldiAnalyseResidualsTest.h PoldiAutoCorrelationCoreTest.h diff --git a/Code/Mantid/Framework/SINQ/src/PoldiFitPeaks2D.cpp b/Code/Mantid/Framework/SINQ/src/PoldiFitPeaks2D.cpp index 6653f1c3cfbc..498f73ef7e27 100644 --- a/Code/Mantid/Framework/SINQ/src/PoldiFitPeaks2D.cpp +++ b/Code/Mantid/Framework/SINQ/src/PoldiFitPeaks2D.cpp @@ -18,7 +18,7 @@ use the Build/wiki_maker.py script to generate your full wiki page. #include "MantidSINQ/PoldiUtilities/PoldiPeakCollection.h" #include "MantidSINQ/PoldiUtilities/PoldiInstrumentAdapter.h" #include "MantidSINQ/PoldiUtilities/PoldiDeadWireDecorator.h" -#include "MantidSINQ/PoldiUtilities/PeakFunctionIntegrator.h" +#include "MantidAPI/PeakFunctionIntegrator.h" #include "MantidAPI/IPeakFunction.h" #include "MantidSINQ/PoldiUtilities/Poldi2DFunction.h" diff --git a/Code/Mantid/Framework/SINQ/src/PoldiIndexKnownCompounds.cpp b/Code/Mantid/Framework/SINQ/src/PoldiIndexKnownCompounds.cpp index 4f33df0617b0..ee0bf9f4dd06 100644 --- a/Code/Mantid/Framework/SINQ/src/PoldiIndexKnownCompounds.cpp +++ b/Code/Mantid/Framework/SINQ/src/PoldiIndexKnownCompounds.cpp @@ -1,5 +1,4 @@ #include "MantidSINQ/PoldiIndexKnownCompounds.h" -#include "MantidSINQ/PoldiUtilities/PeakFunctionIntegrator.h" #include "MantidKernel/ArrayProperty.h" #include "MantidKernel/MandatoryValidator.h" From 3d01a3f714b9d4eea7a7df4f6ae2ca1818e78e8a Mon Sep 17 00:00:00 2001 From: Michael Wedel Date: Wed, 18 Feb 2015 10:42:08 +0100 Subject: [PATCH 02/18] Refs #11104. Fixing doxygen comments --- .../inc/MantidAPI/PeakFunctionIntegrator.h | 5 +++- .../API/src/PeakFunctionIntegrator.cpp | 29 +++++++++---------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/Code/Mantid/Framework/API/inc/MantidAPI/PeakFunctionIntegrator.h b/Code/Mantid/Framework/API/inc/MantidAPI/PeakFunctionIntegrator.h index a191dd280707..b1f6b71b83a8 100644 --- a/Code/Mantid/Framework/API/inc/MantidAPI/PeakFunctionIntegrator.h +++ b/Code/Mantid/Framework/API/inc/MantidAPI/PeakFunctionIntegrator.h @@ -13,10 +13,13 @@ namespace API { General integration of peaks (in the form of IPeakFunction) by wrapping the corresponding GSL-functions. Integration with infinity limits is supported. + PeakFunctionIntegrator allocates a GSL integration workspace on construction + and frees the memory when it's destroyed. + @author Michael Wedel, Paul Scherrer Institut - SINQ @date 24/04/2014 - Copyright © 2014 PSI-MSS + Copyright © 2014,2015 PSI-MSS This file is part of Mantid. diff --git a/Code/Mantid/Framework/API/src/PeakFunctionIntegrator.cpp b/Code/Mantid/Framework/API/src/PeakFunctionIntegrator.cpp index 056af5b73fe9..cc3673b46f3c 100644 --- a/Code/Mantid/Framework/API/src/PeakFunctionIntegrator.cpp +++ b/Code/Mantid/Framework/API/src/PeakFunctionIntegrator.cpp @@ -45,12 +45,11 @@ double PeakFunctionIntegrator::requiredRelativePrecision() const { } /** Integration of peak function on the interval [-Inf, +Inf]. Internally, - *gsl_integration_qagi is used - * for this. If a default constructed IPeakFunction_const_sptr is passed to the - *function, std::invalid_argument is thrown. - * The results are returned as IntegrationResult-struct, which contains the - *approximation of the integral along - * with other information such as an error estimate (absolute). + * gsl_integration_qagi is used for this. If a default constructed + * IPeakFunction_const_sptr is passed to the function, + * std::invalid_argument is thrown. The results are returned as + * IntegrationResult-struct, which contains the approximation of the integral + * along with other information such as an error estimate (absolute). * * @param peakFunction :: Peak function to integrate. */ @@ -72,9 +71,9 @@ IntegrationResult PeakFunctionIntegrator::integrateInfinity( } /** Integration of peak function on the interval [a, +Inf]. Internally, - *gsl_integration_qagiu is used - * for this. If a default constructed IPeakFunction_const_sptr is passed to the - *function, std::invalid_argument is thrown. + * gsl_integration_qagiu is used for this. If a default constructed + * IPeakFunction_const_sptr is passed to the function, + * std::invalid_argument is thrown. * * @param peakFunction :: Peak function to integrate. */ @@ -96,9 +95,9 @@ IntegrationResult PeakFunctionIntegrator::integratePositiveInfinity( } /** Integration of peak function on the interval [-Inf, b]. Internally, - *gsl_integration_qagil is used - * for this. If a default constructed IPeakFunction_const_sptr is passed to the - *function, std::invalid_argument is thrown. + * gsl_integration_qagil is used for this. If a default constructed + * IPeakFunction_const_sptr is passed to the function, + * std::invalid_argument is thrown. * * @param peakFunction :: Peak function to integrate. */ @@ -120,9 +119,9 @@ IntegrationResult PeakFunctionIntegrator::integrateNegativeInfinity( } /** Integration of peak function on the interval [a, b]. Internally, - *gsl_integration_qags is used - * for this. If a default constructed IPeakFunction_const_sptr is passed to the - *function, std::invalid_argument is thrown. + * gsl_integration_qags is used for this. If a default constructed + * IPeakFunction_const_sptr is passed to the function, + * std::invalid_argument is thrown. * * @param peakFunction :: Peak function to integrate. */ From 3be3b0e8a6b427fd903460d9d1e1604474091e22 Mon Sep 17 00:00:00 2001 From: Michael Wedel Date: Wed, 18 Feb 2015 11:19:01 +0100 Subject: [PATCH 03/18] Refs #11104. Changing signatures of PeakFunctionIntegrator The interface is not limited to smart pointers anymore now, using references instead. --- .../inc/MantidAPI/PeakFunctionIntegrator.h | 11 ++-- .../API/src/PeakFunctionIntegrator.cpp | 53 ++++++------------- .../API/test/PeakFunctionIntegratorTest.h | 29 ++++------ .../Framework/SINQ/src/PoldiFitPeaks2D.cpp | 2 +- 4 files changed, 32 insertions(+), 63 deletions(-) diff --git a/Code/Mantid/Framework/API/inc/MantidAPI/PeakFunctionIntegrator.h b/Code/Mantid/Framework/API/inc/MantidAPI/PeakFunctionIntegrator.h index b1f6b71b83a8..f07e262b1843 100644 --- a/Code/Mantid/Framework/API/inc/MantidAPI/PeakFunctionIntegrator.h +++ b/Code/Mantid/Framework/API/inc/MantidAPI/PeakFunctionIntegrator.h @@ -58,20 +58,19 @@ class MANTID_API_DLL PeakFunctionIntegrator { double requiredRelativePrecision() const; IntegrationResult - integrateInfinity(IPeakFunction_const_sptr peakFunction) const; + integrateInfinity(const IPeakFunction &peakFunction) const; IntegrationResult - integratePositiveInfinity(IPeakFunction_const_sptr peakFunction, + integratePositiveInfinity(const IPeakFunction &peakFunction, double lowerLimit) const; IntegrationResult - integrateNegativeInfinity(IPeakFunction_const_sptr peakFunction, + integrateNegativeInfinity(const IPeakFunction &peakFunction, double upperLimit) const; - IntegrationResult integrate(IPeakFunction_const_sptr peakFunction, + IntegrationResult integrate(const IPeakFunction &peakFunction, double lowerLimit, double upperLimit) const; protected: - gsl_function getGSLFunction(IPeakFunction_const_sptr peakFunction) const; - void throwIfInvalid(IPeakFunction_const_sptr peakFunction) const; + gsl_function getGSLFunction(const IPeakFunction &peakFunction) const; gsl_integration_workspace *m_integrationWorkspace; diff --git a/Code/Mantid/Framework/API/src/PeakFunctionIntegrator.cpp b/Code/Mantid/Framework/API/src/PeakFunctionIntegrator.cpp index cc3673b46f3c..75fcc48e3c40 100644 --- a/Code/Mantid/Framework/API/src/PeakFunctionIntegrator.cpp +++ b/Code/Mantid/Framework/API/src/PeakFunctionIntegrator.cpp @@ -29,8 +29,7 @@ PeakFunctionIntegrator::~PeakFunctionIntegrator() { } /** This method sets the desired numerical relative precision that's passed on - *to the - * GSL integration-routines. + * to the GSL integration-routines. * * @param newPrecision :: Desired relative precision for integrations. */ @@ -45,18 +44,14 @@ double PeakFunctionIntegrator::requiredRelativePrecision() const { } /** Integration of peak function on the interval [-Inf, +Inf]. Internally, - * gsl_integration_qagi is used for this. If a default constructed - * IPeakFunction_const_sptr is passed to the function, - * std::invalid_argument is thrown. The results are returned as + * gsl_integration_qagi is used for this. The results are returned as * IntegrationResult-struct, which contains the approximation of the integral * along with other information such as an error estimate (absolute). * * @param peakFunction :: Peak function to integrate. */ IntegrationResult PeakFunctionIntegrator::integrateInfinity( - IPeakFunction_const_sptr peakFunction) const { - throwIfInvalid(peakFunction); - + const IPeakFunction &peakFunction) const { IntegrationResult result; gsl_function f = getGSLFunction(peakFunction); @@ -71,16 +66,12 @@ IntegrationResult PeakFunctionIntegrator::integrateInfinity( } /** Integration of peak function on the interval [a, +Inf]. Internally, - * gsl_integration_qagiu is used for this. If a default constructed - * IPeakFunction_const_sptr is passed to the function, - * std::invalid_argument is thrown. + * gsl_integration_qagiu is used for this. * * @param peakFunction :: Peak function to integrate. */ IntegrationResult PeakFunctionIntegrator::integratePositiveInfinity( - IPeakFunction_const_sptr peakFunction, double lowerLimit) const { - throwIfInvalid(peakFunction); - + const IPeakFunction &peakFunction, double lowerLimit) const { IntegrationResult result; gsl_function f = getGSLFunction(peakFunction); @@ -95,16 +86,12 @@ IntegrationResult PeakFunctionIntegrator::integratePositiveInfinity( } /** Integration of peak function on the interval [-Inf, b]. Internally, - * gsl_integration_qagil is used for this. If a default constructed - * IPeakFunction_const_sptr is passed to the function, - * std::invalid_argument is thrown. + * gsl_integration_qagil is used for this. * * @param peakFunction :: Peak function to integrate. */ IntegrationResult PeakFunctionIntegrator::integrateNegativeInfinity( - IPeakFunction_const_sptr peakFunction, double upperLimit) const { - throwIfInvalid(peakFunction); - + const IPeakFunction &peakFunction, double upperLimit) const { IntegrationResult result; gsl_function f = getGSLFunction(peakFunction); @@ -119,17 +106,13 @@ IntegrationResult PeakFunctionIntegrator::integrateNegativeInfinity( } /** Integration of peak function on the interval [a, b]. Internally, - * gsl_integration_qags is used for this. If a default constructed - * IPeakFunction_const_sptr is passed to the function, - * std::invalid_argument is thrown. + * gsl_integration_qags is used for this. * * @param peakFunction :: Peak function to integrate. */ IntegrationResult -PeakFunctionIntegrator::integrate(IPeakFunction_const_sptr peakFunction, +PeakFunctionIntegrator::integrate(const IPeakFunction &peakFunction, double lowerLimit, double upperLimit) const { - throwIfInvalid(peakFunction); - IntegrationResult result; gsl_function f = getGSLFunction(peakFunction); @@ -148,24 +131,22 @@ PeakFunctionIntegrator::integrate(IPeakFunction_const_sptr peakFunction, * @param peakFunction :: Peak function to wrap. */ gsl_function PeakFunctionIntegrator::getGSLFunction( - IPeakFunction_const_sptr peakFunction) const { + const IPeakFunction &peakFunction) const { gsl_function f; f.function = &Mantid::API::gsl_peak_wrapper; - f.params = &peakFunction; + f.params = + reinterpret_cast(&const_cast(peakFunction)); return f; } -void PeakFunctionIntegrator::throwIfInvalid( - IPeakFunction_const_sptr peakFunction) const { +double gsl_peak_wrapper(double x, void *parameters) { + IPeakFunction *peakFunction = reinterpret_cast(parameters); + if (!peakFunction) { - throw std::invalid_argument("Can not integrate NULL-function."); + throw std::runtime_error( + "Cannot process NULL-pointer in gsl_peak_wrapper."); } -} - -double gsl_peak_wrapper(double x, void *parameters) { - IPeakFunction_const_sptr peakFunction = - *(IPeakFunction_const_sptr *)parameters; double y; diff --git a/Code/Mantid/Framework/API/test/PeakFunctionIntegratorTest.h b/Code/Mantid/Framework/API/test/PeakFunctionIntegratorTest.h index 96162318a7be..49c3be3b83e4 100644 --- a/Code/Mantid/Framework/API/test/PeakFunctionIntegratorTest.h +++ b/Code/Mantid/Framework/API/test/PeakFunctionIntegratorTest.h @@ -99,18 +99,7 @@ class PeakFunctionIntegratorTest : public CxxTest::TestSuite { IPeakFunction_sptr gaussian = getGaussian(0.0, 1.0, 2.0); - TS_ASSERT_EQUALS(gsl_peak_wrapper(0.0, &gaussian), 2.0); - } - - void testNullPointer() - { - PeakFunctionIntegrator integrator; - - TS_ASSERT_THROWS(integrator.integrateInfinity(IPeakFunction_sptr()), std::invalid_argument); - TS_ASSERT_THROWS(integrator.integratePositiveInfinity(IPeakFunction_sptr(), 0.0), std::invalid_argument); - TS_ASSERT_THROWS(integrator.integrateNegativeInfinity(IPeakFunction_sptr(), 0.0), std::invalid_argument); - TS_ASSERT_THROWS(integrator.integrate(IPeakFunction_sptr(), 0.0, 0.0), std::invalid_argument); - + TS_ASSERT_EQUALS(gsl_peak_wrapper(0.0, &(*gaussian)), 2.0); } void testIntegrateInfinityGaussian() @@ -118,13 +107,13 @@ class PeakFunctionIntegratorTest : public CxxTest::TestSuite IPeakFunction_sptr gaussian = getGaussian(0.0, 1.0, 1.0); PeakFunctionIntegrator integrator; - IntegrationResult result = integrator.integrateInfinity(gaussian); + IntegrationResult result = integrator.integrateInfinity(*gaussian); TS_ASSERT_EQUALS(result.errorCode, static_cast(GSL_SUCCESS)); TS_ASSERT_DELTA(result.result, getGaussianAnalyticalInfiniteIntegral(gaussian), integrator.requiredRelativePrecision()); TS_ASSERT_DELTA(result.error, 0.0, integrator.requiredRelativePrecision()); integrator.setRequiredRelativePrecision(1e-14); - IntegrationResult otherResult = integrator.integrateInfinity(gaussian); + IntegrationResult otherResult = integrator.integrateInfinity(*gaussian); TS_ASSERT_EQUALS(otherResult.errorCode, static_cast(GSL_EBADTOL)); TS_ASSERT_EQUALS(otherResult.result, 0.0); TS_ASSERT_EQUALS(otherResult.error, 0.0); @@ -134,7 +123,7 @@ class PeakFunctionIntegratorTest : public CxxTest::TestSuite { IPeakFunction_sptr gaussian = getGaussian(0.0, 1.0, 1.0); PeakFunctionIntegrator integrator; - IntegrationResult result = integrator.integratePositiveInfinity(gaussian, 0.0); + IntegrationResult result = integrator.integratePositiveInfinity(*gaussian, 0.0); TS_ASSERT_EQUALS(result.errorCode, static_cast(GSL_SUCCESS)); TS_ASSERT_DELTA(result.result, getGaussianAnalyticalInfiniteIntegral(gaussian) / 2.0, integrator.requiredRelativePrecision()); @@ -144,7 +133,7 @@ class PeakFunctionIntegratorTest : public CxxTest::TestSuite { IPeakFunction_sptr gaussian = getGaussian(0.0, 1.0, 1.0); PeakFunctionIntegrator integrator; - IntegrationResult result = integrator.integrateNegativeInfinity(gaussian, 0.0); + IntegrationResult result = integrator.integrateNegativeInfinity(*gaussian, 0.0); TS_ASSERT_EQUALS(result.errorCode, static_cast(GSL_SUCCESS)); TS_ASSERT_DELTA(result.result, getGaussianAnalyticalInfiniteIntegral(gaussian) / 2.0, integrator.requiredRelativePrecision()); @@ -161,15 +150,15 @@ class PeakFunctionIntegratorTest : public CxxTest::TestSuite IPeakFunction_sptr gaussian = getGaussian(0.0, 2.0 * sqrt(2.0 * log(2.0)), 1.0 / sqrt(2.0 * M_PI)); PeakFunctionIntegrator integrator(1e-10); - IntegrationResult rOneSigma = integrator.integrate(gaussian, -1.0, 1.0); + IntegrationResult rOneSigma = integrator.integrate(*gaussian, -1.0, 1.0); TS_ASSERT_EQUALS(rOneSigma.errorCode, static_cast(GSL_SUCCESS)); TS_ASSERT_DELTA(rOneSigma.result, 0.682689492137086, integrator.requiredRelativePrecision()); - IntegrationResult rTwoSigma = integrator.integrate(gaussian, -2.0, 2.0); + IntegrationResult rTwoSigma = integrator.integrate(*gaussian, -2.0, 2.0); TS_ASSERT_EQUALS(rTwoSigma.errorCode, static_cast(GSL_SUCCESS)); TS_ASSERT_DELTA(rTwoSigma.result, 0.954499736103642, integrator.requiredRelativePrecision()); - IntegrationResult rThreeSigma = integrator.integrate(gaussian, -3.0, 3.0); + IntegrationResult rThreeSigma = integrator.integrate(*gaussian, -3.0, 3.0); TS_ASSERT_EQUALS(rThreeSigma.errorCode, static_cast(GSL_SUCCESS)); TS_ASSERT_DELTA(rThreeSigma.result, 0.997300203936740, integrator.requiredRelativePrecision()); } @@ -179,7 +168,7 @@ class PeakFunctionIntegratorTest : public CxxTest::TestSuite IPeakFunction_sptr lorentzian = getLorentzian(0.0, 3.0, 8.0); PeakFunctionIntegrator integrator(1e-8); - IntegrationResult result = integrator.integrateInfinity(lorentzian); + IntegrationResult result = integrator.integrateInfinity(*lorentzian); TS_ASSERT_EQUALS(result.errorCode, static_cast(GSL_SUCCESS)); TS_ASSERT_DELTA(result.result, getLorentzianAnalyticalInfiniteIntegral(lorentzian), integrator.requiredRelativePrecision()); TS_ASSERT_LESS_THAN(result.intervals, 1000); diff --git a/Code/Mantid/Framework/SINQ/src/PoldiFitPeaks2D.cpp b/Code/Mantid/Framework/SINQ/src/PoldiFitPeaks2D.cpp index 498f73ef7e27..2f5ab76ffb23 100644 --- a/Code/Mantid/Framework/SINQ/src/PoldiFitPeaks2D.cpp +++ b/Code/Mantid/Framework/SINQ/src/PoldiFitPeaks2D.cpp @@ -571,7 +571,7 @@ PoldiPeakCollection_sptr PoldiFitPeaks2D::getIntegratedPeakCollection( profileFunction->setCentre(0.0); IntegrationResult integration = - peakIntegrator.integrateInfinity(profileFunction); + peakIntegrator.integrateInfinity(*profileFunction); if (!integration.success) { throw std::runtime_error("Problem during peak integration. Aborting."); From 06e5025c0c5e58c90c3ecad2194f5c7a0b8211d2 Mon Sep 17 00:00:00 2001 From: Michael Wedel Date: Wed, 18 Feb 2015 13:31:08 +0100 Subject: [PATCH 04/18] Refs #11104. Re-enabling unit tests in GaussianTest Re-enabled some of the disabled unit tests in GaussianTest.h. The other tests have some issues, this has to be handled in another ticket. --- Code/Mantid/Framework/CurveFitting/test/GaussianTest.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Mantid/Framework/CurveFitting/test/GaussianTest.h b/Code/Mantid/Framework/CurveFitting/test/GaussianTest.h index 760c5712f462..87069b7b3bb6 100644 --- a/Code/Mantid/Framework/CurveFitting/test/GaussianTest.h +++ b/Code/Mantid/Framework/CurveFitting/test/GaussianTest.h @@ -160,7 +160,7 @@ class GaussianTest : public CxxTest::TestSuite for (size_t i=0; i < 41; i++) e[i] = sqrt( y[i] ); } - void xtest_with_Levenberg_Marquardt() + void test_with_Levenberg_Marquardt() { API::FunctionDomain1D_sptr domain(new API::FunctionDomain1DVector( 79292.4, 79603.6, 41)); API::FunctionValues mockData(*domain); @@ -426,7 +426,7 @@ class GaussianTest : public CxxTest::TestSuite } - void xtestAgainstMockDataSimplex2() + void testAgainstMockDataSimplex2() { // create mock data to test against std::string wsName = "GaussMockDataSimplex2"; From 173c23197e5c2d5caff7ca6cb891379b60f022c5 Mon Sep 17 00:00:00 2001 From: Michael Wedel Date: Wed, 18 Feb 2015 13:32:07 +0100 Subject: [PATCH 05/18] Refs #11104. Add intensity/setIntensity methods to IPeakFunction --- .../API/inc/MantidAPI/IPeakFunction.h | 6 +++++ .../Framework/API/src/IPeakFunction.cpp | 27 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/Code/Mantid/Framework/API/inc/MantidAPI/IPeakFunction.h b/Code/Mantid/Framework/API/inc/MantidAPI/IPeakFunction.h index 7405ca45a731..f36c1ad37261 100644 --- a/Code/Mantid/Framework/API/inc/MantidAPI/IPeakFunction.h +++ b/Code/Mantid/Framework/API/inc/MantidAPI/IPeakFunction.h @@ -49,6 +49,12 @@ class MANTID_API_DLL IPeakFunction : public IFunctionWithLocation { /// Sets the parameters such that FWHM = w virtual void setFwhm(const double w) = 0; + /// Returns the integral intensity of the peak + virtual double intensity() const; + + /// Sets the integral intensity of the peak + virtual void setIntensity(const double intensity); + /// General implementation of the method for all peaks. void function1D(double *out, const double *xValues, const size_t nData) const; /// General implementation of the method for all peaks. diff --git a/Code/Mantid/Framework/API/src/IPeakFunction.cpp b/Code/Mantid/Framework/API/src/IPeakFunction.cpp index 04e9b34dc2b2..edac0d20c107 100644 --- a/Code/Mantid/Framework/API/src/IPeakFunction.cpp +++ b/Code/Mantid/Framework/API/src/IPeakFunction.cpp @@ -3,6 +3,7 @@ //---------------------------------------------------------------------- #include "MantidAPI/IPeakFunction.h" #include "MantidAPI/Jacobian.h" +#include "MantidAPI/PeakFunctionIntegrator.h" #include "MantidKernel/Exception.h" #include "MantidKernel/ConfigService.h" @@ -130,5 +131,31 @@ void IPeakFunction::setPeakRadius(const int &r) { } } +double IPeakFunction::intensity() const { + double x0 = centre(); + double dx = fabs(s_peakRadius * fwhm()); + + PeakFunctionIntegrator integrator; + IntegrationResult result = integrator.integrate(*this, x0 - dx, x0 + dx); + + if(!result.success) { + return 0.0; + } + + return result.result; +} + +void IPeakFunction::setIntensity(const double newIntensity) +{ + double currentHeight = height(); + double currentIntensity = intensity(); + + if(currentIntensity == 0.0) { + setHeight(0.0); + } else { + setHeight(newIntensity / currentIntensity * currentHeight); + } +} + } // namespace API } // namespace Mantid From 1e56cbde5b7f8350dbc0f3359a413ce19fdb3d5f Mon Sep 17 00:00:00 2001 From: Michael Wedel Date: Wed, 18 Feb 2015 13:42:33 +0100 Subject: [PATCH 06/18] Refs #11104. Adding unit test for Gaussian. --- .../CurveFitting/test/GaussianTest.h | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Code/Mantid/Framework/CurveFitting/test/GaussianTest.h b/Code/Mantid/Framework/CurveFitting/test/GaussianTest.h index 87069b7b3bb6..4c885c4edbe0 100644 --- a/Code/Mantid/Framework/CurveFitting/test/GaussianTest.h +++ b/Code/Mantid/Framework/CurveFitting/test/GaussianTest.h @@ -583,6 +583,37 @@ class GaussianTest : public CxxTest::TestSuite ConfigService::Instance().setString("curvefitting.peakRadius",priorRadius); } + void testIntensity() + { + boost::shared_ptr fn( new Gaussian() ); + fn->initialize(); + fn->setHeight(2.0); + fn->setFwhm(0.125); + fn->setCentre(-200.0); + + // Area under a gaussian is height * sigma * sqrt(2 * pi) + TS_ASSERT_DELTA(fn->intensity(), 0.26611675485780654483, 1e-10); + } + + void testSetIntensity() + { + boost::shared_ptr fn( new Gaussian() ); + fn->initialize(); + fn->setHeight(2.0); + fn->setFwhm(0.125); + fn->setCentre(-200.0); + + TS_ASSERT_THROWS_NOTHING(fn->setIntensity(0.5)); + + TS_ASSERT_DELTA(fn->intensity(), 0.5, 1e-10); + + // FWHM does not change + TS_ASSERT_EQUALS(fn->fwhm(), 0.125); + + // Height changes + TS_ASSERT_DELTA(fn->height(), 3.75774911479860533509, 1e-10); + } + }; From a9dfb0fed59e4ec35ff877fca275b256b6e1f928 Mon Sep 17 00:00:00 2001 From: Michael Wedel Date: Wed, 18 Feb 2015 13:43:06 +0100 Subject: [PATCH 07/18] Refs #11104. Changing parameter name. --- Code/Mantid/Framework/API/inc/MantidAPI/IPeakFunction.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Mantid/Framework/API/inc/MantidAPI/IPeakFunction.h b/Code/Mantid/Framework/API/inc/MantidAPI/IPeakFunction.h index f36c1ad37261..80e2899f880f 100644 --- a/Code/Mantid/Framework/API/inc/MantidAPI/IPeakFunction.h +++ b/Code/Mantid/Framework/API/inc/MantidAPI/IPeakFunction.h @@ -53,7 +53,7 @@ class MANTID_API_DLL IPeakFunction : public IFunctionWithLocation { virtual double intensity() const; /// Sets the integral intensity of the peak - virtual void setIntensity(const double intensity); + virtual void setIntensity(const double newIntensity); /// General implementation of the method for all peaks. void function1D(double *out, const double *xValues, const size_t nData) const; From 5d101c018d183fd3c975ff195c7d2efb511404cc Mon Sep 17 00:00:00 2001 From: Michael Wedel Date: Wed, 18 Feb 2015 14:14:56 +0100 Subject: [PATCH 08/18] Refs #11104. Adding another Gaussian test, formatting IPeakFunction --- .../Framework/API/src/IPeakFunction.cpp | 22 +++++++++---------- .../CurveFitting/test/GaussianTest.h | 11 ++++++++++ 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/Code/Mantid/Framework/API/src/IPeakFunction.cpp b/Code/Mantid/Framework/API/src/IPeakFunction.cpp index edac0d20c107..e7ba60ec1895 100644 --- a/Code/Mantid/Framework/API/src/IPeakFunction.cpp +++ b/Code/Mantid/Framework/API/src/IPeakFunction.cpp @@ -138,23 +138,23 @@ double IPeakFunction::intensity() const { PeakFunctionIntegrator integrator; IntegrationResult result = integrator.integrate(*this, x0 - dx, x0 + dx); - if(!result.success) { - return 0.0; + if (!result.success) { + return 0.0; } return result.result; } -void IPeakFunction::setIntensity(const double newIntensity) -{ - double currentHeight = height(); - double currentIntensity = intensity(); +void IPeakFunction::setIntensity(const double newIntensity) { + double currentHeight = height(); + double currentIntensity = intensity(); - if(currentIntensity == 0.0) { - setHeight(0.0); - } else { - setHeight(newIntensity / currentIntensity * currentHeight); - } + if (currentIntensity == 0.0) { + throw std::invalid_argument( + "Cannot set new intensity, not enough information available."); + } + + setHeight(newIntensity / currentIntensity * currentHeight); } } // namespace API diff --git a/Code/Mantid/Framework/CurveFitting/test/GaussianTest.h b/Code/Mantid/Framework/CurveFitting/test/GaussianTest.h index 4c885c4edbe0..e7bc607d7898 100644 --- a/Code/Mantid/Framework/CurveFitting/test/GaussianTest.h +++ b/Code/Mantid/Framework/CurveFitting/test/GaussianTest.h @@ -614,6 +614,17 @@ class GaussianTest : public CxxTest::TestSuite TS_ASSERT_DELTA(fn->height(), 3.75774911479860533509, 1e-10); } + void testSetIntensityDefault() + { + boost::shared_ptr fn( new Gaussian() ); + fn->initialize(); + + TS_ASSERT_EQUALS(fn->intensity(), 0.0); + + TS_ASSERT_THROWS(fn->setIntensity(20.0), std::invalid_argument); + TS_ASSERT_EQUALS(fn->intensity(), 0.0); + } + }; From 7a4cefb04619f9ed8613ce709ac2bc96b804c91b Mon Sep 17 00:00:00 2001 From: Michael Wedel Date: Wed, 18 Feb 2015 15:01:14 +0100 Subject: [PATCH 09/18] Refs #11104. Adding intensity test for Lorentzian --- .../Framework/CurveFitting/test/LorentzianTest.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Code/Mantid/Framework/CurveFitting/test/LorentzianTest.h b/Code/Mantid/Framework/CurveFitting/test/LorentzianTest.h index 660939553f9b..f9781ce2b345 100644 --- a/Code/Mantid/Framework/CurveFitting/test/LorentzianTest.h +++ b/Code/Mantid/Framework/CurveFitting/test/LorentzianTest.h @@ -103,6 +103,21 @@ class LorentzianTest : public CxxTest::TestSuite TS_ASSERT_EQUALS(y[0], 0.0); } + void testIntensity() + { + Mantid::CurveFitting::Lorentzian lor; + lor.initialize(); + lor.setHeight(2.0); + lor.setCentre(3.0); + lor.setFwhm(1.0); + + TS_ASSERT_DELTA(lor.intensity(), 1.873097930277787, 1e-10); + TS_ASSERT_THROWS_NOTHING(lor.setIntensity(2.0)); + + TS_ASSERT_DELTA(lor.intensity(), 2.0, 1e-10); + TS_ASSERT_EQUALS(lor.fwhm(), 1.0); + } + private: class TestableLorentzian : public Mantid::CurveFitting::Lorentzian From 5a2a0706568f08da23fc56e23c4c3994bcb02b6a Mon Sep 17 00:00:00 2001 From: Michael Wedel Date: Wed, 18 Feb 2015 16:36:38 +0100 Subject: [PATCH 10/18] Refs #11104. Python exports. --- .../mantid/api/src/Exports/IPeakFunction.cpp | 22 +++++--- .../python/mantid/api/IPeakFunctionTest.py | 53 +++++++++++++++++++ 2 files changed, 67 insertions(+), 8 deletions(-) diff --git a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/IPeakFunction.cpp b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/IPeakFunction.cpp index 1164cfe661d7..0d1a5c71e0a9 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/IPeakFunction.cpp +++ b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/IPeakFunction.cpp @@ -7,12 +7,18 @@ using Mantid::API::IPeakFunction; using Mantid::PythonInterface::IPeakFunctionAdapter; using namespace boost::python; -void export_IPeakFunction() -{ - class_, boost::shared_ptr, - boost::noncopyable>("IPeakFunction") - .def("functionLocal", (object (IPeakFunctionAdapter::*)(const object &)const)&IPeakFunction::functionLocal, - "Calculate the values of the function for the given x values. The output should be stored in the out array") - ; +void export_IPeakFunction() { + class_, + boost::shared_ptr, boost::noncopyable>( + "IPeakFunction") + .def("functionLocal", + (object (IPeakFunctionAdapter::*)(const object &)const) & + IPeakFunction::functionLocal, + "Calculate the values of the function for the given x values. The " + "output should be stored in the out array") + .def("intensity", &IPeakFunction::intensity, + "Returns the integral intensity of the peak function.") + .def("setIntensity", &IPeakFunction::setIntensity, + "Changes the integral intensity of the peak function by setting its " + "height."); } - diff --git a/Code/Mantid/Framework/PythonInterface/test/python/mantid/api/IPeakFunctionTest.py b/Code/Mantid/Framework/PythonInterface/test/python/mantid/api/IPeakFunctionTest.py index 3832a39214ed..2ac78d6d5376 100644 --- a/Code/Mantid/Framework/PythonInterface/test/python/mantid/api/IPeakFunctionTest.py +++ b/Code/Mantid/Framework/PythonInterface/test/python/mantid/api/IPeakFunctionTest.py @@ -13,6 +13,41 @@ def init(self): def functionLocal(self, xvals): return 5*xvals +class RectangularFunction(IPeakFunction): + def init(self): + self.declareParameter("Height") + self.declareParameter("Fwhm") + self.declareParameter("Center") + + def centre(self): + return self.getParameterValue("Center") + + def setCentre(self, newCenter): + self.setParameter("Center", newCenter) + + def height(self): + return self.getParameterValue("Height") + + def setHeight(self, newHeight): + self.setParameter("Height", newHeight) + + def fwhm(self): + return self.getParameterValue("Fwhm") + + def setFwhm(self, newFwhm): + self.setParameter("Fwhm", newFwhm) + + def functionLocal(self, xvals): + center = self.getParameterValue("Center") + fwhm = self.getParameterValue("Fwhm") + height = self.getParameterValue("Height") + + values = np.zeros(xvals.shape) + nonZero = (xvals > (center - fwhm/2.0)) & (xvals < (center + fwhm / 2.0)) + values[nonZero] = height + + return values + class IPeakFunctionTest(unittest.TestCase): def test_instance_can_be_created_standalone(self): @@ -38,5 +73,23 @@ def test_functionLocal_can_be_called_directly(self): self.assertEquals(10., out[1]) self.assertEquals(15., out[2]) + def test_get_set_intensity(self): + func = RectangularFunction() + func.initialize() + func.setCentre(1.0) + func.setHeight(2.0) + func.setFwhm(3.0) + + # This is a rectangle function with height 2 and width 3, centered + # around 1.0. The intensity should be 6.0 (height * width) + self.assertAlmostEquals(func.intensity(), 6.0, delta=1e-10) + + # Setting the intensity only changes height, not width + func.setIntensity(12.0) + + self.assertEquals(func.fwhm(), 3.0) + self.assertAlmostEquals(func.height(), 4.0, delta=1e-10) + self.assertAlmostEquals(func.intensity(), 12.0, delta=1e-10) + if __name__ == '__main__': unittest.main() From 84f8193a86d0a92099e3fdb409b32b2675cd0961 Mon Sep 17 00:00:00 2001 From: Michael Wedel Date: Wed, 18 Feb 2015 16:40:14 +0100 Subject: [PATCH 11/18] Refs #11104. Adding comments. --- Code/Mantid/Framework/API/src/IPeakFunction.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Code/Mantid/Framework/API/src/IPeakFunction.cpp b/Code/Mantid/Framework/API/src/IPeakFunction.cpp index e7ba60ec1895..f5995bf995bb 100644 --- a/Code/Mantid/Framework/API/src/IPeakFunction.cpp +++ b/Code/Mantid/Framework/API/src/IPeakFunction.cpp @@ -131,6 +131,8 @@ void IPeakFunction::setPeakRadius(const int &r) { } } +/// Returns the integral intensity of the peak function, using the peak radius +/// to determine integration borders. double IPeakFunction::intensity() const { double x0 = centre(); double dx = fabs(s_peakRadius * fwhm()); @@ -145,6 +147,7 @@ double IPeakFunction::intensity() const { return result.result; } +/// Sets the integral intensity of the peak by adjusting the height. void IPeakFunction::setIntensity(const double newIntensity) { double currentHeight = height(); double currentIntensity = intensity(); From d7baf2780fe217477cd86a4a8f304e9422f43ef6 Mon Sep 17 00:00:00 2001 From: Michael Wedel Date: Wed, 18 Feb 2015 17:22:01 +0100 Subject: [PATCH 12/18] Refs #11104. Removing accidentally added file --- .../PoldiBatchFitIndividualPeaks.py | 181 ------------------ 1 file changed, 181 deletions(-) delete mode 100644 Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/PoldiBatchFitIndividualPeaks.py diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/PoldiBatchFitIndividualPeaks.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/PoldiBatchFitIndividualPeaks.py deleted file mode 100644 index b77beeb9d17c..000000000000 --- a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/PoldiBatchFitIndividualPeaks.py +++ /dev/null @@ -1,181 +0,0 @@ -from mantid.api import * -from mantid.kernel import * -from mantid.simpleapi import * -import os -import math -import sys - -class PoldiSample: - def __init__(self, initString): - self._name, self._runList = self.parseInitString(initString) - - def name(self): - return self._name - - def runList(self): - return self._runList - - def runNames(self): - return [x[0] for x in self._runList] - - def parseInitString(self, initString): - parts = initString.split(':') - - if not len(parts) == 2: - raise RuntimeError("Unable to parse init string.") - - sampleName = parts[0] - runDict = self.parseRunDictString(parts[1]) - - return (sampleName, runDict) - - def parseRunDictString(self, runDictString): - runRanges = filter(bool, runDictString.strip().split(';')) - - newRunList = [] - for runRange in runRanges: - runPoints = self.parseRunRangeString(runRange) - newRunList += runPoints - - return newRunList - - def parseRunRangeString(self, runRangeString): - runRangeParameters = [int(x) for x in runRangeString.split(',')] - - if not len(runRangeParameters) == 3: - raise RuntimeError("Unable to parse run range string.") - - begin, end, step = runRangeParameters - - runList = [] - for i in range(begin, end + 1, step): - runList.append((i + step - 1, [str(x) for x in range(i, i + step)])) - - print runList - - return runList - -class PoldiProject: - def __init__(self, projectName, sampleListFile): - self._name = projectName - self._sampleList = self.parseSampleListFile(sampleListFile) - - def sampleList(self): - return self._sampleList - - def name(self): - return self._name - - def parseSampleListFile(self, sampleListFile): - fh = open(sampleListFile, 'r') - - sampleList = [] - for line in fh: - if len(line.strip()) > 0 and not line.strip()[0] == '#': - sampleList.append(PoldiSample(line)) - - return sampleList - -class PoldiBatchFitIndividualPeaks(PythonAlgorithm): - prefixes = {'raw': 'raw_', - 'data': 'data_'} - - suffixes = {'correlation': '_correlation', - 'raw_peaks': '_peaks_raw', - 'fit_peaks_1d': '_peaks_fit_1d', - 'fit_peaks_2d': '_peaks_fit_2d', - 'calculated_2d': '_spectrum_fitted_2d', - 'residuals': '_residuals'} - - def category(self): - return "Workflow\\Poldi" - - def name(self): - return "PoldiBatchFitIndividualPeaks" - - def summary(self): - return "Load a file with instructions for batch processing POLDI fits." - - def PyInit(self): - self.declareProperty("ProjectName", "", "Project name to use for labeling") - self.declareProperty(FileProperty(name="SampleListFile", defaultValue="", - action=FileAction.Load)) - self.declareProperty(FileProperty(name="OutputDirectory", defaultValue="", - action=FileAction.OptionalDirectory)) - self.declareProperty(FileProperty(name="CrystalStructures", - defaultValue="", - action=FileAction.OptionalLoad)) - self.declareProperty("PeakNumber", 10, "Number of peaks to fit.") - - def PyExec(self): - poldiProject = PoldiProject(self.getProperty("ProjectName"), - self.getProperty("SampleListFile").valueAsStr) - - sampleCount = len(poldiProject.sampleList()) - progress = Progress(self, start=0.0, end=1.0, nreports=sampleCount) - - for i, sample in enumerate(poldiProject.sampleList()): - self.processSample(sample) - progress.report("Processed sample " + str(i + 1) + " of " + str(sampleCount)) - - def processSample(self, poldiSample): - sampleList = poldiSample.runList() - - for dataPoint in sampleList: - self.processDataPoint(dataPoint) - - def processDataPoint(self, dataPointTuple): - self.loadDataPoint(dataPointTuple) - self.runPoldiAnalysis(dataPointTuple[0]) - - def loadDataPoint(self, dataPointTuple): - dataWorkspaceName = self.prefixes['data'] + str(dataPointTuple[0]) - - rawWorkspaceNames = [ - self.prefixes['raw'] + str(x) for x in dataPointTuple[1]] - - for numor,rawWsName in zip(dataPointTuple[1], rawWorkspaceNames): - LoadSINQ(Instrument="POLDI", Year=2014, - Numor=numor, OutputWorkspace=rawWsName) - LoadInstrument(rawWsName, InstrumentName="POLDI") - - if len(dataPointTuple[1]) > 1: - PoldiMerge(rawWorkspaceNames, OutputWorkspace=dataWorkspaceName) - - for ws in rawWorkspaceNames: - DeleteWorkspace(ws) - - else: - RenameWorkspace(rawWorkspaceNames[0], OutputWorkspace=dataWorkspaceName) - - return dataWorkspaceName - - def runPoldiAnalysis(self, dataPointName): - dataWorkspaceName = self.prefixes['data'] + str(dataPointName) - - correlationWsName = dataWorkspaceName + self.suffixes['correlation'] - PoldiAutoCorrelation(dataWorkspaceName, wlenmin=1.1, wlenmax=5.0, - OutputWorkspace=correlationWsName) - - peakSearchWsName = dataWorkspaceName + self.suffixes['raw_peaks'] - PoldiPeakSearch(correlationWsName, OutputWorkspace=peakSearchWsName) - - DeleteTableRows(peakSearchWsName, - self.getProperty("PeakNumber").valueAsStr + '-30') - - peakFit1DWsName = dataWorkspaceName + self.suffixes['fit_peaks_1d'] - PoldiFitPeaks1D(correlationWsName, PoldiPeakTable=peakSearchWsName, - OutputWorkspace=peakFit1DWsName) - - peakFit2DWsName = dataWorkspaceName + self.suffixes['fit_peaks_2d'] - spectrum2DCalc = dataWorkspaceName + self.suffixes['calculated_2d'] - PoldiFitPeaks2D(dataWorkspaceName, PoldiPeakWorkspace=peakFit1DWsName, - MaximumIterations=100, OutputWorkspace=spectrum2DCalc, - RefinedPoldiPeakWorkspace=peakFit2DWsName) - - residualsWsName = dataWorkspaceName + self.suffixes['residuals'] - PoldiAnalyseResiduals(dataWorkspaceName, spectrum2DCalc, - OutputWorkspace=residualsWsName, - MaxIterations=5) - -AlgorithmFactory.subscribe(PoldiBatchFitIndividualPeaks) \ No newline at end of file From 6a32a8324a1d49e858ff034f0b864cfcba4e5adc Mon Sep 17 00:00:00 2001 From: Michael Wedel Date: Wed, 18 Feb 2015 20:42:09 +0100 Subject: [PATCH 13/18] Refs #11104. Reverting clang-format on python export The clang-format command seemed to cause a compilation error on all systems. Going back to the old format fixes it. --- .../mantid/api/src/Exports/IPeakFunction.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/IPeakFunction.cpp b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/IPeakFunction.cpp index 0d1a5c71e0a9..c8589a927a72 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/IPeakFunction.cpp +++ b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/IPeakFunction.cpp @@ -7,18 +7,16 @@ using Mantid::API::IPeakFunction; using Mantid::PythonInterface::IPeakFunctionAdapter; using namespace boost::python; -void export_IPeakFunction() { - class_, - boost::shared_ptr, boost::noncopyable>( - "IPeakFunction") - .def("functionLocal", - (object (IPeakFunctionAdapter::*)(const object &)const) & - IPeakFunction::functionLocal, - "Calculate the values of the function for the given x values. The " - "output should be stored in the out array") +void export_IPeakFunction() +{ + class_, boost::shared_ptr, + boost::noncopyable>("IPeakFunction") + .def("functionLocal", (object (IPeakFunctionAdapter::*)(const object &)const)&IPeakFunction::functionLocal, + "Calculate the values of the function for the given x values. The output should be stored in the out array") .def("intensity", &IPeakFunction::intensity, "Returns the integral intensity of the peak function.") .def("setIntensity", &IPeakFunction::setIntensity, "Changes the integral intensity of the peak function by setting its " - "height."); + "height.") + ; } From 4181b1f3c1c8455bb5b2299f677d038b93fe74b7 Mon Sep 17 00:00:00 2001 From: Michael Wedel Date: Wed, 18 Feb 2015 21:15:14 +0100 Subject: [PATCH 14/18] Refs #11104. Replacing delta argument with places It seems that the unittest module on RHEL6 does not know the delta-parameter for assertAlmostEquals yet, so instead the number of places is used. --- .../test/python/mantid/api/IPeakFunctionTest.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Code/Mantid/Framework/PythonInterface/test/python/mantid/api/IPeakFunctionTest.py b/Code/Mantid/Framework/PythonInterface/test/python/mantid/api/IPeakFunctionTest.py index 2ac78d6d5376..937f02a18f3d 100644 --- a/Code/Mantid/Framework/PythonInterface/test/python/mantid/api/IPeakFunctionTest.py +++ b/Code/Mantid/Framework/PythonInterface/test/python/mantid/api/IPeakFunctionTest.py @@ -82,14 +82,14 @@ def test_get_set_intensity(self): # This is a rectangle function with height 2 and width 3, centered # around 1.0. The intensity should be 6.0 (height * width) - self.assertAlmostEquals(func.intensity(), 6.0, delta=1e-10) + self.assertAlmostEquals(func.intensity(), 6.0, places=10) # Setting the intensity only changes height, not width func.setIntensity(12.0) self.assertEquals(func.fwhm(), 3.0) - self.assertAlmostEquals(func.height(), 4.0, delta=1e-10) - self.assertAlmostEquals(func.intensity(), 12.0, delta=1e-10) + self.assertAlmostEquals(func.height(), 4.0, places=10) + self.assertAlmostEquals(func.intensity(), 12.0, places=10) if __name__ == '__main__': unittest.main() From 203539339bb27a42aef20f3288d0475dbce56667 Mon Sep 17 00:00:00 2001 From: Michael Wedel Date: Thu, 19 Feb 2015 11:06:54 +0100 Subject: [PATCH 15/18] Refs #11104. Adding general test for IPeakFunction::intensity --- .../Framework/CurveFitting/CMakeLists.txt | 1 + .../test/IPeakFunctionIntensityTest.h | 152 ++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 Code/Mantid/Framework/CurveFitting/test/IPeakFunctionIntensityTest.h diff --git a/Code/Mantid/Framework/CurveFitting/CMakeLists.txt b/Code/Mantid/Framework/CurveFitting/CMakeLists.txt index edcb417d8e0a..1907f29a5e01 100644 --- a/Code/Mantid/Framework/CurveFitting/CMakeLists.txt +++ b/Code/Mantid/Framework/CurveFitting/CMakeLists.txt @@ -257,6 +257,7 @@ set ( TEST_FILES GaussianTest.h GramCharlierComptonProfileTest.h IkedaCarpenterPVTest.h + IPeakFunctionIntensityTest.h LeBailFitTest.h LeBailFunctionTest.h LeastSquaresTest.h diff --git a/Code/Mantid/Framework/CurveFitting/test/IPeakFunctionIntensityTest.h b/Code/Mantid/Framework/CurveFitting/test/IPeakFunctionIntensityTest.h new file mode 100644 index 000000000000..12fa0c8f286e --- /dev/null +++ b/Code/Mantid/Framework/CurveFitting/test/IPeakFunctionIntensityTest.h @@ -0,0 +1,152 @@ +#ifndef IPEAKFUNCTIONINTENSITYTEST_H +#define IPEAKFUNCTIONINTENSITYTEST_H + +#include +#include "MantidAPI/FrameworkManager.h" +#include "MantidAPI/FunctionFactory.h" +#include "MantidAPI/IPeakFunction.h" +#include + +using namespace Mantid::API; + +#define DBL2STR(x) boost::lexical_cast(x) + +struct ParameterSet { + ParameterSet(double c, double h, double f) : center(c), height(h), fwhm(f) {} + + double center; + double height; + double fwhm; +}; + +class IPeakFunctionIntensityTest : public CxxTest::TestSuite { +public: + // This pair of boilerplate methods prevent the suite being created statically + // This means the constructor isn't called when running other tests + static IPeakFunctionIntensityTest *createSuite() { + return new IPeakFunctionIntensityTest(); + } + static void destroySuite(IPeakFunctionIntensityTest *suite) { delete suite; } + + IPeakFunctionIntensityTest() : m_blackList() { + FrameworkManager::Instance(); + + m_blackList.insert("BackToBackExponential"); + m_blackList.insert("DeltaFunction"); + m_blackList.insert("ElasticDiffRotDiscreteCircle"); + m_blackList.insert("ElasticDiffSphere"); + + m_peakFunctions = getAllPeakFunctions(m_blackList); + m_parameterSets = getParameterSets(); + } + + /* This test sets all peak function parameters (center, fwhm, height) + * to the values supplied in the first ParameterSet contained in + * m_parameterSets. + * + * Then it retrieves the intensities of the peak functions and stores them. + * Each time new parameters are set, the ratio of the height parameter to + * the previous step is compared to the intensity ratio - they should be + * the same. + */ + void testAllFunctions() { + initializePeakFunctions(m_peakFunctions, m_parameterSets[0]); + + std::vector initialIntensities = getIntensities(m_peakFunctions); + + for (size_t i = 1; i < m_parameterSets.size(); ++i) { + double oldHeight = m_parameterSets[i - 1].height; + double newHeight = m_parameterSets[i].height; + double heightRatio = newHeight / oldHeight; + + initializePeakFunctions(m_peakFunctions, m_parameterSets[i]); + + std::vector newIntensities = getIntensities(m_peakFunctions); + + for (size_t j = 0; j < initialIntensities.size(); ++j) { + double oldIntensity = initialIntensities[j]; + double newIntensity = newIntensities[j]; + double intensityRatio = newIntensity / oldIntensity; + + TSM_ASSERT_DELTA( + "ITERATION " + DBL2STR(i) + ", " + m_peakFunctions[j]->name() + + ": Height was increased from " + DBL2STR(oldHeight) + " to " + + DBL2STR(newHeight) + " (ratio " + DBL2STR(heightRatio) + + "), but intensity changed from " + DBL2STR(oldIntensity) + + " to " + DBL2STR(newIntensity) + " (ratio " + + DBL2STR(intensityRatio) + ").", + intensityRatio, heightRatio, 1e-10); + } + + initialIntensities = newIntensities; + } + } + +private: + std::vector + getAllPeakFunctions(const std::set &blackList) const { + std::vector peakFunctions; + + std::vector registeredFunctions = + FunctionFactory::Instance().getFunctionNames(); + + for (auto it = registeredFunctions.begin(); it != registeredFunctions.end(); + ++it) { + if (blackList.count(*it) == 0) { + IPeakFunction_sptr peakFunction = + boost::dynamic_pointer_cast( + FunctionFactory::Instance().createFunction(*it)); + + if (peakFunction) { + peakFunctions.push_back(peakFunction); + } + } + } + + return peakFunctions; + } + + void initializePeakFunctions(const std::vector &peaks, + const ParameterSet ¶meters) const { + + for (auto it = peaks.begin(); it != peaks.end(); ++it) { + (*it)->setCentre(parameters.center); + + // for Ikeda-Carpenter it's not allowed to set Fwhm + try { + (*it)->setFwhm(parameters.fwhm); + } + catch (std::invalid_argument) { + } + + (*it)->setHeight(parameters.height); + } + } + + std::vector getParameterSets() const { + std::vector parameterSets; + parameterSets.push_back(ParameterSet(0.0, 4.34, 0.25)); + parameterSets.push_back(ParameterSet(0.0, 5.34, 0.25)); + parameterSets.push_back(ParameterSet(0.0, 6.34, 0.25)); + parameterSets.push_back(ParameterSet(0.0, 7.34, 0.25)); + + return parameterSets; + } + + std::vector + getIntensities(const std::vector &peaks) const { + std::vector intensities; + + for (auto it = peaks.begin(); it != peaks.end(); ++it) { + intensities.push_back((*it)->intensity()); + } + + return intensities; + } + + std::vector m_peakFunctions; + std::vector m_parameterSets; + std::set m_blackList; +}; + +#endif // IPEAKFUNCTIONINTENSITYTEST_H From 27e306588bf126895eccd2f79cd7aa575d8c7bb8 Mon Sep 17 00:00:00 2001 From: Michael Wedel Date: Thu, 19 Feb 2015 11:53:05 +0100 Subject: [PATCH 16/18] Refs #11104. Adding Muon_ExpDecayOscTest to blacklist --- .../Framework/CurveFitting/test/IPeakFunctionIntensityTest.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Code/Mantid/Framework/CurveFitting/test/IPeakFunctionIntensityTest.h b/Code/Mantid/Framework/CurveFitting/test/IPeakFunctionIntensityTest.h index 12fa0c8f286e..ade73e302e1c 100644 --- a/Code/Mantid/Framework/CurveFitting/test/IPeakFunctionIntensityTest.h +++ b/Code/Mantid/Framework/CurveFitting/test/IPeakFunctionIntensityTest.h @@ -35,6 +35,7 @@ class IPeakFunctionIntensityTest : public CxxTest::TestSuite { m_blackList.insert("DeltaFunction"); m_blackList.insert("ElasticDiffRotDiscreteCircle"); m_blackList.insert("ElasticDiffSphere"); + m_blackList.insert("Muon_ExpDecayOscTest"); m_peakFunctions = getAllPeakFunctions(m_blackList); m_parameterSets = getParameterSets(); From e64f93044bf72b49fbd7ea0e4c5256d63c42d52a Mon Sep 17 00:00:00 2001 From: Michael Wedel Date: Thu, 19 Feb 2015 15:09:59 +0100 Subject: [PATCH 17/18] Refs #11104. Not giving up on setIntensity so quickly If intensity is 0, we first try to set height to a different, arbitrary value, following Roman's suggestion. If it's still 0 after that, there's nothing left to do. --- Code/Mantid/Framework/API/src/IPeakFunction.cpp | 13 +++++++++++-- .../Framework/CurveFitting/test/GaussianTest.h | 7 +++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Code/Mantid/Framework/API/src/IPeakFunction.cpp b/Code/Mantid/Framework/API/src/IPeakFunction.cpp index f5995bf995bb..07053b760fda 100644 --- a/Code/Mantid/Framework/API/src/IPeakFunction.cpp +++ b/Code/Mantid/Framework/API/src/IPeakFunction.cpp @@ -153,8 +153,17 @@ void IPeakFunction::setIntensity(const double newIntensity) { double currentIntensity = intensity(); if (currentIntensity == 0.0) { - throw std::invalid_argument( - "Cannot set new intensity, not enough information available."); + // Try to set a different height first. + setHeight(2.0); + + currentHeight = height(); + currentIntensity = intensity(); + + // If the current intensity is still 0, there's nothing left to do. + if (currentIntensity == 0.0) { + throw std::invalid_argument( + "Cannot set new intensity, not enough information available."); + } } setHeight(newIntensity / currentIntensity * currentHeight); diff --git a/Code/Mantid/Framework/CurveFitting/test/GaussianTest.h b/Code/Mantid/Framework/CurveFitting/test/GaussianTest.h index e7bc607d7898..ee2a682fdf6a 100644 --- a/Code/Mantid/Framework/CurveFitting/test/GaussianTest.h +++ b/Code/Mantid/Framework/CurveFitting/test/GaussianTest.h @@ -621,8 +621,15 @@ class GaussianTest : public CxxTest::TestSuite TS_ASSERT_EQUALS(fn->intensity(), 0.0); + // This does not work, because fwhm is 0 and height is 0 TS_ASSERT_THROWS(fn->setIntensity(20.0), std::invalid_argument); TS_ASSERT_EQUALS(fn->intensity(), 0.0); + + // Now, fwhm is not zero + fn->setFwhm(0.02); + + TS_ASSERT_THROWS_NOTHING(fn->setIntensity(20.0)); + TS_ASSERT_DELTA(fn->intensity(), 20.0, 1e-10); } From f8445a1425781d236267bdb586e2cc33d4897c37 Mon Sep 17 00:00:00 2001 From: Michael Wedel Date: Thu, 19 Feb 2015 15:57:21 +0100 Subject: [PATCH 18/18] Refs #11104. Adding special case code for BackToBackExponential BackToBackExponential already has an intensity parameter, so the methods are overriden to get/set this parameter. --- .../BackToBackExponential.h | 4 ++++ .../test/BackToBackExponentialTest.h | 19 +++++++++++++++++++ .../test/IPeakFunctionIntensityTest.h | 1 - 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Code/Mantid/Framework/CurveFitting/inc/MantidCurveFitting/BackToBackExponential.h b/Code/Mantid/Framework/CurveFitting/inc/MantidCurveFitting/BackToBackExponential.h index 1feb4dcec305..103d8679b413 100644 --- a/Code/Mantid/Framework/CurveFitting/inc/MantidCurveFitting/BackToBackExponential.h +++ b/Code/Mantid/Framework/CurveFitting/inc/MantidCurveFitting/BackToBackExponential.h @@ -61,6 +61,10 @@ class DLLExport BackToBackExponential : public API::IPeakFunction { virtual void setHeight(const double h); virtual double fwhm() const; virtual void setFwhm(const double w); + virtual double intensity() const { return getParameter("I"); } + virtual void setIntensity(const double newIntensity) { + setParameter("I", newIntensity); + } /// overwrite IFunction base class methods std::string name() const { return "BackToBackExponential"; } diff --git a/Code/Mantid/Framework/CurveFitting/test/BackToBackExponentialTest.h b/Code/Mantid/Framework/CurveFitting/test/BackToBackExponentialTest.h index ab520925e308..31d564cca1f8 100644 --- a/Code/Mantid/Framework/CurveFitting/test/BackToBackExponentialTest.h +++ b/Code/Mantid/Framework/CurveFitting/test/BackToBackExponentialTest.h @@ -185,6 +185,25 @@ class BackToBackExponentialTest : public CxxTest::TestSuite } } + void testIntensity() + { + const double s = 4.0; + const double I = 2.1; + BackToBackExponential b2bExp; + b2bExp.initialize(); + b2bExp.setParameter("I", I); + b2bExp.setParameter("A", 6.0);// large A and B make + b2bExp.setParameter("B", 6.0);// the exponentials narrow + b2bExp.setParameter("X0",0.0); + b2bExp.setParameter("S", s); + + TS_ASSERT_EQUALS(b2bExp.intensity(), 2.1); + TS_ASSERT_THROWS_NOTHING(b2bExp.setIntensity(3.0)); + + TS_ASSERT_EQUALS(b2bExp.intensity(), 3.0); + TS_ASSERT_EQUALS(b2bExp.getParameter("I"), 3.0); + } + }; diff --git a/Code/Mantid/Framework/CurveFitting/test/IPeakFunctionIntensityTest.h b/Code/Mantid/Framework/CurveFitting/test/IPeakFunctionIntensityTest.h index ade73e302e1c..513f22227ae1 100644 --- a/Code/Mantid/Framework/CurveFitting/test/IPeakFunctionIntensityTest.h +++ b/Code/Mantid/Framework/CurveFitting/test/IPeakFunctionIntensityTest.h @@ -31,7 +31,6 @@ class IPeakFunctionIntensityTest : public CxxTest::TestSuite { IPeakFunctionIntensityTest() : m_blackList() { FrameworkManager::Instance(); - m_blackList.insert("BackToBackExponential"); m_blackList.insert("DeltaFunction"); m_blackList.insert("ElasticDiffRotDiscreteCircle"); m_blackList.insert("ElasticDiffSphere");