diff --git a/Code/Mantid/Framework/Algorithms/CMakeLists.txt b/Code/Mantid/Framework/Algorithms/CMakeLists.txt index 369c4dc5f6e40f17299161dec3af67b9d87cf88f..82a22cf9a427d00824fc6f8c31a8f7f104657c58 100644 --- a/Code/Mantid/Framework/Algorithms/CMakeLists.txt +++ b/Code/Mantid/Framework/Algorithms/CMakeLists.txt @@ -60,6 +60,7 @@ set ( SRC_FILES src/CreatePSDBleedMask.cpp src/CreatePeaksWorkspace.cpp src/CreateSingleValuedWorkspace.cpp + src/CreateTransmissionWorkspace.cpp src/CreateWorkspace.cpp src/CropWorkspace.cpp src/CrossCorrelate.cpp @@ -169,6 +170,7 @@ set ( SRC_FILES src/Rebunch.cpp src/RecordPythonScript.cpp src/ReflectometryReductionOne.cpp + src/ReflectometryWorkflowBase.cpp src/Regroup.cpp src/RemoveBins.cpp src/RemoveExpDecay.cpp @@ -282,6 +284,7 @@ set ( INC_FILES inc/MantidAlgorithms/CreatePSDBleedMask.h inc/MantidAlgorithms/CreatePeaksWorkspace.h inc/MantidAlgorithms/CreateSingleValuedWorkspace.h + inc/MantidAlgorithms/CreateTransmissionWorkspace.h inc/MantidAlgorithms/CreateWorkspace.h inc/MantidAlgorithms/CropWorkspace.h inc/MantidAlgorithms/CrossCorrelate.h @@ -392,6 +395,7 @@ set ( INC_FILES inc/MantidAlgorithms/Rebunch.h inc/MantidAlgorithms/RecordPythonScript.h inc/MantidAlgorithms/ReflectometryReductionOne.h + inc/MantidAlgorithms/ReflectometryWorkflowBase.h inc/MantidAlgorithms/Regroup.h inc/MantidAlgorithms/RemoveBins.h inc/MantidAlgorithms/RemoveExpDecay.h diff --git a/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/CreateTransmissionWorkspace.h b/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/CreateTransmissionWorkspace.h new file mode 100644 index 0000000000000000000000000000000000000000..965a2aa15694fdc3e2401e308976df906886137f --- /dev/null +++ b/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/CreateTransmissionWorkspace.h @@ -0,0 +1,65 @@ +#ifndef MANTID_ALGORITHMS_CREATETRANSMISSIONWORKSPACE_H_ +#define MANTID_ALGORITHMS_CREATETRANSMISSIONWORKSPACE_H_ + +#include "MantidKernel/System.h" +#include "MantidAlgorithms/ReflectometryWorkflowBase.h" + +namespace Mantid +{ + namespace Algorithms + { + + /** CreateTransmissionWorkspace : Create a transmission run workspace in Wavelength given one or more TOF workspaces + + Copyright © 2013 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory + + This file is part of Mantid. + + Mantid is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Mantid is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + File change history is stored at: <https://github.com/mantidproject/mantid> + Code Documentation is available at: <http://doxygen.mantidproject.org> + */ + class DLLExport CreateTransmissionWorkspace: public ReflectometryWorkflowBase + { + public: + CreateTransmissionWorkspace(); + virtual ~CreateTransmissionWorkspace(); + + virtual const std::string name() const; + virtual int version() const; + virtual const std::string category() const; + + private: + + /// Make a transmission correction workspace + API::MatrixWorkspace_sptr makeTransmissionCorrection(const WorkspaceIndexList& detectorIndexes, + const MinMax& wavelengthInterval, const MinMax& wavelengthMonitorBackgroundInterval, + const MinMax& wavelengthMonitorIntegrationInterval, const int& i0MonitorIndex, + API::MatrixWorkspace_sptr firstTransmissionRun, + OptionalMatrixWorkspace_sptr secondTransmissionRun, const OptionalDouble& stitchingStartQ, + const OptionalDouble& stitchingDeltaQ, const OptionalDouble& stitchingEndQ, + const OptionalDouble& stitchingStartOverlapQ, const OptionalDouble& stitchingEndOverlapQ, + const double& wavelengthStep); + + virtual void initDocs(); + void init(); + void exec(); + + }; + + } // namespace Algorithms +} // namespace Mantid + +#endif /* MANTID_ALGORITHMS_CREATETRANSMISSIONWORKSPACE_H_ */ diff --git a/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/ReflectometryReductionOne.h b/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/ReflectometryReductionOne.h index 22d53d41c4f91654b5e2b81ee49a1bc1f6ec6ca3..b890bdc7317d6875ed4781bba50a296d0821a73d 100644 --- a/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/ReflectometryReductionOne.h +++ b/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/ReflectometryReductionOne.h @@ -2,14 +2,11 @@ #define MANTID_ALGORITHMS_REFLECTOMETRYREDUCTIONONE_H_ #include "MantidKernel/System.h" -#include "MantidAPI/DataProcessorAlgorithm.h" #include "MantidAPI/MatrixWorkspace.h" #include "MantidGeometry/Instrument.h" #include "MantidGeometry/IComponent.h" #include "MantidGeometry/IDetector.h" -#include <boost/optional.hpp> -#include <boost/tuple/tuple.hpp> -#include <vector> +#include "MantidAlgorithms/ReflectometryWorkflowBase.h" namespace Mantid { @@ -38,18 +35,10 @@ namespace Mantid File change history is stored at: <https://github.com/mantidproject/mantid> Code Documentation is available at: <http://doxygen.mantidproject.org> */ - class DLLExport ReflectometryReductionOne: public API::DataProcessorAlgorithm + class DLLExport ReflectometryReductionOne: public ReflectometryWorkflowBase { public: - // Class typedefs - typedef boost::tuple<double, double> MinMax; - typedef boost::optional<double> OptionalDouble; - typedef boost::optional<Mantid::API::MatrixWorkspace_sptr> OptionalMatrixWorkspace_sptr; - typedef std::vector<int> WorkspaceIndexList; - typedef boost::optional<std::vector<int> > OptionalWorkspaceIndexes; - typedef boost::tuple<Mantid::API::MatrixWorkspace_sptr, Mantid::API::MatrixWorkspace_sptr> DetectorMonitorWorkspacePair; - /// Constructor ReflectometryReductionOne(); /// Destructor @@ -59,11 +48,6 @@ namespace Mantid virtual int version() const; virtual const std::string category() const; - /// Convert the input workspace to wavelength, splitting according to the properties provided. - DetectorMonitorWorkspacePair toLam(Mantid::API::MatrixWorkspace_sptr toConvert, - const WorkspaceIndexList& detectorIndexRange, const int monitorIndex, - const MinMax& wavelengthMinMax, const MinMax& backgroundMinMax, const double& wavelengthStep); - /// Convert to an IvsQ workspace. Performs detector positional corrections based on the component name and the theta value. Mantid::API::MatrixWorkspace_sptr toIvsQ(API::MatrixWorkspace_sptr toConvert, const bool correctPosition, OptionalDouble& thetaInDeg, Geometry::IComponent_const_sptr sample, Geometry::IComponent_const_sptr detector); @@ -77,49 +61,6 @@ namespace Mantid void exec(); - /** Auxillary getters and validators **/ - bool isPropertyDefault(const std::string& propertyName) const; - - /// Get a workspace index list. - WorkspaceIndexList getWorkspaceIndexList() const; - - /// Get min max indexes. - void fetchOptionalLowerUpperPropertyValue(const std::string& propertyName, bool isPointDetector, - OptionalWorkspaceIndexes& optionalUpperLower) const; - - /// Get the min/max property values - MinMax getMinMax(const std::string& minProperty, const std::string& maxProperty) const; - - /// Get the transmission correction properties - void getTransmissionRunInfo(OptionalMatrixWorkspace_sptr& firstTransmissionRun, - OptionalMatrixWorkspace_sptr& secondTransmissionRun, OptionalDouble& stitchingStartQ, - OptionalDouble& stitchingDeltaQ, OptionalDouble& stitchingEndQ, - OptionalDouble& stitchingStartOverlapQ, OptionalDouble& stitchingEndOverlapQ) const; - - /// Validate the transmission correction property inputs - void validateTransmissionInputs() const; - - /** Algorithm running methods **/ - - /// Convert the monitor parts of the input workspace to wavelength - API::MatrixWorkspace_sptr toLamMonitor(const API::MatrixWorkspace_sptr& toConvert, - const int monitorIndex, const MinMax& backgroundMinMax); - - /// Convert the detector spectrum of the input workspace to wavelength - API::MatrixWorkspace_sptr toLamDetector(const WorkspaceIndexList& detectorIndexRange, - const API::MatrixWorkspace_sptr& toConvert, const MinMax& wavelengthMinMax, const double& wavelengthStep); - - /// Perform a transmission correction on the input IvsLam workspace - API::MatrixWorkspace_sptr transmissonCorrection(API::MatrixWorkspace_sptr IvsLam, - const MinMax& wavelengthInterval, const MinMax& wavelengthMonitorBackgroundInterval, - const MinMax& wavelengthMonitorIntegrationInterval, const int& i0MonitorIndex, - API::MatrixWorkspace_sptr firstTransmissionRun, - OptionalMatrixWorkspace_sptr secondTransmissionRun, const OptionalDouble& stitchingStartQ, - const OptionalDouble& stitchingDeltaQ, const OptionalDouble& stitchingEndQ, - const OptionalDouble& stitchingStartOverlapQ, const OptionalDouble& stitchingEndOverlapQ, - const double& wavelengthStep - ); - /// Get the surface sample component Mantid::Geometry::IComponent_const_sptr getSurfaceSampleComponent(Mantid::Geometry::Instrument_const_sptr inst); @@ -133,6 +74,16 @@ namespace Mantid /// Sum spectra. Mantid::API::MatrixWorkspace_sptr sumSpectraOverRange(API::MatrixWorkspace_sptr inWS, const int startIndex, const int endIndex); + /// Perform a transmission correction on the input IvsLam workspace + API::MatrixWorkspace_sptr transmissonCorrection(API::MatrixWorkspace_sptr IvsLam, + const MinMax& wavelengthInterval, const MinMax& wavelengthMonitorBackgroundInterval, + const MinMax& wavelengthMonitorIntegrationInterval, const int& i0MonitorIndex, + API::MatrixWorkspace_sptr firstTransmissionRun, + OptionalMatrixWorkspace_sptr secondTransmissionRun, const OptionalDouble& stitchingStartQ, + const OptionalDouble& stitchingDeltaQ, const OptionalDouble& stitchingEndQ, + const OptionalDouble& stitchingStartOverlapQ, const OptionalDouble& stitchingEndOverlapQ, + const double& wavelengthStep ); + }; } // namespace Algorithms diff --git a/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/ReflectometryWorkflowBase.h b/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/ReflectometryWorkflowBase.h new file mode 100644 index 0000000000000000000000000000000000000000..5b81afd47ce9e307a258b77dc71383ee04373046 --- /dev/null +++ b/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/ReflectometryWorkflowBase.h @@ -0,0 +1,110 @@ +#ifndef MANTID_ALGORITHMS_REFLECTOMETRYWORKFLOWBASE_H_ +#define MANTID_ALGORITHMS_REFLECTOMETRYWORKFLOWBASE_H_ + +#include "MantidKernel/System.h" +#include "MantidAPI/DataProcessorAlgorithm.h" + +#include <boost/optional.hpp> +#include <boost/tuple/tuple.hpp> +#include <vector> + +namespace Mantid +{ + namespace Algorithms + { + + /** ReflectometryWorkflowBase : Abstract workflow algortithm base class containing common implementation functionality usable + * by concrete reflectometry workflow algorithms. + + Copyright © 2013 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory + + This file is part of Mantid. + + Mantid is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Mantid is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + File change history is stored at: <https://github.com/mantidproject/mantid> + Code Documentation is available at: <http://doxygen.mantidproject.org> + */ + class DLLExport ReflectometryWorkflowBase: public API::DataProcessorAlgorithm + { + public: + + // Class typedefs + typedef boost::tuple<double, double> MinMax; + typedef boost::optional<double> OptionalDouble; + typedef boost::optional<Mantid::API::MatrixWorkspace_sptr> OptionalMatrixWorkspace_sptr; + typedef std::vector<int> WorkspaceIndexList; + typedef boost::optional<std::vector<int> > OptionalWorkspaceIndexes; + typedef boost::tuple<Mantid::API::MatrixWorkspace_sptr, Mantid::API::MatrixWorkspace_sptr> DetectorMonitorWorkspacePair; + + ReflectometryWorkflowBase(); + virtual ~ReflectometryWorkflowBase(); + + /// Convert the input workspace to wavelength, splitting according to the properties provided. + DetectorMonitorWorkspacePair toLam(Mantid::API::MatrixWorkspace_sptr toConvert, + const WorkspaceIndexList& detectorIndexRange, const int monitorIndex, + const MinMax& wavelengthMinMax, const MinMax& backgroundMinMax, const double& wavelengthStep); + + protected: + + /// Determine if the property has it's default value. + bool isPropertyDefault(const std::string& propertyName) const; + + /// Get a workspace index list. + WorkspaceIndexList getWorkspaceIndexList() const; + + /// Get min max indexes. + void fetchOptionalLowerUpperPropertyValue(const std::string& propertyName, bool isPointDetector, + OptionalWorkspaceIndexes& optionalUpperLower) const; + + /// Get the min/max property values + MinMax getMinMax(const std::string& minProperty, const std::string& maxProperty) const; + + /// Get the transmission correction properties + void getTransmissionRunInfo(OptionalMatrixWorkspace_sptr& firstTransmissionRun, + OptionalMatrixWorkspace_sptr& secondTransmissionRun, OptionalDouble& stitchingStart, + OptionalDouble& stitchingDelta, OptionalDouble& stitchingEnd, + OptionalDouble& stitchingStartOverlap, OptionalDouble& stitchingEndOverlap) const; + + /// Init common index inputs + void initIndexInputs(); + /// Init common wavelength inputs + void initWavelengthInputs(); + /// Init common stitching inputs + void initStitchingInputs(); + + private: + + /// Validate the transmission correction property inputs + void validateSecondTransmissionInputs(const bool firstTransmissionInWavelength) const; + + /// Validate the the first transmission workspace. + bool validateFirstTransmissionInputs() const; + + /// Convert the monitor parts of the input workspace to wavelength + API::MatrixWorkspace_sptr toLamMonitor(const API::MatrixWorkspace_sptr& toConvert, + const int monitorIndex, const MinMax& backgroundMinMax); + + /// Convert the detector spectrum of the input workspace to wavelength + API::MatrixWorkspace_sptr toLamDetector(const WorkspaceIndexList& detectorIndexRange, + const API::MatrixWorkspace_sptr& toConvert, const MinMax& wavelengthMinMax, + const double& wavelengthStep); + + }; + + + } // namespace Algorithms +} // namespace Mantid + +#endif /* MANTID_ALGORITHMS_REFLECTOMETRYWORKFLOWBASE_H_ */ diff --git a/Code/Mantid/Framework/Algorithms/src/CreateTransmissionWorkspace.cpp b/Code/Mantid/Framework/Algorithms/src/CreateTransmissionWorkspace.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5678f0c86bbd8ba6ff8c19fc96b1a964805d591c --- /dev/null +++ b/Code/Mantid/Framework/Algorithms/src/CreateTransmissionWorkspace.cpp @@ -0,0 +1,247 @@ +/*WIKI* + Creates a transmission run workspace given one or more TOF workspaces and the original run Workspace. If two workspaces are provided, then + the workspaces are stitched together using [[Stitch1D]]. InputWorkspaces must be in TOF. A single output workspace is generated with x-units of Wavlength in angstroms. + *WIKI*/ + +#include "MantidAlgorithms/CreateTransmissionWorkspace.h" + +#include "MantidAPI/WorkspaceValidators.h" +#include "MantidKernel/MandatoryValidator.h" +#include "MantidKernel/ArrayProperty.h" +#include "MantidKernel/EnabledWhenProperty.h" +#include "MantidKernel/RebinParamsValidator.h" +#include "MantidKernel/BoundedValidator.h" +#include <boost/make_shared.hpp> +#include <boost/assign/list_of.hpp> + +using namespace Mantid::Kernel; +using namespace Mantid::API; + +namespace Mantid +{ + namespace Algorithms + { + + // Register the algorithm into the AlgorithmFactory + DECLARE_ALGORITHM(CreateTransmissionWorkspace) + + //---------------------------------------------------------------------------------------------- + /** Constructor + */ + CreateTransmissionWorkspace::CreateTransmissionWorkspace() + { + } + + //---------------------------------------------------------------------------------------------- + /** Destructor + */ + CreateTransmissionWorkspace::~CreateTransmissionWorkspace() + { + } + + //---------------------------------------------------------------------------------------------- + /// Algorithm's name for identification. @see Algorithm::name + const std::string CreateTransmissionWorkspace::name() const + { + return "CreateTransmissionWorkspace"; + } + ; + + /// Algorithm's version for identification. @see Algorithm::version + int CreateTransmissionWorkspace::version() const + { + return 1; + } + ; + + /// Algorithm's category for identification. @see Algorithm::category + const std::string CreateTransmissionWorkspace::category() const + { + return "Reflectometry\\ISIS"; + } + + //---------------------------------------------------------------------------------------------- + /// Sets documentation strings for this algorithm + void CreateTransmissionWorkspace::initDocs() + { + this->setWikiSummary( + "Creates a transmission run workspace in Wavelength from input TOF workspaces."); + this->setOptionalMessage(this->getWikiSummary()); + } + + //---------------------------------------------------------------------------------------------- + /** Initialize the algorithm's properties. + */ + void CreateTransmissionWorkspace::init() + { + boost::shared_ptr<CompositeValidator> inputValidator = boost::make_shared<CompositeValidator>(); + inputValidator->add(boost::make_shared<WorkspaceUnitValidator>("TOF")); + + declareProperty( + new WorkspaceProperty<MatrixWorkspace>("FirstTransmissionRun", "", Direction::Input, + PropertyMode::Mandatory, inputValidator->clone()), + "First transmission run, or the low wavelength transmision run if SecondTransmissionRun is also provided."); + + declareProperty( + new WorkspaceProperty<MatrixWorkspace>("SecondTransmissionRun", "", Direction::Input, + PropertyMode::Optional, inputValidator->clone()), + "Second, high wavelength transmission run. Optional. Causes the InputWorkspace to be treated as the low wavelength transmission run."); + + this->initStitchingInputs(); + this->initIndexInputs(); + this->initWavelengthInputs(); + + declareProperty(new WorkspaceProperty<MatrixWorkspace>("OutputWorkspace", "", Direction::Output), + "Output Workspace IvsQ."); + + setPropertySettings("Params", + new Kernel::EnabledWhenProperty("SecondTransmissionWorkspace", IS_NOT_DEFAULT)); + + setPropertySettings("StartOverlap", + new Kernel::EnabledWhenProperty("SecondTransmissionWorkspace", IS_NOT_DEFAULT)); + + setPropertySettings("EndOverlap", + new Kernel::EnabledWhenProperty("SecondTransmissionWorkspace", IS_NOT_DEFAULT)); + + } + + //---------------------------------------------------------------------------------------------- + /** Execute the algorithm. + */ + void CreateTransmissionWorkspace::exec() + { + OptionalMatrixWorkspace_sptr firstTransmissionRun; + OptionalMatrixWorkspace_sptr secondTransmissionRun; + OptionalDouble stitchingStart; + OptionalDouble stitchingDelta; + OptionalDouble stitchingEnd; + OptionalDouble stitchingStartOverlap; + OptionalDouble stitchingEndOverlap; + + // Get the transmission run property information. + getTransmissionRunInfo(firstTransmissionRun, secondTransmissionRun, stitchingStart, + stitchingDelta, stitchingEnd, stitchingStartOverlap, stitchingEndOverlap); + + // Get wavelength intervals. + const MinMax wavelengthInterval = this->getMinMax("WavelengthMin", "WavelengthMax"); + const double wavelengthStep = getProperty("WavelengthStep"); + const MinMax monitorBackgroundWavelengthInterval = getMinMax("MonitorBackgroundWavelengthMin", + "MonitorBackgroundWavelengthMax"); + const MinMax monitorIntegrationWavelengthInterval = getMinMax("MonitorIntegrationWavelengthMin", + "MonitorIntegrationWavelengthMax"); + + // Get the index list + const WorkspaceIndexList indexList = getWorkspaceIndexList(); + + // Get the monitor i0 index + const int i0MonitorIndex = getProperty("I0MonitorIndex"); + + // Create the transmission workspace. + MatrixWorkspace_sptr outWS = this->makeTransmissionCorrection(indexList, wavelengthInterval, + monitorBackgroundWavelengthInterval, monitorIntegrationWavelengthInterval, i0MonitorIndex, + firstTransmissionRun.get(), secondTransmissionRun, stitchingStart, stitchingDelta, stitchingEnd, + stitchingStartOverlap, stitchingEndOverlap, wavelengthStep); + + + setProperty("OutputWorkspace", outWS); + } + + + + /** + * Create a transmission corrections workspace utilising one or two workspaces. + * + * Input workspaces are in TOF. These are converted to lambda, normalized and stitched together (if two given). + * + * @param IvsLam : Run workspace which is to be normalized by the results of the transmission corrections. + * @param wavelengthInterval : Wavelength interval for the run workspace. + * @param wavelengthMonitorBackgroundInterval : Wavelength interval for the monitor background + * @param wavelengthMonitorIntegrationInterval : Wavelength interval for the monitor integration + * @param i0MonitorIndex : Monitor index for the I0 monitor + * @param firstTransmissionRun : The first transmission run + * @param secondTransmissionRun : The second transmission run (optional) + * @param stitchingStart : Stitching start (optional but dependent on secondTransmissionRun) + * @param stitchingDelta : Stitching delta (optional but dependent on secondTransmissionRun) + * @param stitchingEnd : Stitching end (optional but dependent on secondTransmissionRun) + * @param stitchingStartOverlap : Stitching start overlap (optional but dependent on secondTransmissionRun) + * @param stitchingEndOverlap : Stitching end overlap (optional but dependent on secondTransmissionRun) + * @param wavelengthStep : Step in angstroms for rebinning for workspaces converted into wavelength. + * @return A transmission workspace in Wavelength units. + */ + MatrixWorkspace_sptr CreateTransmissionWorkspace::makeTransmissionCorrection( + const WorkspaceIndexList& detectorIndexes, + const MinMax& wavelengthInterval, + const MinMax& wavelengthMonitorBackgroundInterval, + const MinMax& wavelengthMonitorIntegrationInterval, + const int& i0MonitorIndex, + MatrixWorkspace_sptr firstTransmissionRun, + OptionalMatrixWorkspace_sptr secondTransmissionRun, + const OptionalDouble& stitchingStart, + const OptionalDouble& stitchingDelta, + const OptionalDouble& stitchingEnd, + const OptionalDouble& stitchingStartOverlap, + const OptionalDouble& stitchingEndOverlap, + const double& wavelengthStep) + { + auto trans1InLam = toLam(firstTransmissionRun, detectorIndexes, i0MonitorIndex, wavelengthInterval, + wavelengthMonitorBackgroundInterval, wavelengthStep); + MatrixWorkspace_sptr trans1Detector = trans1InLam.get<0>(); + MatrixWorkspace_sptr trans1Monitor = trans1InLam.get<1>(); + + // Monitor integration ... can this happen inside the toLam routine? + auto integrationAlg = this->createChildAlgorithm("Integration"); + integrationAlg->initialize(); + integrationAlg->setProperty("InputWorkspace", trans1Monitor); + integrationAlg->setProperty("RangeLower", wavelengthMonitorIntegrationInterval.get<0>()); + integrationAlg->setProperty("RangeUpper", wavelengthMonitorIntegrationInterval.get<1>()); + integrationAlg->execute(); + trans1Monitor = integrationAlg->getProperty("OutputWorkspace"); + + MatrixWorkspace_sptr transmissionWS = trans1Detector / trans1Monitor; + + if (secondTransmissionRun.is_initialized()) + { + auto transRun2 = secondTransmissionRun.get(); + g_log.debug("Extracting second transmission run workspace indexes from spectra"); + + auto trans2InLam = toLam(transRun2, detectorIndexes, i0MonitorIndex, wavelengthInterval, + wavelengthMonitorBackgroundInterval, wavelengthStep); + + // Unpack the conversion results. + MatrixWorkspace_sptr trans2Detector = trans2InLam.get<0>(); + MatrixWorkspace_sptr trans2Monitor = trans2InLam.get<1>(); + + // Monitor integration ... can this happen inside the toLam routine? + auto integrationAlg = this->createChildAlgorithm("Integration"); + integrationAlg->initialize(); + integrationAlg->setProperty("InputWorkspace", trans2Monitor); + integrationAlg->setProperty("RangeLower", wavelengthMonitorIntegrationInterval.get<0>()); + integrationAlg->setProperty("RangeUpper", wavelengthMonitorIntegrationInterval.get<1>()); + integrationAlg->execute(); + trans2Monitor = integrationAlg->getProperty("OutputWorkspace"); + + MatrixWorkspace_sptr normalizedTrans2 = trans2Detector / trans2Monitor; + + // Stitch the results. + auto stitch1DAlg = this->createChildAlgorithm("Stitch1D"); + stitch1DAlg->initialize(); + AnalysisDataService::Instance().addOrReplace("transmissionWS", transmissionWS); + AnalysisDataService::Instance().addOrReplace("normalizedTrans2", normalizedTrans2); + stitch1DAlg->setProperty("LHSWorkspace", transmissionWS); + stitch1DAlg->setProperty("RHSWorkspace", normalizedTrans2); + stitch1DAlg->setProperty("StartOverlap", stitchingStartOverlap.get()); + stitch1DAlg->setProperty("EndOverlap", stitchingEndOverlap.get()); + const std::vector<double> params = boost::assign::list_of(stitchingStart.get())( + stitchingDelta.get())(stitchingEnd.get()).convert_to_container<std::vector<double> >(); + stitch1DAlg->setProperty("Params", params); + stitch1DAlg->execute(); + transmissionWS = stitch1DAlg->getProperty("OutputWorkspace"); + AnalysisDataService::Instance().remove("transmissionWS"); + AnalysisDataService::Instance().remove("normalizedTrans2"); + } + + return transmissionWS; + } + + } // namespace Algorithms +} // namespace Mantid diff --git a/Code/Mantid/Framework/Algorithms/src/ReflectometryReductionOne.cpp b/Code/Mantid/Framework/Algorithms/src/ReflectometryReductionOne.cpp index b6b0e1840d4f5c1507f1c47143260b9db45bf16a..02d788913448f34e5db41c1a3ea74774401fe24b 100644 --- a/Code/Mantid/Framework/Algorithms/src/ReflectometryReductionOne.cpp +++ b/Code/Mantid/Framework/Algorithms/src/ReflectometryReductionOne.cpp @@ -58,11 +58,11 @@ namespace Mantid * @param hostWS : Workspace onto which the resulting workspace indexes will be hosted * @return Remapped wokspace indexes applicable for the host workspace. */ - ReflectometryReductionOne::WorkspaceIndexList createWorkspaceIndexListFromDetectorWorkspace( + ReflectometryWorkflowBase::WorkspaceIndexList createWorkspaceIndexListFromDetectorWorkspace( MatrixWorkspace_const_sptr originWS, MatrixWorkspace_const_sptr hostWS) { auto spectrumMap = originWS->getSpectrumToWorkspaceIndexMap(); - ReflectometryReductionOne::WorkspaceIndexList translatedIndexList; + ReflectometryWorkflowBase::WorkspaceIndexList translatedIndexList; for (auto it = spectrumMap.begin(); it != spectrumMap.end(); ++it) { specid_t specId = (*it).first; @@ -71,6 +71,7 @@ namespace Mantid return translatedIndexList; } + /** * Helper non-member function * Get indexes in terms of an end-point host workspace. @@ -81,7 +82,7 @@ namespace Mantid * @param originIndexes : Indexes in terms of the origin workspace * @return WorkspaceIndexes in terms of the host workspace */ - ReflectometryReductionOne::WorkspaceIndexList getIndexesInTermsOf( + ReflectometryWorkflowBase::WorkspaceIndexList getIndexesInTermsOf( MatrixWorkspace_const_sptr hostWS, MatrixWorkspace_sptr originWS, const ReflectometryReductionOne::WorkspaceIndexList& originIndexes) { @@ -95,18 +96,10 @@ namespace Mantid return translatedIndexList; } - /** - * Helper method used with the stl to determine whether values are negative - * @param value : Value to check - * @return : True if negative. - */ - bool checkNotPositive(const int value) - { - return value < 0; - } - const std::string multiDetectorAnalysis = "MultiDetectorAnalysis"; const std::string pointDetectorAnalysis = "PointDetectorAnalysis"; + const std::string tofUnitId = "TOF"; + const std::string wavelengthUnitId = "Wavelength"; } /* End of ananomous namespace */ @@ -163,7 +156,7 @@ namespace Mantid void ReflectometryReductionOne::init() { boost::shared_ptr<CompositeValidator> inputValidator = boost::make_shared<CompositeValidator>(); - inputValidator->add(boost::make_shared<WorkspaceUnitValidator>("TOF")); + inputValidator->add(boost::make_shared<WorkspaceUnitValidator>(tofUnitId)); declareProperty( new WorkspaceProperty<MatrixWorkspace>("InputWorkspace", "", Direction::Input, inputValidator), @@ -182,52 +175,9 @@ namespace Mantid declareProperty(new ArrayProperty<int>("RegionOfDirectBeam"), "Indices of the spectra a pair (lower, upper) that mark the ranges that correspond to the direct beam in multi-detector mode."); - declareProperty( - new PropertyWithValue<double>("WavelengthMin", Mantid::EMPTY_DBL(), - boost::make_shared<MandatoryValidator<double> >(), Direction::Input), - "Wavelength minimum in angstroms"); - declareProperty( - new PropertyWithValue<double>("WavelengthMax", Mantid::EMPTY_DBL(), - boost::make_shared<MandatoryValidator<double> >(), Direction::Input), - "Wavelength maximum in angstroms"); - - declareProperty( - new PropertyWithValue<double>("WavelengthStep", 0.05, - boost::make_shared<MandatoryValidator<double> >(), Direction::Input), - "Wavelength rebinning step in angstroms. Defaults to 0.05. Used for rebinning intermediate workspaces converted into wavelength."); - - boost::shared_ptr<CompositeValidator> mandatoryWorkspaceIndex = boost::make_shared< - CompositeValidator>(); - mandatoryWorkspaceIndex->add(boost::make_shared<MandatoryValidator<int> >()); - auto boundedIndex = boost::make_shared<BoundedValidator<int> >(); - boundedIndex->setLower(0); - mandatoryWorkspaceIndex->add(boundedIndex); + this->initIndexInputs(); + this->initWavelengthInputs(); - declareProperty( - new PropertyWithValue<int>("I0MonitorIndex", Mantid::EMPTY_INT(), mandatoryWorkspaceIndex), - "I0 monitor index"); - - declareProperty( - new PropertyWithValue<double>("MonitorBackgroundWavelengthMin", Mantid::EMPTY_DBL(), - boost::make_shared<MandatoryValidator<double> >(), Direction::Input), - "Wavelength minimum for monitor background in angstroms. Taken to be WavelengthMin if not provided."); - - declareProperty( - new PropertyWithValue<double>("MonitorBackgroundWavelengthMax", Mantid::EMPTY_DBL(), - boost::make_shared<MandatoryValidator<double> >(), Direction::Input), - "Wavelength maximum for monitor background in angstroms. Taken to be WavelengthMax if not provided."); - - declareProperty( - new PropertyWithValue<double>("MonitorIntegrationWavelengthMin", Mantid::EMPTY_DBL(), - boost::make_shared<MandatoryValidator<double> >(), Direction::Input), - "Wavelength minimum for integration in angstroms. Taken to be WavelengthMin if not provided."); - declareProperty( - new PropertyWithValue<double>("MonitorIntegrationWavelengthMax", Mantid::EMPTY_DBL(), - boost::make_shared<MandatoryValidator<double> >(), Direction::Input), - "Wavelength maximum for integration in angstroms. Taken to be WavelengthMax if not provided."); - - declareProperty(new ArrayProperty<int>("WorkspaceIndexList"), - "Indices of the spectra in pairs (lower, upper) that mark the ranges that correspond to detectors of interest."); declareProperty(new PropertyWithValue<std::string>("DetectorComponentName", "", Direction::Input), "Name of the detector component i.e. point-detector. If these are not specified, the algorithm will attempt lookup using a standard naming convention."); @@ -248,38 +198,27 @@ namespace Mantid declareProperty( new WorkspaceProperty<MatrixWorkspace>("FirstTransmissionRun", "", Direction::Input, - PropertyMode::Optional, inputValidator->clone()), + PropertyMode::Optional), "First transmission run, or the low wavelength transmision run if SecondTransmissionRun is also provided."); declareProperty( new WorkspaceProperty<MatrixWorkspace>("SecondTransmissionRun", "", Direction::Input, PropertyMode::Optional, inputValidator->clone()), "Second, high wavelength transmission run. Optional. Causes the FirstTransmissionRun to be treated as the low wavelength transmission run."); - declareProperty( - new ArrayProperty<double>("Params", boost::make_shared<RebinParamsValidator>(true)), - "A comma separated list of first bin boundary, width, last bin boundary. " - "These parameters are used for stitching together transmission runs. " - "Values are in q. This input is only needed if a SecondTransmission run is provided."); - - declareProperty( - new PropertyWithValue<double>("StartOverlapQ", Mantid::EMPTY_DBL(), Direction::Input), - "Start Q for stitching transmission runs together"); - declareProperty( - new PropertyWithValue<double>("EndOverlapQ", Mantid::EMPTY_DBL(), Direction::Input), - "End Q for stitching transmission runs together"); + this->initStitchingInputs(); setPropertyGroup("FirstTransmissionRun", "Transmission"); setPropertyGroup("SecondTransmissionRun", "Transmission"); setPropertyGroup("Params", "Transmission"); - setPropertyGroup("StartOverlapQ", "Transmission"); - setPropertyGroup("EndOverlapQ", "Transmission"); + setPropertyGroup("StartOverlap", "Transmission"); + setPropertyGroup("EndOverlap", "Transmission"); // Only do transmission corrections when point detector. setPropertySettings("FirstTransmissionRun", new Kernel::EnabledWhenProperty("AnalysisMode", IS_EQUAL_TO, "PointDetectorAnalysis")); setPropertySettings("SecondTransmissionRun", new Kernel::EnabledWhenProperty("AnalysisMode", IS_EQUAL_TO, "PointDetectorAnalysis")); setPropertySettings("Params", new Kernel::EnabledWhenProperty("AnalysisMode", IS_EQUAL_TO, "PointDetectorAnalysis")); - setPropertySettings("StartOverlapQ", new Kernel::EnabledWhenProperty("AnalysisMode", IS_EQUAL_TO, "PointDetectorAnalysis")); - setPropertySettings("EndOverlapQ", new Kernel::EnabledWhenProperty("AnalysisMode", IS_EQUAL_TO, "PointDetectorAnalysis")); + setPropertySettings("StartOverlap", new Kernel::EnabledWhenProperty("AnalysisMode", IS_EQUAL_TO, "PointDetectorAnalysis")); + setPropertySettings("EndOverlap", new Kernel::EnabledWhenProperty("AnalysisMode", IS_EQUAL_TO, "PointDetectorAnalysis")); // Only use region of interest when in multi-detector analysis mode setPropertySettings("RegionOfInterest", @@ -290,433 +229,6 @@ namespace Mantid new Kernel::EnabledWhenProperty("AnalysisMode", IS_EQUAL_TO, "MultiDetectorAnalysis")); } - /** - * Determine if the property value is the same as the default value. - * This can be used to determine if the property has not been set. - * @param propertyName : Name of property to query - * @return: True only if the property has it's default value. - */ - bool ReflectometryReductionOne::isPropertyDefault(const std::string& propertyName) const - { - Property* property = this->getProperty(propertyName); - return property->isDefault(); - } - - /** - * Get the workspace index list - * @return Workspace index list. - */ - ReflectometryReductionOne::WorkspaceIndexList ReflectometryReductionOne::getWorkspaceIndexList() const - { - WorkspaceIndexList indexList = getProperty("WorkspaceIndexList"); - if (indexList.size() % 2 != 0 || indexList.size() == 0) - { - throw std::invalid_argument( - "WorkspaceIndex list must be composed of pairs of min index, max index."); - } - - if (std::find_if(indexList.begin(), indexList.end(), checkNotPositive) != indexList.end()) - { - throw std::invalid_argument("WorkspaceIndexList contains negative indexes"); - } - - for (size_t i = 0; (i + 1) < indexList.size(); i += 2) - { - if (indexList[i] > indexList[i + 1]) - throw std::invalid_argument("WorkspaceIndexList pairs must be in min, max order"); - } - return indexList; - } - - /** - * Fetch min, max inputs as a vector (int) if they are non-default and set them to the optionalUpperLower object. - * Performs checks to verify that invalid indexes have not been passed in. - * @param propertyName : Property name to fetch - * @param isPointDetector : Flag indicates that the execution is in point detector mode. - * @param optionalUpperLower : Object to set min and max on. - */ - void ReflectometryReductionOne::fetchOptionalLowerUpperPropertyValue(const std::string& propertyName, - bool isPointDetector, OptionalWorkspaceIndexes& optionalUpperLower) const - { - if (!isPropertyDefault(propertyName)) - { - // Validation of property inputs. - if (isPointDetector) - { - throw std::invalid_argument( - "Cannot have a region of interest property in point detector mode."); - } - std::vector<int> temp = this->getProperty(propertyName); - if (temp.size() != 2) - { - const std::string message = propertyName + " requires a lower and upper boundary"; - throw std::invalid_argument(message); - } - if (temp[0] > temp[1]) - { - throw std::invalid_argument("Min must be <= Max index"); - } - if (std::find_if(temp.begin(), temp.end(), checkNotPositive) != temp.end()) - { - const std::string message = propertyName + " contains negative indexes"; - throw std::invalid_argument(message); - } - // Assignment - optionalUpperLower = temp; - } - } - - /** - * Get min max pairs as a tuple. - * @param minProperty : Property name for the min property - * @param maxProperty : Property name for the max property - * @return A tuple consisting of min, max - */ - ReflectometryReductionOne::MinMax ReflectometryReductionOne::getMinMax( - const std::string& minProperty, const std::string& maxProperty) const - { - const double min = getProperty(minProperty); - const double max = getProperty(maxProperty); - if (min > max) - { - throw std::invalid_argument("Cannot have any WavelengthMin > WavelengthMax"); - } - return MinMax(min, max); - } - - /** - * Validate the transmission workspace inputs when a second transmission run is provided. - * Throws if any of the property values do not make sense. - */ - void ReflectometryReductionOne::validateTransmissionInputs() const - { - // Verify that all the required inputs for the second transmission run are now given. - if (isPropertyDefault("FirstTransmissionRun")) - { - throw std::invalid_argument( - "A SecondTransmissionRun is only valid if a FirstTransmissionRun is provided."); - } - if (isPropertyDefault("Params")) - { - throw std::invalid_argument( - "If a SecondTransmissionRun has been given, then stitching Params for the transmission runs are also required."); - } - if (isPropertyDefault("StartOverlapQ")) - { - throw std::invalid_argument( - "If a SecondTransmissionRun has been given, then a stitching StartOverlapQ for the transmission runs is also required."); - } - if (isPropertyDefault("EndOverlapQ")) - { - throw std::invalid_argument( - "If a SecondTransmissionRun has been given, then a stitching EndOverlapQ for the transmission runs is also required."); - } - const double startOverlapQ = this->getProperty("StartOverlapQ"); - const double endOverlapQ = this->getProperty("EndOverlapQ"); - if (startOverlapQ >= endOverlapQ) - { - throw std::invalid_argument("EndOverlapQ must be > StartOverlapQ"); - } - - } - - /** - * Get the transmission run information. - * - * Transmission runs are optional, but you cannot have the second without the first. Also, stitching - * parameters are required if the second is present. This getter fetches and assigns to the optional reference arguments - * - * @param firstTransmissionRun - * @param secondTransmissionRun - * @param stitchingStartQ - * @param stitchingDeltaQ - * @param stitchingEndQ - */ - void ReflectometryReductionOne::getTransmissionRunInfo( - OptionalMatrixWorkspace_sptr& firstTransmissionRun, - OptionalMatrixWorkspace_sptr& secondTransmissionRun, OptionalDouble& stitchingStartQ, - OptionalDouble& stitchingDeltaQ, OptionalDouble& stitchingEndQ, - OptionalDouble& stitchingStartOverlapQ, OptionalDouble& stitchingEndOverlapQ) const - { - if (!isPropertyDefault("FirstTransmissionRun")) - { - MatrixWorkspace_sptr temp = this->getProperty("FirstTransmissionRun"); - /* - if(temp->getNumberHistograms() > 1) - { - throw std::invalid_argument("Error with FirstTransmissionRun. Only one histogram is permitted for a transmission run."); - } - */ - firstTransmissionRun = temp; - } - - if (!isPropertyDefault("SecondTransmissionRun")) - { - // Check that the property values provided make sense together. - validateTransmissionInputs(); - - // Set the values. - { - MatrixWorkspace_sptr temp = this->getProperty("SecondTransmissionRun"); - secondTransmissionRun = temp; - } - { - std::vector<double> params = getProperty("Params"); - stitchingStartQ = params[0]; - stitchingDeltaQ = params[1]; - stitchingEndQ = params[2]; - } - { - double temp = this->getProperty("StartOverlapQ"); - stitchingStartOverlapQ = temp; - temp = this->getProperty("EndOverlapQ"); - stitchingEndOverlapQ = temp; - } - } - - } - - - /** - * Convert the TOF workspace into a monitor workspace. Crops to the monitorIndex and applying flat background correction as part of the process. - * @param toConvert : TOF wavlength to convert. - * @param monitorIndex : Monitor index to crop to - * @param backgroundMinMax : Min and Max Lambda range for Flat background correction. - * @return The cropped and corrected monitor workspace. - */ - MatrixWorkspace_sptr ReflectometryReductionOne::toLamMonitor(const MatrixWorkspace_sptr& toConvert, const int monitorIndex, const MinMax& backgroundMinMax) - { - // Convert Units. - auto convertUnitsAlg = this->createChildAlgorithm("ConvertUnits"); - convertUnitsAlg->initialize(); - convertUnitsAlg->setProperty("InputWorkspace", toConvert); - convertUnitsAlg->setProperty("Target", "Wavelength"); - convertUnitsAlg->setProperty("AlignBins", true); - convertUnitsAlg->execute(); - - // Crop the to the monitor index. - MatrixWorkspace_sptr monitorWS = convertUnitsAlg->getProperty("OutputWorkspace"); - auto cropWorkspaceAlg = this->createChildAlgorithm("CropWorkspace"); - cropWorkspaceAlg->initialize(); - cropWorkspaceAlg->setProperty("InputWorkspace", monitorWS); - cropWorkspaceAlg->setProperty("StartWorkspaceIndex", monitorIndex); - cropWorkspaceAlg->setProperty("EndWorkspaceIndex", monitorIndex); - cropWorkspaceAlg->execute(); - monitorWS = cropWorkspaceAlg->getProperty("OutputWorkspace"); - - // Flat background correction - auto correctMonitorsAlg = this->createChildAlgorithm("CalculateFlatBackground"); - correctMonitorsAlg->initialize(); - correctMonitorsAlg->setProperty("InputWorkspace", monitorWS); - correctMonitorsAlg->setProperty("WorkspaceIndexList", - boost::assign::list_of(0).convert_to_container<std::vector<int> >()); - correctMonitorsAlg->setProperty("StartX", backgroundMinMax.get<0>()); - correctMonitorsAlg->setProperty("EndX", backgroundMinMax.get<1>()); - correctMonitorsAlg->execute(); - monitorWS = correctMonitorsAlg->getProperty("OutputWorkspace"); - - return monitorWS; - } - - /** - * Convert to a detector workspace in lambda. - * @param detectorIndexRange : Workspace index ranges to keep - * @param toConvert : TOF wavelength to convert. - * @param wavelengthMinMax : Wavelength minmax to keep. Crop out the rest. - * @param wavelengthStep : Wavelength step for rebinning - * @return Detector workspace in wavelength - */ - MatrixWorkspace_sptr ReflectometryReductionOne::toLamDetector( - const WorkspaceIndexList& detectorIndexRange, const MatrixWorkspace_sptr& toConvert, - const MinMax& wavelengthMinMax, const double& wavelengthStep) - { - // Detector Workspace Processing - MatrixWorkspace_sptr detectorWS; - - // Loop over pairs of detector index ranges. Peform the cropping and then conjoin the results into a single workspace. - for (size_t i = 0; i < detectorIndexRange.size(); i += 2) - { - auto cropWorkspaceAlg = this->createChildAlgorithm("CropWorkspace"); - cropWorkspaceAlg->initialize(); - cropWorkspaceAlg->setProperty("InputWorkspace", toConvert); - cropWorkspaceAlg->setProperty("StartWorkspaceIndex", detectorIndexRange[i]); - cropWorkspaceAlg->setProperty("EndWorkspaceIndex", detectorIndexRange[i + 1]); - cropWorkspaceAlg->execute(); - MatrixWorkspace_sptr subRange = cropWorkspaceAlg->getProperty("OutputWorkspace"); - if (i == 0) - { - detectorWS = subRange; - } - else - { - auto conjoinWorkspaceAlg = this->createChildAlgorithm("ConjoinWorkspaces"); - conjoinWorkspaceAlg->initialize(); - conjoinWorkspaceAlg->setProperty("InputWorkspace1", detectorWS); - conjoinWorkspaceAlg->setProperty("InputWorkspace2", subRange); - conjoinWorkspaceAlg->execute(); - detectorWS = conjoinWorkspaceAlg->getProperty("InputWorkspace1"); - } - } - // Now convert units. Do this after the conjoining step otherwise the x bins will not match up. - auto convertUnitsAlg = this->createChildAlgorithm("ConvertUnits"); - convertUnitsAlg->initialize(); - convertUnitsAlg->setProperty("InputWorkspace", detectorWS); - convertUnitsAlg->setProperty("Target", "Wavelength"); - convertUnitsAlg->setProperty("AlignBins", true); - convertUnitsAlg->execute(); - detectorWS = convertUnitsAlg->getProperty("OutputWorkspace"); - - // Crop out the lambda x-ranges now that the workspace is in wavelength. - auto cropWorkspaceAlg = this->createChildAlgorithm("CropWorkspace"); - cropWorkspaceAlg->initialize(); - cropWorkspaceAlg->setProperty("InputWorkspace", detectorWS); - cropWorkspaceAlg->setProperty("XMin", wavelengthMinMax.get<0>()); - cropWorkspaceAlg->setProperty("XMax", wavelengthMinMax.get<1>()); - cropWorkspaceAlg->execute(); - detectorWS = cropWorkspaceAlg->getProperty("OutputWorkspace"); - - auto rebinWorkspaceAlg = this->createChildAlgorithm("Rebin"); - rebinWorkspaceAlg->initialize(); - std::vector<double> params = boost::assign::list_of(wavelengthStep); - rebinWorkspaceAlg->setProperty("Params", params); - rebinWorkspaceAlg->setProperty("InputWorkspace", detectorWS); - rebinWorkspaceAlg->execute(); - detectorWS = rebinWorkspaceAlg->getProperty("OutputWorkspace"); - - return detectorWS; - } - - /** - * Convert From a TOF workspace into a detector and monitor workspace both in Lambda. - * @param toConvert: TOF workspace to convert - * @param detectorIndexRange : Detector index ranges - * @param monitorIndex : Monitor index - * @param wavelengthMinMax : Wavelength min max for detector workspace - * @param backgroundMinMax : Wavelength min max for flat background correction of monitor workspace - * @param wavelengthStep : Wavlength step size for rebinning. - * @return Tuple of detector and monitor workspaces - */ - ReflectometryReductionOne::DetectorMonitorWorkspacePair ReflectometryReductionOne::toLam(MatrixWorkspace_sptr toConvert, - const WorkspaceIndexList& detectorIndexRange, const int monitorIndex, - const MinMax& wavelengthMinMax, const MinMax& backgroundMinMax, const double& wavelengthStep) - { - // Detector Workspace Processing - MatrixWorkspace_sptr detectorWS = toLamDetector(detectorIndexRange, toConvert, wavelengthMinMax, wavelengthStep); - - // Monitor Workspace Processing - MatrixWorkspace_sptr monitorWS = toLamMonitor(toConvert, monitorIndex, backgroundMinMax); - - // Rebin the Monitor Workspace to match the Detector Workspace. - auto rebinToWorkspaceAlg = this->createChildAlgorithm("RebinToWorkspace"); - rebinToWorkspaceAlg->initialize(); - rebinToWorkspaceAlg->setProperty("WorkspaceToRebin", monitorWS); - rebinToWorkspaceAlg->setProperty("WorkspaceToMatch", detectorWS); - rebinToWorkspaceAlg->execute(); - monitorWS = rebinToWorkspaceAlg->getProperty("OutputWorkspace"); - - return DetectorMonitorWorkspacePair( detectorWS, monitorWS ); - } - - /** - * Perform Transmission Corrections. - * @param IvsLam : Run workspace which is to be normalized by the results of the transmission corrections. - * @param wavelengthInterval : Wavelength interval for the run workspace. - * @param wavelengthMonitorBackgroundInterval : Wavelength interval for the monitor background - * @param wavelengthMonitorIntegrationInterval : Wavelength interval for the monitor integration - * @param i0MonitorIndex : Monitor index for the I0 monitor - * @param firstTransmissionRun : The first transmission run - * @param secondTransmissionRun : The second transmission run (optional) - * @param stitchingStartQ : Stitching start Q (optional but dependent on secondTransmissionRun) - * @param stitchingDeltaQ : Stitching delta Q (optional but dependent on secondTransmissionRun) - * @param stitchingEndQ : Stitching end Q (optional but dependent on secondTransmissionRun) - * @param stitchingStartOverlapQ : Stitching start Q overlap (optional but dependent on secondTransmissionRun) - * @param stitchingEndOverlapQ : Stitching end Q overlap (optional but dependent on secondTransmissionRun) - * @param wavelengthStep : Step in angstroms for rebinning for workspaces converted into wavelength. - * @return Normalized run workspace by the transmission workspace, which have themselves been converted to Lam, normalized by monitors and possibly stitched together. - */ - MatrixWorkspace_sptr ReflectometryReductionOne::transmissonCorrection(MatrixWorkspace_sptr IvsLam, - const MinMax& wavelengthInterval, - const MinMax& wavelengthMonitorBackgroundInterval, - const MinMax& wavelengthMonitorIntegrationInterval, - const int& i0MonitorIndex, - MatrixWorkspace_sptr firstTransmissionRun, - OptionalMatrixWorkspace_sptr secondTransmissionRun, - const OptionalDouble& stitchingStartQ, - const OptionalDouble& stitchingDeltaQ, - const OptionalDouble& stitchingEndQ, - const OptionalDouble& stitchingStartOverlapQ, - const OptionalDouble& stitchingEndOverlapQ, - const double& wavelengthStep - ) - { - g_log.debug("Extracting first transmission run workspace indexes from spectra"); - const WorkspaceIndexList detectorIndexes = createWorkspaceIndexListFromDetectorWorkspace(IvsLam, firstTransmissionRun); - auto trans1InLam = toLam(firstTransmissionRun, detectorIndexes, i0MonitorIndex, wavelengthInterval, wavelengthMonitorBackgroundInterval, wavelengthStep); - MatrixWorkspace_sptr trans1Detector = trans1InLam.get<0>(); - MatrixWorkspace_sptr trans1Monitor = trans1InLam.get<1>(); - - // Monitor integration ... can this happen inside the toLam routine? - auto integrationAlg = this->createChildAlgorithm("Integration"); - integrationAlg->initialize(); - integrationAlg->setProperty("InputWorkspace", trans1Monitor); - integrationAlg->setProperty("RangeLower", wavelengthMonitorIntegrationInterval.get<0>()); - integrationAlg->setProperty("RangeUpper", wavelengthMonitorIntegrationInterval.get<1>()); - integrationAlg->execute(); - trans1Monitor = integrationAlg->getProperty("OutputWorkspace"); - - MatrixWorkspace_sptr denominator = trans1Detector / trans1Monitor; - - if (secondTransmissionRun.is_initialized()) - { - auto transRun2 = secondTransmissionRun.get(); - g_log.debug("Extracting second transmission run workspace indexes from spectra"); - const WorkspaceIndexList detectorIndexes = createWorkspaceIndexListFromDetectorWorkspace(IvsLam, transRun2); - - auto trans2InLam = toLam(transRun2, detectorIndexes, i0MonitorIndex, wavelengthInterval, - wavelengthMonitorBackgroundInterval, wavelengthStep); - - // Unpack the conversion results. - MatrixWorkspace_sptr trans2Detector = trans2InLam.get<0>(); - MatrixWorkspace_sptr trans2Monitor = trans2InLam.get<1>(); - - // Monitor integration ... can this happen inside the toLam routine? - auto integrationAlg = this->createChildAlgorithm("Integration"); - integrationAlg->initialize(); - integrationAlg->setProperty("InputWorkspace", trans2Monitor); - integrationAlg->setProperty("RangeLower", wavelengthMonitorIntegrationInterval.get<0>()); - integrationAlg->setProperty("RangeUpper", wavelengthMonitorIntegrationInterval.get<1>()); - integrationAlg->execute(); - trans2Monitor = integrationAlg->getProperty("OutputWorkspace"); - - MatrixWorkspace_sptr normalizedTrans2 = trans2Detector / trans2Monitor; - - // Stitch the results. - auto stitch1DAlg = this->createChildAlgorithm("Stitch1D"); - stitch1DAlg->initialize(); - AnalysisDataService::Instance().addOrReplace("denominator", denominator); - AnalysisDataService::Instance().addOrReplace("normalizedTrans2", normalizedTrans2); - stitch1DAlg->setProperty("LHSWorkspace", denominator); - stitch1DAlg->setProperty("RHSWorkspace", normalizedTrans2); - stitch1DAlg->setProperty("StartOverlap", stitchingStartOverlapQ.get() ); - stitch1DAlg->setProperty("EndOverlap", stitchingEndOverlapQ.get() ); - const std::vector<double> params = boost::assign::list_of(stitchingStartQ.get())(stitchingDeltaQ.get())(stitchingEndQ.get()).convert_to_container<std::vector< double > >(); - stitch1DAlg->setProperty("Params", params); - stitch1DAlg->execute(); - denominator = stitch1DAlg->getProperty("OutputWorkspace"); - AnalysisDataService::Instance().remove("denominator"); - AnalysisDataService::Instance().remove("normalizedTrans2"); - } - - auto rebinToWorkspaceAlg = this->createChildAlgorithm("RebinToWorkspace"); - rebinToWorkspaceAlg->initialize(); - rebinToWorkspaceAlg->setProperty("WorkspaceToMatch", IvsLam); - rebinToWorkspaceAlg->setProperty("WorkspaceToRebin", denominator); - rebinToWorkspaceAlg->execute(); - denominator = rebinToWorkspaceAlg->getProperty("OutputWorkspace"); - - MatrixWorkspace_sptr normalizedIvsLam = IvsLam / denominator; - return normalizedIvsLam; - } /** * Correct the position of the detectors based on the input theta value. @@ -883,13 +395,13 @@ namespace Mantid OptionalMatrixWorkspace_sptr firstTransmissionRun; OptionalMatrixWorkspace_sptr secondTransmissionRun; - OptionalDouble stitchingStartQ; - OptionalDouble stitchingDeltaQ; - OptionalDouble stitchingEndQ; - OptionalDouble stitchingStartOverlapQ; - OptionalDouble stitchingEndOverlapQ; + OptionalDouble stitchingStart; + OptionalDouble stitchingDelta; + OptionalDouble stitchingEnd; + OptionalDouble stitchingStartOverlap; + OptionalDouble stitchingEndOverlap; - getTransmissionRunInfo(firstTransmissionRun, secondTransmissionRun, stitchingStartQ, stitchingDeltaQ, stitchingEndQ, stitchingStartOverlapQ, stitchingEndOverlapQ); + getTransmissionRunInfo(firstTransmissionRun, secondTransmissionRun, stitchingStart, stitchingDelta, stitchingEnd, stitchingStartOverlap, stitchingEndOverlap); OptionalDouble theta; if (!isPropertyDefault("ThetaIn")) @@ -945,7 +457,7 @@ namespace Mantid // Perform transmission correction. IvsLam = this->transmissonCorrection(IvsLam, wavelengthInterval, monitorBackgroundWavelengthInterval, monitorIntegrationWavelengthInterval, - i0MonitorIndex, firstTransmissionRun.get(), secondTransmissionRun, stitchingStartQ, stitchingDeltaQ, stitchingEndQ, stitchingStartOverlapQ, stitchingEndOverlapQ, wavelengthStep); + i0MonitorIndex, firstTransmissionRun.get(), secondTransmissionRun, stitchingStart, stitchingDelta, stitchingEnd, stitchingStartOverlap, stitchingEndOverlap, wavelengthStep); } else @@ -980,5 +492,82 @@ namespace Mantid } + + /** + * Perform Transmission Corrections. + * @param IvsLam : Run workspace which is to be normalized by the results of the transmission corrections. + * @param wavelengthInterval : Wavelength interval for the run workspace. + * @param wavelengthMonitorBackgroundInterval : Wavelength interval for the monitor background + * @param wavelengthMonitorIntegrationInterval : Wavelength interval for the monitor integration + * @param i0MonitorIndex : Monitor index for the I0 monitor + * @param firstTransmissionRun : The first transmission run + * @param secondTransmissionRun : The second transmission run (optional) + * @param stitchingStart : Stitching start in wavelength (optional but dependent on secondTransmissionRun) + * @param stitchingDelta : Stitching delta in wavelength (optional but dependent on secondTransmissionRun) + * @param stitchingEnd : Stitching end in wavelength (optional but dependent on secondTransmissionRun) + * @param stitchingStartOverlap : Stitching start wavelength overlap (optional but dependent on secondTransmissionRun) + * @param stitchingEndOverlap : Stitching end wavelength overlap (optional but dependent on secondTransmissionRun) + * @param wavelengthStep : Step in angstroms for rebinning for workspaces converted into wavelength. + * @return Normalized run workspace by the transmission workspace, which have themselves been converted to Lam, normalized by monitors and possibly stitched together. + */ + MatrixWorkspace_sptr ReflectometryReductionOne::transmissonCorrection(MatrixWorkspace_sptr IvsLam, + const MinMax& wavelengthInterval, const MinMax& wavelengthMonitorBackgroundInterval, + const MinMax& wavelengthMonitorIntegrationInterval, const int& i0MonitorIndex, + MatrixWorkspace_sptr firstTransmissionRun, OptionalMatrixWorkspace_sptr secondTransmissionRun, + const OptionalDouble& stitchingStart, const OptionalDouble& stitchingDelta, + const OptionalDouble& stitchingEnd, const OptionalDouble& stitchingStartOverlap, + const OptionalDouble& stitchingEndOverlap, const double& wavelengthStep) + { + g_log.debug("Extracting first transmission run workspace indexes from spectra"); + const WorkspaceIndexList detectorIndexes = createWorkspaceIndexListFromDetectorWorkspace(IvsLam, + firstTransmissionRun); + + // TODO if firstInputWorkspace is in wavelength, do not create the transmission workspace, just do the division. + + MatrixWorkspace_sptr denominator = firstTransmissionRun; + Unit_const_sptr xUnit = firstTransmissionRun->getAxis(0)->unit(); + if (xUnit->unitID() == tofUnitId) + { + // Make the transmission run. + auto alg = this->createChildAlgorithm("CreateTransmissionWorkspace"); + alg->initialize(); + alg->setProperty("FirstTransmissionRun", firstTransmissionRun); + if (secondTransmissionRun.is_initialized()) + { + alg->setProperty("SecondTransmissionRun", secondTransmissionRun.get()); + const std::vector<double> params = boost::assign::list_of(stitchingStart.get())( + stitchingDelta.get())(stitchingEnd.get()).convert_to_container<std::vector<double> >(); + alg->setProperty("Params", params); + alg->setProperty("StartOverlap", stitchingStartOverlap.get()); + alg->setProperty("EndOverlap", stitchingEndOverlap.get()); + } + alg->setProperty("WorkspaceIndexList", detectorIndexes); + alg->setProperty("I0MonitorIndex", i0MonitorIndex); + alg->setProperty("WavelengthMin", wavelengthInterval.get<0>()); + alg->setProperty("WavelengthMax", wavelengthInterval.get<1>()); + alg->setProperty("WavelengthStep", wavelengthStep); + alg->setProperty("MonitorBackgroundWavelengthMin", wavelengthMonitorBackgroundInterval.get<0>()); + alg->setProperty("MonitorBackgroundWavelengthMax", wavelengthMonitorBackgroundInterval.get<1>()); + alg->setProperty("MonitorIntegrationWavelengthMin", + wavelengthMonitorIntegrationInterval.get<0>()); + alg->setProperty("MonitorIntegrationWavelengthMax", + wavelengthMonitorIntegrationInterval.get<1>()); + alg->execute(); + denominator = alg->getProperty("OutputWorkspace"); + } + + // Rebin the transmission run to be the same as the input. + auto rebinToWorkspaceAlg = this->createChildAlgorithm("RebinToWorkspace"); + rebinToWorkspaceAlg->initialize(); + rebinToWorkspaceAlg->setProperty("WorkspaceToMatch", IvsLam); + rebinToWorkspaceAlg->setProperty("WorkspaceToRebin", denominator); + rebinToWorkspaceAlg->execute(); + denominator = rebinToWorkspaceAlg->getProperty("OutputWorkspace"); + + // Do normalization. + MatrixWorkspace_sptr normalizedIvsLam = IvsLam / denominator; + return normalizedIvsLam; + } + } // namespace Algorithms } // namespace Mantid diff --git a/Code/Mantid/Framework/Algorithms/src/ReflectometryWorkflowBase.cpp b/Code/Mantid/Framework/Algorithms/src/ReflectometryWorkflowBase.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9ef98e83c82a1d21322c919edcd5bccedcf7e1a4 --- /dev/null +++ b/Code/Mantid/Framework/Algorithms/src/ReflectometryWorkflowBase.cpp @@ -0,0 +1,498 @@ +#include "MantidAPI/WorkspaceValidators.h" +#include "MantidKernel/MandatoryValidator.h" +#include "MantidKernel/ArrayProperty.h" +#include "MantidKernel/RebinParamsValidator.h" +#include "MantidKernel/BoundedValidator.h" +#include "MantidAlgorithms/ReflectometryWorkflowBase.h" + +#include <boost/assign/list_of.hpp> + +using namespace Mantid::API; +using namespace Mantid::Kernel; + +namespace Mantid +{ + namespace Algorithms + { + namespace + { + + /** + * Helper method used with the stl to determine whether values are negative + * @param value : Value to check + * @return : True if negative. + */ + bool checkNotPositive(const int value) + { + return value < 0; + } + } + + //---------------------------------------------------------------------------------------------- + /** Constructor + */ + ReflectometryWorkflowBase::ReflectometryWorkflowBase() + { + } + + //---------------------------------------------------------------------------------------------- + /** Destructor + */ + ReflectometryWorkflowBase::~ReflectometryWorkflowBase() + { + } + + /** + * Init index properties. + */ + void ReflectometryWorkflowBase::initIndexInputs() + { + + boost::shared_ptr<CompositeValidator> mandatoryWorkspaceIndex = boost::make_shared< + CompositeValidator>(); + mandatoryWorkspaceIndex->add(boost::make_shared<MandatoryValidator<int> >()); + auto boundedIndex = boost::make_shared<BoundedValidator<int> >(); + boundedIndex->setLower(0); + mandatoryWorkspaceIndex->add(boundedIndex); + + declareProperty( + new PropertyWithValue<int>("I0MonitorIndex", Mantid::EMPTY_INT(), mandatoryWorkspaceIndex), + "I0 monitor index"); + + declareProperty(new ArrayProperty<int>("WorkspaceIndexList"), + "Indices of the spectra in pairs (lower, upper) that mark the ranges that correspond to detectors of interest."); + + } + + /** + * Init common wavelength inputs. + */ + void ReflectometryWorkflowBase::initWavelengthInputs() + { + declareProperty( + new PropertyWithValue<double>("WavelengthMin", Mantid::EMPTY_DBL(), + boost::make_shared<MandatoryValidator<double> >(), Direction::Input), + "Wavelength minimum in angstroms"); + + declareProperty( + new PropertyWithValue<double>("WavelengthMax", Mantid::EMPTY_DBL(), + boost::make_shared<MandatoryValidator<double> >(), Direction::Input), + "Wavelength maximum in angstroms"); + + declareProperty( + new PropertyWithValue<double>("WavelengthStep", 0.05, + boost::make_shared<MandatoryValidator<double> >(), Direction::Input), + "Wavelength rebinning step in angstroms. Defaults to 0.05. Used for rebinning intermediate workspaces converted into wavelength."); + + declareProperty( + new PropertyWithValue<double>("MonitorBackgroundWavelengthMin", Mantid::EMPTY_DBL(), + boost::make_shared<MandatoryValidator<double> >(), Direction::Input), + "Wavelength minimum for monitor background in angstroms."); + + declareProperty( + new PropertyWithValue<double>("MonitorBackgroundWavelengthMax", Mantid::EMPTY_DBL(), + boost::make_shared<MandatoryValidator<double> >(), Direction::Input), + "Wavelength maximum for monitor background in angstroms."); + + declareProperty( + new PropertyWithValue<double>("MonitorIntegrationWavelengthMin", Mantid::EMPTY_DBL(), + boost::make_shared<MandatoryValidator<double> >(), Direction::Input), + "Wavelength minimum for integration in angstroms."); + declareProperty( + new PropertyWithValue<double>("MonitorIntegrationWavelengthMax", Mantid::EMPTY_DBL(), + boost::make_shared<MandatoryValidator<double> >(), Direction::Input), + "Wavelength maximum for integration in angstroms."); + } + + /** + * Init stitching inputs + */ + void ReflectometryWorkflowBase::initStitchingInputs() + { + declareProperty( + new ArrayProperty<double>("Params", boost::make_shared<RebinParamsValidator>(true)), + "A comma separated list of first bin boundary, width, last bin boundary. " + "These parameters are used for stitching together transmission runs. " + "Values are in wavelength (angstroms). This input is only needed if a SecondTransmission run is provided."); + + declareProperty( + new PropertyWithValue<double>("StartOverlap", Mantid::EMPTY_DBL(), Direction::Input), + "Start wavelength for stitching transmission runs together"); + + declareProperty( + new PropertyWithValue<double>("EndOverlap", Mantid::EMPTY_DBL(), Direction::Input), + "End wavelength (angstroms) for stitching transmission runs together"); + + } + + /** + * Determine if the property value is the same as the default value. + * This can be used to determine if the property has not been set. + * @param propertyName : Name of property to query + * @return: True only if the property has it's default value. + */ + bool ReflectometryWorkflowBase::isPropertyDefault(const std::string& propertyName) const + { + Property* property = this->getProperty(propertyName); + return property->isDefault(); + } + + /** + * Get the workspace index list + * @return Workspace index list. + */ + ReflectometryWorkflowBase::WorkspaceIndexList ReflectometryWorkflowBase::getWorkspaceIndexList() const + { + WorkspaceIndexList indexList = getProperty("WorkspaceIndexList"); + if (indexList.size() % 2 != 0 || indexList.size() == 0) + { + throw std::invalid_argument( + "WorkspaceIndex list must be composed of pairs of min index, max index."); + } + + if (std::find_if(indexList.begin(), indexList.end(), checkNotPositive) != indexList.end()) + { + throw std::invalid_argument("WorkspaceIndexList contains negative indexes"); + } + + for (size_t i = 0; (i + 1) < indexList.size(); i += 2) + { + if (indexList[i] > indexList[i + 1]) + throw std::invalid_argument("WorkspaceIndexList pairs must be in min, max order"); + } + return indexList; + } + + /** + * Fetch min, max inputs as a vector (int) if they are non-default and set them to the optionalUpperLower object. + * Performs checks to verify that invalid indexes have not been passed in. + * @param propertyName : Property name to fetch + * @param isPointDetector : Flag indicates that the execution is in point detector mode. + * @param optionalUpperLower : Object to set min and max on. + */ + void ReflectometryWorkflowBase::fetchOptionalLowerUpperPropertyValue(const std::string& propertyName, + bool isPointDetector, OptionalWorkspaceIndexes& optionalUpperLower) const + { + if (!isPropertyDefault(propertyName)) + { + // Validation of property inputs. + if (isPointDetector) + { + throw std::invalid_argument( + "Cannot have a region of interest property in point detector mode."); + } + std::vector<int> temp = this->getProperty(propertyName); + if (temp.size() != 2) + { + const std::string message = propertyName + " requires a lower and upper boundary"; + throw std::invalid_argument(message); + } + if (temp[0] > temp[1]) + { + throw std::invalid_argument("Min must be <= Max index"); + } + if (std::find_if(temp.begin(), temp.end(), checkNotPositive) != temp.end()) + { + const std::string message = propertyName + " contains negative indexes"; + throw std::invalid_argument(message); + } + // Assignment + optionalUpperLower = temp; + } + } + + /** + * Get min max pairs as a tuple. + * @param minProperty : Property name for the min property + * @param maxProperty : Property name for the max property + * @return A tuple consisting of min, max + */ + ReflectometryWorkflowBase::MinMax ReflectometryWorkflowBase::getMinMax( + const std::string& minProperty, const std::string& maxProperty) const + { + const double min = getProperty(minProperty); + const double max = getProperty(maxProperty); + if (min > max) + { + throw std::invalid_argument("Cannot have any WavelengthMin > WavelengthMax"); + } + return MinMax(min, max); + } + + /** + * Check the first transmission run units. + * + * @return True only if the units of the first transmission run are in wavelength. + * + */ + bool ReflectometryWorkflowBase::validateFirstTransmissionInputs() const + { + WorkspaceUnitValidator tofValidator("TOF"); + WorkspaceUnitValidator wavelengthValidator("Wavelength"); + MatrixWorkspace_sptr firstTransmissionRun = this->getProperty("FirstTransmissionRun"); + if (!tofValidator.isValid(firstTransmissionRun).empty() + && !wavelengthValidator.isValid(firstTransmissionRun).empty()) + { + throw std::invalid_argument("FirstTransmissionRun must be either in TOF or Wavelength"); + } + + const bool bInWavelength = (!wavelengthValidator.isValid(firstTransmissionRun).empty()); + return bInWavelength; + } + + /** + * Validate the transmission workspace inputs when a second transmission run is provided. + * Throws if any of the property values do not make sense. + * @param firstTransmissionInWavelength: Indicates that the first transmission run is in units of wavlength. + */ + void ReflectometryWorkflowBase::validateSecondTransmissionInputs(const bool firstTransmissionInWavelength) const + { + // Verify that all the required inputs for the second transmission run are now given. + if (isPropertyDefault("FirstTransmissionRun")) + { + throw std::invalid_argument( + "A SecondTransmissionRun is only valid if a FirstTransmissionRun is provided."); + if (firstTransmissionInWavelength) + { + this->g_log.warning( + "The first transmission run is in wavelength so is assumed to be correctly stitched in wavelength. " + "The second transmission run and associated inputs will be ignored." + "Run CreateTransmissionWorkspace to create a transmission workspace from TOF runs."); + return; + } + } + if (isPropertyDefault("Params")) + { + throw std::invalid_argument( + "If a SecondTransmissionRun has been given, then stitching Params for the transmission runs are also required."); + } + if (isPropertyDefault("StartOverlap")) + { + throw std::invalid_argument( + "If a SecondTransmissionRun has been given, then a stitching StartOverlap for the transmission runs is also required."); + } + if (isPropertyDefault("EndOverlap")) + { + throw std::invalid_argument( + "If a SecondTransmissionRun has been given, then a stitching EndOverlap for the transmission runs is also required."); + } + const double startOverlap = this->getProperty("StartOverlap"); + const double endOverlap = this->getProperty("EndOverlap"); + if (startOverlap >= endOverlap) + { + throw std::invalid_argument("EndOverlap must be > StartOverlap"); + } + + if( !isPropertyDefault("SecondTransmissionRun") ) + { + MatrixWorkspace_sptr trans1 = this->getProperty("FirstTransmissionRun"); + MatrixWorkspace_sptr trans2 = this->getProperty("SecondTransmissionRun"); + + auto firstMap = trans1->getSpectrumToWorkspaceIndexMap(); + auto secondMap = trans2->getSpectrumToWorkspaceIndexMap(); + if(firstMap != secondMap) + { + throw std::invalid_argument("Spectrum maps differ between the transmission runs. They must be the same."); + } + } + + } + + /** + * Get the transmission run information. + * + * Transmission runs are optional, but you cannot have the second without the first. Also, stitching + * parameters are required if the second is present. This getter fetches and assigns to the optional reference arguments + * + * @param firstTransmissionRun + * @param secondTransmissionRun + * @param stitchingStart + * @param stitchingDelta + * @param stitchingEnd + */ + void ReflectometryWorkflowBase::getTransmissionRunInfo( + OptionalMatrixWorkspace_sptr& firstTransmissionRun, + OptionalMatrixWorkspace_sptr& secondTransmissionRun, OptionalDouble& stitchingStart, + OptionalDouble& stitchingDelta, OptionalDouble& stitchingEnd, + OptionalDouble& stitchingStartOverlap, OptionalDouble& stitchingEndOverlap) const + { + bool bFirstTransInWavelength = false; + if (!isPropertyDefault("FirstTransmissionRun")) + { + bFirstTransInWavelength = validateFirstTransmissionInputs(); + + MatrixWorkspace_sptr temp = this->getProperty("FirstTransmissionRun"); + firstTransmissionRun = temp; + } + + if (!isPropertyDefault("SecondTransmissionRun")) + { + // Check that the property values provided make sense together. + validateSecondTransmissionInputs(bFirstTransInWavelength); + + // Set the values. + { + MatrixWorkspace_sptr temp = this->getProperty("SecondTransmissionRun"); + secondTransmissionRun = temp; + } + { + std::vector<double> params = getProperty("Params"); + stitchingStart = params[0]; + stitchingDelta = params[1]; + stitchingEnd = params[2]; + } + { + double temp = this->getProperty("StartOverlap"); + stitchingStartOverlap = temp; + temp = this->getProperty("EndOverlap"); + stitchingEndOverlap = temp; + } + } + + } + + /** + * Convert the TOF workspace into a monitor workspace. Crops to the monitorIndex and applying flat background correction as part of the process. + * @param toConvert : TOF wavlength to convert. + * @param monitorIndex : Monitor index to crop to + * @param backgroundMinMax : Min and Max Lambda range for Flat background correction. + * @return The cropped and corrected monitor workspace. + */ + MatrixWorkspace_sptr ReflectometryWorkflowBase::toLamMonitor(const MatrixWorkspace_sptr& toConvert, + const int monitorIndex, const MinMax& backgroundMinMax) + { + // Convert Units. + auto convertUnitsAlg = this->createChildAlgorithm("ConvertUnits"); + convertUnitsAlg->initialize(); + convertUnitsAlg->setProperty("InputWorkspace", toConvert); + convertUnitsAlg->setProperty("Target", "Wavelength"); + convertUnitsAlg->setProperty("AlignBins", true); + convertUnitsAlg->execute(); + + // Crop the to the monitor index. + MatrixWorkspace_sptr monitorWS = convertUnitsAlg->getProperty("OutputWorkspace"); + auto cropWorkspaceAlg = this->createChildAlgorithm("CropWorkspace"); + cropWorkspaceAlg->initialize(); + cropWorkspaceAlg->setProperty("InputWorkspace", monitorWS); + cropWorkspaceAlg->setProperty("StartWorkspaceIndex", monitorIndex); + cropWorkspaceAlg->setProperty("EndWorkspaceIndex", monitorIndex); + cropWorkspaceAlg->execute(); + monitorWS = cropWorkspaceAlg->getProperty("OutputWorkspace"); + + // Flat background correction + auto correctMonitorsAlg = this->createChildAlgorithm("CalculateFlatBackground"); + correctMonitorsAlg->initialize(); + correctMonitorsAlg->setProperty("InputWorkspace", monitorWS); + correctMonitorsAlg->setProperty("WorkspaceIndexList", + boost::assign::list_of(0).convert_to_container<std::vector<int> >()); + correctMonitorsAlg->setProperty("StartX", backgroundMinMax.get<0>()); + correctMonitorsAlg->setProperty("EndX", backgroundMinMax.get<1>()); + correctMonitorsAlg->execute(); + monitorWS = correctMonitorsAlg->getProperty("OutputWorkspace"); + + return monitorWS; + } + + /** + * Convert to a detector workspace in lambda. + * @param detectorIndexRange : Workspace index ranges to keep + * @param toConvert : TOF wavelength to convert. + * @param wavelengthMinMax : Wavelength minmax to keep. Crop out the rest. + * @param wavelengthStep : Wavelength step for rebinning + * @return Detector workspace in wavelength + */ + MatrixWorkspace_sptr ReflectometryWorkflowBase::toLamDetector( + const WorkspaceIndexList& detectorIndexRange, const MatrixWorkspace_sptr& toConvert, + const MinMax& wavelengthMinMax, const double& wavelengthStep) + { + // Detector Workspace Processing + MatrixWorkspace_sptr detectorWS; + + // Loop over pairs of detector index ranges. Peform the cropping and then conjoin the results into a single workspace. + for (size_t i = 0; i < detectorIndexRange.size(); i += 2) + { + auto cropWorkspaceAlg = this->createChildAlgorithm("CropWorkspace"); + cropWorkspaceAlg->initialize(); + cropWorkspaceAlg->setProperty("InputWorkspace", toConvert); + cropWorkspaceAlg->setProperty("StartWorkspaceIndex", detectorIndexRange[i]); + cropWorkspaceAlg->setProperty("EndWorkspaceIndex", detectorIndexRange[i + 1]); + cropWorkspaceAlg->execute(); + MatrixWorkspace_sptr subRange = cropWorkspaceAlg->getProperty("OutputWorkspace"); + if (i == 0) + { + detectorWS = subRange; + } + else + { + auto conjoinWorkspaceAlg = this->createChildAlgorithm("ConjoinWorkspaces"); + conjoinWorkspaceAlg->initialize(); + conjoinWorkspaceAlg->setProperty("InputWorkspace1", detectorWS); + conjoinWorkspaceAlg->setProperty("InputWorkspace2", subRange); + conjoinWorkspaceAlg->execute(); + detectorWS = conjoinWorkspaceAlg->getProperty("InputWorkspace1"); + } + } + // Now convert units. Do this after the conjoining step otherwise the x bins will not match up. + auto convertUnitsAlg = this->createChildAlgorithm("ConvertUnits"); + convertUnitsAlg->initialize(); + convertUnitsAlg->setProperty("InputWorkspace", detectorWS); + convertUnitsAlg->setProperty("Target", "Wavelength"); + convertUnitsAlg->setProperty("AlignBins", true); + convertUnitsAlg->execute(); + detectorWS = convertUnitsAlg->getProperty("OutputWorkspace"); + + // Crop out the lambda x-ranges now that the workspace is in wavelength. + auto cropWorkspaceAlg = this->createChildAlgorithm("CropWorkspace"); + cropWorkspaceAlg->initialize(); + cropWorkspaceAlg->setProperty("InputWorkspace", detectorWS); + cropWorkspaceAlg->setProperty("XMin", wavelengthMinMax.get<0>()); + cropWorkspaceAlg->setProperty("XMax", wavelengthMinMax.get<1>()); + cropWorkspaceAlg->execute(); + detectorWS = cropWorkspaceAlg->getProperty("OutputWorkspace"); + + auto rebinWorkspaceAlg = this->createChildAlgorithm("Rebin"); + rebinWorkspaceAlg->initialize(); + std::vector<double> params = boost::assign::list_of(wavelengthStep); + rebinWorkspaceAlg->setProperty("Params", params); + rebinWorkspaceAlg->setProperty("InputWorkspace", detectorWS); + rebinWorkspaceAlg->execute(); + detectorWS = rebinWorkspaceAlg->getProperty("OutputWorkspace"); + + return detectorWS; + } + + /** + * Convert From a TOF workspace into a detector and monitor workspace both in Lambda. + * @param toConvert: TOF workspace to convert + * @param detectorIndexRange : Detector index ranges + * @param monitorIndex : Monitor index + * @param wavelengthMinMax : Wavelength min max for detector workspace + * @param backgroundMinMax : Wavelength min max for flat background correction of monitor workspace + * @param wavelengthStep : Wavlength step size for rebinning. + * @return Tuple of detector and monitor workspaces + */ + ReflectometryWorkflowBase::DetectorMonitorWorkspacePair ReflectometryWorkflowBase::toLam( + MatrixWorkspace_sptr toConvert, const WorkspaceIndexList& detectorIndexRange, + const int monitorIndex, const MinMax& wavelengthMinMax, const MinMax& backgroundMinMax, + const double& wavelengthStep) + { + // Detector Workspace Processing + MatrixWorkspace_sptr detectorWS = toLamDetector(detectorIndexRange, toConvert, wavelengthMinMax, + wavelengthStep); + + // Monitor Workspace Processing + MatrixWorkspace_sptr monitorWS = toLamMonitor(toConvert, monitorIndex, backgroundMinMax); + + // Rebin the Monitor Workspace to match the Detector Workspace. + auto rebinToWorkspaceAlg = this->createChildAlgorithm("RebinToWorkspace"); + rebinToWorkspaceAlg->initialize(); + rebinToWorkspaceAlg->setProperty("WorkspaceToRebin", monitorWS); + rebinToWorkspaceAlg->setProperty("WorkspaceToMatch", detectorWS); + rebinToWorkspaceAlg->execute(); + monitorWS = rebinToWorkspaceAlg->getProperty("OutputWorkspace"); + + return DetectorMonitorWorkspacePair(detectorWS, monitorWS); + } + + } // namespace Algorithms +} // namespace Mantid diff --git a/Code/Mantid/Framework/Algorithms/test/ReflectometryReductionOneTest.h b/Code/Mantid/Framework/Algorithms/test/ReflectometryReductionOneTest.h index b1b7456b1c8b3206f8b5beec5f172df344d7bf9a..5d526b87c77fdcb848e231185b3f38f330e174e1 100644 --- a/Code/Mantid/Framework/Algorithms/test/ReflectometryReductionOneTest.h +++ b/Code/Mantid/Framework/Algorithms/test/ReflectometryReductionOneTest.h @@ -9,7 +9,7 @@ using namespace Mantid; using namespace Mantid::Kernel; using namespace Mantid::API; -using Mantid::Algorithms::ReflectometryReductionOne; +using namespace Mantid::Algorithms; class ReflectometryReductionOneTest: public CxxTest::TestSuite { @@ -49,7 +49,7 @@ public: ReflectometryReductionOne alg; // Run the conversion. - ReflectometryReductionOne::DetectorMonitorWorkspacePair inLam = alg.toLam(toConvert, + ReflectometryWorkflowBase::DetectorMonitorWorkspacePair inLam = alg.toLam(toConvert, detectorIndexRange, monitorIndex, boost::tuple<double, double>(wavelengthMin, wavelengthMax), boost::tuple<double, double>(backgroundWavelengthMin, backgroundWavelengthMax), wavelengthStep); diff --git a/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt b/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt index c68b6d8ba1f853d05c8a4aa7f8ed7eac835833d7..7bad2236ccb57350a81a654937c665271a99216c 100644 --- a/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt +++ b/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt @@ -7,6 +7,7 @@ set ( TEST_PY_FILES ConjoinSpectraTest.py CreateLeBailFitInputTest.py CreateWorkspaceTest.py + CreateTransmissionWorkspaceTest.py DakotaChiSquaredTest.py FilterLogByTimeTest.py FindReflectometryLinesTest.py diff --git a/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/CreateTransmissionWorkspaceTest.py b/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/CreateTransmissionWorkspaceTest.py new file mode 100644 index 0000000000000000000000000000000000000000..7ceca8566a6e08baa2ddc660ce19fd945603c7c8 --- /dev/null +++ b/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/CreateTransmissionWorkspaceTest.py @@ -0,0 +1,198 @@ +import unittest +import mantid.api +from mantid.simpleapi import CreateTransmissionWorkspace, CreateWorkspace, DeleteWorkspace, Load +from testhelpers.algorithm_decorator import make_decorator + +import inspect +import re + +class CreateTransmissionWorkspaceTest(unittest.TestCase): + + def setUp(self): + tof = CreateWorkspace(UnitX="TOF", DataX=[0,0,0,0], DataY=[0,0,0], NSpec=1) + not_tof = CreateWorkspace(UnitX="1/q", DataX=[0,0,0,0], DataY=[0,0,0], NSpec=1) + self.__tof = tof + self.__not_tof = not_tof + + def tearDown(self): + DeleteWorkspace(self.__tof) + DeleteWorkspace(self.__not_tof) + + def construct_standard_algorithm(self): + alg = make_decorator(CreateTransmissionWorkspace) + alg.set_FirstTransmissionRun(self.__tof) + alg.set_WavelengthMin(0.0) + alg.set_WavelengthMax(1.0) + alg.set_I0MonitorIndex(0) + alg.set_WorkspaceIndexList([0, 1]) + alg.set_MonitorBackgroundWavelengthMin(0.0) + alg.set_MonitorBackgroundWavelengthMax(1.0) + alg.set_MonitorIntegrationWavelengthMin(0.0) + alg.set_MonitorIntegrationWavelengthMax(1.0) + return alg + + def test_input_workspace_not_tof_throws(self): + alg = self.construct_standard_algorithm() + alg.set_FirstTransmissionRun(self.__not_tof) + self.assertRaises(ValueError, alg.execute) + + def test_second_transmission_workspace_not_tof_throws(self): + alg = self.construct_standard_algorithm() + alg.set_SecondTransmissionRun(self.__not_tof) + self.assertRaises(ValueError, alg.execute) + + def test_provide_second_transmission_run_without_params_throws(self): + alg = self.construct_standard_algorithm() + alg.set_SecondTransmissionRun(self.__tof) + self.assertRaises(ValueError, alg.execute) + + def test_provide_second_transmission_run_without_start_overlap_q_throws(self): + alg = self.construct_standard_algorithm() + alg.set_SecondTransmissionRun(self.__tof) + alg.set_Params([0, 0.1, 1]) + alg.set_EndOverlap( 0.4 ) + self.assertRaises(ValueError, alg.execute) + + def test_provide_end_transmission_run_without_end_overlap_q_throws(self): + alg = self.construct_standard_algorithm() + alg.set_SecondTransmissionRun(self.__tof) + alg.set_Params([0, 0.1, 1]) + alg.set_StartOverlap( 0.4 ) + self.assertRaises(ValueError, alg.execute) + + def test_end_overlap_q_must_be_greater_than_start_overlap_q_or_throw(self): + alg = self.construct_standard_algorithm() + alg.set_SecondTransmissionRun(self.__tof) + alg.set_Params([0, 0.1, 1]) + alg.set_StartOverlap( 0.6 ) + alg.set_EndOverlap( 0.4 ) + self.assertRaises(ValueError, alg.execute) + + def test_must_provide_wavelengths(self): + self.assertRaises(RuntimeError, CreateTransmissionWorkspace, FirstTransmissionRun=self.__tof, SecondTransmissionRun=self.__tof, WavelengthMin=1.0) + self.assertRaises(RuntimeError, CreateTransmissionWorkspace, FirstTransmissionRun=self.__tof, SecondTransmissionRun=self.__tof, WavelengthMax=1.0) + + def test_wavelength_min_greater_wavelength_max_throws(self): + alg = self.construct_standard_algorithm() + alg.set_WavelengthMin(1.0) + alg.set_WavelengthMax(0.0) + self.assertRaises(ValueError, alg.execute) + + def test_monitor_background_wavelength_min_greater_monitor_background_wavelength_max_throws(self): + alg = self.construct_standard_algorithm() + alg.set_MonitorBackgroundWavelengthMin(1.0) + alg.set_MonitorBackgroundWavelengthMax(0.0) + self.assertRaises(ValueError, alg.execute) + + def test_monitor_integration_wavelength_min_greater_monitor_integration_wavelength_max_throws(self): + alg = self.construct_standard_algorithm() + alg.set_MonitorIntegrationWavelengthMin(1.0) + alg.set_MonitorIntegrationWavelengthMax(0.0) + self.assertRaises(ValueError, alg.execute) + + def test_monitor_index_positive(self): + alg = self.construct_standard_algorithm() + alg.set_I0MonitorIndex(-1) + self.assertRaises(ValueError, alg.execute) + + def test_workspace_index_list_throw_if_not_pairs(self): + alg = self.construct_standard_algorithm() + alg.set_WorkspaceIndexList([0]) + self.assertRaises(ValueError, alg.execute) + + def test_workspace_index_list_values_not_positive_throws(self): + alg = self.construct_standard_algorithm() + alg.set_WorkspaceIndexList([-1, 0]) # -1 is not acceptable. + self.assertRaises(ValueError, alg.execute) + + def test_workspace_index_list_min_max_pairs_throw_if_min_greater_than_max(self): + alg = self.construct_standard_algorithm() + alg.set_WorkspaceIndexList([1, 0]) # 1 > 0 + self.assertRaises(ValueError, alg.execute) + + def test_spectrum_map_mismatch_throws(self): + alg = self.construct_standard_algorithm() + trans_run1 = Load('INTER00013463.nxs') + trans_run2 = self.__tof + + alg.set_WorkspaceIndexList([3,4]) + alg.set_FirstTransmissionRun(trans_run1) + alg.set_SecondTransmissionRun(trans_run2) + alg.set_Params([0, 0.1, 1]) + alg.set_StartOverlap(1) + alg.set_EndOverlap(2) + self.assertRaises(ValueError, alg.execute) + + DeleteWorkspace(trans_run1) + + def test_execute_one_tranmission(self): + alg = make_decorator(CreateTransmissionWorkspace) + + trans_run1 = Load('INTER00013463.nxs') + + alg.set_WorkspaceIndexList([3,4]) + alg.set_FirstTransmissionRun(trans_run1) + alg.set_I0MonitorIndex(0) + alg.set_WavelengthMin(0.0) + alg.set_WavelengthMax(17.9) + alg.set_WavelengthStep(0.5) + alg.set_MonitorBackgroundWavelengthMin(15.0) + alg.set_MonitorBackgroundWavelengthMax(17.0) + alg.set_MonitorIntegrationWavelengthMin(4.0) + alg.set_MonitorIntegrationWavelengthMax(10.0) + + transmission_ws = alg.execute() + + self.assertTrue(isinstance(transmission_ws, mantid.api.MatrixWorkspace), "Should be a matrix workspace") + self.assertEqual("Wavelength", transmission_ws.getAxis(0).getUnit().unitID()) + + # Because we have one transmission workspaces, binning should come from the WavelengthStep. + x = transmission_ws.readX(0) + actual_binning = x[1] - x[0] + step = alg.get_WavelengthStep() + self.assertAlmostEqual( actual_binning, step, 6) + + DeleteWorkspace(trans_run1) + DeleteWorkspace(transmission_ws) + + def test_execute_two_tranmissions(self): + alg = make_decorator(CreateTransmissionWorkspace) + + trans_run1 = Load('INTER00013463.nxs') + trans_run2 = Load('INTER00013464.nxs') + + alg.set_WorkspaceIndexList([3,4]) + alg.set_FirstTransmissionRun(trans_run1) + alg.set_SecondTransmissionRun(trans_run2) + alg.set_I0MonitorIndex(0) + alg.set_WavelengthMin(0.0) + alg.set_WavelengthMax(17.9) + alg.set_WavelengthStep(0.5) + alg.set_MonitorBackgroundWavelengthMin(15.0) + alg.set_MonitorBackgroundWavelengthMax(17.0) + alg.set_MonitorIntegrationWavelengthMin(4.0) + alg.set_MonitorIntegrationWavelengthMax(10.0) + alg.set_Params([1.5, 0.02, 17]) + alg.set_StartOverlap( 10.0 ) + alg.set_EndOverlap( 12.0 ) + + transmission_ws = alg.execute() + + self.assertTrue(isinstance(transmission_ws, mantid.api.MatrixWorkspace), "Should be a matrix workspace") + self.assertEqual("Wavelength", transmission_ws.getAxis(0).getUnit().unitID()) + + # Because we have two transmission workspaces, binning should come from the Params for stitching. + x = transmission_ws.readX(0) + actual_binning = x[1] - x[0] + params = alg.get_Params() + self.assertAlmostEqual( actual_binning, params[1], 6) + self.assertAlmostEqual( 1.5, params[0], 6) + self.assertAlmostEqual( 17, params[2], 6) + + DeleteWorkspace(trans_run1) + DeleteWorkspace(trans_run2) + DeleteWorkspace(transmission_ws) + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/ReflectometryReductionOneTest.py b/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/ReflectometryReductionOneTest.py index e8da251aae6274fe4fe9e831ce7e041aac96ed19..104c18accbf9d30f7af0aeb2c5361780c0e73205 100644 --- a/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/ReflectometryReductionOneTest.py +++ b/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/ReflectometryReductionOneTest.py @@ -36,7 +36,7 @@ class ReflectometryReductionOneTest(unittest.TestCase): alg.set_InputWorkspace(self.__not_tof) self.assertRaises(ValueError, alg.execute) - def test_check_first_transmission_workspace_not_tof_throws(self): + def test_check_first_transmission_workspace_not_tof_or_wavelength_throws(self): alg = self.construct_standard_algorithm() alg.set_FirstTransmissionRun(self.__not_tof) self.assertRaises(ValueError, alg.execute) @@ -62,7 +62,7 @@ class ReflectometryReductionOneTest(unittest.TestCase): alg.set_FirstTransmissionRun(self.__tof) alg.set_SecondTransmissionRun(self.__tof) alg.set_Params([0, 0.1, 1]) - alg.set_EndOverlapQ( 0.4 ) + alg.set_EndOverlap( 0.4 ) self.assertRaises(ValueError, alg.execute) def test_provide_end_transmission_run_without_end_overlap_q_throws(self): @@ -70,7 +70,7 @@ class ReflectometryReductionOneTest(unittest.TestCase): alg.set_FirstTransmissionRun(self.__tof) alg.set_SecondTransmissionRun(self.__tof) alg.set_Params([0, 0.1, 1]) - alg.set_StartOverlapQ( 0.4 ) + alg.set_StartOverlap( 0.4 ) self.assertRaises(ValueError, alg.execute) def test_end_overlap_q_must_be_greater_than_start_overlap_q_or_throw(self): @@ -78,8 +78,8 @@ class ReflectometryReductionOneTest(unittest.TestCase): alg.set_FirstTransmissionRun(self.__tof) alg.set_SecondTransmissionRun(self.__tof) alg.set_Params([0, 0.1, 1]) - alg.set_StartOverlapQ( 0.6 ) - alg.set_EndOverlapQ( 0.4 ) + alg.set_StartOverlap( 0.6 ) + alg.set_EndOverlap( 0.4 ) self.assertRaises(ValueError, alg.execute) def test_must_provide_wavelengths(self): @@ -205,24 +205,33 @@ class ReflectometryReductionOneTest(unittest.TestCase): alg.set_WorkspaceIndexList([3,4]) alg.set_FirstTransmissionRun(trans_run1) alg.set_SecondTransmissionRun(trans_run2) + alg.set_Params([1.5, 0.02, 17]) - alg.set_StartOverlapQ( 10.0 ) - alg.set_EndOverlapQ( 12.0 ) + alg.set_StartOverlap( 10.0 ) + alg.set_EndOverlap( 12.0 ) alg.set_ThetaIn(0.2) out_ws_q, out_ws_lam, theta = alg.execute() - self.assertTrue(isinstance(out_ws_lam, mantid.api.MatrixWorkspace), "Should be a matrix workspace") - self.assertEqual("Wavelength", out_ws_lam.getAxis(0).getUnit().unitID()) + DeleteWorkspace(real_run) + DeleteWorkspace(trans_run1) + DeleteWorkspace(trans_run2) + + def test_spectrum_map_mismatch_throws(self): + alg = self.construct_standard_algorithm() + real_run = Load('INTER00013460.nxs') + trans_run1 = Load('INTER00013463.nxs') + trans_run2 = self.__tof - self.assertTrue(isinstance(out_ws_q, mantid.api.MatrixWorkspace), "Should be a matrix workspace") - self.assertEqual("MomentumTransfer", out_ws_q.getAxis(0).getUnit().unitID()) + alg.set_InputWorkspace(real_run) + alg.set_WorkspaceIndexList([3,4]) + alg.set_FirstTransmissionRun(trans_run1) + alg.set_SecondTransmissionRun(trans_run2) + self.assertRaises(ValueError, alg.execute) - self.assertEqual(2, out_ws_lam.getNumberHistograms()) DeleteWorkspace(real_run) DeleteWorkspace(trans_run1) - DeleteWorkspace(trans_run2) def test_calculate_theta(self): alg = self.construct_standard_algorithm()