diff --git a/Framework/Algorithms/CMakeLists.txt b/Framework/Algorithms/CMakeLists.txt index e4cb073c014753d63fd01ef7120e319a550d4cff..cfd3a9ae6c4eed9e9103535eaed947e1cbef9964 100644 --- a/Framework/Algorithms/CMakeLists.txt +++ b/Framework/Algorithms/CMakeLists.txt @@ -78,7 +78,9 @@ set ( SRC_FILES src/CreateSampleWorkspace.cpp src/CreateSingleValuedWorkspace.cpp src/CreateTransmissionWorkspace.cpp + src/CreateTransmissionWorkspace2.cpp src/CreateTransmissionWorkspaceAuto.cpp + src/CreateTransmissionWorkspaceAuto2.cpp src/CreateUserDefinedBackground.cpp src/CreateWorkspace.cpp src/CropToComponent.cpp @@ -220,8 +222,11 @@ set ( SRC_FILES src/Rebunch.cpp src/RecordPythonScript.cpp src/ReflectometryReductionOne.cpp + src/ReflectometryReductionOne2.cpp src/ReflectometryReductionOneAuto.cpp + src/ReflectometryReductionOneAuto2.cpp src/ReflectometryWorkflowBase.cpp + src/ReflectometryWorkflowBase2.cpp src/Regroup.cpp src/RemoveBackground.cpp src/RemoveBins.cpp @@ -265,6 +270,7 @@ set ( SRC_FILES src/SpecularReflectionAlgorithm.cpp src/SpecularReflectionCalculateTheta.cpp src/SpecularReflectionPositionCorrect.cpp + src/SpecularReflectionPositionCorrect2.cpp src/SphericalAbsorption.cpp src/Stitch1D.cpp src/Stitch1DMany.cpp @@ -386,7 +392,9 @@ set ( INC_FILES inc/MantidAlgorithms/CreateSampleWorkspace.h inc/MantidAlgorithms/CreateSingleValuedWorkspace.h inc/MantidAlgorithms/CreateTransmissionWorkspace.h + inc/MantidAlgorithms/CreateTransmissionWorkspace2.h inc/MantidAlgorithms/CreateTransmissionWorkspaceAuto.h + inc/MantidAlgorithms/CreateTransmissionWorkspaceAuto2.h inc/MantidAlgorithms/CreateUserDefinedBackground.h inc/MantidAlgorithms/CreateWorkspace.h inc/MantidAlgorithms/CropToComponent.h @@ -532,8 +540,11 @@ set ( INC_FILES inc/MantidAlgorithms/Rebunch.h inc/MantidAlgorithms/RecordPythonScript.h inc/MantidAlgorithms/ReflectometryReductionOne.h + inc/MantidAlgorithms/ReflectometryReductionOne2.h inc/MantidAlgorithms/ReflectometryReductionOneAuto.h + inc/MantidAlgorithms/ReflectometryReductionOneAuto2.h inc/MantidAlgorithms/ReflectometryWorkflowBase.h + inc/MantidAlgorithms/ReflectometryWorkflowBase2.h inc/MantidAlgorithms/Regroup.h inc/MantidAlgorithms/RemoveBackground.h inc/MantidAlgorithms/RemoveBins.h @@ -578,6 +589,7 @@ set ( INC_FILES inc/MantidAlgorithms/SpecularReflectionAlgorithm.h inc/MantidAlgorithms/SpecularReflectionCalculateTheta.h inc/MantidAlgorithms/SpecularReflectionPositionCorrect.h + inc/MantidAlgorithms/SpecularReflectionPositionCorrect2.h inc/MantidAlgorithms/SphericalAbsorption.h inc/MantidAlgorithms/Stitch1D.h inc/MantidAlgorithms/Stitch1DMany.h @@ -707,7 +719,9 @@ set ( TEST_FILES CreateSampleWorkspaceTest.h CreateSingleValuedWorkspaceTest.h CreateTransmissionWorkspaceAutoTest.h + CreateTransmissionWorkspaceAuto2Test.h CreateTransmissionWorkspaceTest.h + CreateTransmissionWorkspace2Test.h CreateUserDefinedBackgroundTest.h CreateWorkspaceTest.h CropToComponentTest.h @@ -840,7 +854,9 @@ set ( TEST_FILES RebunchTest.h RectangularBeamProfileTest.h ReflectometryReductionOneAutoTest.h + ReflectometryReductionOneAuto2Test.h ReflectometryReductionOneTest.h + ReflectometryReductionOne2Test.h RegroupTest.h RemoveBackgroundTest.h RemoveBinsTest.h @@ -875,6 +891,7 @@ set ( TEST_FILES SpatialGroupingTest.h SpecularReflectionCalculateThetaTest.h SpecularReflectionPositionCorrectTest.h + SpecularReflectionPositionCorrect2Test.h SphericalAbsorptionTest.h Stitch1DManyTest.h Stitch1DTest.h diff --git a/Framework/Algorithms/inc/MantidAlgorithms/CreateTransmissionWorkspace2.h b/Framework/Algorithms/inc/MantidAlgorithms/CreateTransmissionWorkspace2.h new file mode 100644 index 0000000000000000000000000000000000000000..03d9025360afc8c886d55c8c92622e2e7d02463d --- /dev/null +++ b/Framework/Algorithms/inc/MantidAlgorithms/CreateTransmissionWorkspace2.h @@ -0,0 +1,57 @@ +#ifndef MANTID_ALGORITHMS_CREATETRANSMISSIONWORKSPACE2_H_ +#define MANTID_ALGORITHMS_CREATETRANSMISSIONWORKSPACE2_H_ + +#include "MantidAlgorithms/ReflectometryWorkflowBase2.h" + +namespace Mantid { +namespace Algorithms { + +/** CreateTransmissionWorkspace2 : Create a transmission run workspace in + Wavelength given one or more TOF workspaces. Version 2 of the algorithm. + + Copyright © 2016 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge + National Laboratory & European Spallation Source + + 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 CreateTransmissionWorkspace2 + : public ReflectometryWorkflowBase2 { +public: + const std::string name() const override; + const std::string summary() const override; + int version() const override; + const std::string category() const override; + +private: + /// Initialize + void init() override; + /// Execute + void exec() override; + /// Validate inputs + std::map<std::string, std::string> validateInputs() override; + + /// Normalize by monitors + API::MatrixWorkspace_sptr + normalizeDetectorsByMonitors(API::MatrixWorkspace_sptr IvsLam); +}; + +} // namespace Algorithms +} // namespace Mantid + +#endif /* MANTID_ALGORITHMS_CREATETRANSMISSIONWORKSPACE2_H_ */ diff --git a/Framework/Algorithms/inc/MantidAlgorithms/CreateTransmissionWorkspaceAuto2.h b/Framework/Algorithms/inc/MantidAlgorithms/CreateTransmissionWorkspaceAuto2.h new file mode 100644 index 0000000000000000000000000000000000000000..d70bbe6c2c9e0ff7685909718dd32e46e98c3f78 --- /dev/null +++ b/Framework/Algorithms/inc/MantidAlgorithms/CreateTransmissionWorkspaceAuto2.h @@ -0,0 +1,56 @@ +#ifndef MANTID_ALGORITHMS_CREATETRANSMISSIONWORKSPACEAUTO2_H_ +#define MANTID_ALGORITHMS_CREATETRANSMISSIONWORKSPACEAUTO2_H_ + +#include "ReflectometryWorkflowBase2.h" + +namespace Mantid { +namespace Algorithms { + +/** CreateTransmissionWorkspaceAuto2 : Creates a transmission run workspace in +Wavelength from input TOF workspaces. Version 2. + +Copyright © 2016 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge +National Laboratory & European Spallation Source + +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 CreateTransmissionWorkspaceAuto2 + : public ReflectometryWorkflowBase2 { +public: + //---------------------------------------------------------------------------------------------- + /// Algorithm's name for identification. @see Algorithm::name + const std::string name() const override { + return "CreateTransmissionWorkspaceAuto"; + } + /// Algorithm's version for identification. @see Algorithm::version + int version() const override { return 2; } + /// Algorithm's category for identification. @see Algorithm::category + const std::string category() const override { return "Reflectometry\\ISIS"; } + /// Algorithm's summary for documentation + const std::string summary() const override; + +private: + void init() override; + void exec() override; +}; + +} // namespace Algorithms +} // namespace Mantid + +#endif /* MANTID_ALGORITHMS_CREATETRANSMISSIONWORKSPACEAUTO2_H_ */ diff --git a/Framework/Algorithms/inc/MantidAlgorithms/ReflectometryReductionOne2.h b/Framework/Algorithms/inc/MantidAlgorithms/ReflectometryReductionOne2.h new file mode 100644 index 0000000000000000000000000000000000000000..34a4d1461b09fb6c5315cb9bd7b088c87f966838 --- /dev/null +++ b/Framework/Algorithms/inc/MantidAlgorithms/ReflectometryReductionOne2.h @@ -0,0 +1,76 @@ +#ifndef MANTID_ALGORITHMS_REFLECTOMETRYREDUCTIONONE2_H_ +#define MANTID_ALGORITHMS_REFLECTOMETRYREDUCTIONONE2_H_ + +#include "MantidAlgorithms/ReflectometryWorkflowBase2.h" + +namespace Mantid { +namespace Algorithms { + +/** ReflectometryReductionOne2 : Reflectometry reduction of a single input TOF + workspace to an IvsQ workspace. Version 2 of the algorithm. + + Copyright © 2013 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge + National Laboratory & European Spallation Source + + 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 ReflectometryReductionOne2 : public ReflectometryWorkflowBase2 { +public: + /// Algorithm's name for identification + const std::string name() const override { + return "ReflectometryReductionOne"; + }; + /// Summary of algorithms purpose + const std::string summary() const override { + return "Reduces a single TOF/Lambda reflectometry run into a mod Q vs I/I0 " + "workspace. Performs monitor normalization and transmission " + "corrections."; + } + /// Algorithm's version for identification. + int version() const override { return 2; }; + /// Algorithm's category for identification. + const std::string category() const override { return "Reflectometry"; }; + +private: + /** Overridden Algorithm methods **/ + + // Initialize the algorithm + void init() override; + // Execute the algorithm + void exec() override; + // Validate inputs + std::map<std::string, std::string> validateInputs() override; + // Create a direct beam workspace from input workspace in wavelength + Mantid::API::MatrixWorkspace_sptr + makeDirectBeamWS(Mantid::API::MatrixWorkspace_sptr inputWS); + // Performs transmission corrections + Mantid::API::MatrixWorkspace_sptr + transmissionCorrection(Mantid::API::MatrixWorkspace_sptr detectorWS); + // Performs transmission corrections using alternative correction algorithms + Mantid::API::MatrixWorkspace_sptr + algorithmicCorrection(Mantid::API::MatrixWorkspace_sptr detectorWS); + // convert to momentum transfer + Mantid::API::MatrixWorkspace_sptr + convertToQ(Mantid::API::MatrixWorkspace_sptr inputWS); +}; + +} // namespace Algorithms +} // namespace Mantid + +#endif /* MANTID_ALGORITHMS_REFLECTOMETRYREDUCTIONONE2_H_ */ diff --git a/Framework/Algorithms/inc/MantidAlgorithms/ReflectometryReductionOneAuto2.h b/Framework/Algorithms/inc/MantidAlgorithms/ReflectometryReductionOneAuto2.h new file mode 100644 index 0000000000000000000000000000000000000000..e8c59c57a225ee78b1d7e8d121013e29c31e4a99 --- /dev/null +++ b/Framework/Algorithms/inc/MantidAlgorithms/ReflectometryReductionOneAuto2.h @@ -0,0 +1,82 @@ +#ifndef MANTID_ALGORITHMS_REFLECTOMETRYREDUCTIONONEAUTO2_H_ +#define MANTID_ALGORITHMS_REFLECTOMETRYREDUCTIONONEAUTO2_H_ + +#include "MantidAPI/WorkspaceGroup_fwd.h" +#include "ReflectometryWorkflowBase2.h" + +namespace Mantid { +namespace Algorithms { + +/** ReflectometryReductionOneAuto2 : Algorithm to run ReflectometryReductionOne, +attempting to pick instrument parameters for missing properties. Version 2. + +Copyright © 2016 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge +National Laboratory & European Spallation Source + +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 ReflectometryReductionOneAuto2 + : public ReflectometryWorkflowBase2 { +public: + const std::string name() const override; + int version() const override; + const std::string category() const override; + const std::string summary() const override; + + /// Validate inputs + std::map<std::string, std::string> validateInputs() override; + + /// For (multiperiod) workspace groups + bool checkGroups() override; + bool processGroups() override; + + /// Sums transmission workspaces belonging to a group + Mantid::API::MatrixWorkspace_sptr + sumTransmissionWorkspaces(Mantid::API::WorkspaceGroup_sptr &transGroup); + +private: + void init() override; + void exec() override; + /// Get the name of the detectors of interest based on processing instructions + std::vector<std::string> + getDetectorNames(const std::string &instructions, + Mantid::API::MatrixWorkspace_sptr inputWS); + /// Correct detector positions vertically + Mantid::API::MatrixWorkspace_sptr + correctDetectorPositions(const std::string &instructions, + Mantid::API::MatrixWorkspace_sptr inputWS); + /// Calculate theta + double calculateTheta(const std::string &instructions, + Mantid::API::MatrixWorkspace_sptr inputWS); + /// Rebin and scale a workspace in Q + Mantid::API::MatrixWorkspace_sptr + rebinAndScale(Mantid::API::MatrixWorkspace_sptr inputWS, double theta, + std::vector<double> ¶ms); + /// Populate direct beam properties + void populateDirectBeamProperties(Mantid::API::IAlgorithm_sptr alg); + /// Populate transmission properties + void populateTransmissionProperties( + Mantid::API::IAlgorithm_sptr alg, + Mantid::Geometry::Instrument_const_sptr instrument); +}; + +} // namespace Algorithms +} // namespace Mantid + +#endif /* MANTID_ALGORITHMS_REFLECTOMETRYREDUCTIONONEAUTO2_H_ */ diff --git a/Framework/Algorithms/inc/MantidAlgorithms/ReflectometryWorkflowBase2.h b/Framework/Algorithms/inc/MantidAlgorithms/ReflectometryWorkflowBase2.h new file mode 100644 index 0000000000000000000000000000000000000000..a25ffa40bef205d940b3416dbc93c280f46154ef --- /dev/null +++ b/Framework/Algorithms/inc/MantidAlgorithms/ReflectometryWorkflowBase2.h @@ -0,0 +1,82 @@ +#ifndef MANTID_ALGORITHMS_REFLECTOMETRYWORKFLOWBASE2_H_ +#define MANTID_ALGORITHMS_REFLECTOMETRYWORKFLOWBASE2_H_ + +#include "MantidAPI/DataProcessorAlgorithm.h" +#include "MantidAPI/MatrixWorkspace_fwd.h" +#include "MantidGeometry/Instrument_fwd.h" + +namespace Mantid { +namespace Algorithms { + +/** ReflectometryWorkflowBase2 : base class containing common implementation + functionality usable by concrete reflectometry workflow algorithms. Version 2. + + Copyright © 2016 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge + National Laboratory & European Spallation Source + + 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 ReflectometryWorkflowBase2 + : public API::DataProcessorAlgorithm { +protected: + /// Initialize monitor properties + void initMonitorProperties(); + /// Initialize direct beam properties + void initDirectBeamProperties(); + /// Initialize transmission properties + void initTransmissionProperties(); + /// Initialize properties for stitching transmission runs + void initStitchProperties(); + /// Initialize corection algorithm properties + void initAlgorithmicProperties(bool autodetect = false); + /// Initialize momentum transfer properties + void initMomentumTransferProperties(); + /// Validate direct beam properties + std::map<std::string, std::string> validateDirectBeamProperties() const; + /// Validate transmission properties + std::map<std::string, std::string> validateTransmissionProperties() const; + /// Validate wavelength range + std::map<std::string, std::string> validateWavelengthRanges() const; + /// Convert a workspace from TOF to wavelength + Mantid::API::MatrixWorkspace_sptr + convertToWavelength(Mantid::API::MatrixWorkspace_sptr inputWS); + /// Crop a workspace in wavelength + Mantid::API::MatrixWorkspace_sptr + cropWavelength(Mantid::API::MatrixWorkspace_sptr inputWS); + // Create a detector workspace from input workspace in wavelength + Mantid::API::MatrixWorkspace_sptr + makeDetectorWS(Mantid::API::MatrixWorkspace_sptr inputWS); + // Create a monitor workspace from input workspace in wavelength + Mantid::API::MatrixWorkspace_sptr + makeMonitorWS(Mantid::API::MatrixWorkspace_sptr inputWS, + bool integratedMonitors); + // Read monitor properties from instrument + void + populateMonitorProperties(Mantid::API::IAlgorithm_sptr alg, + Mantid::Geometry::Instrument_const_sptr instrument); + /// Populate processing instructions + std::string populateProcessingInstructions( + Mantid::API::IAlgorithm_sptr alg, + Mantid::Geometry::Instrument_const_sptr instrument, + Mantid::API::MatrixWorkspace_sptr inputWS) const; +}; +} // namespace Algorithms +} // namespace Mantid + +#endif /* MANTID_ALGORITHMS_REFLECTOMETRYWORKFLOWBASE2_H_ */ diff --git a/Framework/Algorithms/inc/MantidAlgorithms/SpecularReflectionPositionCorrect2.h b/Framework/Algorithms/inc/MantidAlgorithms/SpecularReflectionPositionCorrect2.h new file mode 100644 index 0000000000000000000000000000000000000000..e015c4d451ae3e334da49534a59faf3f8fd3fb98 --- /dev/null +++ b/Framework/Algorithms/inc/MantidAlgorithms/SpecularReflectionPositionCorrect2.h @@ -0,0 +1,52 @@ +#ifndef MANTID_ALGORITHMS_SPECULARREFLECTIONPOSITIONCORRECT2_H_ +#define MANTID_ALGORITHMS_SPECULARREFLECTIONPOSITIONCORRECT2_H_ + +#include "MantidAPI/Algorithm.h" + +namespace Mantid { +namespace Algorithms { + +/** SpecularReflectionPositionCorrect : Algorithm to perform vertical position +corrections based on the specular reflection condition. Version 2. + +Copyright © 2016 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge +National Laboratory & European Spallation Source + +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 SpecularReflectionPositionCorrect2 : public API::Algorithm { +public: + /// Name of this algorithm + const std::string name() const override; + /// Summary of algorithms purpose + const std::string summary() const override; + /// Version + int version() const override; + /// Category + const std::string category() const override; + +private: + void init() override; + void exec() override; +}; + +} // namespace Algorithms +} // namespace Mantid + +#endif /* MANTID_ALGORITHMS_SPECULARREFLECTIONPOSITIONCORRECT2_H_ */ diff --git a/Framework/Algorithms/src/CreateTransmissionWorkspace2.cpp b/Framework/Algorithms/src/CreateTransmissionWorkspace2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8ff6e9831fc879d8ea1ef3e0904d0e86b0c4a0e9 --- /dev/null +++ b/Framework/Algorithms/src/CreateTransmissionWorkspace2.cpp @@ -0,0 +1,172 @@ +#include "MantidAlgorithms/CreateTransmissionWorkspace2.h" + +#include "MantidAPI/WorkspaceUnitValidator.h" +#include "MantidKernel/MandatoryValidator.h" + +using namespace Mantid::Kernel; +using namespace Mantid::API; + +namespace Mantid { +namespace Algorithms { + +// Register the algorithm into the AlgorithmFactory +DECLARE_ALGORITHM(CreateTransmissionWorkspace2) + +//---------------------------------------------------------------------------------------------- +/// Algorithm's name for identification. @see Algorithm::name +const std::string CreateTransmissionWorkspace2::name() const { + return "CreateTransmissionWorkspace"; +} +/// Summary of algorithm's purpose +const std::string CreateTransmissionWorkspace2::summary() const { + return "Creates a transmission run workspace in wavelength from one or two " + "input workspaces in TOF."; +} +/// Algorithm's version for identification. @see Algorithm::version +int CreateTransmissionWorkspace2::version() const { return 2; } + +/// Algorithm's category for identification. @see Algorithm::category +const std::string CreateTransmissionWorkspace2::category() const { + return "Reflectometry"; +} + +//---------------------------------------------------------------------------------------------- + +//---------------------------------------------------------------------------------------------- +/** Initialize the algorithm's properties. + */ +void CreateTransmissionWorkspace2::init() { + auto inputValidator = boost::make_shared<WorkspaceUnitValidator>("TOF"); + + declareProperty(make_unique<WorkspaceProperty<MatrixWorkspace>>( + "FirstTransmissionRun", "", Direction::Input, + PropertyMode::Mandatory, inputValidator->clone()), + "First transmission run. Corresponds to the low wavelength " + "transmision run if a SecondTransmissionRun is also " + "provided."); + + declareProperty(make_unique<WorkspaceProperty<MatrixWorkspace>>( + "SecondTransmissionRun", "", Direction::Input, + PropertyMode::Optional, inputValidator->clone()), + "High wavelength transmission run. Optional. Causes the " + "first transmission run to be treated as the low wavelength " + "transmission run."); + + declareProperty(Kernel::make_unique<PropertyWithValue<std::string>>( + "ProcessingInstructions", "", + boost::make_shared<MandatoryValidator<std::string>>(), + Direction::Input), + "Grouping pattern on workspace indexes to yield only " + "the detectors of interest. See GroupDetectors for details."); + + declareProperty(make_unique<PropertyWithValue<double>>( + "WavelengthMin", Mantid::EMPTY_DBL(), + boost::make_shared<MandatoryValidator<double>>(), + Direction::Input), + "Wavelength minimum in angstroms"); + + declareProperty(make_unique<PropertyWithValue<double>>( + "WavelengthMax", Mantid::EMPTY_DBL(), + boost::make_shared<MandatoryValidator<double>>(), + Direction::Input), + "Wavelength maximum in angstroms"); + + initMonitorProperties(); + + initStitchProperties(); + + declareProperty(make_unique<WorkspaceProperty<MatrixWorkspace>>( + "OutputWorkspace", "", Direction::Output), + "Output workspace in wavelength."); +} + +/** Validate inputs +* @return :: error message to show +*/ +std::map<std::string, std::string> +CreateTransmissionWorkspace2::validateInputs() { + + std::map<std::string, std::string> results; + + // Validate wavelength range + // Validate monitor background range + // Validate monitor integration range + const auto wavelength = validateWavelengthRanges(); + results.insert(wavelength.begin(), wavelength.end()); + + return results; +} + +//---------------------------------------------------------------------------------------------- +/** Execute the algorithm. + */ +void CreateTransmissionWorkspace2::exec() { + + MatrixWorkspace_sptr firstTransWS = getProperty("FirstTransmissionRun"); + firstTransWS = convertToWavelength(firstTransWS); + firstTransWS = normalizeDetectorsByMonitors(firstTransWS); + firstTransWS = cropWavelength(firstTransWS); + + MatrixWorkspace_sptr secondTransWS = getProperty("SecondTransmissionRun"); + if (secondTransWS) { + secondTransWS = convertToWavelength(secondTransWS); + secondTransWS = normalizeDetectorsByMonitors(secondTransWS); + secondTransWS = cropWavelength(secondTransWS); + + // Stitch the results. + auto stitch = createChildAlgorithm("Stitch1D"); + stitch->initialize(); + stitch->setProperty("LHSWorkspace", firstTransWS); + stitch->setProperty("RHSWorkspace", secondTransWS); + stitch->setPropertyValue("StartOverlap", getPropertyValue("StartOverlap")); + stitch->setPropertyValue("EndOverlap", getPropertyValue("EndOverlap")); + stitch->setPropertyValue("Params", getPropertyValue("Params")); + stitch->execute(); + MatrixWorkspace_sptr outWS = stitch->getProperty("OutputWorkspace"); + setProperty("OutputWorkspace", outWS); + } else { + setProperty("OutputWorkspace", firstTransWS); + } +} + +/** Normalize detectors by monitors +* @param IvsLam :: a workspace in wavelength that contains spectra for both +* monitors and detectors +* @return :: the normalized workspace +*/ +MatrixWorkspace_sptr CreateTransmissionWorkspace2::normalizeDetectorsByMonitors( + const MatrixWorkspace_sptr IvsLam) { + + // Detector workspace + MatrixWorkspace_sptr detectorWS = makeDetectorWS(IvsLam); + + // Monitor workspace + // Only if I0MonitorIndex, MonitorBackgroundWavelengthMin + // and MonitorBackgroundWavelengthMax have been given + + Property *monProperty = getProperty("I0MonitorIndex"); + Property *backgroundMinProperty = + getProperty("MonitorBackgroundWavelengthMin"); + Property *backgroundMaxProperty = + getProperty("MonitorBackgroundWavelengthMin"); + if (monProperty->isDefault() || backgroundMinProperty->isDefault() || + backgroundMaxProperty->isDefault()) { + return detectorWS; + } + + // Normalization by integrated monitors + // Only if both MonitorIntegrationWavelengthMin and + // MonitorIntegrationWavelengthMax are have been given + + Property *intMinProperty = getProperty("MonitorIntegrationWavelengthMin"); + Property *intMaxProperty = getProperty("MonitorIntegrationWavelengthMax"); + const bool integratedMonitors = + !(intMinProperty->isDefault() || intMaxProperty->isDefault()); + + auto monitorWS = makeMonitorWS(IvsLam, integratedMonitors); + + return divide(detectorWS, monitorWS); +} + +} // namespace Algorithms +} // namespace Mantid diff --git a/Framework/Algorithms/src/CreateTransmissionWorkspaceAuto.cpp b/Framework/Algorithms/src/CreateTransmissionWorkspaceAuto.cpp index 733a0c8495cd900717183f21cb304a7303b15a32..921d8a2888a460c6a1300924afe91a93c287eb73 100644 --- a/Framework/Algorithms/src/CreateTransmissionWorkspaceAuto.cpp +++ b/Framework/Algorithms/src/CreateTransmissionWorkspaceAuto.cpp @@ -12,7 +12,6 @@ #include "MantidAlgorithms/CreateTransmissionWorkspaceAuto.h" #include "MantidAPI/WorkspaceUnitValidator.h" #include "MantidKernel/ArrayProperty.h" -#include "MantidKernel/BoundedValidator.h" #include "MantidKernel/ListValidator.h" #include "MantidKernel/RebinParamsValidator.h" @@ -169,7 +168,7 @@ void CreateTransmissionWorkspaceAuto::exec() { // construct the algorithm IAlgorithm_sptr algCreateTransWS = - createChildAlgorithm("CreateTransmissionWorkspace"); + createChildAlgorithm("CreateTransmissionWorkspace", -1, -1, true, 1); algCreateTransWS->setRethrows(true); algCreateTransWS->initialize(); diff --git a/Framework/Algorithms/src/CreateTransmissionWorkspaceAuto2.cpp b/Framework/Algorithms/src/CreateTransmissionWorkspaceAuto2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..86b9dcf70cc6cff90a5771274529ce97fd04004a --- /dev/null +++ b/Framework/Algorithms/src/CreateTransmissionWorkspaceAuto2.cpp @@ -0,0 +1,119 @@ +#include "MantidAlgorithms/CreateTransmissionWorkspaceAuto2.h" +#include "MantidAlgorithms/BoostOptionalToAlgorithmProperty.h" +#include "MantidAPI/WorkspaceUnitValidator.h" +#include "MantidKernel/ListValidator.h" + +using namespace Mantid::Kernel; +using namespace Mantid::API; + +namespace Mantid { +namespace Algorithms { + +// Register the algorithm into the AlgorithmFactory +DECLARE_ALGORITHM(CreateTransmissionWorkspaceAuto2) + +//---------------------------------------------------------------------------------------------- +/// Sets documentation strings for this algorithm +const std::string CreateTransmissionWorkspaceAuto2::summary() const { + return "Creates a transmission run workspace in Wavelength from input TOF " + "workspaces."; +} + +//---------------------------------------------------------------------------------------------- +/** Initialize the algorithm's properties. + */ +void CreateTransmissionWorkspaceAuto2::init() { + + declareProperty(make_unique<WorkspaceProperty<MatrixWorkspace>>( + "FirstTransmissionRun", "", Direction::Input, + boost::make_shared<WorkspaceUnitValidator>("TOF")), + "Input workspace."); + declareProperty(make_unique<WorkspaceProperty<MatrixWorkspace>>( + "SecondTransmissionRun", "", Direction::Input, + PropertyMode::Optional, + boost::make_shared<WorkspaceUnitValidator>("TOF")), + "Second transmission run workspace in TOF."); + + // Analysis mode + const std::vector<std::string> analysisMode{"PointDetectorAnalysis", + "MultiDetectorAnalysis"}; + auto analysisModeValidator = + boost::make_shared<StringListValidator>(analysisMode); + declareProperty("AnalysisMode", analysisMode[0], analysisModeValidator, + "Analysis mode. This property is only used when " + "ProcessingInstructions is not set.", + Direction::Input); + + // Processing instructions + declareProperty(make_unique<PropertyWithValue<std::string>>( + "ProcessingInstructions", "", Direction::Input), + "Grouping pattern of workspace indices to yield only the" + " detectors of interest. See GroupDetectors for syntax."); + + // Wavelength range + declareProperty("WavelengthMin", Mantid::EMPTY_DBL(), + "Wavelength Min in angstroms", Direction::Input); + declareProperty("WavelengthMax", Mantid::EMPTY_DBL(), + "Wavelength Max in angstroms", Direction::Input); + + // Monitor properties + initMonitorProperties(); + + // Properties for stitching transmission runs + initStitchProperties(); + + declareProperty(make_unique<WorkspaceProperty<MatrixWorkspace>>( + "OutputWorkspace", "", Direction::Output), + "Output transmission workspace in wavelength."); +} + +//---------------------------------------------------------------------------------------------- +/** Execute the algorithm. + */ +void CreateTransmissionWorkspaceAuto2::exec() { + + // Transmission runs + MatrixWorkspace_sptr firstWS = getProperty("FirstTransmissionRun"); + MatrixWorkspace_sptr secondWS = getProperty("SecondTransmissionRun"); + + // Instrument + auto instrument = firstWS->getInstrument(); + + IAlgorithm_sptr alg = createChildAlgorithm("CreateTransmissionWorkspace"); + alg->initialize(); + + // Mandatory properties + + alg->setProperty("FirstTransmissionRun", firstWS); + + double wavMin = checkForMandatoryInstrumentDefault<double>( + this, "WavelengthMin", instrument, "LambdaMin"); + alg->setProperty("WavelengthMin", wavMin); + double wavMax = checkForMandatoryInstrumentDefault<double>( + this, "WavelengthMax", instrument, "LambdaMax"); + alg->setProperty("WavelengthMax", wavMax); + + // Optional properties + + // Second transmission run and stitching params + if (secondWS) { + alg->setProperty("SecondTransmissionRun", secondWS); + alg->setPropertyValue("StartOverlap", getPropertyValue("StartOverlap")); + alg->setPropertyValue("EndOverlap", getPropertyValue("EndOverlap")); + alg->setPropertyValue("Params", getPropertyValue("Params")); + } + + // Monitor properties + populateMonitorProperties(alg, instrument); + + // Processing instructions + populateProcessingInstructions(alg, instrument, firstWS); + + alg->execute(); + MatrixWorkspace_sptr outWS = alg->getProperty("OutputWorkspace"); + + setProperty("OutputWorkspace", outWS); +} + +} // namespace Algorithms +} // namespace Mantid diff --git a/Framework/Algorithms/src/ReflectometryReductionOne.cpp b/Framework/Algorithms/src/ReflectometryReductionOne.cpp index 0e08c3036f88412e0d4ed3c779403c062d847b44..14e917ac5c421ce724d48548693f80e32ec49489 100644 --- a/Framework/Algorithms/src/ReflectometryReductionOne.cpp +++ b/Framework/Algorithms/src/ReflectometryReductionOne.cpp @@ -1,8 +1,6 @@ #include "MantidAlgorithms/BoostOptionalToAlgorithmProperty.h" #include "MantidAlgorithms/ReflectometryReductionOne.h" #include "MantidAPI/Axis.h" -#include "MantidAPI/MatrixWorkspace.h" -#include "MantidAPI/WorkspaceFactory.h" #include "MantidAPI/WorkspaceUnitValidator.h" #include "MantidGeometry/Instrument/ReferenceFrame.h" #include "MantidKernel/ListValidator.h" @@ -10,7 +8,6 @@ #include "MantidKernel/EnabledWhenProperty.h" #include "MantidKernel/Tolerance.h" #include "MantidKernel/Unit.h" -#include <boost/make_shared.hpp> using namespace Mantid::Kernel; using namespace Mantid::API; @@ -291,8 +288,8 @@ ReflectometryReductionOne::correctPosition(API::MatrixWorkspace_sptr &toCorrect, const bool isPointDetector) { g_log.debug("Correcting position using theta."); - auto correctPosAlg = - this->createChildAlgorithm("SpecularReflectionPositionCorrect"); + auto correctPosAlg = this->createChildAlgorithm( + "SpecularReflectionPositionCorrect", -1, -1, true, 1); correctPosAlg->initialize(); correctPosAlg->setProperty("InputWorkspace", toCorrect); @@ -635,8 +632,7 @@ void ReflectometryReductionOne::exec() { // if the DQQ is not given for this run. // we will use CalculateResoltion to produce this value // for us. - IAlgorithm_sptr calcResAlg = - AlgorithmManager::Instance().create("CalculateResolution"); + IAlgorithm_sptr calcResAlg = createChildAlgorithm("CalculateResolution"); calcResAlg->setProperty("Workspace", runWS); calcResAlg->setProperty("TwoTheta", theta.get()); calcResAlg->execute(); @@ -745,7 +741,8 @@ MatrixWorkspace_sptr ReflectometryReductionOne::transmissonCorrection( } // Make the transmission run. - auto alg = this->createChildAlgorithm("CreateTransmissionWorkspace"); + auto alg = this->createChildAlgorithm("CreateTransmissionWorkspace", -1, -1, + true, 1); alg->initialize(); alg->setProperty("FirstTransmissionRun", firstTransmissionRun); if (secondTransmissionRun.is_initialized()) { diff --git a/Framework/Algorithms/src/ReflectometryReductionOne2.cpp b/Framework/Algorithms/src/ReflectometryReductionOne2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ad7bb3d4b89fea46d2e763ebc5eda8200624dae1 --- /dev/null +++ b/Framework/Algorithms/src/ReflectometryReductionOne2.cpp @@ -0,0 +1,364 @@ +#include "MantidAlgorithms/ReflectometryReductionOne2.h" +#include "MantidAPI/Axis.h" +#include "MantidAPI/MatrixWorkspace.h" +#include "MantidKernel/MandatoryValidator.h" +#include "MantidKernel/Unit.h" + +using namespace Mantid::Kernel; +using namespace Mantid::API; + +namespace Mantid { +namespace Algorithms { + +/*Anonomous namespace */ +namespace { + +/** +* Translate all the workspace indexes in an origin workspace into workspace +* indexes of a host end-point workspace. This is done using spectrum numbers as +* the intermediate. +* +* @param originWS : Origin workspace, which provides the original workspace +* index to spectrum number mapping. +* @param hostWS : Workspace onto which the resulting workspace indexes will be +* hosted +* @throws :: If the specId are not found to exist on the host end-point +*workspace. +* @return :: Remapped workspace indexes applicable for the host workspace. +*results +*as comma separated string. +*/ +std::string +createProcessingCommandsFromDetectorWS(MatrixWorkspace_const_sptr originWS, + MatrixWorkspace_const_sptr hostWS) { + auto spectrumMap = originWS->getSpectrumToWorkspaceIndexMap(); + auto it = spectrumMap.begin(); + std::stringstream result; + specnum_t specId = (*it).first; + result << static_cast<int>(hostWS->getIndexFromSpectrumNumber(specId)); + ++it; + for (; it != spectrumMap.end(); ++it) { + specId = (*it).first; + result << "," + << static_cast<int>(hostWS->getIndexFromSpectrumNumber(specId)); + } + return result.str(); +} + +/** +@param ws1 : First workspace to compare +@param ws2 : Second workspace to compare against +@param severe: True to indicate that failure to verify should result in an +exception. Otherwise a warning is generated. +@return : true if spectrum maps match. False otherwise +*/ +bool verifySpectrumMaps(MatrixWorkspace_const_sptr ws1, + MatrixWorkspace_const_sptr ws2) { + auto map1 = ws1->getSpectrumToWorkspaceIndexMap(); + auto map2 = ws2->getSpectrumToWorkspaceIndexMap(); + if (map1 != map2) { + return false; + } else { + return true; + } +} +} + +// Register the algorithm into the AlgorithmFactory +DECLARE_ALGORITHM(ReflectometryReductionOne2) + +//---------------------------------------------------------------------------------------------- +/** Initialize the algorithm's properties. +*/ +void ReflectometryReductionOne2::init() { + + // Input workspace + declareProperty(make_unique<WorkspaceProperty<MatrixWorkspace>>( + "InputWorkspace", "", Direction::Input), + "Run to reduce."); + + // Processing instructions + declareProperty(Kernel::make_unique<PropertyWithValue<std::string>>( + "ProcessingInstructions", "", + boost::make_shared<MandatoryValidator<std::string>>(), + Direction::Input), + "Grouping pattern on workspace indexes to yield only " + "the detectors of interest. See GroupDetectors for details."); + + // Minimum wavelength + declareProperty(make_unique<PropertyWithValue<double>>( + "WavelengthMin", Mantid::EMPTY_DBL(), + boost::make_shared<MandatoryValidator<double>>(), + Direction::Input), + "Wavelength minimum in angstroms"); + + // Maximum wavelength + declareProperty(make_unique<PropertyWithValue<double>>( + "WavelengthMax", Mantid::EMPTY_DBL(), + boost::make_shared<MandatoryValidator<double>>(), + Direction::Input), + "Wavelength maximum in angstroms"); + + // Properties for direct beam normalization + initDirectBeamProperties(); + + // Init properties for monitors + initMonitorProperties(); + // Normalization by integrated monitors + declareProperty("NormalizeByIntegratedMonitors", true, + "Normalize by dividing by the integrated monitors."); + + // Init properties for transmission normalization + initTransmissionProperties(); + + // Init properties for algorithmic corrections + initAlgorithmicProperties(); + + declareProperty(make_unique<WorkspaceProperty<>>("OutputWorkspace", "", + Direction::Output), + "Output Workspace IvsQ."); + + declareProperty(make_unique<WorkspaceProperty<>>("OutputWorkspaceWavelength", + "", Direction::Output, + PropertyMode::Optional), + "Output Workspace IvsLam. Intermediate workspace."); +} + +/** Validate inputs +*/ +std::map<std::string, std::string> +ReflectometryReductionOne2::validateInputs() { + + std::map<std::string, std::string> results; + + const auto wavelength = validateWavelengthRanges(); + results.insert(wavelength.begin(), wavelength.end()); + + const auto directBeam = validateDirectBeamProperties(); + results.insert(directBeam.begin(), directBeam.end()); + + const auto transmission = validateTransmissionProperties(); + results.insert(transmission.begin(), transmission.end()); + + return results; +} + +/** Execute the algorithm. +*/ +void ReflectometryReductionOne2::exec() { + MatrixWorkspace_sptr runWS = getProperty("InputWorkspace"); + + const auto xUnitID = runWS->getAxis(0)->unit()->unitID(); + + // Neither TOF or Lambda? Abort. + if ((xUnitID != "Wavelength") && (xUnitID != "TOF")) + throw std::invalid_argument( + "InputWorkspace must have units of TOF or Wavelength"); + + // Output workspace in wavelength + MatrixWorkspace_sptr IvsLam; + + if (xUnitID == "Wavelength") { + IvsLam = runWS; + } else { + // xUnitID == "TOF" + + IvsLam = convertToWavelength(runWS); + + // Detector workspace + auto detectorWS = makeDetectorWS(IvsLam); + + // Normalization by direct beam (optional) + Property *directBeamProperty = getProperty("RegionOfDirectBeam"); + if (!directBeamProperty->isDefault()) { + const auto directBeam = makeDirectBeamWS(IvsLam); + detectorWS = divide(detectorWS, directBeam); + } + + // Monitor workspace (only if I0MonitorIndex, MonitorBackgroundWavelengthMin + // and MonitorBackgroundWavelengthMax have been given) + Property *monProperty = getProperty("I0MonitorIndex"); + Property *backgroundMinProperty = + getProperty("MonitorBackgroundWavelengthMin"); + Property *backgroundMaxProperty = + getProperty("MonitorBackgroundWavelengthMin"); + if (!monProperty->isDefault() && !backgroundMinProperty->isDefault() && + !backgroundMaxProperty->isDefault()) { + const bool integratedMonitors = + getProperty("NormalizeByIntegratedMonitors"); + const auto monitorWS = makeMonitorWS(IvsLam, integratedMonitors); + IvsLam = divide(detectorWS, monitorWS); + } else { + IvsLam = detectorWS; + } + + // Crop to wavelength limits + IvsLam = cropWavelength(IvsLam); + } + + // Transmission correction + MatrixWorkspace_sptr transRun = getProperty("FirstTransmissionRun"); + if (transRun) { + IvsLam = transmissionCorrection(IvsLam); + } else if (getPropertyValue("CorrectionAlgorithm") != "None") { + IvsLam = algorithmicCorrection(IvsLam); + } + + // Convert to Q + auto IvsQ = convertToQ(IvsLam); + + setProperty("OutputWorkspaceWavelength", IvsLam); + setProperty("OutputWorkspace", IvsQ); +} + +/** Creates a direct beam workspace from an input workspace in wavelength. This +* method should only be called if RegionOfDirectBeam is provided. +* +* @param inputWS :: the input workspace in wavelength +* @return :: the monitor workspace +*/ +MatrixWorkspace_sptr +ReflectometryReductionOne2::makeDirectBeamWS(MatrixWorkspace_sptr inputWS) { + + std::vector<int> directBeamRegion = getProperty("RegionOfDirectBeam"); + // Sum over the direct beam. + const std::string processingCommands = std::to_string(directBeamRegion[0]) + + "-" + + std::to_string(directBeamRegion[1]); + + auto groupDirectBeamAlg = this->createChildAlgorithm("GroupDetectors"); + groupDirectBeamAlg->initialize(); + groupDirectBeamAlg->setProperty("GroupingPattern", processingCommands); + groupDirectBeamAlg->setProperty("InputWorkspace", inputWS); + groupDirectBeamAlg->execute(); + MatrixWorkspace_sptr directBeamWS = + groupDirectBeamAlg->getProperty("OutputWorkspace"); + + return directBeamWS; +} + +/** Perform transmission correction by running 'CreateTransmissionWorkspace' on +* the input workspace +* @param detectorWS :: the input workspace +* @return :: the input workspace normalized by transmission +*/ +MatrixWorkspace_sptr ReflectometryReductionOne2::transmissionCorrection( + MatrixWorkspace_sptr detectorWS) { + + const bool strictSpectrumChecking = getProperty("StrictSpectrumChecking"); + + MatrixWorkspace_sptr transmissionWS = getProperty("FirstTransmissionRun"); + Unit_const_sptr xUnit = transmissionWS->getAxis(0)->unit(); + + if (xUnit->unitID() == "TOF") { + + // Processing instructions for transmission workspace + std::string transmissionCommands = getProperty("ProcessingInstructions"); + if (strictSpectrumChecking) { + // If we have strict spectrum checking, the processing commands need to be + // made from the + // numerator workspace AND the transmission workspace based on matching + // spectrum numbers. + transmissionCommands = + createProcessingCommandsFromDetectorWS(detectorWS, transmissionWS); + } + + MatrixWorkspace_sptr secondTransmissionWS = + getProperty("SecondTransmissionRun"); + auto alg = this->createChildAlgorithm("CreateTransmissionWorkspace"); + alg->initialize(); + alg->setProperty("FirstTransmissionRun", transmissionWS); + alg->setProperty("SecondTransmissionRun", secondTransmissionWS); + alg->setPropertyValue("Params", getPropertyValue("Params")); + alg->setPropertyValue("StartOverlap", getPropertyValue("StartOverlap")); + alg->setPropertyValue("EndOverlap", getPropertyValue("EndOverlap")); + alg->setPropertyValue("I0MonitorIndex", getPropertyValue("I0MonitorIndex")); + alg->setPropertyValue("WavelengthMin", getPropertyValue("WavelengthMin")); + alg->setPropertyValue("WavelengthMax", getPropertyValue("WavelengthMax")); + alg->setPropertyValue("MonitorBackgroundWavelengthMin", + getPropertyValue("MonitorBackgroundWavelengthMin")); + alg->setPropertyValue("MonitorBackgroundWavelengthMax", + getPropertyValue("MonitorBackgroundWavelengthMax")); + alg->setPropertyValue("MonitorIntegrationWavelengthMin", + getPropertyValue("MonitorIntegrationWavelengthMin")); + alg->setPropertyValue("MonitorIntegrationWavelengthMax", + getPropertyValue("MonitorIntegrationWavelengthMax")); + alg->setProperty("ProcessingInstructions", transmissionCommands); + alg->execute(); + transmissionWS = alg->getProperty("OutputWorkspace"); + } + + // Rebin the transmission run to be the same as the input. + auto rebinToWorkspaceAlg = this->createChildAlgorithm("RebinToWorkspace"); + rebinToWorkspaceAlg->initialize(); + rebinToWorkspaceAlg->setProperty("WorkspaceToMatch", detectorWS); + rebinToWorkspaceAlg->setProperty("WorkspaceToRebin", transmissionWS); + rebinToWorkspaceAlg->execute(); + transmissionWS = rebinToWorkspaceAlg->getProperty("OutputWorkspace"); + + const bool match = verifySpectrumMaps(detectorWS, transmissionWS); + if (!match) { + const std::string message = + "Spectrum maps between workspaces do NOT match up."; + if (strictSpectrumChecking) { + throw std::invalid_argument(message); + } else { + g_log.warning(message); + } + } + + MatrixWorkspace_sptr normalized = divide(detectorWS, transmissionWS); + return normalized; +} + +/** +* Perform transmission correction using alternative correction algorithms +* @param detectorWS : workspace in wavelength which is to be normalized by the +* results of the transmission corrections. +* @return : corrected workspace +*/ +MatrixWorkspace_sptr ReflectometryReductionOne2::algorithmicCorrection( + MatrixWorkspace_sptr detectorWS) { + + const std::string corrAlgName = getProperty("CorrectionAlgorithm"); + + IAlgorithm_sptr corrAlg = createChildAlgorithm(corrAlgName); + corrAlg->initialize(); + if (corrAlgName == "PolynomialCorrection") { + corrAlg->setPropertyValue("Coefficients", getPropertyValue("Polynomial")); + } else if (corrAlgName == "ExponentialCorrection") { + corrAlg->setPropertyValue("C0", getPropertyValue("C0")); + corrAlg->setPropertyValue("C1", getPropertyValue("C1")); + } else { + throw std::runtime_error("Unknown correction algorithm: " + corrAlgName); + } + + corrAlg->setProperty("InputWorkspace", detectorWS); + corrAlg->setProperty("Operation", "Divide"); + corrAlg->execute(); + + return corrAlg->getProperty("OutputWorkspace"); +} + +/** +* The input workspace (in wavelength) to convert to Q +* @param inputWS : the input workspace to convert +* @return : output workspace in Q +*/ +MatrixWorkspace_sptr +ReflectometryReductionOne2::convertToQ(MatrixWorkspace_sptr inputWS) { + + // Convert to Q + auto convertUnits = this->createChildAlgorithm("ConvertUnits"); + convertUnits->initialize(); + convertUnits->setProperty("InputWorkspace", inputWS); + convertUnits->setProperty("Target", "MomentumTransfer"); + convertUnits->setProperty("AlignBins", false); + convertUnits->execute(); + MatrixWorkspace_sptr IvsQ = convertUnits->getProperty("OutputWorkspace"); + + return IvsQ; +} + +} // namespace Algorithms +} // namespace Mantid diff --git a/Framework/Algorithms/src/ReflectometryReductionOneAuto.cpp b/Framework/Algorithms/src/ReflectometryReductionOneAuto.cpp index ca95d270a211bff87c2741a947bbe2d0697d463e..9ee2cbc95904d1c90128e6c7fad94643196b3f79 100644 --- a/Framework/Algorithms/src/ReflectometryReductionOneAuto.cpp +++ b/Framework/Algorithms/src/ReflectometryReductionOneAuto.cpp @@ -365,7 +365,8 @@ void ReflectometryReductionOneAuto::exec() { // Pass the arguments and execute the main algorithm. - IAlgorithm_sptr refRedOne = createChildAlgorithm("ReflectometryReductionOne"); + IAlgorithm_sptr refRedOne = + createChildAlgorithm("ReflectometryReductionOne", -1, -1, true, 1); refRedOne->initialize(); if (refRedOne->isInitialized()) { refRedOne->setProperty("InputWorkspace", in_ws); diff --git a/Framework/Algorithms/src/ReflectometryReductionOneAuto2.cpp b/Framework/Algorithms/src/ReflectometryReductionOneAuto2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c4937ff9300c7867b01b863c0d2e85abc6ccbf54 --- /dev/null +++ b/Framework/Algorithms/src/ReflectometryReductionOneAuto2.cpp @@ -0,0 +1,780 @@ +#include "MantidAlgorithms/ReflectometryReductionOneAuto2.h" +#include "MantidAPI/MatrixWorkspace.h" +#include "MantidAPI/WorkspaceGroup.h" +#include "MantidAlgorithms/BoostOptionalToAlgorithmProperty.h" +#include "MantidKernel/ArrayProperty.h" +#include "MantidKernel/ListValidator.h" +#include "MantidKernel/make_unique.h" + +namespace Mantid { +namespace Algorithms { + +using namespace Mantid::API; +using namespace Mantid::Geometry; +using namespace Mantid::Kernel; + +// Register the algorithm into the AlgorithmFactory +DECLARE_ALGORITHM(ReflectometryReductionOneAuto2) + +//---------------------------------------------------------------------------------------------- + +/// Algorithm's name for identification. @see Algorithm::name +const std::string ReflectometryReductionOneAuto2::name() const { + return "ReflectometryReductionOneAuto"; +} + +/// Algorithm's version for identification. @see Algorithm::version +int ReflectometryReductionOneAuto2::version() const { return 2; } + +/// Algorithm's category for identification. @see Algorithm::category +const std::string ReflectometryReductionOneAuto2::category() const { + return "Reflectometry\\ISIS"; +} + +/// Algorithm's summary for use in the GUI and help. @see Algorithm::summary +const std::string ReflectometryReductionOneAuto2::summary() const { + return "Reduces a single TOF/Lambda reflectometry run into a mod Q vs I/I0 " + "workspace attempting to pick instrument parameters for missing " + "properties"; +} + +/** Validate transmission runs +* +* @return :: result of the validation as a map +*/ +std::map<std::string, std::string> +ReflectometryReductionOneAuto2::validateInputs() { + + std::map<std::string, std::string> results; + + // Validate transmission runs only if our input workspace is a group + if (!checkGroups()) + return results; + + auto group = AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>( + getPropertyValue("InputWorkspace")); + if (!group) + return results; + + // First transmission run + const std::string firstStr = getPropertyValue("FirstTransmissionRun"); + if (!firstStr.empty()) { + auto firstTransGroup = + AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(firstStr); + // If it is not a group, we don't need to validate its size + if (!firstTransGroup) + return results; + + const bool polarizationCorrections = + getPropertyValue("PolarizationAnalysis") != "None"; + + if (group->size() != firstTransGroup->size() && !polarizationCorrections) { + // If they are not the same size then we cannot associate a transmission + // group member with every input group member. + results["FirstTransmissionRun"] = + "FirstTransmissionRun group must be the " + "same size as the InputWorkspace group " + "when polarization analysis is 'None'."; + } + } + + // The same for the second transmission run + const std::string secondStr = getPropertyValue("SecondTransmissionRun"); + if (!secondStr.empty()) { + auto secondTransGroup = + AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(secondStr); + // If it is not a group, we don't need to validate its size + if (!secondTransGroup) + return results; + const bool polarizationCorrections = + getPropertyValue("PolarizationAnalysis") != "None"; + + if (group->size() != secondTransGroup->size() && !polarizationCorrections) { + results["SecondTransmissionRun"] = + "SecondTransmissionRun group must be the " + "same size as the InputWorkspace group " + "when polarization analysis is 'None'."; + } + } + + return results; +} + +/** Initialize the algorithm's properties. +*/ +void ReflectometryReductionOneAuto2::init() { + + // Input ws + declareProperty( + make_unique<WorkspaceProperty<MatrixWorkspace>>( + "InputWorkspace", "", Direction::Input, PropertyMode::Mandatory), + "Input run in TOF or wavelength"); + + // Analysis mode + const std::vector<std::string> analysisMode{"PointDetectorAnalysis", + "MultiDetectorAnalysis"}; + auto analysisModeValidator = + boost::make_shared<StringListValidator>(analysisMode); + declareProperty("AnalysisMode", analysisMode[0], analysisModeValidator, + "Analysis mode. This property is only used when " + "ProcessingInstructions is not set.", + Direction::Input); + + // Processing instructions + declareProperty(make_unique<PropertyWithValue<std::string>>( + "ProcessingInstructions", "", Direction::Input), + "Grouping pattern of workspace indices to yield only the" + " detectors of interest. See GroupDetectors for syntax."); + + // Theta + declareProperty("ThetaIn", Mantid::EMPTY_DBL(), "Angle in degrees", + Direction::Input); + + // Wavelength limits + declareProperty("WavelengthMin", Mantid::EMPTY_DBL(), + "Wavelength Min in angstroms", Direction::Input); + declareProperty("WavelengthMax", Mantid::EMPTY_DBL(), + "Wavelength Max in angstroms", Direction::Input); + + // Direct beam + initDirectBeamProperties(); + + // Monitor properties + initMonitorProperties(); + // Normalization by integrated monitors + declareProperty("NormalizeByIntegratedMonitors", true, + "Normalize by dividing by the integrated monitors."); + + // Init properties for transmission normalization + initTransmissionProperties(); + + // Init properties for algorithmic corrections + initAlgorithmicProperties(true); + + // Momentum transfer properties + initMomentumTransferProperties(); + + // Polarization correction + std::vector<std::string> propOptions = {"None", "PA", "PNR"}; + declareProperty("PolarizationAnalysis", "None", + boost::make_shared<StringListValidator>(propOptions), + "Polarization analysis mode."); + declareProperty( + Kernel::make_unique<ArrayProperty<double>>("CPp", Direction::Input), + "Effective polarizing power of the polarizing system. " + "Expressed as a ratio 0 < Pp < 1"); + declareProperty( + Kernel::make_unique<ArrayProperty<double>>("CAp", Direction::Input), + "Effective polarizing power of the analyzing system. " + "Expressed as a ratio 0 < Ap < 1"); + declareProperty( + Kernel::make_unique<ArrayProperty<double>>("CRho", Direction::Input), + "Ratio of efficiencies of polarizer spin-down to polarizer " + "spin-up. This is characteristic of the polarizer flipper. " + "Values are constants for each term in a polynomial " + "expression."); + declareProperty( + Kernel::make_unique<ArrayProperty<double>>("CAlpha", Direction::Input), + "Ratio of efficiencies of analyzer spin-down to analyzer " + "spin-up. This is characteristic of the analyzer flipper. " + "Values are factors for each term in a polynomial " + "expression."); + setPropertyGroup("PolarizationAnalysis", "Polarization Corrections"); + setPropertyGroup("CPp", "Polarization Corrections"); + setPropertyGroup("CAp", "Polarization Corrections"); + setPropertyGroup("CRho", "Polarization Corrections"); + setPropertyGroup("CAlpha", "Polarization Corrections"); + + // Output workspace in Q + declareProperty(make_unique<WorkspaceProperty<MatrixWorkspace>>( + "OutputWorkspaceBinned", "", Direction::Output), + "Output workspace in Q (rebinned workspace)"); + + // Output workspace in Q (unbinned) + declareProperty(make_unique<WorkspaceProperty<MatrixWorkspace>>( + "OutputWorkspace", "", Direction::Output), + "Output workspace in Q (native binning)"); + + // Output workspace in wavelength + declareProperty(make_unique<WorkspaceProperty<MatrixWorkspace>>( + "OutputWorkspaceWavelength", "", Direction::Output), + "Output workspace in wavelength"); +} + +/** Execute the algorithm. +*/ +void ReflectometryReductionOneAuto2::exec() { + + MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace"); + auto instrument = inputWS->getInstrument(); + + IAlgorithm_sptr alg = createChildAlgorithm("ReflectometryReductionOne"); + alg->initialize(); + + // Mandatory properties + + double wavMin = checkForMandatoryInstrumentDefault<double>( + this, "WavelengthMin", instrument, "LambdaMin"); + alg->setProperty("WavelengthMin", wavMin); + double wavMax = checkForMandatoryInstrumentDefault<double>( + this, "WavelengthMax", instrument, "LambdaMax"); + alg->setProperty("WavelengthMax", wavMax); + + const auto instructions = + populateProcessingInstructions(alg, instrument, inputWS); + + // Now that we know the detectors of interest, we can move them if necessary + // (i.e. if theta is given). If not, we calculate theta from the current + // detector positions + double theta; + if (!getPointerToProperty("ThetaIn")->isDefault()) { + theta = getProperty("ThetaIn"); + inputWS = correctDetectorPositions(instructions, inputWS); + } else { + // Calculate theta + theta = calculateTheta(instructions, inputWS); + } + + // Optional properties + + populateDirectBeamProperties(alg); + populateMonitorProperties(alg, instrument); + alg->setPropertyValue("NormalizeByIntegratedMonitors", + getPropertyValue("NormalizeByIntegratedMonitors")); + populateTransmissionProperties(alg, instrument); + + alg->setProperty("InputWorkspace", inputWS); + alg->execute(); + + MatrixWorkspace_sptr IvsLam = alg->getProperty("OutputWorkspaceWavelength"); + MatrixWorkspace_sptr IvsQ = alg->getProperty("OutputWorkspace"); + + std::vector<double> params; + MatrixWorkspace_sptr IvsQB = rebinAndScale(IvsQ, theta, params); + + setProperty("OutputWorkspaceWavelength", IvsLam); + setProperty("OutputWorkspace", IvsQ); + setProperty("OutputWorkspaceBinned", IvsQB); + + // Set other properties so they can be updated in the Reflectometry interface + setProperty("ThetaIn", theta); + if (!params.empty()) { + if (params.size() == 3) { + setProperty("MomentumTransferMin", params[0]); + setProperty("MomentumTransferStep", -params[1]); + setProperty("MomentumTransferMax", params[2]); + } else { + setProperty("MomentumTransferMin", IvsQ->x(0).front()); + setProperty("MomentumTransferMax", IvsQ->x(0).back()); + setProperty("MomentumTransferStep", -params[0]); + } + } + if (getPointerToProperty("ScaleFactor")->isDefault()) + setProperty("ScaleFactor", 1.0); +} + +/** Returns the detectors of interest, specified via processing instructions +* +* @param instructions :: processing instructions defining detectors of interest +* @param inputWS :: the input workspace +* @return :: the names of the detectors of interest +*/ +std::vector<std::string> ReflectometryReductionOneAuto2::getDetectorNames( + const std::string &instructions, MatrixWorkspace_sptr inputWS) { + + std::vector<std::string> wsIndices; + boost::split(wsIndices, instructions, boost::is_any_of(":,-")); + // vector of comopnents + std::vector<std::string> detectors; + + for (const auto wsIndex : wsIndices) { + + size_t index = boost::lexical_cast<size_t>(wsIndex); + + auto detector = inputWS->getDetector(index); + auto parent = detector->getParent(); + + if (parent) { + auto parentType = parent->type(); + auto detectorName = (parentType == "Instrument") ? detector->getName() + : parent->getName(); + detectors.push_back(detectorName); + } + } + return detectors; +} + +/** Correct an instrument component vertically. +* +* @param instructions :: processing instructions defining the detectors of +* interest +* @param inputWS :: the input workspace +* @return :: the corrected workspace +*/ +MatrixWorkspace_sptr ReflectometryReductionOneAuto2::correctDetectorPositions( + const std::string &instructions, MatrixWorkspace_sptr inputWS) { + + auto detectorsOfInterest = getDetectorNames(instructions, inputWS); + + // Detectors of interest may be empty. This happens for instance when we input + // a workspace that was previously reduced using this algorithm. In this case, + // we shouldn't correct the detector positions + if (detectorsOfInterest.empty()) + return inputWS; + + const std::set<std::string> detectorSet(detectorsOfInterest.begin(), + detectorsOfInterest.end()); + + const double theta = getProperty("ThetaIn"); + + MatrixWorkspace_sptr corrected = inputWS; + + for (const auto &detector : detectorSet) { + IAlgorithm_sptr alg = + createChildAlgorithm("SpecularReflectionPositionCorrect"); + alg->setProperty("InputWorkspace", corrected); + alg->setProperty("TwoTheta", theta * 2); + alg->setProperty("DetectorComponentName", detector); + alg->execute(); + corrected = alg->getProperty("OutputWorkspace"); + } + + return corrected; +} + +/** Calculate the theta value of the detector of interest specified via +* processing instructions +* +* @param instructions :: processing instructions defining the detectors of +* interest +* @param inputWS :: the input workspace +* @return :: the angle of the detector (only the first detector is considered) +*/ +double +ReflectometryReductionOneAuto2::calculateTheta(const std::string &instructions, + MatrixWorkspace_sptr inputWS) { + + const auto detectorsOfInterest = getDetectorNames(instructions, inputWS); + + // Detectors of interest may be empty. This happens for instance when we input + // a workspace that was previously reduced using this algorithm. In this case, + // we can't calculate theta + if (detectorsOfInterest.empty()) + return 0.0; + + IAlgorithm_sptr alg = + createChildAlgorithm("SpecularReflectionCalculateTheta"); + alg->setProperty("InputWorkspace", inputWS); + alg->setProperty("DetectorComponentName", detectorsOfInterest[0]); + alg->execute(); + const double theta = alg->getProperty("TwoTheta"); + // First factor 0.5 detector position, which isexpected to be at 2 * theta + // Second factor 0.5 comes from SpecularReflectionCalculateTheta, which + // outputs 2 * theta + return theta * 0.5 * 0.5; +} + +/** Set direct beam properties +* +* @param alg :: ReflectometryReductionOne algorithm +*/ +void ReflectometryReductionOneAuto2::populateDirectBeamProperties( + IAlgorithm_sptr alg) { + + alg->setPropertyValue("RegionOfDirectBeam", + getPropertyValue("RegionOfDirectBeam")); +} + +/** Set transmission properties +* +* @param alg :: ReflectometryReductionOne algorithm +* @param instrument :: the instrument attached to the workspace +*/ +void ReflectometryReductionOneAuto2::populateTransmissionProperties( + IAlgorithm_sptr alg, Instrument_const_sptr instrument) { + + // Transmission run(s) + + MatrixWorkspace_sptr firstWS = getProperty("FirstTransmissionRun"); + if (firstWS) { + alg->setProperty("FirstTransmissionRun", firstWS); + alg->setPropertyValue("StrictSpectrumChecking", + getPropertyValue("StrictSpectrumChecking")); + MatrixWorkspace_sptr secondWS = getProperty("SecondTransmissionRun"); + if (secondWS) { + alg->setProperty("SecondTransmissionRun", secondWS); + alg->setPropertyValue("StartOverlap", getPropertyValue("StartOverlap")); + alg->setPropertyValue("EndOverlap", getPropertyValue("EndOverlap")); + alg->setPropertyValue("Params", getPropertyValue("Params")); + } + return; + } + + // No transmission runs, try algorithmic corrections + // With algorithmic corrections, monitors should not be integrated, see below + + const std::string correctionAlgorithm = getProperty("CorrectionAlgorithm"); + + if (correctionAlgorithm == "PolynomialCorrection") { + alg->setProperty("NormalizeByIntegratedMonitors", false); + alg->setProperty("CorrectionAlgorithm", "PolynomialCorrection"); + alg->setPropertyValue("Polynomial", getPropertyValue("Polynomial")); + + } else if (correctionAlgorithm == "ExponentialCorrection") { + alg->setProperty("NormalizeByIntegratedMonitors", false); + alg->setProperty("CorrectionAlgorithm", "ExponentialCorrection"); + alg->setProperty("C0", getPropertyValue("C0")); + alg->setProperty("C1", getPropertyValue("C1")); + + } else if (correctionAlgorithm == "AutoDetect") { + // Figure out what to do from the instrument + try { + const auto corrVec = instrument->getStringParameter("correction"); + if (corrVec.empty()) { + throw std::runtime_error( + "Could not find parameter 'correction' in " + "parameter file. Cannot auto detect the type of " + "correction."); + } + + const std::string correctionStr = corrVec[0]; + + if (correctionStr == "polynomial") { + const auto polyVec = instrument->getStringParameter("polystring"); + if (polyVec.empty()) + throw std::runtime_error("Could not find parameter 'polystring' in " + "parameter file. Cannot apply polynomial " + "correction."); + alg->setProperty("CorrectionAlgorithm", "PolynomialCorrection"); + alg->setProperty("Polynomial", polyVec[0]); + } else if (correctionStr == "exponential") { + const auto c0Vec = instrument->getStringParameter("C0"); + if (c0Vec.empty()) + throw std::runtime_error( + "Could not find parameter 'C0' in parameter " + "file. Cannot apply exponential correction."); + const auto c1Vec = instrument->getStringParameter("C1"); + if (c1Vec.empty()) + throw std::runtime_error( + "Could not find parameter 'C1' in parameter " + "file. Cannot apply exponential correction."); + alg->setProperty("C0", c0Vec[0]); + alg->setProperty("C1", c1Vec[0]); + } + alg->setProperty("NormalizeByIntegratedMonitors", false); + } catch (std::runtime_error &e) { + g_log.error() << e.what() + << ". Polynomial correction will not be performed."; + alg->setProperty("CorrectionAlgorithm", "None"); + } + } else { + alg->setProperty("CorrectionAlgorithm", "None"); + } +} + +/** Rebin and scale a workspace in Q. +* +* @param inputWS :: the workspace in Q +* @param theta :: the angle of this run +* @param params :: [output] rebin parameters +* @return :: the output workspace +*/ +MatrixWorkspace_sptr +ReflectometryReductionOneAuto2::rebinAndScale(MatrixWorkspace_sptr inputWS, + const double theta, + std::vector<double> ¶ms) { + + Property *qStepProp = getProperty("MomentumTransferStep"); + double qstep; + if (!qStepProp->isDefault()) { + qstep = getProperty("MomentumTransferStep"); + qstep = -qstep; + } else { + if (theta == 0.0) { + throw std::runtime_error( + "Theta determined from the detector positions is " + "0.0. Please provide a value for theta manually " + "or correct the detector position before running " + "this algorithm."); + } + + IAlgorithm_sptr calcRes = createChildAlgorithm("CalculateResolution"); + calcRes->setProperty("Workspace", inputWS); + calcRes->setProperty("TwoTheta", 2 * theta); + calcRes->execute(); + + if (!calcRes->isExecuted()) { + g_log.error("CalculateResolution failed. Workspace in Q will not be " + "rebinned. Please provide dQ/Q."); + return inputWS; + } + qstep = calcRes->getProperty("Resolution"); + qstep = -qstep; + } + + Property *qMin = getProperty("MomentumTransferMin"); + Property *qMax = getProperty("MomentumTransferMax"); + if (!qMin->isDefault() && !qMax->isDefault()) { + double qmin = getProperty("MomentumTransferMin"); + double qmax = getProperty("MomentumTransferMax"); + params.push_back(qmin); + params.push_back(qstep); + params.push_back(qmax); + } else { + params.push_back(qstep); + } + + // Rebin + IAlgorithm_sptr algRebin = createChildAlgorithm("Rebin"); + algRebin->initialize(); + algRebin->setProperty("InputWorkspace", inputWS); + algRebin->setProperty("OutputWorkspace", inputWS); + algRebin->setProperty("Params", params); + algRebin->execute(); + MatrixWorkspace_sptr IvsQ = algRebin->getProperty("OutputWorkspace"); + + // Scale (optional) + Property *scaleProp = getProperty("ScaleFactor"); + if (!scaleProp->isDefault()) { + double scaleFactor = getProperty("ScaleFactor"); + IAlgorithm_sptr algScale = createChildAlgorithm("Scale"); + algScale->initialize(); + algScale->setProperty("InputWorkspace", IvsQ); + algScale->setProperty("OutputWorkspace", IvsQ); + algScale->setProperty("Factor", 1.0 / scaleFactor); + algScale->execute(); + IvsQ = algScale->getProperty("OutputWorkspace"); + } + + return IvsQ; +} + +/** Check if input workspace is a group +*/ +bool ReflectometryReductionOneAuto2::checkGroups() { + + const std::string wsName = getPropertyValue("InputWorkspace"); + + try { + auto ws = + AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(wsName); + if (ws) + return true; + } catch (...) { + } + return false; +} + +/** Process groups. Groups are processed differently depending on transmission + * runs and polarization analysis. If transmission run is a matrix workspace, it + * will be applied to each of the members in the input workspace group. If + * transmission run is a workspace group, the behaviour is different depending + * on polarization analysis. If polarization analysis is off (i.e. + * 'PolarizationAnalysis' is set to 'None') each item in the transmission group + * is associated with the corresponding item in the input workspace group. If + * polarization analysis is on (i.e. 'PolarizationAnalysis' is 'PA' or 'PNR') + * items in the transmission group will be summed to produce a matrix workspace + * that will be applied to each of the items in the input workspace group. See + * documentation of this algorithm for more details. +*/ +bool ReflectometryReductionOneAuto2::processGroups() { + // this algorithm effectively behaves as MultiPeriodGroupAlgorithm + m_usingBaseProcessGroups = true; + + // Get our input workspace group + auto group = AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>( + getPropertyValue("InputWorkspace")); + // Get name of IvsQ workspace (native binning) + const std::string outputIvsQ = getPropertyValue("OutputWorkspace"); + // Get name of IvsQ (native binning) workspace + const std::string outputIvsQBinned = + getPropertyValue("OutputWorkspaceBinned"); + // Get name of IvsLam workspace + const std::string outputIvsLam = + getPropertyValue("OutputWorkspaceWavelength"); + + // Create a copy of ourselves + Algorithm_sptr alg = + createChildAlgorithm(name(), -1, -1, isLogging(), version()); + alg->setChild(false); + alg->setRethrows(true); + + // Copy all the non-workspace properties over + const std::vector<Property *> props = getProperties(); + for (auto &prop : props) { + if (prop) { + IWorkspaceProperty *wsProp = dynamic_cast<IWorkspaceProperty *>(prop); + if (!wsProp) + alg->setPropertyValue(prop->name(), prop->value()); + } + } + + const bool polarizationAnalysisOn = + getPropertyValue("PolarizationAnalysis") != "None"; + + // Check if the transmission runs are groups or not + + const std::string firstTrans = getPropertyValue("FirstTransmissionRun"); + WorkspaceGroup_sptr firstTransG; + MatrixWorkspace_sptr firstTransSum; + if (!firstTrans.empty()) { + auto firstTransWS = + AnalysisDataService::Instance().retrieveWS<Workspace>(firstTrans); + firstTransG = boost::dynamic_pointer_cast<WorkspaceGroup>(firstTransWS); + if (!firstTransG) { + alg->setProperty("FirstTransmissionRun", firstTrans); + } else if (polarizationAnalysisOn) { + firstTransSum = sumTransmissionWorkspaces(firstTransG); + } + } + const std::string secondTrans = getPropertyValue("SecondTransmissionRun"); + WorkspaceGroup_sptr secondTransG; + MatrixWorkspace_sptr secondTransSum; + if (!secondTrans.empty()) { + auto secondTransWS = + AnalysisDataService::Instance().retrieveWS<Workspace>(secondTrans); + secondTransG = boost::dynamic_pointer_cast<WorkspaceGroup>(secondTransWS); + if (!secondTransG) { + alg->setProperty("SecondTransmissionRun", secondTrans); + } else if (polarizationAnalysisOn) { + secondTransSum = sumTransmissionWorkspaces(secondTransG); + } + } + + std::vector<std::string> IvsQGroup, IvsQUnbinnedGroup, IvsLamGroup; + + // Execute algorithm over each group member + for (size_t i = 0; i < group->size(); ++i) { + + const std::string IvsQName = outputIvsQ + "_" + std::to_string(i + 1); + const std::string IvsQBinnedName = + outputIvsQBinned + "_" + std::to_string(i + 1); + const std::string IvsLamName = outputIvsLam + "_" + std::to_string(i + 1); + + if (firstTransG) { + if (!polarizationAnalysisOn) + alg->setProperty("FirstTransmissionRun", + firstTransG->getItem(i)->getName()); + else + alg->setProperty("FirstTransmissionRun", firstTransSum); + } + if (secondTransG) { + if (!polarizationAnalysisOn) + alg->setProperty("SecondTransmissionRun", + secondTransG->getItem(i)->getName()); + else + alg->setProperty("SecondTransmissionRun", secondTransSum); + } + + alg->setProperty("InputWorkspace", group->getItem(i)->getName()); + alg->setProperty("OutputWorkspace", IvsQName); + alg->setProperty("OutputWorkspaceBinned", IvsQBinnedName); + alg->setProperty("OutputWorkspaceWavelength", IvsLamName); + alg->execute(); + + IvsQGroup.push_back(IvsQName); + IvsQUnbinnedGroup.push_back(IvsQBinnedName); + IvsLamGroup.push_back(IvsLamName); + } + + // Group the IvsQ and IvsLam workspaces + Algorithm_sptr groupAlg = createChildAlgorithm("GroupWorkspaces"); + groupAlg->setChild(false); + groupAlg->setRethrows(true); + groupAlg->setProperty("InputWorkspaces", IvsLamGroup); + groupAlg->setProperty("OutputWorkspace", outputIvsLam); + groupAlg->execute(); + groupAlg->setProperty("InputWorkspaces", IvsQGroup); + groupAlg->setProperty("OutputWorkspace", outputIvsQ); + groupAlg->execute(); + groupAlg->setProperty("InputWorkspaces", IvsQUnbinnedGroup); + groupAlg->setProperty("OutputWorkspace", outputIvsQBinned); + groupAlg->execute(); + + if (!polarizationAnalysisOn) { + // No polarization analysis. Reduction stops here + setPropertyValue("OutputWorkspace", outputIvsQ); + setPropertyValue("OutputWorkspaceBinned", outputIvsQBinned); + setPropertyValue("OutputWorkspaceWavelength", outputIvsLam); + return true; + } + + if (!group->isMultiperiod()) { + g_log.warning("Polarization corrections can only be performed on " + "multiperiod workspaces."); + setPropertyValue("OutputWorkspace", outputIvsQ); + setPropertyValue("OutputWorkspaceBinned", outputIvsQBinned); + setPropertyValue("OutputWorkspaceWavelength", outputIvsLam); + return true; + } + + Algorithm_sptr polAlg = createChildAlgorithm("PolarizationCorrection"); + polAlg->setChild(false); + polAlg->setRethrows(true); + polAlg->setProperty("InputWorkspace", outputIvsLam); + polAlg->setProperty("OutputWorkspace", outputIvsLam); + polAlg->setProperty("PolarizationAnalysis", + getPropertyValue("PolarizationAnalysis")); + polAlg->setProperty("CPp", getPropertyValue("CPp")); + polAlg->setProperty("CRho", getPropertyValue("CRho")); + polAlg->setProperty("CAp", getPropertyValue("CAp")); + polAlg->setProperty("CAlpha", getPropertyValue("CAlpha")); + polAlg->execute(); + + // Now we've overwritten the IvsLam workspaces, we'll need to recalculate + // the IvsQ ones + alg->setProperty("FirstTransmissionRun", ""); + alg->setProperty("SecondTransmissionRun", ""); + alg->setProperty("CorrectionAlgorithm", "None"); + alg->setProperty("ThetaIn", Mantid::EMPTY_DBL()); + alg->setProperty("ProcessingInstructions", "0"); + for (size_t i = 0; i < group->size(); ++i) { + const std::string IvsQName = outputIvsQ + "_" + std::to_string(i + 1); + const std::string IvsQBinnedName = + outputIvsQBinned + "_" + std::to_string(i + 1); + const std::string IvsLamName = outputIvsLam + "_" + std::to_string(i + 1); + alg->setProperty("InputWorkspace", IvsLamName); + alg->setProperty("OutputWorkspace", IvsQName); + alg->setProperty("OutputWorkspaceBinned", IvsQBinnedName); + alg->setProperty("OutputWorkspaceWavelength", IvsLamName); + alg->execute(); + } + + setPropertyValue("OutputWorkspace", outputIvsQ); + setPropertyValue("OutputWorkspaceBinned", outputIvsQBinned); + setPropertyValue("OutputWorkspaceWavelength", outputIvsLam); + return true; +} + +/** +* Sum transmission workspaces that belong to a workspace group +* @param transGroup : The transmission group containing the transmission runs +* @return :: A workspace pointer containing the sum of transmission workspaces +*/ +MatrixWorkspace_sptr ReflectometryReductionOneAuto2::sumTransmissionWorkspaces( + WorkspaceGroup_sptr &transGroup) { + + const std::string transSum = "trans_sum"; + Workspace_sptr sumWS = transGroup->getItem(0)->clone(); + + /// For this step to appear in the history of the output workspaces I need to + /// set child to false and work with the ADS + auto plusAlg = createChildAlgorithm("Plus"); + plusAlg->setChild(false); + plusAlg->initialize(); + + for (size_t item = 1; item < transGroup->size(); item++) { + plusAlg->setProperty("LHSWorkspace", sumWS); + plusAlg->setProperty("RHSWorkspace", transGroup->getItem(item)); + plusAlg->setProperty("OutputWorkspace", transSum); + plusAlg->execute(); + sumWS = AnalysisDataService::Instance().retrieve(transSum); + } + MatrixWorkspace_sptr result = + boost::dynamic_pointer_cast<MatrixWorkspace>(sumWS); + AnalysisDataService::Instance().remove(transSum); + return result; +} + +} // namespace Algorithms +} // namespace Mantid diff --git a/Framework/Algorithms/src/ReflectometryWorkflowBase2.cpp b/Framework/Algorithms/src/ReflectometryWorkflowBase2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..63bdf4748848a3af5c6fb16f08720284214b6869 --- /dev/null +++ b/Framework/Algorithms/src/ReflectometryWorkflowBase2.cpp @@ -0,0 +1,494 @@ +#include "MantidAlgorithms/BoostOptionalToAlgorithmProperty.h" +#include "MantidAlgorithms/ReflectometryWorkflowBase2.h" +#include "MantidAPI/Axis.h" +#include "MantidAPI/WorkspaceUnitValidator.h" +#include "MantidGeometry/Instrument.h" +#include "MantidKernel/ArrayProperty.h" +#include "MantidKernel/ListValidator.h" +#include "MantidKernel/RebinParamsValidator.h" +#include "MantidKernel/Unit.h" + +using namespace Mantid::API; +using namespace Mantid::Kernel; +using namespace Mantid::Geometry; + +namespace Mantid { +namespace Algorithms { + +/** Initialize properties related to direct beam normalization +*/ +void ReflectometryWorkflowBase2::initDirectBeamProperties() { + + declareProperty(make_unique<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."); +} + +/** Initialize properties related to monitors +*/ +void ReflectometryWorkflowBase2::initMonitorProperties() { + + // Monitor workspace index + declareProperty(make_unique<PropertyWithValue<int>>( + "I0MonitorIndex", Mantid::EMPTY_INT(), Direction::Input), + "I0 monitor workspace index"); + + // Minimum wavelength for background subtraction + declareProperty( + make_unique<PropertyWithValue<double>>("MonitorBackgroundWavelengthMin", + Mantid::EMPTY_DBL(), + Direction::Input), + "Wavelength minimum for monitor background subtraction in angstroms."); + // Maximum wavelength for background subtraction + declareProperty( + make_unique<PropertyWithValue<double>>("MonitorBackgroundWavelengthMax", + Mantid::EMPTY_DBL(), + Direction::Input), + "Wavelength maximum for monitor background subtraction in angstroms."); + + // Minimum wavelength for monitor integration + declareProperty(make_unique<PropertyWithValue<double>>( + "MonitorIntegrationWavelengthMin", Mantid::EMPTY_DBL(), + Direction::Input), + "Wavelength minimum for integration in angstroms."); + // Maximum wavelength for monitor integration + declareProperty(make_unique<PropertyWithValue<double>>( + "MonitorIntegrationWavelengthMax", Mantid::EMPTY_DBL(), + Direction::Input), + "Wavelength maximum for integration in angstroms."); +} + +/** Initialize properties related to transmission normalization +*/ +void ReflectometryWorkflowBase2::initTransmissionProperties() { + + declareProperty( + make_unique<WorkspaceProperty<MatrixWorkspace>>( + "FirstTransmissionRun", "", Direction::Input, PropertyMode::Optional), + "First transmission run, or the low wavelength transmission run if " + "SecondTransmissionRun is also provided."); + + auto inputValidator = boost::make_shared<WorkspaceUnitValidator>("TOF"); + declareProperty(make_unique<WorkspaceProperty<MatrixWorkspace>>( + "SecondTransmissionRun", "", Direction::Input, + PropertyMode::Optional, inputValidator), + "Second, high wavelength transmission run. Optional. Causes " + "the FirstTransmissionRun to be treated as the low " + "wavelength transmission run."); + + initStitchProperties(); + + declareProperty(make_unique<PropertyWithValue<bool>>("StrictSpectrumChecking", + true, Direction::Input), + "Enforces spectrum number checking prior to normalization by " + "transmission workspace. Applies to input workspace and " + "transmission workspace."); + + setPropertyGroup("FirstTransmissionRun", "Transmission"); + setPropertyGroup("SecondTransmissionRun", "Transmission"); + setPropertyGroup("Params", "Transmission"); + setPropertyGroup("StartOverlap", "Transmission"); + setPropertyGroup("EndOverlap", "Transmission"); + setPropertyGroup("StrictSpectrumChecking", "Transmission"); +} + +/** Initialize properties used for stitching transmission runs +*/ +void ReflectometryWorkflowBase2::initStitchProperties() { + + declareProperty( + make_unique<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(make_unique<PropertyWithValue<double>>( + "StartOverlap", Mantid::EMPTY_DBL(), Direction::Input), + "Start wavelength for stitching transmission runs together. " + "Only used if a second transmission run is provided."); + + declareProperty(make_unique<PropertyWithValue<double>>( + "EndOverlap", Mantid::EMPTY_DBL(), Direction::Input), + "End wavelength (angstroms) for stitching transmission runs " + "together. Only used if a second transmission run is " + "provided."); +} + +/** Initialize algorithmic correction properties +* +* @param autoDetect :: True to include 'AutoDetect' option. False otherwise. +*/ +void ReflectometryWorkflowBase2::initAlgorithmicProperties(bool autoDetect) { + + std::vector<std::string> correctionAlgorithms = { + "None", "PolynomialCorrection", "ExponentialCorrection"}; + std::string defaultCorrection = "None"; + + if (autoDetect) { + correctionAlgorithms.insert(correctionAlgorithms.begin() + 1, "AutoDetect"); + defaultCorrection = "AutoDetect"; + } + + declareProperty("CorrectionAlgorithm", defaultCorrection, + boost::make_shared<StringListValidator>(correctionAlgorithms), + "The type of correction to perform."); + + declareProperty(make_unique<ArrayProperty<double>>("Polynomial"), + "Coefficients to be passed to the PolynomialCorrection" + " algorithm."); + + declareProperty( + make_unique<PropertyWithValue<double>>("C0", 0.0, Direction::Input), + "C0 value to be passed to the ExponentialCorrection algorithm."); + + declareProperty( + make_unique<PropertyWithValue<double>>("C1", 0.0, Direction::Input), + "C1 value to be passed to the ExponentialCorrection algorithm."); + + setPropertyGroup("CorrectionAlgorithm", "Polynomial Corrections"); + setPropertyGroup("Polynomial", "Polynomial Corrections"); + setPropertyGroup("C0", "Polynomial Corrections"); + setPropertyGroup("C1", "Polynomial Corrections"); +} + +/** Initialize momentum transfer properties +*/ +void ReflectometryWorkflowBase2::initMomentumTransferProperties() { + + declareProperty("MomentumTransferMin", Mantid::EMPTY_DBL(), + "Minimum Q value in IvsQ " + "Workspace. Used for Rebinning " + "the IvsQ Workspace", + Direction::Input); + declareProperty("MomentumTransferStep", Mantid::EMPTY_DBL(), + "Resolution value in IvsQ Workspace. Used for Rebinning the " + "IvsQ Workspace. This value will be made minus to apply " + "logarithmic rebinning. If you wish to have linear " + "bin-widths then please provide a negative value.", + Direction::Input); + declareProperty("MomentumTransferMax", Mantid::EMPTY_DBL(), + "Maximum Q value in IvsQ " + "Workspace. Used for Rebinning " + "the IvsQ Workspace", + Direction::Input); + declareProperty("ScaleFactor", Mantid::EMPTY_DBL(), + "Factor you wish to scale Q workspace by.", Direction::Input); +} + +/** Validate direct beam if given +* +* @return :: A map with results of validation +*/ +std::map<std::string, std::string> +ReflectometryWorkflowBase2::validateDirectBeamProperties() const { + + std::map<std::string, std::string> results; + + // Validate direct beam if given + Property *directBeamProperty = getProperty("RegionOfDirectBeam"); + if (!directBeamProperty->isDefault()) { + + const std::vector<int> directBeamRegion = getProperty("RegionOfDirectBeam"); + if (directBeamRegion.size() != 2) { + results["RegionOfDirectBeam"] = + "RegionOfDirect beam requires a lower and upper boundary"; + } + if (directBeamRegion[0] > directBeamRegion[1]) { + results["RegionOfDirectBeam"] = + "First index must be less or equal than max index"; + } + } + + return results; +} + +/** Validate transmission runs if given +* +* @return :: A map with results of validation +*/ +std::map<std::string, std::string> +ReflectometryWorkflowBase2::validateTransmissionProperties() const { + + std::map<std::string, std::string> results; + + MatrixWorkspace_sptr firstTransmissionRun = + getProperty("FirstTransmissionRun"); + if (firstTransmissionRun) { + const auto xUnitFirst = firstTransmissionRun->getAxis(0)->unit()->unitID(); + if (xUnitFirst != "TOF" && xUnitFirst != "Wavelength") { + results["FirstTransmissionRun"] = + "First transmission run must be in TOF or wavelength"; + } + MatrixWorkspace_sptr secondTransmissionRun = + getProperty("SecondTransmissionRun"); + if (secondTransmissionRun) { + const auto xUnitSecond = + secondTransmissionRun->getAxis(0)->unit()->unitID(); + if (xUnitSecond != "TOF") + results["SecondTransmissionRun"] = + "Second transmission run must be in TOF"; + if (xUnitFirst != "TOF") + results["FirstTransmissionRun"] = "When a second transmission run is " + "given, first transmission run must " + "be in TOF"; + } + } + + return results; +} + +/** Validate various wavelength ranges +* +* @return :: A map with results of validation +*/ +std::map<std::string, std::string> +ReflectometryWorkflowBase2::validateWavelengthRanges() const { + + std::map<std::string, std::string> results; + + // Validate wavelength range + double wavMin = getProperty("WavelengthMin"); + double wavMax = getProperty("WavelengthMax"); + if (wavMin > wavMax) + results["WavelengthMin"] = + "WavelengthMax must be greater than WavelengthMin"; + + // Validate monitor background range + double monMin = getProperty("MonitorBackgroundWavelengthMin"); + double monMax = getProperty("MonitorBackgroundWavelengthMax"); + if (monMin > monMax) + results["MonitorBackgroundWavelengthMin"] = + "MonitorBackgroundWavelengthMax must be greater than " + "MonitorBackgroundWavelengthMin"; + + // Validate monitor integration range + double monIntMin = getProperty("MonitorIntegrationWavelengthMin"); + double monIntMax = getProperty("MonitorIntegrationWavelengthMax"); + if (monIntMin > monIntMax) + results["MonitorIntegrationWavelengthMax"] = + "MonitorIntegrationWavelengthMax must be greater than " + "MonitorIntegrationWavelengthMin"; + + return results; +} + +/** Converts an input workspace in TOF to wavelength +* @param inputWS :: the workspace to convert +* @return :: the workspace in wavelength +*/ +MatrixWorkspace_sptr +ReflectometryWorkflowBase2::convertToWavelength(MatrixWorkspace_sptr inputWS) { + + auto convertUnitsAlg = createChildAlgorithm("ConvertUnits"); + convertUnitsAlg->initialize(); + convertUnitsAlg->setProperty("InputWorkspace", inputWS); + convertUnitsAlg->setProperty("Target", "Wavelength"); + convertUnitsAlg->setProperty("AlignBins", true); + convertUnitsAlg->execute(); + MatrixWorkspace_sptr outputWS = + convertUnitsAlg->getProperty("OutputWorkspace"); + + return outputWS; +} + +/** Crops a workspace in wavelength to specified limits +* @param inputWS :: the workspace to crop +* @return :: the cropped workspace +*/ +MatrixWorkspace_sptr +ReflectometryWorkflowBase2::cropWavelength(MatrixWorkspace_sptr inputWS) { + + // Crop out the lambda x-ranges now that the workspace is in wavelength. + double wavelengthMin = getProperty("WavelengthMin"); + double wavelengthMax = getProperty("WavelengthMax"); + + auto cropWorkspaceAlg = createChildAlgorithm("CropWorkspace"); + cropWorkspaceAlg->initialize(); + cropWorkspaceAlg->setProperty("InputWorkspace", inputWS); + cropWorkspaceAlg->setProperty("XMin", wavelengthMin); + cropWorkspaceAlg->setProperty("XMax", wavelengthMax); + cropWorkspaceAlg->execute(); + MatrixWorkspace_sptr outputWS = + cropWorkspaceAlg->getProperty("OutputWorkspace"); + + return outputWS; +} + +/** Process an input workspace according to specified processing commands to get +* a detector workspace. +* @param inputWS :: the input workspace in wavelength +* @return :: the detector workspace +*/ +MatrixWorkspace_sptr +ReflectometryWorkflowBase2::makeDetectorWS(MatrixWorkspace_sptr inputWS) { + + const std::string processingCommands = + getPropertyValue("ProcessingInstructions"); + auto groupAlg = createChildAlgorithm("GroupDetectors"); + groupAlg->initialize(); + groupAlg->setProperty("GroupingPattern", processingCommands); + groupAlg->setProperty("InputWorkspace", inputWS); + groupAlg->execute(); + MatrixWorkspace_sptr detectorWS = groupAlg->getProperty("OutputWorkspace"); + + return detectorWS; +} + +/** Creates a monitor workspace. This method should only be called if +* IOMonitorIndex has been specified and MonitorBackgroundWavelengthMin and +* MonitorBackgroundWavelengthMax have been given. +* @param inputWS :: the input workspace in wavelength +* @param integratedMonitors :: boolean to indicate if monitors should be +* integrated +* @return :: the monitor workspace +*/ +MatrixWorkspace_sptr +ReflectometryWorkflowBase2::makeMonitorWS(MatrixWorkspace_sptr inputWS, + const bool integratedMonitors) { + + // Extract the monitor workspace + const int monitorIndex = getProperty("I0MonitorIndex"); + auto cropWorkspaceAlg = createChildAlgorithm("CropWorkspace"); + cropWorkspaceAlg->initialize(); + cropWorkspaceAlg->setProperty("InputWorkspace", inputWS); + cropWorkspaceAlg->setProperty("StartWorkspaceIndex", monitorIndex); + cropWorkspaceAlg->setProperty("EndWorkspaceIndex", monitorIndex); + cropWorkspaceAlg->execute(); + MatrixWorkspace_sptr monitorWS = + cropWorkspaceAlg->getProperty("OutputWorkspace"); + + // Flat background correction + const double backgroundMin = getProperty("MonitorBackgroundWavelengthMin"); + const double backgroundMax = getProperty("MonitorBackgroundWavelengthMax"); + auto correctMonitorsAlg = createChildAlgorithm("CalculateFlatBackground"); + correctMonitorsAlg->initialize(); + correctMonitorsAlg->setProperty("InputWorkspace", monitorWS); + correctMonitorsAlg->setProperty("StartX", backgroundMin); + correctMonitorsAlg->setProperty("EndX", backgroundMax); + correctMonitorsAlg->setProperty("SkipMonitors", false); + correctMonitorsAlg->execute(); + monitorWS = correctMonitorsAlg->getProperty("OutputWorkspace"); + + // Normalization by integrated monitors ? + if (!integratedMonitors) { + return monitorWS; + } + + auto integrationAlg = createChildAlgorithm("Integration"); + integrationAlg->initialize(); + integrationAlg->setProperty("InputWorkspace", monitorWS); + + Property *integrationMinProperty = + getProperty("MonitorIntegrationWavelengthMin"); + if (!integrationMinProperty->isDefault()) { + integrationAlg->setProperty("RangeLower", integrationMinProperty->value()); + } + + Property *integrationMaxProperty = + getProperty("MonitorIntegrationWavelengthMax"); + if (!integrationMaxProperty->isDefault()) { + integrationAlg->setProperty("RangeUpper", integrationMaxProperty->value()); + } + integrationAlg->execute(); + MatrixWorkspace_sptr integratedMonitor = + integrationAlg->getProperty("OutputWorkspace"); + + return integratedMonitor; +} + +/** Set monitor properties +* +* @param alg :: ReflectometryReductionOne algorithm +* @param instrument :: the instrument attached to the workspace +*/ +void ReflectometryWorkflowBase2::populateMonitorProperties( + IAlgorithm_sptr alg, Instrument_const_sptr instrument) { + + const auto monitorIndex = checkForOptionalInstrumentDefault<int>( + this, "I0MonitorIndex", instrument, "I0MonitorIndex"); + if (monitorIndex.is_initialized()) + alg->setProperty("I0MonitorIndex", monitorIndex.get()); + const auto backgroundMin = checkForOptionalInstrumentDefault<double>( + this, "MonitorBackgroundWavelengthMin", instrument, + "MonitorBackgroundMin"); + if (backgroundMin.is_initialized()) + alg->setProperty("MonitorBackgroundWavelengthMin", backgroundMin.get()); + const auto backgroundMax = checkForOptionalInstrumentDefault<double>( + this, "MonitorBackgroundWavelengthMax", instrument, + "MonitorBackgroundMax"); + if (backgroundMax.is_initialized()) + alg->setProperty("MonitorBackgroundWavelengthMax", backgroundMax.get()); + const auto integrationMin = checkForOptionalInstrumentDefault<double>( + this, "MonitorIntegrationWavelengthMin", instrument, + "MonitorIntegralMin"); + if (integrationMin.is_initialized()) + alg->setProperty("MonitorIntegrationWavelengthMin", integrationMin.get()); + const auto integrationMax = checkForOptionalInstrumentDefault<double>( + this, "MonitorIntegrationWavelengthMax", instrument, + "MonitorIntegralMax"); + if (integrationMax.is_initialized()) + alg->setProperty("MonitorIntegrationWavelengthMax", integrationMax.get()); +} + +/** Set processing instructions +* +* @param alg :: ReflectometryReductionOne algorithm +* @param instrument :: the instrument attached to the workspace +* @param inputWS :: the input workspace +* @return :: processing instructions as a string +*/ +std::string ReflectometryWorkflowBase2::populateProcessingInstructions( + IAlgorithm_sptr alg, Instrument_const_sptr instrument, + MatrixWorkspace_sptr inputWS) const { + + if (!getPointerToProperty("ProcessingInstructions")->isDefault()) { + const std::string instructions = getProperty("ProcessingInstructions"); + alg->setProperty("ProcessingInstructions", instructions); + return instructions; + } + + const std::string analysisMode = getProperty("AnalysisMode"); + + if (analysisMode == "PointDetectorAnalysis") { + const std::vector<double> pointStart = + instrument->getNumberParameter("PointDetectorStart"); + const std::vector<double> pointStop = + instrument->getNumberParameter("PointDetectorStop"); + + if (pointStart.empty() || pointStop.empty()) + throw std::runtime_error("Could not find 'PointDetectorStart' and/or " + "'PointDetectorStop' in parameter file. Please " + "provide processing instructions manually or " + "set analysis mode to 'MultiDetectorAnalysis'."); + + const int detStart = static_cast<int>(pointStart[0]); + const int detStop = static_cast<int>(pointStop[0]); + + auto instructions = std::to_string(detStart); + if (detStart != detStop) + instructions += ":" + std::to_string(detStop); + alg->setProperty("ProcessingInstructions", instructions); + return instructions; + } + + else { + const std::vector<double> multiStart = + instrument->getNumberParameter("MultiDetectorStart"); + if (multiStart.empty()) + throw std::runtime_error("Could not find 'MultiDetectorStart in " + "parameter file. Please provide processing " + "instructions manually or set analysis mode to " + "'PointDetectorAnalysis'."); + + auto instructions = std::to_string(static_cast<int>(multiStart[0])) + ":" + + std::to_string(inputWS->getNumberHistograms() - 1); + alg->setProperty("ProcessingInstructions", instructions); + return instructions; + } +} + +} // namespace Algorithms +} // namespace Mantid diff --git a/Framework/Algorithms/src/SpecularReflectionPositionCorrect2.cpp b/Framework/Algorithms/src/SpecularReflectionPositionCorrect2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c45b91c16a5d11ed0481be66c8f2e467bad7b0e7 --- /dev/null +++ b/Framework/Algorithms/src/SpecularReflectionPositionCorrect2.cpp @@ -0,0 +1,135 @@ +#include "MantidAlgorithms/SpecularReflectionPositionCorrect2.h" +#include "MantidAPI/MatrixWorkspace.h" +#include "MantidGeometry/Instrument.h" +#include "MantidGeometry/Instrument/ReferenceFrame.h" +#include "MantidKernel/BoundedValidator.h" +#include "MantidKernel/CompositeValidator.h" +#include "MantidKernel/MandatoryValidator.h" + +using namespace Mantid::API; +using namespace Mantid::Geometry; +using namespace Mantid::Kernel; + +namespace Mantid { +namespace Algorithms { + +// Register the algorithm into the AlgorithmFactory +DECLARE_ALGORITHM(SpecularReflectionPositionCorrect2) + +//---------------------------------------------------------------------------------------------- +/// Algorithm's name for identification. @see Algorithm::name +const std::string SpecularReflectionPositionCorrect2::name() const { + return "SpecularReflectionPositionCorrect"; +} + +/// Algorithm's summary. @see Algorithm::summary +const std::string SpecularReflectionPositionCorrect2::summary() const { + return "Corrects a detector component vertically based on TwoTheta."; +} + +/// Algorithm's version for identification. @see Algorithm::version +int SpecularReflectionPositionCorrect2::version() const { return 2; } + +/// Algorithm's category for identification. @see Algorithm::category +const std::string SpecularReflectionPositionCorrect2::category() const { + return "Reflectometry"; +} + +//---------------------------------------------------------------------------------------------- + +//---------------------------------------------------------------------------------------------- +/** Initialize the algorithm's properties. +*/ +void SpecularReflectionPositionCorrect2::init() { + + declareProperty(make_unique<WorkspaceProperty<MatrixWorkspace>>( + "InputWorkspace", "", Direction::Input), + "An input workspace to correct."); + + auto thetaValidator = boost::make_shared<CompositeValidator>(); + thetaValidator->add(boost::make_shared<MandatoryValidator<double>>()); + thetaValidator->add( + boost::make_shared<BoundedValidator<double>>(0, 90, true)); + declareProperty( + make_unique<PropertyWithValue<double>>("TwoTheta", Mantid::EMPTY_DBL(), + thetaValidator, Direction::Input), + "Angle used to correct the detector component."); + + declareProperty( + Mantid::Kernel::make_unique<PropertyWithValue<std::string>>( + "DetectorComponentName", "", + boost::make_shared<MandatoryValidator<std::string>>(), + Direction::Input), + "Name of the detector component to correct, i.e. point-detector"); + + declareProperty( + Mantid::Kernel::make_unique<PropertyWithValue<std::string>>( + "SampleComponentName", "some-surface-holder", Direction::Input), + "Name of the sample component, i.e. some-surface-holder"); + + declareProperty( + Mantid::Kernel::make_unique<WorkspaceProperty<MatrixWorkspace>>( + "OutputWorkspace", "", Direction::Output), + "An output workspace."); +} + +//---------------------------------------------------------------------------------------------- +/** Execute the algorithm. +*/ +void SpecularReflectionPositionCorrect2::exec() { + + MatrixWorkspace_sptr inWS = this->getProperty("InputWorkspace"); + + auto cloneWS = createChildAlgorithm("CloneWorkspace"); + cloneWS->initialize(); + cloneWS->setProperty("InputWorkspace", inWS); + cloneWS->execute(); + Workspace_sptr tmp = cloneWS->getProperty("OutputWorkspace"); + MatrixWorkspace_sptr outWS = + boost::dynamic_pointer_cast<MatrixWorkspace>(tmp); + + const double twoThetaIn = getProperty("TwoTheta"); + const double twoThetaInRad = twoThetaIn * (M_PI / 180.0); + + auto inst = outWS->getInstrument(); + + // Detector + const std::string detectorName = getProperty("DetectorComponentName"); + IComponent_const_sptr detector = inst->getComponentByName(detectorName); + const V3D detectorPosition = detector->getPos(); + + // Sample + const std::string sampleName = getProperty("SampleComponentName"); + IComponent_const_sptr sample = inst->getComponentByName(sampleName); + const V3D samplePosition = sample->getPos(); + + // Sample-to-detector + const V3D sampleToDetector = detectorPosition - samplePosition; + // Reference frame + auto referenceFrame = inst->getReferenceFrame(); + auto beamAxis = referenceFrame->pointingAlongBeamAxis(); + auto horizontalAxis = referenceFrame->pointingHorizontalAxis(); + auto upAxis = referenceFrame->pointingUpAxis(); + + // We just recalculate beam offset. + const double beamOffset = + sampleToDetector.scalar_prod(referenceFrame->vecPointingAlongBeam()); + // We only correct vertical position + const double upOffset = (beamOffset * std::tan(twoThetaInRad)); + + auto moveAlg = createChildAlgorithm("MoveInstrumentComponent"); + moveAlg->initialize(); + moveAlg->setProperty("Workspace", outWS); + moveAlg->setProperty("ComponentName", detectorName); + moveAlg->setProperty("RelativePosition", false); + moveAlg->setProperty(beamAxis, detectorPosition.scalar_prod( + referenceFrame->vecPointingAlongBeam())); + moveAlg->setProperty(horizontalAxis, 0.0); + moveAlg->setProperty(upAxis, upOffset); + moveAlg->execute(); + + setProperty("OutputWorkspace", outWS); +} + +} // namespace Algorithms +} // namespace Mantid diff --git a/Framework/Algorithms/test/CreateTransmissionWorkspace2Test.h b/Framework/Algorithms/test/CreateTransmissionWorkspace2Test.h new file mode 100644 index 0000000000000000000000000000000000000000..21dd30ea9faa08106584ab1835a803f88595ef1e --- /dev/null +++ b/Framework/Algorithms/test/CreateTransmissionWorkspace2Test.h @@ -0,0 +1,315 @@ +#ifndef ALGORITHMS_TEST_CREATETRANSMISSIONWORKSPACE2TEST_H_ +#define ALGORITHMS_TEST_CREATETRANSMISSIONWORKSPACE2TEST_H_ + +#include <cxxtest/TestSuite.h> +#include "MantidAlgorithms/CreateTransmissionWorkspace2.h" +#include "MantidAPI/Axis.h" +#include "MantidAPI/FrameworkManager.h" +#include "MantidAPI/MatrixWorkspace.h" +#include "MantidKernel/Unit.h" +#include "MantidTestHelpers/WorkspaceCreationHelper.h" +#include <algorithm> + +using namespace Mantid; +using namespace Mantid::Kernel; +using namespace Mantid::API; +using namespace Mantid::Algorithms; +using namespace WorkspaceCreationHelper; + +class CreateTransmissionWorkspace2Test : public CxxTest::TestSuite { +private: + MatrixWorkspace_sptr m_multiDetectorWS; + MatrixWorkspace_sptr m_wavelengthWS; + +public: + // This pair of boilerplate methods prevent the suite being created statically + // This means the constructor isn't called when running other tests + static CreateTransmissionWorkspace2Test *createSuite() { + return new CreateTransmissionWorkspace2Test(); + } + static void destroySuite(CreateTransmissionWorkspace2Test *suite) { + delete suite; + } + + CreateTransmissionWorkspace2Test() { + FrameworkManager::Instance(); + // A multi detector ws + m_multiDetectorWS = + create2DWorkspaceWithReflectometryInstrumentMultiDetector(); + // A workspace in wavelength + m_wavelengthWS = + create2DWorkspaceWithReflectometryInstrumentMultiDetector(); + m_wavelengthWS->getAxis(0)->setUnit("Wavelength"); + } + + void test_execute() { + CreateTransmissionWorkspace2 alg; + alg.initialize(); + alg.setChild(true); + alg.setProperty("FirstTransmissionRun", m_multiDetectorWS); + alg.setProperty("ProcessingInstructions", "1"); + alg.setProperty("WavelengthMin", 1.5); + alg.setProperty("WavelengthMax", 15.0); + alg.setPropertyValue("OutputWorkspace", "outWS"); + TS_ASSERT_THROWS_NOTHING(alg.execute()); + } + + void test_trans_run_in_wavelength_throws() { + + CreateTransmissionWorkspace2 alg; + alg.setChild(true); + alg.initialize(); + TS_ASSERT_THROWS_ANYTHING( + alg.setProperty("FirstTransmissionRun", m_wavelengthWS)); + TS_ASSERT_THROWS_ANYTHING( + alg.setProperty("SecondTransmissionRun", m_wavelengthWS)); + } + + void test_wavelength_min_is_mandatory() { + + CreateTransmissionWorkspace2 alg; + alg.initialize(); + alg.setChild(true); + alg.setProperty("FirstTransmissionRun", m_multiDetectorWS); + alg.setProperty("ProcessingInstructions", "1"); + alg.setProperty("WavelengthMax", 15.0); + alg.setPropertyValue("OutputWorkspace", "outWS"); + TS_ASSERT_THROWS_ANYTHING(alg.execute()); + } + + void test_wavelength_max_is_mandatory() { + + CreateTransmissionWorkspace2 alg; + alg.initialize(); + alg.setChild(true); + alg.setProperty("FirstTransmissionRun", m_multiDetectorWS); + alg.setProperty("ProcessingInstructions", "1"); + alg.setProperty("WavelengthMin", 1.5); + alg.setPropertyValue("OutputWorkspace", "outWS"); + TS_ASSERT_THROWS_ANYTHING(alg.execute()); + } + + void test_processing_instructions_is_mandatory() { + + CreateTransmissionWorkspace2 alg; + alg.initialize(); + alg.setChild(true); + alg.setProperty("FirstTransmissionRun", m_multiDetectorWS); + alg.setProperty("WavelengthMin", 1.5); + alg.setProperty("WavelengthMax", 15.0); + alg.setPropertyValue("OutputWorkspace", "outWS"); + TS_ASSERT_THROWS_ANYTHING(alg.execute()); + } + + void test_bad_wavelength_range() { + + CreateTransmissionWorkspace2 alg; + alg.initialize(); + alg.setChild(true); + alg.setProperty("FirstTransmissionRun", m_multiDetectorWS); + alg.setProperty("ProcessingInstructions", "1"); + alg.setProperty("WavelengthMin", 15.0); + alg.setProperty("WavelengthMax", 1.5); + alg.setPropertyValue("OutputWorkspace", "outWS"); + TS_ASSERT_THROWS_ANYTHING(alg.execute()); + } + + void test_bad_monitor_range() { + + CreateTransmissionWorkspace2 alg; + alg.initialize(); + alg.setChild(true); + alg.setProperty("FirstTransmissionRun", m_multiDetectorWS); + alg.setProperty("ProcessingInstructions", "1"); + alg.setProperty("WavelengthMin", 1.5); + alg.setProperty("WavelengthMax", 15.0); + alg.setProperty("MonitorBackgroundWavelengthMin", 15.0); + alg.setProperty("MonitorBackgroundWavelengthMax", 10.0); + alg.setPropertyValue("OutputWorkspace", "outWS"); + TS_ASSERT_THROWS_ANYTHING(alg.execute()); + } + + void test_bad_monitor_integration_range() { + + CreateTransmissionWorkspace2 alg; + alg.initialize(); + alg.setChild(true); + alg.setProperty("FirstTransmissionRun", m_multiDetectorWS); + alg.setProperty("ProcessingInstructions", "1"); + alg.setProperty("WavelengthMin", 1.5); + alg.setProperty("WavelengthMax", 15.0); + alg.setProperty("MonitorIntegrationWavelengthMin", 1.0); + alg.setProperty("MonitorIntegrationWavelengthMax", 0.0); + alg.setPropertyValue("OutputWorkspace", "outWS"); + TS_ASSERT_THROWS_ANYTHING(alg.execute()); + } + + void test_one_tranmission_run() { + + CreateTransmissionWorkspace2 alg; + alg.setChild(true); + alg.initialize(); + alg.setProperty("FirstTransmissionRun", m_multiDetectorWS); + alg.setProperty("WavelengthMin", 1.5); + alg.setProperty("WavelengthMax", 15.0); + alg.setPropertyValue("ProcessingInstructions", "1"); + alg.setPropertyValue("OutputWorkspace", "outWS"); + alg.execute(); + MatrixWorkspace_sptr outLam = alg.getProperty("OutputWorkspace"); + + TS_ASSERT(outLam); + TS_ASSERT_EQUALS("Wavelength", outLam->getAxis(0)->unit()->unitID()); + TS_ASSERT_EQUALS(outLam->getNumberHistograms(), 1); + TS_ASSERT_EQUALS(outLam->blocksize(), 8); + TS_ASSERT(outLam->x(0)[0] >= 1.5); + TS_ASSERT(outLam->x(0)[7] <= 15.0); + TS_ASSERT_DELTA(outLam->y(0)[0], 3.1530, 0.0001); + TS_ASSERT_DELTA(outLam->y(0)[7], 3.1530, 0.0001); + } + + void test_one_run_processing_instructions() { + + CreateTransmissionWorkspace2 alg; + alg.setChild(true); + alg.initialize(); + alg.setProperty("FirstTransmissionRun", m_multiDetectorWS); + alg.setProperty("WavelengthMin", 1.5); + alg.setProperty("WavelengthMax", 15.0); + alg.setPropertyValue("ProcessingInstructions", "1+2"); + alg.setPropertyValue("OutputWorkspace", "outWS"); + alg.execute(); + MatrixWorkspace_sptr outLam = alg.getProperty("OutputWorkspace"); + + TS_ASSERT(outLam); + TS_ASSERT_EQUALS("Wavelength", outLam->getAxis(0)->unit()->unitID()); + TS_ASSERT_EQUALS(outLam->getNumberHistograms(), 1); + TS_ASSERT_EQUALS(outLam->blocksize(), 8); + TS_ASSERT(outLam->x(0)[0] >= 1.5); + TS_ASSERT(outLam->x(0)[7] <= 15.0); + // Y counts, should be 3.1530 * 2 + TS_ASSERT_DELTA(outLam->y(0)[0], 6.3060, 0.0001); + TS_ASSERT_DELTA(outLam->y(0)[7], 6.3060, 0.0001); + } + + void test_one_run_monitor_normalization() { + // I0MonitorIndex: 0 + // MonitorBackgroundWavelengthMin : 0.5 + // MonitorBackgroundWavelengthMax : 3.0 + // Normalize by integrated monitors : No + + // Modify counts in monitor (only for this test) + // Modify counts only for range that will be fitted + auto inputWS = m_multiDetectorWS; + auto &Y = inputWS->mutableY(0); + std::fill(Y.begin(), Y.begin() + 2, 1.0); + + CreateTransmissionWorkspace2 alg; + alg.setChild(true); + alg.initialize(); + alg.setProperty("FirstTransmissionRun", inputWS); + alg.setProperty("WavelengthMin", 0.0); + alg.setProperty("WavelengthMax", 15.0); + alg.setProperty("I0MonitorIndex", "0"); + alg.setProperty("MonitorBackgroundWavelengthMin", 0.5); + alg.setProperty("MonitorBackgroundWavelengthMax", 3.0); + alg.setPropertyValue("ProcessingInstructions", "1"); + alg.setPropertyValue("OutputWorkspace", "outWS"); + alg.execute(); + MatrixWorkspace_sptr outLam = alg.getProperty("OutputWorkspace"); + + TS_ASSERT_EQUALS(outLam->getNumberHistograms(), 1); + TS_ASSERT_EQUALS(outLam->blocksize(), 10); + TS_ASSERT(outLam->x(0)[0] >= 0.0); + TS_ASSERT(outLam->x(0)[7] <= 15.0); + // Expected values are 2.4996 = 3.15301 (detectors) / 1.26139 (monitors) + TS_ASSERT_DELTA(outLam->y(0)[2], 2.4996, 0.0001); + TS_ASSERT_DELTA(outLam->y(0)[4], 2.4996, 0.0001); + TS_ASSERT_DELTA(outLam->y(0)[7], 2.4996, 0.0001); + } + + void test_one_run_integrated_monitor_normalization() { + // I0MonitorIndex: 0 + // MonitorBackgroundWavelengthMin : 0.5 + // MonitorBackgroundWavelengthMax : 3.0 + // Normalize by integrated monitors : No + + // Modify counts in monitor (only for this test) + // Modify counts only for range that will be fitted + auto inputWS = m_multiDetectorWS; + auto &Y = inputWS->mutableY(0); + std::fill(Y.begin(), Y.begin() + 2, 1.0); + + CreateTransmissionWorkspace2 alg; + alg.setChild(true); + alg.initialize(); + alg.setProperty("FirstTransmissionRun", inputWS); + alg.setProperty("WavelengthMin", 0.0); + alg.setProperty("WavelengthMax", 15.0); + alg.setProperty("I0MonitorIndex", "0"); + alg.setProperty("MonitorBackgroundWavelengthMin", 0.5); + alg.setProperty("MonitorBackgroundWavelengthMax", 3.0); + alg.setProperty("MonitorIntegrationWavelengthMin", 1.5); + alg.setProperty("MonitorIntegrationWavelengthMax", 15.0); + alg.setPropertyValue("ProcessingInstructions", "1"); + alg.setPropertyValue("OutputWorkspace", "outWS"); + alg.execute(); + MatrixWorkspace_sptr outLam = alg.getProperty("OutputWorkspace"); + + TS_ASSERT_EQUALS(outLam->getNumberHistograms(), 1); + TS_ASSERT_EQUALS(outLam->blocksize(), 10); + TS_ASSERT(outLam->x(0)[0] >= 0.0); + TS_ASSERT(outLam->x(0)[7] <= 15.0); + // Expected values are 0.3124 = 3.15301 (detectors) / (1.26139*8) (monitors) + TS_ASSERT_DELTA(outLam->y(0)[0], 0.3124, 0.0001); + TS_ASSERT_DELTA(outLam->y(0)[7], 0.3124, 0.0001); + } + + void test_two_transmission_runs() { + + CreateTransmissionWorkspace2 alg; + alg.setChild(true); + alg.initialize(); + alg.setProperty("FirstTransmissionRun", m_multiDetectorWS); + alg.setProperty("SecondTransmissionRun", m_multiDetectorWS); + alg.setProperty("WavelengthMin", 1.5); + alg.setProperty("WavelengthMax", 15.0); + alg.setPropertyValue("ProcessingInstructions", "1"); + alg.setPropertyValue("OutputWorkspace", "outWS"); + alg.execute(); + MatrixWorkspace_sptr outLam = alg.getProperty("OutputWorkspace"); + + TS_ASSERT_EQUALS(outLam->getNumberHistograms(), 1); + TS_ASSERT_EQUALS(outLam->blocksize(), 8); + TS_ASSERT(outLam->x(0)[0] >= 1.5); + TS_ASSERT(outLam->x(0)[7] <= 15.0); + TS_ASSERT_DELTA(outLam->y(0)[0], 3.1530, 0.0001); + TS_ASSERT_DELTA(outLam->y(0)[7], 3.1530, 0.0001); + } + + void test_two_transmission_runs_stitch_params() { + + CreateTransmissionWorkspace2 alg; + alg.setChild(true); + alg.initialize(); + alg.setProperty("FirstTransmissionRun", m_multiDetectorWS); + alg.setProperty("SecondTransmissionRun", m_multiDetectorWS); + alg.setProperty("WavelengthMin", 1.5); + alg.setProperty("WavelengthMax", 15.0); + alg.setProperty("Params", "0.1"); + alg.setPropertyValue("ProcessingInstructions", "1"); + alg.setPropertyValue("OutputWorkspace", "outWS"); + alg.execute(); + MatrixWorkspace_sptr outLam = alg.getProperty("OutputWorkspace"); + + TS_ASSERT_EQUALS(outLam->getNumberHistograms(), 1); + TS_ASSERT_EQUALS(outLam->blocksize(), 113); + TS_ASSERT(outLam->x(0)[0] >= 1.5); + TS_ASSERT(outLam->x(0)[7] <= 15.0); + TS_ASSERT_DELTA(outLam->x(0)[0], 2.8257, 0.0001); + TS_ASSERT_DELTA(outLam->x(0)[1], 2.9257, 0.0001); + TS_ASSERT_DELTA(outLam->x(0)[2], 3.0257, 0.0001); + TS_ASSERT_DELTA(outLam->x(0)[3], 3.1257, 0.0001); + } +}; + +#endif /* ALGORITHMS_TEST_CREATETRANSMISSIONWORKSPACE2TEST_H_ */ diff --git a/Framework/Algorithms/test/CreateTransmissionWorkspaceAuto2Test.h b/Framework/Algorithms/test/CreateTransmissionWorkspaceAuto2Test.h new file mode 100644 index 0000000000000000000000000000000000000000..b85c57cf82faf41d8d23189ac15510957b3380ba --- /dev/null +++ b/Framework/Algorithms/test/CreateTransmissionWorkspaceAuto2Test.h @@ -0,0 +1,141 @@ +#ifndef MANTID_ALGORITHMS_CREATETRANSMISSIONWORKSPACEAUTO2TEST_H_ +#define MANTID_ALGORITHMS_CREATETRANSMISSIONWORKSPACEAUTO2TEST_H_ + +#include <cxxtest/TestSuite.h> +#include "MantidAPI/AnalysisDataService.h" +#include "MantidAPI/MatrixWorkspace.h" +#include "MantidAPI/WorkspaceHistory.h" +#include "MantidAlgorithms/CreateTransmissionWorkspaceAuto2.h" +#include "MantidAPI/FrameworkManager.h" +#include "MantidAPI/AlgorithmManager.h" +#include "MantidGeometry/Instrument.h" +#include "MantidKernel/PropertyHistory.h" +#include <boost/lexical_cast.hpp> + +using Mantid::Algorithms::CreateTransmissionWorkspaceAuto2; +using namespace Mantid::API; +using namespace Mantid::Kernel; + +namespace { +class PropertyFinder { +private: + const std::string m_propertyName; + +public: + PropertyFinder(const std::string &propertyName) + : m_propertyName(propertyName) {} + bool operator()(const PropertyHistories::value_type &candidate) const { + return candidate->name() == m_propertyName; + } +}; + +template <typename T> +T findPropertyValue(PropertyHistories &histories, + const std::string &propertyName) { + PropertyFinder finder(propertyName); + auto it = std::find_if(histories.begin(), histories.end(), finder); + return boost::lexical_cast<T>((*it)->value()); +} +} + +class CreateTransmissionWorkspaceAuto2Test : public CxxTest::TestSuite { + +private: + MatrixWorkspace_sptr m_dataWS; + +public: + // This pair of boilerplate methods prevent the suite being created statically + // This means the constructor isn't called when running other tests + static CreateTransmissionWorkspaceAuto2Test *createSuite() { + return new CreateTransmissionWorkspaceAuto2Test(); + } + static void destroySuite(CreateTransmissionWorkspaceAuto2Test *suite) { + delete suite; + } + + CreateTransmissionWorkspaceAuto2Test() { + FrameworkManager::Instance(); + + IAlgorithm_sptr lAlg = AlgorithmManager::Instance().create("Load"); + lAlg->setChild(true); + lAlg->initialize(); + lAlg->setProperty("Filename", "INTER00013463.nxs"); + lAlg->setPropertyValue("OutputWorkspace", "demo_ws"); + lAlg->execute(); + Workspace_sptr temp = lAlg->getProperty("OutputWorkspace"); + m_dataWS = boost::dynamic_pointer_cast<MatrixWorkspace>(temp); + } + + ~CreateTransmissionWorkspaceAuto2Test() override {} + + void test_init() { + CreateTransmissionWorkspaceAuto2 alg; + TS_ASSERT_THROWS_NOTHING(alg.initialize()) + TS_ASSERT(alg.isInitialized()) + } + + void test_exec() { + + IAlgorithm_sptr alg = + AlgorithmManager::Instance().create("CreateTransmissionWorkspaceAuto"); + alg->setRethrows(true); + alg->initialize(); + + alg->setProperty("FirstTransmissionRun", m_dataWS); + alg->setPropertyValue("OutputWorkspace", "outWS"); + alg->execute(); + TS_ASSERT(alg->isExecuted()); + + MatrixWorkspace_sptr outWS = + AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("outWS"); + + const auto workspaceHistory = outWS->getHistory(); + AlgorithmHistory_const_sptr workerAlgHistory = + workspaceHistory.getAlgorithmHistory(0)->getChildAlgorithmHistory(0); + auto vecPropertyHistories = workerAlgHistory->getProperties(); + + const double wavelengthMin = + findPropertyValue<double>(vecPropertyHistories, "WavelengthMin"); + const double wavelengthMax = + findPropertyValue<double>(vecPropertyHistories, "WavelengthMax"); + const double monitorBackgroundWavelengthMin = findPropertyValue<double>( + vecPropertyHistories, "MonitorBackgroundWavelengthMin"); + const double monitorBackgroundWavelengthMax = findPropertyValue<double>( + vecPropertyHistories, "MonitorBackgroundWavelengthMax"); + const double monitorIntegrationWavelengthMin = findPropertyValue<double>( + vecPropertyHistories, "MonitorIntegrationWavelengthMin"); + const double monitorIntegrationWavelengthMax = findPropertyValue<double>( + vecPropertyHistories, "MonitorIntegrationWavelengthMax"); + const int i0MonitorIndex = + findPropertyValue<int>(vecPropertyHistories, "I0MonitorIndex"); + const std::string processingInstructions = findPropertyValue<std::string>( + vecPropertyHistories, "ProcessingInstructions"); + std::vector<std::string> pointDetectorStartStop; + boost::split(pointDetectorStartStop, processingInstructions, + boost::is_any_of(":")); + + auto inst = m_dataWS->getInstrument(); + TS_ASSERT_EQUALS(inst->getNumberParameter("LambdaMin").at(0), + wavelengthMin); + TS_ASSERT_EQUALS(inst->getNumberParameter("LambdaMax").at(0), + wavelengthMax); + TS_ASSERT_EQUALS(inst->getNumberParameter("MonitorBackgroundMin").at(0), + monitorBackgroundWavelengthMin); + TS_ASSERT_EQUALS(inst->getNumberParameter("MonitorBackgroundMax").at(0), + monitorBackgroundWavelengthMax); + TS_ASSERT_EQUALS(inst->getNumberParameter("MonitorIntegralMin").at(0), + monitorIntegrationWavelengthMin); + TS_ASSERT_EQUALS(inst->getNumberParameter("MonitorIntegralMax").at(0), + monitorIntegrationWavelengthMax); + TS_ASSERT_EQUALS(inst->getNumberParameter("I0MonitorIndex").at(0), + i0MonitorIndex); + TS_ASSERT_EQUALS(inst->getNumberParameter("PointDetectorStart").at(0), + boost::lexical_cast<double>(pointDetectorStartStop.at(0))); + TS_ASSERT_EQUALS(inst->getNumberParameter("PointDetectorStop").at(0), + boost::lexical_cast<double>(pointDetectorStartStop.at(1))); + + AnalysisDataService::Instance().remove("outWS"); + } +}; + +#endif /* MANTID_ALGORITHMS_CREATETRANSMISSIONWORKSPACEAUTO2TEST_H_ */ diff --git a/Framework/Algorithms/test/CreateTransmissionWorkspaceAutoTest.h b/Framework/Algorithms/test/CreateTransmissionWorkspaceAutoTest.h index b4dd34ca8db59bfdb48eaba635c39e9aee502f4e..0917066e8b52555d54cb201ee74f8f0f2dbbaa23 100644 --- a/Framework/Algorithms/test/CreateTransmissionWorkspaceAutoTest.h +++ b/Framework/Algorithms/test/CreateTransmissionWorkspaceAutoTest.h @@ -75,8 +75,8 @@ public: } void test_exec() { - IAlgorithm_sptr alg = - AlgorithmManager::Instance().create("CreateTransmissionWorkspaceAuto"); + IAlgorithm_sptr alg = AlgorithmManager::Instance().create( + "CreateTransmissionWorkspaceAuto", 1); alg->setRethrows(true); TS_ASSERT_THROWS_NOTHING(alg->initialize()); TS_ASSERT_THROWS_NOTHING( diff --git a/Framework/Algorithms/test/CreateTransmissionWorkspaceTest.h b/Framework/Algorithms/test/CreateTransmissionWorkspaceTest.h index 6b1f814bc643e6b4f8f924c0db3d5e816a0f8a74..9f715efd114ee6cd38c1f9eaa01e34482070dcbd 100644 --- a/Framework/Algorithms/test/CreateTransmissionWorkspaceTest.h +++ b/Framework/Algorithms/test/CreateTransmissionWorkspaceTest.h @@ -33,8 +33,8 @@ private: private: IAlgorithm_sptr construct_standard_algorithm() { - auto alg = - AlgorithmManager::Instance().create("CreateTransmissionWorkspaceAuto"); + auto alg = AlgorithmManager::Instance().create( + "CreateTransmissionWorkspaceAuto", 1); alg->initialize(); alg->setChild(true); alg->setProperty("FirstTransmissionRun", m_TOF); @@ -113,7 +113,7 @@ public: void test_must_provide_wavelengths() { auto alg = - AlgorithmManager::Instance().create("CreateTransmissionWorkspace"); + AlgorithmManager::Instance().create("CreateTransmissionWorkspace", 1); alg->initialize(); alg->setChild(true); alg->setProperty("FirstTransmissionRun", m_TOF); @@ -155,7 +155,7 @@ public: void test_execute_one_tranmission() { IAlgorithm_sptr alg = - AlgorithmManager::Instance().create("CreateTransmissionWorkspace"); + AlgorithmManager::Instance().create("CreateTransmissionWorkspace", 1); alg->setChild(true); alg->initialize(); diff --git a/Framework/Algorithms/test/ReflectometryReductionOne2Test.h b/Framework/Algorithms/test/ReflectometryReductionOne2Test.h new file mode 100644 index 0000000000000000000000000000000000000000..7a21d09f10aa23a8a4b36421f1419923fb3093e4 --- /dev/null +++ b/Framework/Algorithms/test/ReflectometryReductionOne2Test.h @@ -0,0 +1,430 @@ +#ifndef ALGORITHMS_TEST_REFLECTOMETRYREDUCTIONONE2TEST_H_ +#define ALGORITHMS_TEST_REFLECTOMETRYREDUCTIONONE2TEST_H_ + +#include <cxxtest/TestSuite.h> +#include "MantidAlgorithms/ReflectometryReductionOne2.h" +#include "MantidAPI/AlgorithmManager.h" +#include "MantidAPI/Axis.h" +#include "MantidAPI/FrameworkManager.h" +#include "MantidAPI/MatrixWorkspace.h" +#include "MantidHistogramData/HistogramY.h" +#include "MantidTestHelpers/WorkspaceCreationHelper.h" + +#include <algorithm> + +using namespace Mantid::API; +using namespace Mantid::Algorithms; +using namespace WorkspaceCreationHelper; + +class ReflectometryReductionOne2Test : public CxxTest::TestSuite { +private: + MatrixWorkspace_sptr m_multiDetectorWS; + MatrixWorkspace_sptr m_wavelengthWS; + +public: + // This pair of boilerplate methods prevent the suite being created statically + // This means the constructor isn't called when running other tests + static ReflectometryReductionOne2Test *createSuite() { + return new ReflectometryReductionOne2Test(); + } + static void destroySuite(ReflectometryReductionOne2Test *suite) { + delete suite; + } + + ReflectometryReductionOne2Test() { + FrameworkManager::Instance(); + // A multi detector ws + m_multiDetectorWS = + create2DWorkspaceWithReflectometryInstrumentMultiDetector(); + // A workspace in wavelength + m_wavelengthWS = + create2DWorkspaceWithReflectometryInstrumentMultiDetector(); + m_wavelengthWS->getAxis(0)->setUnit("Wavelength"); + } + + void test_IvsLam() { + // Test IvsLam workspace + // No monitor normalization + // No direct beam normalization + // No transmission correction + + ReflectometryReductionOne2 alg; + alg.setChild(true); + alg.initialize(); + alg.setProperty("InputWorkspace", m_multiDetectorWS); + alg.setProperty("WavelengthMin", 1.5); + alg.setProperty("WavelengthMax", 15.0); + alg.setPropertyValue("ProcessingInstructions", "1"); + alg.setPropertyValue("OutputWorkspace", "IvsQ"); + alg.setPropertyValue("OutputWorkspaceWavelength", "IvsLam"); + alg.execute(); + MatrixWorkspace_sptr outLam = alg.getProperty("OutputWorkspaceWavelength"); + + TS_ASSERT(outLam); + TS_ASSERT_EQUALS(outLam->getNumberHistograms(), 1); + TS_ASSERT_EQUALS(outLam->blocksize(), 8); + TS_ASSERT(outLam->x(0)[0] >= 1.5); + TS_ASSERT(outLam->x(0)[7] <= 15.0); + TS_ASSERT_DELTA(outLam->y(0)[0], 3.1530, 0.0001); + TS_ASSERT_DELTA(outLam->y(0)[7], 3.1530, 0.0001); + } + + void test_IvsLam_processing_instructions_1to2() { + // Test IvsLam workspace + // No monitor normalization + // No direct beam normalization + // No transmission correction + // Processing instructions : 1+2 + + ReflectometryReductionOne2 alg; + alg.setChild(true); + alg.initialize(); + alg.setProperty("InputWorkspace", m_multiDetectorWS); + alg.setProperty("WavelengthMin", 1.5); + alg.setProperty("WavelengthMax", 15.0); + alg.setPropertyValue("ProcessingInstructions", "1+2"); + alg.setPropertyValue("OutputWorkspace", "IvsQ"); + alg.setPropertyValue("OutputWorkspaceWavelength", "IvsLam"); + alg.execute(); + MatrixWorkspace_sptr outLam = alg.getProperty("OutputWorkspaceWavelength"); + + TS_ASSERT_EQUALS(outLam->getNumberHistograms(), 1); + TS_ASSERT_EQUALS(outLam->blocksize(), 8); + TS_ASSERT(outLam->x(0)[0] >= 1.5); + TS_ASSERT(outLam->x(0)[7] <= 15.0); + // Y counts, should be 3.1530 * 2 + TS_ASSERT_DELTA(outLam->y(0)[0], 6.3060, 0.0001); + TS_ASSERT_DELTA(outLam->y(0)[7], 6.3060, 0.0001); + } + + void test_IvsLam_processing_instructions_1to3() { + // Test IvsLam workspace + // No monitor normalization + // No direct beam normalization + // No transmission correction + // Processing instructions : 1-3 + + ReflectometryReductionOne2 alg; + alg.setChild(true); + alg.initialize(); + alg.setProperty("InputWorkspace", m_multiDetectorWS); + alg.setProperty("WavelengthMin", 1.5); + alg.setProperty("WavelengthMax", 15.0); + alg.setPropertyValue("ProcessingInstructions", "1-3"); + alg.setPropertyValue("OutputWorkspace", "IvsQ"); + alg.setPropertyValue("OutputWorkspaceWavelength", "IvsLam"); + alg.execute(); + MatrixWorkspace_sptr outLam = alg.getProperty("OutputWorkspaceWavelength"); + + TS_ASSERT_EQUALS(outLam->getNumberHistograms(), 1); + TS_ASSERT_EQUALS(outLam->blocksize(), 8); + TS_ASSERT(outLam->x(0)[0] >= 1.5); + TS_ASSERT(outLam->x(0)[7] <= 15.0); + // Y counts, should be 3.1530 * 3 + TS_ASSERT_DELTA(outLam->y(0)[0], 9.4590, 0.0001); + TS_ASSERT_DELTA(outLam->y(0)[7], 9.4590, 0.0001); + } + + void test_bad_processing_instructions() { + // Processing instructions : 5+6 + + auto alg = AlgorithmManager::Instance().create("ReflectometryReductionOne"); + alg->setChild(true); + alg->initialize(); + alg->setProperty("InputWorkspace", m_multiDetectorWS); + alg->setProperty("WavelengthMin", 1.5); + alg->setProperty("WavelengthMax", 15.0); + alg->setPropertyValue("OutputWorkspace", "IvsQ"); + alg->setPropertyValue("OutputWorkspaceWavelength", "IvsLam"); + alg->setPropertyValue("ProcessingInstructions", "5+6"); + // Must throw as spectrum 2 is not defined + TS_ASSERT_THROWS_ANYTHING(alg->execute()); + } + + void test_IvsLam_direct_beam() { + // Test IvsLam workspace + // No monitor normalization + // Direct beam normalization: 2-3 + // No transmission correction + // Processing instructions : 1 + + ReflectometryReductionOne2 alg; + alg.setChild(true); + alg.initialize(); + alg.setProperty("InputWorkspace", m_multiDetectorWS); + alg.setProperty("WavelengthMin", 1.5); + alg.setProperty("WavelengthMax", 15.0); + alg.setPropertyValue("ProcessingInstructions", "1"); + alg.setPropertyValue("RegionOfDirectBeam", "2-3"); + alg.setPropertyValue("OutputWorkspace", "IvsQ"); + alg.setPropertyValue("OutputWorkspaceWavelength", "IvsLam"); + alg.execute(); + MatrixWorkspace_sptr outLam = alg.getProperty("OutputWorkspaceWavelength"); + + TS_ASSERT_EQUALS(outLam->getNumberHistograms(), 1); + TS_ASSERT_EQUALS(outLam->blocksize(), 8); + // Y counts, should be 0.5 = 1 (from detector ws) / 2 (from direct beam) + TS_ASSERT_DELTA(outLam->y(0)[0], 0.5, 0.0001); + } + + void test_bad_direct_beam() { + // Direct beam : 4-5 + + auto alg = AlgorithmManager::Instance().create("ReflectometryReductionOne"); + alg->setChild(true); + alg->initialize(); + alg->setProperty("InputWorkspace", m_multiDetectorWS); + alg->setProperty("WavelengthMin", 1.5); + alg->setProperty("WavelengthMax", 15.0); + alg->setPropertyValue("ProcessingInstructions", "1"); + alg->setPropertyValue("OutputWorkspace", "IvsQ"); + alg->setPropertyValue("OutputWorkspaceWavelength", "IvsLam"); + alg->setPropertyValue("RegionOfDirectBeam", "4-5"); + TS_ASSERT_THROWS_ANYTHING(alg->execute()); + } + + void test_IvsLam_no_monitors() { + // Test IvsLam workspace + // No monitor normalization + // Direct beam normalization: 2-3 + // No transmission correction + // Processing instructions : 1 + + // I0MonitorIndex: 0 + // MonitorBackgroundWavelengthMin : Not given + // MonitorBackgroundWavelengthMax : Not given + + ReflectometryReductionOne2 alg; + alg.setChild(true); + alg.initialize(); + alg.setProperty("InputWorkspace", m_multiDetectorWS); + alg.setProperty("WavelengthMin", 1.5); + alg.setProperty("WavelengthMax", 15.0); + alg.setProperty("I0MonitorIndex", "0"); + alg.setPropertyValue("ProcessingInstructions", "1"); + alg.setPropertyValue("OutputWorkspace", "IvsQ"); + alg.setPropertyValue("OutputWorkspaceWavelength", "IvsLam"); + alg.execute(); + MatrixWorkspace_sptr outLam = alg.getProperty("OutputWorkspaceWavelength"); + + TS_ASSERT_EQUALS(outLam->getNumberHistograms(), 1); + TS_ASSERT_EQUALS(outLam->blocksize(), 8); + TS_ASSERT(outLam->x(0)[0] >= 1.5); + TS_ASSERT(outLam->x(0)[7] <= 15.0); + // No monitors considered because MonitorBackgroundWavelengthMin + // and MonitorBackgroundWavelengthMax were not set + // Y counts must be 3.1530 + TS_ASSERT_DELTA(outLam->y(0)[0], 3.1530, 0.0001); + TS_ASSERT_DELTA(outLam->y(0)[7], 3.1530, 0.0001); + } + + void test_IvsLam_monitor_normalization() { + // Test IvsLam workspace + // Monitor normalization + // No direct beam normalization + // No transmission correction + // Processing instructions : 1 + + // I0MonitorIndex: 0 + // MonitorBackgroundWavelengthMin : 0.5 + // MonitorBackgroundWavelengthMax : 3.0 + // Normalize by integrated monitors : No + + // Modify counts in monitor (only for this test) + // Modify counts only for range that will be fitted + auto inputWS = m_multiDetectorWS; + auto &Y = inputWS->mutableY(0); + std::fill(Y.begin(), Y.begin() + 2, 1.0); + + ReflectometryReductionOne2 alg; + alg.setChild(true); + alg.initialize(); + alg.setProperty("InputWorkspace", inputWS); + alg.setProperty("WavelengthMin", 0.0); + alg.setProperty("WavelengthMax", 15.0); + alg.setProperty("I0MonitorIndex", "0"); + alg.setProperty("MonitorBackgroundWavelengthMin", 0.5); + alg.setProperty("MonitorBackgroundWavelengthMax", 3.0); + alg.setProperty("NormalizeByIntegratedMonitors", "0"); + alg.setPropertyValue("ProcessingInstructions", "1"); + alg.setPropertyValue("OutputWorkspace", "IvsQ"); + alg.setPropertyValue("OutputWorkspaceWavelength", "IvsLam"); + alg.execute(); + MatrixWorkspace_sptr outLam = alg.getProperty("OutputWorkspaceWavelength"); + + TS_ASSERT_EQUALS(outLam->getNumberHistograms(), 1); + TS_ASSERT_EQUALS(outLam->blocksize(), 10); + TS_ASSERT(outLam->x(0)[0] >= 0.0); + TS_ASSERT(outLam->x(0)[7] <= 15.0); + // Expected values are 2.4996 = 3.15301 (detectors) / 1.26139 (monitors) + TS_ASSERT_DELTA(outLam->y(0)[2], 2.4996, 0.0001); + TS_ASSERT_DELTA(outLam->y(0)[4], 2.4996, 0.0001); + TS_ASSERT_DELTA(outLam->y(0)[7], 2.4996, 0.0001); + } + + void test_IvsLam_integrated_monitors() { + // Test IvsLam workspace + // Monitor normalization + // No direct beam normalization + // No transmission correction + // Processing instructions : 1 + + // I0MonitorIndex: 0 + // MonitorBackgroundWavelengthMin : 0.5 + // MonitorBackgroundWavelengthMax : 3.0 + // Normalize by integrated monitors : Yes + + // Modify counts in monitor (only for this test) + // Modify counts only for range that will be fitted + auto inputWS = m_multiDetectorWS; + auto &Y = inputWS->mutableY(0); + std::fill(Y.begin(), Y.begin() + 2, 1.0); + + ReflectometryReductionOne2 alg; + alg.setChild(true); + alg.initialize(); + alg.setProperty("InputWorkspace", inputWS); + alg.setProperty("WavelengthMin", 0.0); + alg.setProperty("WavelengthMax", 15.0); + alg.setProperty("I0MonitorIndex", "0"); + alg.setProperty("MonitorBackgroundWavelengthMin", 0.5); + alg.setProperty("MonitorBackgroundWavelengthMax", 3.0); + alg.setProperty("NormalizeByIntegratedMonitors", "1"); + alg.setProperty("MonitorIntegrationWavelengthMin", 1.5); + alg.setProperty("MonitorIntegrationWavelengthMax", 15.0); + alg.setPropertyValue("ProcessingInstructions", "1"); + alg.setPropertyValue("OutputWorkspace", "IvsQ"); + alg.setPropertyValue("OutputWorkspaceWavelength", "IvsLam"); + alg.execute(); + MatrixWorkspace_sptr outLam = alg.getProperty("OutputWorkspaceWavelength"); + + TS_ASSERT_EQUALS(outLam->getNumberHistograms(), 1); + TS_ASSERT_EQUALS(outLam->blocksize(), 10); + TS_ASSERT(outLam->x(0)[0] >= 0.0); + TS_ASSERT(outLam->x(0)[7] <= 15.0); + // Expected values are 0.3124 = 3.15301 (detectors) / (1.26139*8) (monitors) + TS_ASSERT_DELTA(outLam->y(0)[0], 0.3124, 0.0001); + TS_ASSERT_DELTA(outLam->y(0)[7], 0.3124, 0.0001); + } + + void test_transmission_correction_run() { + // Transmission run is the same as input run + + ReflectometryReductionOne2 alg; + alg.setChild(true); + alg.initialize(); + alg.setProperty("InputWorkspace", m_multiDetectorWS); + alg.setProperty("FirstTransmissionRun", m_multiDetectorWS); + alg.setProperty("WavelengthMin", 1.5); + alg.setProperty("WavelengthMax", 15.0); + alg.setProperty("ProcessingInstructions", "1"); + alg.setPropertyValue("OutputWorkspace", "IvsQ"); + alg.setPropertyValue("OutputWorkspaceWavelength", "IvsLam"); + alg.execute(); + MatrixWorkspace_sptr outLam = alg.getProperty("OutputWorkspaceWavelength"); + + TS_ASSERT_EQUALS(outLam->getNumberHistograms(), 1); + TS_ASSERT_EQUALS(outLam->blocksize(), 8); + // Expected values are 1 = m_wavelength / m_wavelength + TS_ASSERT_DELTA(outLam->y(0)[0], 1.0000, 0.0001); + TS_ASSERT_DELTA(outLam->y(0)[7], 1.0000, 0.0001); + } + + void test_transmission_correction_two_runs() { + // Transmission run is the same as input run + + ReflectometryReductionOne2 alg; + alg.setChild(true); + alg.initialize(); + alg.setProperty("InputWorkspace", m_multiDetectorWS); + alg.setProperty("FirstTransmissionRun", m_multiDetectorWS); + alg.setProperty("SecondTransmissionRun", m_multiDetectorWS); + alg.setProperty("StartOverlap", 2.5); + alg.setProperty("EndOverlap", 3.0); + alg.setProperty("Params", "0.1"); + alg.setProperty("WavelengthMin", 1.5); + alg.setProperty("WavelengthMax", 15.0); + alg.setProperty("ProcessingInstructions", "1"); + alg.setPropertyValue("OutputWorkspace", "IvsQ"); + alg.setPropertyValue("OutputWorkspaceWavelength", "IvsLam"); + alg.execute(); + MatrixWorkspace_sptr outLam = alg.getProperty("OutputWorkspaceWavelength"); + + TS_ASSERT_EQUALS(outLam->getNumberHistograms(), 1); + TS_ASSERT_EQUALS(outLam->blocksize(), 8); + // Expected values are 1 = m_wavelength / m_wavelength + TS_ASSERT_DELTA(outLam->y(0)[0], 1.0000, 0.0001); + TS_ASSERT_DELTA(outLam->y(0)[7], 1.0000, 0.0001); + } + + void test_exponential_correction() { + // CorrectionAlgorithm: ExponentialCorrection + + ReflectometryReductionOne2 alg; + alg.setChild(true); + alg.initialize(); + alg.setProperty("InputWorkspace", m_multiDetectorWS); + alg.setProperty("WavelengthMin", 1.5); + alg.setProperty("WavelengthMax", 15.0); + alg.setProperty("ProcessingInstructions", "1"); + alg.setProperty("CorrectionAlgorithm", "ExponentialCorrection"); + alg.setProperty("C0", 0.2); + alg.setProperty("C1", 0.1); + alg.setPropertyValue("OutputWorkspace", "IvsQ"); + alg.setPropertyValue("OutputWorkspaceWavelength", "IvsLam"); + alg.execute(); + MatrixWorkspace_sptr outLam = alg.getProperty("OutputWorkspaceWavelength"); + + TS_ASSERT_EQUALS(outLam->getNumberHistograms(), 1); + TS_ASSERT_EQUALS(outLam->blocksize(), 8); + // Expected values are 29.0459 and 58.4912 + TS_ASSERT_DELTA(outLam->y(0)[0], 22.4437, 0.0001); + TS_ASSERT_DELTA(outLam->y(0)[7], 60.3415, 0.0001); + } + + void test_polynomial_correction() { + // CorrectionAlgorithm: PolynomialCorrection + + ReflectometryReductionOne2 alg; + alg.setChild(true); + alg.initialize(); + alg.setProperty("InputWorkspace", m_multiDetectorWS); + alg.setProperty("WavelengthMin", 1.5); + alg.setProperty("WavelengthMax", 15.0); + alg.setProperty("ProcessingInstructions", "1"); + alg.setProperty("CorrectionAlgorithm", "PolynomialCorrection"); + alg.setProperty("Polynomial", "0.1,0.3,0.5"); + alg.setPropertyValue("OutputWorkspace", "IvsQ"); + alg.setPropertyValue("OutputWorkspaceWavelength", "IvsLam"); + alg.execute(); + MatrixWorkspace_sptr outLam = alg.getProperty("OutputWorkspaceWavelength"); + + TS_ASSERT_EQUALS(outLam->getNumberHistograms(), 1); + TS_ASSERT_EQUALS(outLam->blocksize(), 8); + TS_ASSERT_DELTA(outLam->y(0)[0], 0.4262, 0.0001); + TS_ASSERT_DELTA(outLam->y(0)[7], 0.0334, 0.0001); + } + + void test_IvsQ() { + + ReflectometryReductionOne2 alg; + alg.setChild(true); + alg.initialize(); + alg.setProperty("InputWorkspace", m_multiDetectorWS); + alg.setProperty("WavelengthMin", 1.5); + alg.setProperty("WavelengthMax", 15.0); + alg.setProperty("ProcessingInstructions", "1"); + alg.setPropertyValue("OutputWorkspace", "IvsQ"); + alg.setPropertyValue("OutputWorkspaceWavelength", "IvsLam"); + alg.execute(); + MatrixWorkspace_sptr outQ = alg.getProperty("OutputWorkspace"); + + TS_ASSERT_EQUALS(outQ->getNumberHistograms(), 1); + TS_ASSERT_EQUALS(outQ->blocksize(), 8); + // X range in outQ + TS_ASSERT_DELTA(outQ->x(0)[0], 0.3403, 0.0001); + TS_ASSERT_DELTA(outQ->x(0)[7], 1.1345, 0.0001); + } +}; + +#endif /* ALGORITHMS_TEST_REFLECTOMETRYREDUCTIONONE2TEST_H_ */ diff --git a/Framework/Algorithms/test/ReflectometryReductionOneAuto2Test.h b/Framework/Algorithms/test/ReflectometryReductionOneAuto2Test.h new file mode 100644 index 0000000000000000000000000000000000000000..c95b9937c6968dcf3812536583a1eda9035b612b --- /dev/null +++ b/Framework/Algorithms/test/ReflectometryReductionOneAuto2Test.h @@ -0,0 +1,481 @@ +#ifndef MANTID_ALGORITHMS_REFLECTOMETRYREDUCTIONONEAUTO2TEST_H_ +#define MANTID_ALGORITHMS_REFLECTOMETRYREDUCTIONONEAUTO2TEST_H_ + +#include <cxxtest/TestSuite.h> + +#include "MantidAPI/AlgorithmManager.h" +#include "MantidAPI/FrameworkManager.h" +#include "MantidAPI/MatrixWorkspace.h" +#include "MantidAPI/WorkspaceGroup.h" +#include "MantidAlgorithms/ReflectometryReductionOneAuto2.h" +#include "MantidGeometry/Instrument.h" +#include "MantidTestHelpers/WorkspaceCreationHelper.h" + +using Mantid::Algorithms::ReflectometryReductionOneAuto2; +using namespace Mantid::API; + +class ReflectometryReductionOneAuto2Test : public CxxTest::TestSuite { +private: + MatrixWorkspace_sptr m_notTOF; + MatrixWorkspace_sptr m_TOF; + + MatrixWorkspace_sptr loadRun(const std::string &run) { + + IAlgorithm_sptr lAlg = AlgorithmManager::Instance().create("Load"); + lAlg->setChild(true); + lAlg->initialize(); + lAlg->setProperty("Filename", run); + lAlg->setPropertyValue("OutputWorkspace", "demo_ws"); + lAlg->execute(); + Workspace_sptr temp = lAlg->getProperty("OutputWorkspace"); + MatrixWorkspace_sptr matrixWS = + boost::dynamic_pointer_cast<MatrixWorkspace>(temp); + if (matrixWS) + return matrixWS; + + WorkspaceGroup_sptr group = + boost::dynamic_pointer_cast<WorkspaceGroup>(temp); + if (group) { + Workspace_sptr temp = group->getItem(0); + MatrixWorkspace_sptr matrixWS = + boost::dynamic_pointer_cast<MatrixWorkspace>(temp); + if (matrixWS) + return matrixWS; + } + + return MatrixWorkspace_sptr(); + }; + +public: + // This pair of boilerplate methods prevent the suite being created statically + // This means the constructor isn't called when running other tests + static ReflectometryReductionOneAuto2Test *createSuite() { + return new ReflectometryReductionOneAuto2Test(); + } + static void destroySuite(ReflectometryReductionOneAuto2Test *suite) { + delete suite; + } + + ReflectometryReductionOneAuto2Test() { + FrameworkManager::Instance(); + + m_notTOF = + WorkspaceCreationHelper::create2DWorkspaceWithRectangularInstrument( + 1, 10, 10); + m_TOF = WorkspaceCreationHelper:: + create2DWorkspaceWithReflectometryInstrumentMultiDetector(); + } + + ~ReflectometryReductionOneAuto2Test() override {} + + void test_init() { + ReflectometryReductionOneAuto2 alg; + TS_ASSERT_THROWS_NOTHING(alg.initialize()); + TS_ASSERT(alg.isInitialized()); + } + + void test_bad_input_workspace_units() { + ReflectometryReductionOneAuto2 alg; + alg.setChild(true); + alg.initialize(); + alg.setProperty("InputWorkspace", m_notTOF); + alg.setProperty("WavelengthMin", 1.0); + alg.setProperty("WavelengthMax", 15.0); + alg.setProperty("ProcessingInstructions", "0"); + alg.setPropertyValue("OutputWorkspace", "IvsQ"); + alg.setPropertyValue("OutputWorkspaceBinned", "IvsQ_binned"); + alg.setPropertyValue("OutputWorkspaceWavelength", "IvsLam"); + TS_ASSERT_THROWS_ANYTHING(alg.execute()); + } + + void test_bad_wavelength_range() { + ReflectometryReductionOneAuto2 alg; + alg.setChild(true); + alg.initialize(); + alg.setProperty("InputWorkspace", m_TOF); + alg.setProperty("WavelengthMin", 15.0); + alg.setProperty("WavelengthMax", 1.0); + alg.setProperty("ProcessingInstructions", "0"); + alg.setPropertyValue("OutputWorkspace", "IvsQ"); + alg.setPropertyValue("OutputWorkspaceBinned", "IvsQ_binned"); + alg.setPropertyValue("OutputWorkspaceWavelength", "IvsLam"); + TS_ASSERT_THROWS_ANYTHING(alg.execute()); + } + + void test_bad_monitor_background_range() { + ReflectometryReductionOneAuto2 alg; + alg.setChild(true); + alg.initialize(); + alg.setProperty("InputWorkspace", m_TOF); + alg.setProperty("WavelengthMin", 1.0); + alg.setProperty("WavelengthMax", 15.0); + alg.setProperty("ProcessingInstructions", "0"); + alg.setProperty("MonitorBackgroundWavelengthMin", 3.0); + alg.setProperty("MonitorBackgroundWavelengthMax", 0.5); + alg.setPropertyValue("OutputWorkspace", "IvsQ"); + alg.setPropertyValue("OutputWorkspaceBinned", "IvsQ_binned"); + alg.setPropertyValue("OutputWorkspaceWavelength", "IvsLam"); + TS_ASSERT_THROWS_ANYTHING(alg.execute()); + } + + void test_bad_monitor_integration_range() { + ReflectometryReductionOneAuto2 alg; + alg.setChild(true); + alg.initialize(); + alg.setProperty("InputWorkspace", m_TOF); + alg.setProperty("WavelengthMin", 1.0); + alg.setProperty("WavelengthMax", 15.0); + alg.setProperty("ProcessingInstructions", "0"); + alg.setProperty("MonitorIntegrationWavelengthMin", 15.0); + alg.setProperty("MonitorIntegrationWavelengthMax", 1.5); + alg.setPropertyValue("OutputWorkspace", "IvsQ"); + alg.setPropertyValue("OutputWorkspaceBinned", "IvsQ_binned"); + alg.setPropertyValue("OutputWorkspaceWavelength", "IvsLam"); + TS_ASSERT_THROWS_ANYTHING(alg.execute()); + } + + void test_bad_first_transmission_run_units() { + ReflectometryReductionOneAuto2 alg; + alg.setChild(true); + alg.initialize(); + alg.setProperty("InputWorkspace", m_TOF); + alg.setProperty("FirstTransmissionRun", m_notTOF); + alg.setProperty("WavelengthMin", 1.0); + alg.setProperty("WavelengthMax", 15.0); + alg.setProperty("ProcessingInstructions", "0"); + alg.setProperty("MonitorIntegrationWavelengthMin", 1.0); + alg.setProperty("MonitorIntegrationWavelengthMax", 15.0); + alg.setPropertyValue("OutputWorkspace", "IvsQ"); + alg.setPropertyValue("OutputWorkspaceBinned", "IvsQ_binned"); + alg.setPropertyValue("OutputWorkspaceWavelength", "IvsLam"); + TS_ASSERT_THROWS_ANYTHING(alg.execute()); + } + + void test_bad_second_transmission_run_units() { + ReflectometryReductionOneAuto2 alg; + alg.setChild(true); + alg.initialize(); + alg.setProperty("InputWorkspace", m_TOF); + alg.setProperty("FirstTransmissionRun", m_TOF); + TS_ASSERT_THROWS_ANYTHING( + alg.setProperty("SecondTransmissionRun", m_notTOF)); + } + + void test_bad_first_transmission_group_size() { + MatrixWorkspace_sptr first = m_TOF->clone(); + MatrixWorkspace_sptr second = m_TOF->clone(); + MatrixWorkspace_sptr third = m_TOF->clone(); + MatrixWorkspace_sptr fourth = m_TOF->clone(); + + WorkspaceGroup_sptr inputWSGroup = boost::make_shared<WorkspaceGroup>(); + inputWSGroup->addWorkspace(first); + inputWSGroup->addWorkspace(second); + WorkspaceGroup_sptr transWSGroup = boost::make_shared<WorkspaceGroup>(); + transWSGroup->addWorkspace(first); + transWSGroup->addWorkspace(second); + transWSGroup->addWorkspace(third); + transWSGroup->addWorkspace(fourth); + AnalysisDataService::Instance().addOrReplace("input", inputWSGroup); + AnalysisDataService::Instance().addOrReplace("trans", transWSGroup); + + ReflectometryReductionOneAuto2 alg; + alg.initialize(); + alg.setPropertyValue("InputWorkspace", "input"); + alg.setPropertyValue("FirstTransmissionRun", "trans"); + alg.setPropertyValue("PolarizationAnalysis", "None"); + auto results = alg.validateInputs(); + TS_ASSERT(results.count("FirstTransmissionRun")); + + AnalysisDataService::Instance().remove("input"); + AnalysisDataService::Instance().remove("input_1"); + AnalysisDataService::Instance().remove("input_2"); + AnalysisDataService::Instance().remove("trans"); + AnalysisDataService::Instance().remove("trans_3"); + AnalysisDataService::Instance().remove("trans_4"); + } + + void test_bad_second_transmission_group_size() { + MatrixWorkspace_sptr first = m_TOF->clone(); + MatrixWorkspace_sptr second = m_TOF->clone(); + MatrixWorkspace_sptr third = m_TOF->clone(); + MatrixWorkspace_sptr fourth = m_TOF->clone(); + + WorkspaceGroup_sptr inputWSGroup = boost::make_shared<WorkspaceGroup>(); + inputWSGroup->addWorkspace(first); + WorkspaceGroup_sptr firstWSGroup = boost::make_shared<WorkspaceGroup>(); + firstWSGroup->addWorkspace(second); + WorkspaceGroup_sptr secondWSGroup = boost::make_shared<WorkspaceGroup>(); + secondWSGroup->addWorkspace(third); + secondWSGroup->addWorkspace(fourth); + AnalysisDataService::Instance().addOrReplace("input", inputWSGroup); + AnalysisDataService::Instance().addOrReplace("first_trans", firstWSGroup); + AnalysisDataService::Instance().addOrReplace("second_trans", secondWSGroup); + + ReflectometryReductionOneAuto2 alg; + alg.initialize(); + alg.setPropertyValue("InputWorkspace", "input"); + alg.setPropertyValue("FirstTransmissionRun", "first_trans"); + alg.setPropertyValue("SecondTransmissionRun", "second_trans"); + alg.setPropertyValue("PolarizationAnalysis", "None"); + const auto results = alg.validateInputs(); + TS_ASSERT(!results.count("FirstTransmissionRun")); + TS_ASSERT(results.count("SecondTransmissionRun")); + + AnalysisDataService::Instance().remove("input"); + AnalysisDataService::Instance().remove("input_1"); + AnalysisDataService::Instance().remove("first_trans"); + AnalysisDataService::Instance().remove("first_trans_1"); + AnalysisDataService::Instance().remove("second_trans"); + AnalysisDataService::Instance().remove("second_trans_1"); + AnalysisDataService::Instance().remove("second_trans_2"); + } + + void test_correct_detector_position_INTER() { + auto inter = loadRun("INTER00013460.nxs"); + + ReflectometryReductionOneAuto2 alg; + alg.initialize(); + alg.setChild(true); + alg.setProperty("InputWorkspace", inter); + alg.setProperty("ThetaIn", 0.7); + alg.setProperty("CorrectionAlgorithm", "None"); + alg.setProperty("OutputWorkspace", "IvsQ"); + alg.setProperty("OutputWorkspaceBinned", "IvsQ_binned"); + alg.setProperty("OutputWorkspaceWavelength", "IvsLam"); + alg.execute(); + MatrixWorkspace_sptr out = alg.getProperty("OutputWorkspace"); + + // Compare instrument components before and after + auto instIn = inter->getInstrument(); + auto instOut = out->getInstrument(); + + // The following components should not have been moved + TS_ASSERT_EQUALS(instIn->getComponentByName("monitor1")->getPos(), + instOut->getComponentByName("monitor1")->getPos()); + TS_ASSERT_EQUALS(instIn->getComponentByName("monitor2")->getPos(), + instOut->getComponentByName("monitor2")->getPos()); + TS_ASSERT_EQUALS(instIn->getComponentByName("monitor3")->getPos(), + instOut->getComponentByName("monitor3")->getPos()); + TS_ASSERT_EQUALS(instIn->getComponentByName("linear-detector")->getPos(), + instOut->getComponentByName("linear-detector")->getPos()); + + // Only 'point-detector' and 'point-detector2' should have been moved + // vertically (along Y) + + auto point1In = instIn->getComponentByName("point-detector")->getPos(); + auto point2In = instIn->getComponentByName("point-detector2")->getPos(); + auto point1Out = instOut->getComponentByName("point-detector")->getPos(); + auto point2Out = instOut->getComponentByName("point-detector2")->getPos(); + + TS_ASSERT_EQUALS(point1In.X(), point1Out.X()); + TS_ASSERT_EQUALS(point1In.Z(), point1Out.Z()); + TS_ASSERT_EQUALS(point2In.X(), point2Out.X()); + TS_ASSERT_EQUALS(point2In.Z(), point2Out.Z()); + TS_ASSERT_DIFFERS(point1In.Y(), point1Out.Y()); + TS_ASSERT_DIFFERS(point2In.Y(), point2Out.Y()); + TS_ASSERT_DELTA(point1Out.Y() / + (point1Out.Z() - instOut->getSample()->getPos().Z()), + std::tan(0.7 * 2 * M_PI / 180), 1e-4); + TS_ASSERT_DELTA(point2Out.Y() / + (point2Out.Z() - instOut->getSample()->getPos().Z()), + std::tan(0.7 * 2 * M_PI / 180), 1e-4); + } + + void test_correct_detector_position_POLREF() { + // Histograms in this run correspond to 'OSMOND' component + auto polref = loadRun("POLREF00014966.raw"); + + ReflectometryReductionOneAuto2 alg; + alg.initialize(); + alg.setChild(true); + alg.setProperty("InputWorkspace", polref); + alg.setProperty("ThetaIn", 1.5); + alg.setProperty("AnalysisMode", "MultiDetectorAnalysis"); + alg.setProperty("CorrectionAlgorithm", "None"); + alg.setProperty("MomentumTransferStep", 0.01); + alg.setProperty("OutputWorkspace", "IvsQ"); + alg.setProperty("OutputWorkspaceBinned", "IvsQ_binned"); + alg.setProperty("OutputWorkspaceWavelength", "IvsLam"); + alg.execute(); + MatrixWorkspace_sptr out = alg.getProperty("OutputWorkspace"); + + // Compare instrument components before and after + auto instIn = polref->getInstrument(); + auto instOut = out->getInstrument(); + + // The following components should not have been moved + TS_ASSERT_EQUALS(instIn->getComponentByName("monitor1")->getPos(), + instOut->getComponentByName("monitor1")->getPos()); + TS_ASSERT_EQUALS(instIn->getComponentByName("monitor2")->getPos(), + instOut->getComponentByName("monitor2")->getPos()); + TS_ASSERT_EQUALS(instIn->getComponentByName("monitor3")->getPos(), + instOut->getComponentByName("monitor3")->getPos()); + TS_ASSERT_EQUALS(instIn->getComponentByName("point-detector")->getPos(), + instOut->getComponentByName("point-detector")->getPos()); + TS_ASSERT_EQUALS(instIn->getComponentByName("lineardetector")->getPos(), + instOut->getComponentByName("lineardetector")->getPos()); + + // Only 'OSMOND' should have been moved vertically (along Z) + + auto detectorIn = instIn->getComponentByName("OSMOND")->getPos(); + auto detectorOut = instOut->getComponentByName("OSMOND")->getPos(); + + TS_ASSERT_EQUALS(detectorIn.X(), detectorOut.X()); + TS_ASSERT_EQUALS(detectorIn.Y(), detectorOut.Y()); + TS_ASSERT_DELTA(detectorOut.Z() / + (detectorOut.X() - instOut->getSample()->getPos().X()), + std::tan(1.5 * 2 * M_PI / 180), 1e-4); + } + + void test_correct_detector_position_CRISP() { + // Histogram in this run corresponds to 'point-detector' component + auto polref = loadRun("CSP79590.raw"); + + ReflectometryReductionOneAuto2 alg; + alg.initialize(); + alg.setChild(true); + alg.setProperty("InputWorkspace", polref); + alg.setProperty("ThetaIn", 0.25); + alg.setProperty("CorrectionAlgorithm", "None"); + alg.setProperty("MomentumTransferStep", 0.01); + alg.setProperty("OutputWorkspace", "IvsQ"); + alg.setProperty("OutputWorkspaceBinned", "IvsQ_binned"); + alg.setProperty("OutputWorkspaceWavelength", "IvsLam"); + alg.execute(); + MatrixWorkspace_sptr out = alg.getProperty("OutputWorkspace"); + + // Compare instrument components before and after + auto instIn = polref->getInstrument(); + auto instOut = out->getInstrument(); + + // The following components should not have been moved + TS_ASSERT_EQUALS(instIn->getComponentByName("monitor1")->getPos(), + instOut->getComponentByName("monitor1")->getPos()); + TS_ASSERT_EQUALS(instIn->getComponentByName("monitor2")->getPos(), + instOut->getComponentByName("monitor2")->getPos()); + TS_ASSERT_EQUALS(instIn->getComponentByName("linear-detector")->getPos(), + instOut->getComponentByName("linear-detector")->getPos()); + + // Only 'point-detector' should have been moved vertically (along Y) + + auto detectorIn = instIn->getComponentByName("point-detector")->getPos(); + auto detectorOut = instOut->getComponentByName("point-detector")->getPos(); + + TS_ASSERT_EQUALS(detectorIn.X(), detectorOut.X()); + TS_ASSERT_EQUALS(detectorIn.Z(), detectorOut.Z()); + TS_ASSERT_DELTA(detectorOut.Y() / + (detectorOut.Z() - instOut->getSample()->getPos().Z()), + std::tan(0.25 * 2 * M_PI / 180), 1e-4); + } + + void test_sum_transmission_workspaces() { + MatrixWorkspace_sptr first = m_TOF->clone(); + MatrixWorkspace_sptr second = m_TOF->clone(); + MatrixWorkspace_sptr third = m_TOF->clone(); + MatrixWorkspace_sptr fourth = m_TOF->clone(); + + WorkspaceGroup_sptr group = boost::make_shared<WorkspaceGroup>(); + group->addWorkspace(first); + group->addWorkspace(second); + group->addWorkspace(third); + group->addWorkspace(fourth); + + ReflectometryReductionOneAuto2 alg; + auto sum = alg.sumTransmissionWorkspaces(group); + + // Input workspaces remain the same + TS_ASSERT_EQUALS(first->blocksize(), 20); + TS_ASSERT_EQUALS(second->blocksize(), 20); + TS_ASSERT_EQUALS(third->blocksize(), 20); + TS_ASSERT_EQUALS(fourth->blocksize(), 20); + TS_ASSERT_EQUALS(first->y(0)[0], 2); + TS_ASSERT_EQUALS(second->y(0)[0], 2); + TS_ASSERT_EQUALS(third->y(0)[0], 2); + TS_ASSERT_EQUALS(fourth->y(0)[0], 2); + + // Output workspace + TS_ASSERT_EQUALS(sum->blocksize(), 20); + TS_ASSERT_DELTA(sum->y(0)[0], 4 * 2, 1e-6); + } + + void test_IvsQ_linear_binning() { + + ReflectometryReductionOneAuto2 alg; + alg.setChild(true); + alg.initialize(); + alg.setProperty("InputWorkspace", m_TOF); + alg.setProperty("WavelengthMin", 1.5); + alg.setProperty("WavelengthMax", 15.0); + alg.setProperty("ProcessingInstructions", "1"); + alg.setProperty("MomentumTransferMin", 1.0); + alg.setProperty("MomentumTransferMax", 10.0); + alg.setProperty("MomentumTransferStep", -0.04); + alg.setPropertyValue("OutputWorkspace", "IvsQ"); + alg.setPropertyValue("OutputWorkspaceBinned", "IvsQ_binned"); + alg.setPropertyValue("OutputWorkspaceWavelength", "IvsLam"); + alg.execute(); + MatrixWorkspace_sptr outQbinned = alg.getProperty("OutputWorkspaceBinned"); + + TS_ASSERT_EQUALS(outQbinned->getNumberHistograms(), 1); + // blocksize = (10.0 - 1.0) / 0.04 + TS_ASSERT_EQUALS(outQbinned->blocksize(), 225); + TS_ASSERT_DELTA(outQbinned->x(0)[1] - outQbinned->x(0)[0], 0.04, 1e-6); + TS_ASSERT_DELTA(outQbinned->x(0)[2] - outQbinned->x(0)[1], 0.04, 1e-6); + } + + void test_IvsQ_logarithmic_binning() { + + ReflectometryReductionOneAuto2 alg; + alg.setChild(true); + alg.initialize(); + alg.setProperty("InputWorkspace", m_TOF); + alg.setProperty("WavelengthMin", 1.5); + alg.setProperty("WavelengthMax", 15.0); + alg.setProperty("ProcessingInstructions", "1"); + alg.setProperty("MomentumTransferMin", 1.0); + alg.setProperty("MomentumTransferMax", 10.0); + alg.setProperty("MomentumTransferStep", 0.04); + alg.setPropertyValue("OutputWorkspace", "IvsQ"); + alg.setPropertyValue("OutputWorkspaceBinned", "IvsQ_binned"); + alg.setPropertyValue("OutputWorkspaceWavelength", "IvsLam"); + alg.execute(); + MatrixWorkspace_sptr outQbinned = alg.getProperty("OutputWorkspaceBinned"); + + TS_ASSERT_EQUALS(outQbinned->getNumberHistograms(), 1); + TS_ASSERT_DIFFERS(outQbinned->blocksize(), 8); + TS_ASSERT_DELTA(outQbinned->x(0)[1] - outQbinned->x(0)[0], 0.04, 1e-6); + TS_ASSERT(outQbinned->x(0)[7] - outQbinned->x(0)[6] > 0.05); + } + + void test_IvsQ_q_range() { + + ReflectometryReductionOneAuto2 alg; + alg.setChild(true); + alg.initialize(); + alg.setProperty("InputWorkspace", m_TOF); + alg.setProperty("WavelengthMin", 1.5); + alg.setProperty("WavelengthMax", 15.0); + alg.setProperty("ProcessingInstructions", "2"); + alg.setProperty("MomentumTransferStep", 0.04); + alg.setPropertyValue("OutputWorkspace", "IvsQ"); + alg.setPropertyValue("OutputWorkspaceBinned", "IvsQ_binned"); + alg.setPropertyValue("OutputWorkspaceWavelength", "IvsLam"); + alg.execute(); + MatrixWorkspace_sptr outQ = alg.getProperty("OutputWorkspace"); + MatrixWorkspace_sptr outLam = alg.getProperty("OutputWorkspaceWavelength"); + + for (size_t i = 0; i < outQ->blocksize(); i++) + std::cout << outLam->x(0)[i] << "\n"; + + TS_ASSERT_EQUALS(outQ->getNumberHistograms(), 1); + TS_ASSERT_EQUALS(outQ->blocksize(), 8); + // X range in outLam + TS_ASSERT_DELTA(outLam->x(0)[0], 2.8257, 0.0001); + TS_ASSERT_DELTA(outLam->x(0)[7], 12.7158, 0.0001); + // X range in outQ + TS_ASSERT_DELTA(outQ->x(0)[0], 0.3403, 0.0001); + TS_ASSERT_DELTA(outQ->x(0)[7], 1.1345, 0.0001); + } +}; + +#endif /* MANTID_ALGORITHMS_REFLECTOMETRYREDUCTIONONEAUTO2TEST_H_ */ \ No newline at end of file diff --git a/Framework/Algorithms/test/ReflectometryReductionOneAutoTest.h b/Framework/Algorithms/test/ReflectometryReductionOneAutoTest.h index 082e83c04bba5dc49f4914d43d10c7d9be2fe308..6b70e7a807b629ea625a31d922940e3f0167e2d0 100644 --- a/Framework/Algorithms/test/ReflectometryReductionOneAutoTest.h +++ b/Framework/Algorithms/test/ReflectometryReductionOneAutoTest.h @@ -3,14 +3,15 @@ #include <cxxtest/TestSuite.h> -#include "MantidAlgorithms/ReflectometryReductionOneAuto.h" #include "MantidAPI/AlgorithmManager.h" #include "MantidAPI/Axis.h" #include "MantidAPI/FrameworkManager.h" #include "MantidAPI/WorkspaceGroup.h" #include "MantidAPI/WorkspaceHistory.h" +#include "MantidAlgorithms/ReflectometryReductionOneAuto.h" #include "MantidGeometry/Instrument.h" #include "MantidGeometry/Instrument/ReferenceFrame.h" +#include "MantidKernel/Unit.h" #include "MantidTestHelpers/WorkspaceCreationHelper.h" using Mantid::Algorithms::ReflectometryReductionOneAuto; @@ -127,18 +128,20 @@ public: temp = lAlg->getProperty("OutputWorkspace"); m_multiDetectorWorkspace = boost::dynamic_pointer_cast<WorkspaceGroup>(temp); - // m_multiDetectorWorkspace = - // AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>( - // "multidetector_ws_1"); + AnalysisDataService::Instance().addOrReplace("multidetector_group", + m_multiDetectorWorkspace); } ~ReflectometryReductionOneAutoTest() override { AnalysisDataService::Instance().remove("TOF"); AnalysisDataService::Instance().remove("NotTOF"); + AnalysisDataService::Instance().remove("multidetector_group"); + AnalysisDataService::Instance().remove("multidetector_group_1"); + AnalysisDataService::Instance().remove("multidetector_group_2"); } IAlgorithm_sptr construct_standard_algorithm() { auto alg = - AlgorithmManager::Instance().create("ReflectometryReductionOneAuto"); + AlgorithmManager::Instance().create("ReflectometryReductionOneAuto", 1); alg->initialize(); alg->setProperty("InputWorkspace", m_TOF); alg->setProperty("WavelengthMin", 0.0); @@ -199,7 +202,7 @@ public: void test_must_provide_wavelengths() { auto algWithMax = - AlgorithmManager::Instance().create("ReflectometryReductionOneAuto"); + AlgorithmManager::Instance().create("ReflectometryReductionOneAuto", 1); algWithMax->initialize(); algWithMax->setProperty("InputWorkspace", m_TOF); algWithMax->setProperty("FirstTransmissionRun", m_TOF); @@ -213,7 +216,7 @@ public: TS_ASSERT_THROWS(algWithMax->execute(), std::runtime_error); auto algWithMin = - AlgorithmManager::Instance().create("ReflectometryReductionOneAuto"); + AlgorithmManager::Instance().create("ReflectometryReductionOneAuto", 1); algWithMin->initialize(); algWithMin->setProperty("InputWorkspace", m_TOF); algWithMin->setProperty("FirstTransmissionRun", m_TOF); @@ -297,7 +300,7 @@ public: } void test_exec() { IAlgorithm_sptr alg = - AlgorithmManager::Instance().create("ReflectometryReductionOneAuto"); + AlgorithmManager::Instance().create("ReflectometryReductionOneAuto", 1); alg->setRethrows(true); TS_ASSERT_THROWS_NOTHING(alg->initialize()); TS_ASSERT_THROWS_NOTHING( @@ -376,7 +379,7 @@ public: new PropertyWithValue<std::string>("run_number", "12345")); IAlgorithm_sptr alg = - AlgorithmManager::Instance().create("ReflectometryReductionOneAuto"); + AlgorithmManager::Instance().create("ReflectometryReductionOneAuto", 1); alg->setRethrows(true); TS_ASSERT_THROWS_NOTHING(alg->initialize()); TS_ASSERT_THROWS_NOTHING(alg->setProperty("InputWorkspace", tinyWS)); @@ -472,7 +475,7 @@ public: // Reduce IAlgorithm_sptr alg = - AlgorithmManager::Instance().create("ReflectometryReductionOneAuto"); + AlgorithmManager::Instance().create("ReflectometryReductionOneAuto", 1); alg->setRethrows(true); TS_ASSERT_THROWS_NOTHING(alg->initialize()); TS_ASSERT_THROWS_NOTHING(alg->setProperty("InputWorkspace", inWSName)); @@ -549,7 +552,7 @@ public: // Reduce IAlgorithm_sptr alg = - AlgorithmManager::Instance().create("ReflectometryReductionOneAuto"); + AlgorithmManager::Instance().create("ReflectometryReductionOneAuto", 1); alg->setRethrows(true); alg->setChild(true); TS_ASSERT_THROWS_NOTHING(alg->initialize()); @@ -573,6 +576,224 @@ public: // reset the instrument associated with m_dataWorkspace m_dataWorkspace->setInstrument(m_dataWorkspaceInstHolder); } + void test_point_detector_run_with_single_transmission_workspace() { + ReflectometryReductionOneAuto alg; + alg.initialize(); + alg.setChild(true); + alg.setProperty("WavelengthMin", 1.0); + alg.setProperty("WavelengthMax", 2.0); + alg.setProperty("I0MonitorIndex", 0); + alg.setProperty("ProcessingInstructions", "3,4"); + alg.setProperty("MonitorBackgroundWavelengthMin", 0.0); + alg.setProperty("MonitorBackgroundWavelengthMax", 1.0); + alg.setProperty("MonitorIntegrationWavelengthMin", 0.0); + alg.setProperty("MonitorIntegrationWavelengthMax", 1.0); + alg.setProperty("InputWorkspace", m_dataWorkspace); + alg.setProperty("FirstTransmissionRun", m_transWorkspace1); + alg.setProperty("ThetaIn", 0.2); + alg.setPropertyValue("OutputWorkspace", "IvsQ"); + alg.setPropertyValue("OutputWorkspaceWavelength", "IvsLam"); + + TS_ASSERT_THROWS_NOTHING(alg.execute()); + + double thetaOut = alg.getProperty("ThetaOut"); + TSM_ASSERT_EQUALS("Theta in and out should be the same", thetaOut, 0.2); + + MatrixWorkspace_sptr IvsLam = alg.getProperty("OutputWorkspaceWavelength"); + TSM_ASSERT("OutputWorkspaceWavelength should be a valid matrix workspace", + IvsLam); + + MatrixWorkspace_sptr IvsQ = alg.getProperty("OutputWorkspace"); + TSM_ASSERT("OutputWorkspace should be a valid matrix workspace", IvsQ); + + TSM_ASSERT_EQUALS("OutputWorkspaceWavelength should have two histograms", + IvsLam->getNumberHistograms(), 2); + } + + void test_point_detector_run_with_two_transmission_workspaces() { + ReflectometryReductionOneAuto alg; + alg.initialize(); + alg.setChild(true); + alg.setProperty("WavelengthMin", 1.0); + alg.setProperty("WavelengthMax", 2.0); + alg.setProperty("I0MonitorIndex", 0); + alg.setProperty("ProcessingInstructions", "3, 4"); + alg.setProperty("MonitorBackgroundWavelengthMin", 0.0); + alg.setProperty("MonitorBackgroundWavelengthMax", 1.0); + alg.setProperty("MonitorIntegrationWavelengthMin", 0.0); + alg.setProperty("MonitorIntegrationWavelengthMax", 1.0); + alg.setProperty("InputWorkspace", m_dataWorkspace); + alg.setProperty("FirstTransmissionRun", m_transWorkspace1); + alg.setProperty("SecondTransmissionRun", m_transWorkspace2); + alg.setPropertyValue("OutputWorkspace", "IvsQ"); + alg.setPropertyValue("OutputWorkspaceWavelength", "IvsLam"); + + TS_ASSERT_THROWS_NOTHING(alg.execute()); + } + + void test_spectrum_map_mismatch_throws_when_strict() { + ReflectometryReductionOneAuto alg; + alg.initialize(); + alg.setChild(true); + alg.setProperty("WavelengthMin", 1.0); + alg.setProperty("WavelengthMax", 2.0); + alg.setProperty("I0MonitorIndex", 0); + alg.setProperty("ProcessingInstructions", "3"); + alg.setProperty("MonitorBackgroundWavelengthMin", 0.0); + alg.setProperty("MonitorBackgroundWavelengthMax", 1.0); + alg.setProperty("MonitorIntegrationWavelengthMin", 0.0); + alg.setProperty("MonitorIntegrationWavelengthMax", 1.0); + alg.setPropertyValue("OutputWorkspace", "IvsQ"); + alg.setPropertyValue("OutputWorkspaceWavelength", "IvsLam"); + + alg.setProperty("InputWorkspace", m_dataWorkspace); + alg.execute(); + + MatrixWorkspace_sptr trans = alg.getProperty("OutputWorkspaceWavelength"); + alg.setProperty("FirstTransmissionRun", trans); + alg.setProperty("ProcessingInstructions", "4"); + TS_ASSERT_THROWS_ANYTHING(alg.execute()); + } + + void test_spectrum_map_mismatch_doesnt_throw_when_not_strict() { + ReflectometryReductionOneAuto alg; + alg.initialize(); + alg.setChild(true); + alg.setProperty("WavelengthMin", 1.0); + alg.setProperty("WavelengthMax", 2.0); + alg.setProperty("I0MonitorIndex", 0); + alg.setProperty("ProcessingInstructions", "3"); + alg.setProperty("MonitorBackgroundWavelengthMin", 0.0); + alg.setProperty("MonitorBackgroundWavelengthMax", 1.0); + alg.setProperty("MonitorIntegrationWavelengthMin", 0.0); + alg.setProperty("MonitorIntegrationWavelengthMax", 1.0); + alg.setPropertyValue("OutputWorkspace", "IvsQ"); + alg.setPropertyValue("OutputWorkspaceWavelength", "IvsLam"); + + alg.setProperty("InputWorkspace", m_dataWorkspace); + alg.execute(); + + MatrixWorkspace_sptr trans = alg.getProperty("OutputWorkspaceWavelength"); + alg.setProperty("FirstTransmissionRun", trans); + alg.setProperty("ProcessingInstructions", "4"); + alg.setProperty("StrictSpectrumChecking", "0"); + TS_ASSERT_THROWS_NOTHING(alg.execute()); + } + + void test_multidetector_run() { + ReflectometryReductionOneAuto alg; + alg.initialize(); + alg.setChild(false); + alg.setProperty("WavelengthMin", 1.0); + alg.setProperty("WavelengthMax", 2.0); + alg.setProperty("I0MonitorIndex", 0); + alg.setProperty("ProcessingInstructions", "10"); + alg.setProperty("AnalysisMode", "MultiDetectorAnalysis"); + alg.setProperty("CorrectDetectorPositions", "0"); + alg.setProperty("DetectorComponentName", "lineardetector"); + alg.setProperty("RegionOfDirectBeam", "20, 30"); + alg.setProperty("MonitorBackgroundWavelengthMin", 0.0); + alg.setProperty("MonitorBackgroundWavelengthMax", 1.0); + alg.setProperty("MonitorIntegrationWavelengthMin", 0.0); + alg.setProperty("MonitorIntegrationWavelengthMax", 1.0); + alg.setProperty("ThetaIn", 0.1); + alg.setPropertyValue("OutputWorkspace", "IvsQ"); + alg.setPropertyValue("OutputWorkspaceWavelength", "IvsLam"); + alg.setPropertyValue("InputWorkspace", "multidetector_group"); + + TS_ASSERT_THROWS_NOTHING(alg.execute()); + + MatrixWorkspace_sptr IvsLam_1 = + AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("IvsLam_1"); + TSM_ASSERT("OutputWorkspaceWavelength should be a matrix workspace", + IvsLam_1); + TS_ASSERT_EQUALS("Wavelength", IvsLam_1->getAxis(0)->unit()->unitID()); + MatrixWorkspace_sptr IvsLam_2 = + AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("IvsLam_2"); + TSM_ASSERT("OutputWorkspaceWavelength should be a matrix workspace", + IvsLam_2); + TS_ASSERT_EQUALS("Wavelength", IvsLam_2->getAxis(0)->unit()->unitID()); + + MatrixWorkspace_sptr IvsQ_1 = + AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("IvsQ_1"); + TSM_ASSERT("OutputWorkspace should be a matrix workspace", IvsQ_1); + TS_ASSERT_EQUALS("MomentumTransfer", IvsQ_1->getAxis(0)->unit()->unitID()); + MatrixWorkspace_sptr IvsQ_2 = + AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("IvsQ_2"); + TSM_ASSERT("OutputWorkspace should be a matrix workspace", IvsQ_2); + TS_ASSERT_EQUALS("MomentumTransfer", IvsQ_2->getAxis(0)->unit()->unitID()); + + MatrixWorkspace_sptr tempWS = boost::dynamic_pointer_cast<MatrixWorkspace>( + m_multiDetectorWorkspace->getItem(0)); + auto instrBefore = tempWS->getInstrument(); + auto detectorBefore = instrBefore->getComponentByName("lineardetector"); + auto instrAfter = IvsLam_1->getInstrument(); + auto detectorAfter = instrAfter->getComponentByName("lineardetector"); + TS_ASSERT_DELTA(detectorBefore->getPos().Z(), detectorAfter->getPos().Z(), + 0.0001) + + AnalysisDataService::Instance().remove("IvsLam"); + AnalysisDataService::Instance().remove("IvsLam_1"); + AnalysisDataService::Instance().remove("IvsLam_2"); + AnalysisDataService::Instance().remove("IvsQ"); + AnalysisDataService::Instance().remove("IvsQ_1"); + AnalysisDataService::Instance().remove("IvsQ_2"); + } + + void test_multidetector_run_correct_positions() { + ReflectometryReductionOneAuto alg; + alg.initialize(); + alg.setChild(false); + alg.setProperty("WavelengthMin", 1.0); + alg.setProperty("WavelengthMax", 2.0); + alg.setProperty("I0MonitorIndex", 0); + alg.setProperty("ProcessingInstructions", "73"); + alg.setProperty("AnalysisMode", "MultiDetectorAnalysis"); + alg.setProperty("CorrectDetectorPositions", "1"); + alg.setProperty("DetectorComponentName", "lineardetector"); + alg.setProperty("RegionOfDirectBeam", "28, 29"); + alg.setProperty("MonitorBackgroundWavelengthMin", 0.0); + alg.setProperty("MonitorBackgroundWavelengthMax", 1.0); + alg.setProperty("MonitorIntegrationWavelengthMin", 0.0); + alg.setProperty("MonitorIntegrationWavelengthMax", 1.0); + alg.setProperty("ThetaIn", 0.49); + alg.setPropertyValue("OutputWorkspace", "IvsQ"); + alg.setPropertyValue("OutputWorkspaceWavelength", "IvsLam"); + alg.setPropertyValue("InputWorkspace", "multidetector_group"); + + TS_ASSERT_THROWS_NOTHING(alg.execute()); + + MatrixWorkspace_sptr IvsLam_1 = + AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("IvsLam_1"); + TSM_ASSERT("OutputWorkspaceWavelength should be a matrix workspace", + IvsLam_1); + TS_ASSERT_EQUALS("Wavelength", IvsLam_1->getAxis(0)->unit()->unitID()); + MatrixWorkspace_sptr IvsLam_2 = + AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("IvsLam_2"); + TSM_ASSERT("OutputWorkspaceWavelength should be a matrix workspace", + IvsLam_2); + TS_ASSERT_EQUALS("Wavelength", IvsLam_2->getAxis(0)->unit()->unitID()); + + MatrixWorkspace_sptr IvsQ_1 = + AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("IvsQ_1"); + TSM_ASSERT("OutputWorkspace should be a matrix workspace", IvsQ_1); + TS_ASSERT_EQUALS("MomentumTransfer", IvsQ_1->getAxis(0)->unit()->unitID()); + MatrixWorkspace_sptr IvsQ_2 = + AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("IvsQ_2"); + TSM_ASSERT("OutputWorkspace should be a matrix workspace", IvsQ_2); + TS_ASSERT_EQUALS("MomentumTransfer", IvsQ_2->getAxis(0)->unit()->unitID()); + + auto instr = IvsLam_1->getInstrument(); + auto detectorPos = instr->getComponentByName("lineardetector"); + TS_ASSERT_DELTA(-0.05714, detectorPos->getPos().Z(), 0.0001) + + AnalysisDataService::Instance().remove("IvsLam"); + AnalysisDataService::Instance().remove("IvsLam_1"); + AnalysisDataService::Instance().remove("IvsLam_2"); + AnalysisDataService::Instance().remove("IvsQ"); + AnalysisDataService::Instance().remove("IvsQ_1"); + AnalysisDataService::Instance().remove("IvsQ_2"); + } }; #endif /* MANTID_ALGORITHMS_REFLECTOMETRYREDUCTIONONEAUTOTEST_H_ */ diff --git a/Framework/Algorithms/test/ReflectometryReductionOneTest.h b/Framework/Algorithms/test/ReflectometryReductionOneTest.h index 2e246ecd85bbdd9d9ea489057b1f93669740b188..bb3ea8f84fe0c32f0bff754c1c7f13cd06817a04 100644 --- a/Framework/Algorithms/test/ReflectometryReductionOneTest.h +++ b/Framework/Algorithms/test/ReflectometryReductionOneTest.h @@ -179,7 +179,8 @@ public: // set this detector ready for processing instructions m_tinyReflWS->getSpectrum(0).setDetectorID(det->getID()); - auto alg = AlgorithmManager::Instance().create("ReflectometryReductionOne"); + auto alg = + AlgorithmManager::Instance().create("ReflectometryReductionOne", 1); alg->setRethrows(true); alg->setChild(true); alg->initialize(); @@ -338,7 +339,8 @@ public: // set this detector ready for processing instructions m_tinyReflWS->getSpectrum(0).setDetectorID(det->getID()); - auto alg = AlgorithmManager::Instance().create("ReflectometryReductionOne"); + auto alg = + AlgorithmManager::Instance().create("ReflectometryReductionOne", 1); alg->setRethrows(true); alg->setChild(true); alg->initialize(); diff --git a/Framework/Algorithms/test/SpecularReflectionPositionCorrect2Test.h b/Framework/Algorithms/test/SpecularReflectionPositionCorrect2Test.h new file mode 100644 index 0000000000000000000000000000000000000000..a2ed9a1c272b416c23479711632f16c09f652716 --- /dev/null +++ b/Framework/Algorithms/test/SpecularReflectionPositionCorrect2Test.h @@ -0,0 +1,137 @@ +#ifndef MANTID_ALGORITHMS_SPECULARREFLECTIONPOSITIONCORRECT2TEST_H_ +#define MANTID_ALGORITHMS_SPECULARREFLECTIONPOSITIONCORRECT2TEST_H_ + +#include <cxxtest/TestSuite.h> +#include "MantidAlgorithms/SpecularReflectionPositionCorrect2.h" +#include "MantidAPI/AlgorithmManager.h" +#include "MantidAPI/FrameworkManager.h" +#include "MantidGeometry/Instrument.h" +#include "MantidTestHelpers/WorkspaceCreationHelper.h" + +using Mantid::Algorithms::SpecularReflectionPositionCorrect2; +using namespace Mantid::API; +using namespace Mantid::Kernel; +using namespace Mantid::Geometry; + +class SpecularReflectionPositionCorrect2Test : public CxxTest::TestSuite { +private: + MatrixWorkspace_sptr m_interWS; + +public: + // This pair of boilerplate methods prevent the suite being created statically + // This means the constructor isn't called when running other tests + static SpecularReflectionPositionCorrect2Test *createSuite() { + return new SpecularReflectionPositionCorrect2Test(); + } + static void destroySuite(SpecularReflectionPositionCorrect2Test *suite) { + delete suite; + } + + SpecularReflectionPositionCorrect2Test() { + FrameworkManager::Instance(); + + auto load = AlgorithmManager::Instance().create("LoadEmptyInstrument"); + load->initialize(); + load->setChild(true); + load->setProperty("InstrumentName", "INTER"); + load->setPropertyValue("OutputWorkspace", "inter"); + load->execute(); + m_interWS = load->getProperty("OutputWorkspace"); + } + + void test_init() { + SpecularReflectionPositionCorrect2 alg; + TS_ASSERT_THROWS_NOTHING(alg.initialize()) + TS_ASSERT(alg.isInitialized()) + } + + void test_theta_is_mandatory() { + SpecularReflectionPositionCorrect2 alg; + alg.initialize(); + alg.setChild(true); + alg.setProperty("InputWorkspace", m_interWS); + alg.setProperty("DetectorComponentName", "point-detector"); + alg.setPropertyValue("OutputWorkspace", "test_out"); + TS_ASSERT_THROWS(alg.execute(), std::runtime_error &); + } + + void test_theta_bad_value() { + SpecularReflectionPositionCorrect2 alg; + alg.initialize(); + alg.setChild(true); + alg.setProperty("InputWorkspace", m_interWS); + alg.setProperty("DetectorComponentName", "point-detector"); + alg.setPropertyValue("OutputWorkspace", "test_out"); + TS_ASSERT_THROWS(alg.setProperty("TwoTheta", 0.0), std::invalid_argument &); + TS_ASSERT_THROWS(alg.setProperty("TwoTheta", 90.0), + std::invalid_argument &); + } + + void test_detector_component_is_mandatory() { + SpecularReflectionPositionCorrect2 alg; + alg.initialize(); + alg.setChild(true); + alg.setProperty("InputWorkspace", m_interWS); + alg.setProperty("TwoTheta", 1.4); + alg.setPropertyValue("OutputWorkspace", "test_out"); + TS_ASSERT_THROWS_ANYTHING(alg.execute()); + } + + void test_correct_point_detector() { + SpecularReflectionPositionCorrect2 alg; + alg.initialize(); + alg.setChild(true); + alg.setProperty("InputWorkspace", m_interWS); + alg.setProperty("TwoTheta", 1.4); + alg.setProperty("DetectorComponentName", "point-detector"); + alg.setPropertyValue("OutputWorkspace", "test_out"); + TS_ASSERT_THROWS_NOTHING(alg.execute()); + MatrixWorkspace_sptr outWS = alg.getProperty("OutputWorkspace"); + + TS_ASSERT(outWS); + + auto instrIn = m_interWS->getInstrument(); + auto instrOut = outWS->getInstrument(); + + // Sample should not have moved + auto sampleIn = instrIn->getSample()->getPos(); + auto sampleOut = instrOut->getSample()->getPos(); + TS_ASSERT_EQUALS(sampleIn, sampleOut); + // 'point-detector' should have been moved vertically only + auto detIn = instrIn->getComponentByName("point-detector")->getPos(); + auto detOut = instrOut->getComponentByName("point-detector")->getPos(); + TS_ASSERT_EQUALS(detIn.X(), detOut.X()); + TS_ASSERT_EQUALS(detIn.Z(), detOut.Z()); + TS_ASSERT_DELTA(detOut.Y(), 0.06508, 1e-5); + } + + void test_correct_linear_detector() { + SpecularReflectionPositionCorrect2 alg; + alg.initialize(); + alg.setChild(true); + alg.setProperty("InputWorkspace", m_interWS); + alg.setProperty("TwoTheta", 1.4); + alg.setProperty("DetectorComponentName", "linear-detector"); + alg.setPropertyValue("OutputWorkspace", "test_out"); + TS_ASSERT_THROWS_NOTHING(alg.execute()); + MatrixWorkspace_sptr outWS = alg.getProperty("OutputWorkspace"); + + TS_ASSERT(outWS); + + auto instrIn = m_interWS->getInstrument(); + auto instrOut = outWS->getInstrument(); + + // Sample should not have moved + auto sampleIn = instrIn->getSample()->getPos(); + auto sampleOut = instrOut->getSample()->getPos(); + TS_ASSERT_EQUALS(sampleIn, sampleOut); + // 'point-detector' should have been moved vertically only + auto detIn = instrIn->getComponentByName("linear-detector")->getPos(); + auto detOut = instrOut->getComponentByName("linear-detector")->getPos(); + TS_ASSERT_EQUALS(detIn.X(), detOut.X()); + TS_ASSERT_EQUALS(detIn.Z(), detOut.Z()); + TS_ASSERT_DELTA(detOut.Y(), 0.07730, 1e-5); + } +}; + +#endif /* MANTID_ALGORITHMS_SPECULARREFLECTIONPOSITIONCORRECT2TEST_H_ */ diff --git a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/ConvertToReflectometryQ.h b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/ConvertToReflectometryQ.h index 7291d219ca4ea6f76c3698455105684458bd60be..b4e4c9dd97a6ee0174a68590933a5c5536c7e8bb 100644 --- a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/ConvertToReflectometryQ.h +++ b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/ConvertToReflectometryQ.h @@ -48,6 +48,8 @@ public: private: void init() override; void exec() override; + Mantid::API::MatrixWorkspace_sptr + correctDetectors(Mantid::API::MatrixWorkspace_sptr inputWs, double theta); }; } // namespace MDAlgorithms diff --git a/Framework/MDAlgorithms/src/ConvertToReflectometryQ.cpp b/Framework/MDAlgorithms/src/ConvertToReflectometryQ.cpp index 67332bf786317f9b1d5337bccf159c235e5f18e2..825946ea68e8bf3372cb26bf116b2d83482e8002 100644 --- a/Framework/MDAlgorithms/src/ConvertToReflectometryQ.cpp +++ b/Framework/MDAlgorithms/src/ConvertToReflectometryQ.cpp @@ -1,21 +1,17 @@ #include "MantidMDAlgorithms/ConvertToReflectometryQ.h" #include "MantidAPI/Axis.h" -#include "MantidAPI/IEventWorkspace.h" -#include "MantidAPI/ITableWorkspace.h" #include "MantidAPI/HistogramValidator.h" +#include "MantidAPI/ITableWorkspace.h" +#include "MantidAPI/Progress.h" #include "MantidAPI/Run.h" #include "MantidAPI/WorkspaceUnitValidator.h" -#include "MantidAPI/Progress.h" -#include "MantidDataObjects/EventWorkspace.h" -#include "MantidDataObjects/MDEventWorkspace.h" -#include "MantidDataObjects/MDEventFactory.h" #include "MantidDataObjects/TableWorkspace.h" #include "MantidDataObjects/Workspace2D.h" -#include "MantidGeometry/MDGeometry/QLab.h" #include "MantidGeometry/MDGeometry/GeneralFrame.h" +#include "MantidGeometry/MDGeometry/QLab.h" #include "MantidKernel/ArrayProperty.h" #include "MantidKernel/CompositeValidator.h" @@ -25,11 +21,9 @@ #include "MantidKernel/Unit.h" #include "MantidMDAlgorithms/ReflectometryTransformKiKf.h" -#include "MantidMDAlgorithms/ReflectometryTransformQxQz.h" #include "MantidMDAlgorithms/ReflectometryTransformP.h" +#include "MantidMDAlgorithms/ReflectometryTransformQxQz.h" -#include <boost/optional.hpp> -#include <boost/shared_ptr.hpp> #include <boost/make_shared.hpp> using namespace Mantid::API; @@ -141,6 +135,33 @@ void checkOutputDimensionalityChoice(const std::string &outputDimensions) { throw std::runtime_error("Unknown transformation"); } } + +/* +Get the value of theta from the logs +@param inputWs : the input workspace +@return : theta found in the logs +@throw: runtime_errror if 'stheta' was not found. +*/ +double getThetaFromLogs(MatrixWorkspace_sptr inputWs) { + + double theta = -1.; + const Mantid::API::Run &run = inputWs->run(); + try { + Property *p = run.getLogData("stheta"); + auto incidentThetas = + dynamic_cast<Mantid::Kernel::TimeSeriesProperty<double> *>(p); + if (!incidentThetas) { + throw std::runtime_error("stheta log not found"); + } + theta = + incidentThetas->valuesAsVector().back(); // Not quite sure what to do + // with the time series for + // stheta + } catch (Exception::NotFoundError &) { + return theta; + } + return theta; +} } namespace Mantid { @@ -291,31 +312,18 @@ void ConvertToReflectometryQ::exec() { // retired as soon as all // transforms have been - // Extract the incient theta angle from the logs if a user provided one is not - // given. + // Extract the incident theta angle from the logs + double thetaFromLogs = getThetaFromLogs(inputWs); if (!bUseOwnIncidentTheta) { - const Mantid::API::Run &run = inputWs->run(); - try { - Property *p = run.getLogData("stheta"); - auto incidentThetas = - dynamic_cast<Mantid::Kernel::TimeSeriesProperty<double> *>(p); - if (!incidentThetas) { - throw std::runtime_error("stheta log not found"); - } - incidentTheta = - incidentThetas->valuesAsVector().back(); // Not quite sure what to do - // with the time series for - // stheta - checkIncidentTheta(incidentTheta); - std::stringstream stream; - stream << "Extracted initial theta value of: " << incidentTheta; - g_log.information(stream.str()); - } catch (Exception::NotFoundError &) { - throw std::runtime_error( - "The input workspace does not have a stheta log value."); - } + // Use the incident theta angle from the logs if a user provided one is not + // given. + checkIncidentTheta(thetaFromLogs); + incidentTheta = thetaFromLogs; } + // Correct the detectors according to theta read from logs + inputWs = correctDetectors(inputWs, thetaFromLogs); + // Min max extent values. const double dim0min = extents[0]; const double dim0max = extents[1]; @@ -413,5 +421,46 @@ void ConvertToReflectometryQ::exec() { setPropertyProg.report("Success"); } +MatrixWorkspace_sptr +ConvertToReflectometryQ::correctDetectors(MatrixWorkspace_sptr inputWs, + const double theta) { + + if (theta < 0) + return inputWs; + + // Obtain the detector IDs that correspond to spectra in the input workspace + std::set<Mantid::detid_t> detectorIDs; + for (size_t sp = 0; sp < inputWs->getNumberHistograms(); sp++) { + auto ids = inputWs->getSpectrum(sp).getDetectorIDs(); + detectorIDs.insert(ids.begin(), ids.end()); + } + + // Move the parent component of the selected detectors + std::set<std::string> componentsToMove; + for (const auto &id : detectorIDs) { + auto detector = inputWs->getDetectorByID(id); + auto parent = detector->getParent(); + if (parent) { + auto parentType = parent->type(); + auto detectorName = (parentType == "Instrument") ? detector->getName() + : parent->getName(); + componentsToMove.insert(detectorName); + } + } + + MatrixWorkspace_sptr outWS = inputWs; + for (const auto &component : componentsToMove) { + IAlgorithm_sptr alg = + createChildAlgorithm("SpecularReflectionPositionCorrect"); + alg->setProperty("InputWorkspace", outWS); + alg->setProperty("TwoTheta", theta); + alg->setProperty("DetectorComponentName", component); + alg->execute(); + outWS = alg->getProperty("OutputWorkspace"); + } + + return outWS; +} + } // namespace Mantid } // namespace MDAlgorithms diff --git a/Framework/TestHelpers/inc/MantidTestHelpers/WorkspaceCreationHelper.h b/Framework/TestHelpers/inc/MantidTestHelpers/WorkspaceCreationHelper.h index 64e4d5e91a289561cfa64ad4e314bc87c38b7e8f..15e2dbd541ee9541567a6adc55501e1934426365 100644 --- a/Framework/TestHelpers/inc/MantidTestHelpers/WorkspaceCreationHelper.h +++ b/Framework/TestHelpers/inc/MantidTestHelpers/WorkspaceCreationHelper.h @@ -350,6 +350,11 @@ void create2DAngles(std::vector<double> &L2, std::vector<double> &polar, Mantid::API::MatrixWorkspace_sptr create2DWorkspaceWithReflectometryInstrument(double startX = 0); +/// Create a 2D workspace with one monitor and three detectors based around +/// a virtual reflectometry instrument. +Mantid::API::MatrixWorkspace_sptr +create2DWorkspaceWithReflectometryInstrumentMultiDetector(double startX = 0); + void createInstrumentForWorkspaceWithDistances( Mantid::API::MatrixWorkspace_sptr workspace, const Mantid::Kernel::V3D &samplePosition, diff --git a/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp b/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp index 4755e8842de3d4dbd50dcf3ac03201a41368d1a5..12c1b1a669bf9ed7404bc97f84a942f30c704508 100644 --- a/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp +++ b/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp @@ -495,6 +495,71 @@ create2DWorkspaceWithReflectometryInstrument(double startX) { return workspace; } +/** +* Create a very small 2D workspace for a virtual reflectometry instrument with +* multiple detectors +* @return workspace with instrument attached. +* @param startX : X Tof start value for the workspace. +*/ +MatrixWorkspace_sptr +create2DWorkspaceWithReflectometryInstrumentMultiDetector(double startX) { + Instrument_sptr instrument = boost::make_shared<Instrument>(); + instrument->setReferenceFrame( + boost::make_shared<ReferenceFrame>(Y /*up*/, X /*along*/, Left, "0,0,0")); + + ObjComponent *source = new ObjComponent("source"); + source->setPos(V3D(0, 0, 0)); + instrument->add(source); + instrument->markAsSource(source); + + ObjComponent *sample = new ObjComponent("some-surface-holder"); + sample->setPos(V3D(15, 0, 0)); + instrument->add(sample); + instrument->markAsSamplePos(sample); + + Detector *monitor = new Detector("Monitor", 1, nullptr); + monitor->setPos(14, 0, 0); + instrument->add(monitor); + instrument->markAsMonitor(monitor); + + Detector *det1 = new Detector( + "point-detector", 2, + ComponentCreationHelper::createCuboid(0.01, 0.02, 0.03), nullptr); + det1->setPos(20, (20 - sample->getPos().X()), 0); + instrument->add(det1); + instrument->markAsDetector(det1); + + Detector *det2 = new Detector( + "point-detector", 3, + ComponentCreationHelper::createCuboid(0.01, 0.02, 0.03), nullptr); + det2->setPos(20, (20 - sample->getPos().X()), 0); + instrument->add(det2); + instrument->markAsDetector(det2); + + Detector *det3 = new Detector( + "point-detector", 4, + ComponentCreationHelper::createCuboid(0.01, 0.02, 0.03), nullptr); + det3->setPos(20, (20 - sample->getPos().X()), 0); + instrument->add(det3); + instrument->markAsDetector(det3); + + const int nSpectra = 4; + const int nBins = 20; + const double deltaX = 5000; // TOF + auto workspace = create2DWorkspaceBinned(nSpectra, nBins, startX, deltaX); + + workspace->setTitle("Test histogram"); + workspace->getAxis(0)->setUnit("TOF"); + workspace->setYUnit("Counts"); + + workspace->setInstrument(instrument); + workspace->getSpectrum(0).setDetectorID(monitor->getID()); + workspace->getSpectrum(1).setDetectorID(det1->getID()); + workspace->getSpectrum(2).setDetectorID(det2->getID()); + workspace->getSpectrum(3).setDetectorID(det3->getID()); + return workspace; +} + void createInstrumentForWorkspaceWithDistances( MatrixWorkspace_sptr workspace, const V3D &samplePosition, const V3D &sourcePosition, const std::vector<V3D> &detectorPositions) { diff --git a/MantidQt/CustomInterfaces/src/Reflectometry/QtReflSettingsView.cpp b/MantidQt/CustomInterfaces/src/Reflectometry/QtReflSettingsView.cpp index f6511d4e0660ae7f4c336e66477c31f8a63ab6e5..08f0e9d10567b2c7a043cd92cc9170c426e30c17 100644 --- a/MantidQt/CustomInterfaces/src/Reflectometry/QtReflSettingsView.cpp +++ b/MantidQt/CustomInterfaces/src/Reflectometry/QtReflSettingsView.cpp @@ -78,7 +78,6 @@ void QtReflSettingsView::setExpDefaults( m_ui.CAlphaEdit->setText(QString::fromStdString(defaults[3])); m_ui.CApEdit->setText(QString::fromStdString(defaults[4])); m_ui.CPpEdit->setText(QString::fromStdString(defaults[5])); - m_ui.scaleFactorEdit->setText(QString::fromStdString(defaults[6])); } /* Sets default values for all instrument settings given a list of default diff --git a/MantidQt/CustomInterfaces/src/Reflectometry/ReflGenericDataProcessorPresenterFactory.cpp b/MantidQt/CustomInterfaces/src/Reflectometry/ReflGenericDataProcessorPresenterFactory.cpp index 28e4cd55933304b3b9f18bbffc3ca0f850e79fa6..c3f05d383e828cfb5d50c12651328b18167aa909 100644 --- a/MantidQt/CustomInterfaces/src/Reflectometry/ReflGenericDataProcessorPresenterFactory.cpp +++ b/MantidQt/CustomInterfaces/src/Reflectometry/ReflGenericDataProcessorPresenterFactory.cpp @@ -42,14 +42,14 @@ ReflGenericDataProcessorPresenterFactory::create() { "/><i>optional</i><br />To specify two transmission runs, separate " "them with a '+'. If left blank, the sample runs will be normalised " "by monitor only.<br /><br /><b>Example:</b> <samp>1234+12345</samp>"); - whitelist.addElement("Q min", "MomentumTransferMinimum", + whitelist.addElement("Q min", "MomentumTransferMin", "<b>Minimum value of Q to be used</b><br " "/><i>optional</i><br />Unit: Å<sup>-1</sup><br " "/>Data with a value of Q lower than this will be " "discarded. If left blank, this is set to the lowest " "Q value found. This is useful for discarding noisy " "data. <br /><br /><b>Example:</b> <samp>0.1</samp>"); - whitelist.addElement("Q max", "MomentumTransferMaximum", + whitelist.addElement("Q max", "MomentumTransferMax", "<b>Maximum value of Q to be used</b><br " "/><i>optional</i><br />Unit: Å<sup>-1</sup><br " "/>Data with a value of Q higher than this will be " @@ -72,13 +72,14 @@ ReflGenericDataProcessorPresenterFactory::create() { /*The name of the algorithm */ "ReflectometryReductionOneAuto", /*Prefixes to the output workspaces*/ - std::vector<std::string>{"IvsQ_", "IvsLam_"}, + std::vector<std::string>{"IvsQ_binned_", "IvsQ_", "IvsLam_"}, /*The blacklist*/ - std::set<std::string>{ - "ThetaIn", "ThetaOut", "InputWorkspace", "OutputWorkspace", - "OutputWorkspaceWavelength", "FirstTransmissionRun", - "SecondTransmissionRun", "MomentumTransferMinimum", - "MomentumTransferMaximum", "MomentumTransferStep", "ScaleFactor"}); + std::set<std::string>{"ThetaIn", "ThetaOut", "InputWorkspace", + "OutputWorkspace", "OutputWorkspaceBinned", + "OutputWorkspaceWavelength", "FirstTransmissionRun", + "SecondTransmissionRun", "MomentumTransferMin", + "MomentumTransferMax", "MomentumTransferStep", + "ScaleFactor"}); // Pre-processing instructions as a map: // Keys are the column names diff --git a/MantidQt/CustomInterfaces/src/Reflectometry/ReflSettingsPresenter.cpp b/MantidQt/CustomInterfaces/src/Reflectometry/ReflSettingsPresenter.cpp index 338f5f9dc8577ab8f1ee4a7d8bf2774d42a8efa8..d742ff2f0eb36acf789014469efaa891bcf3f08d 100644 --- a/MantidQt/CustomInterfaces/src/Reflectometry/ReflSettingsPresenter.cpp +++ b/MantidQt/CustomInterfaces/src/Reflectometry/ReflSettingsPresenter.cpp @@ -7,7 +7,6 @@ #include "MantidQtCustomInterfaces/Reflectometry/IReflSettingsTabPresenter.h" #include "MantidQtCustomInterfaces/Reflectometry/IReflSettingsView.h" #include "MantidQtMantidWidgets/AlgorithmHintStrategy.h" -#include <boost/algorithm/string.hpp> namespace MantidQt { namespace CustomInterfaces { @@ -300,7 +299,7 @@ void ReflSettingsPresenter::getExpDefaults() { auto inst = createEmptyInstrument(m_currentInstrumentName); // Collect all default values and set them in view - std::vector<std::string> defaults(7); + std::vector<std::string> defaults(6); defaults[0] = alg->getPropertyValue("AnalysisMode"); defaults[1] = alg->getPropertyValue("PolarizationAnalysis"); @@ -320,8 +319,6 @@ void ReflSettingsPresenter::getExpDefaults() { if (!cPp.empty()) defaults[5] = cPp[0]; - defaults[6] = alg->getPropertyValue("ScaleFactor"); - m_view->setExpDefaults(defaults); } @@ -357,13 +354,16 @@ void ReflSettingsPresenter::getInstDefaults() { m_view->setInstDefaults(defaults); } -/** Generates and returns an instance of the ReflectometryReductionOne algorithm +/** Generates and returns an instance of the ReflectometryReductionOneAuto +* algorithm +* @return :: ReflectometryReductionOneAuto algorithm */ IAlgorithm_sptr ReflSettingsPresenter::createReductionAlg() { return AlgorithmManager::Instance().create("ReflectometryReductionOneAuto"); } /** Creates and returns an example empty instrument given an instrument name +* @return :: Empty instrument of a name */ Instrument_const_sptr ReflSettingsPresenter::createEmptyInstrument(const std::string &instName) { diff --git a/MantidQt/CustomInterfaces/test/ReflSettingsPresenterTest.h b/MantidQt/CustomInterfaces/test/ReflSettingsPresenterTest.h index 04529b96055ade06db1b55b57647f868f60cd6f8..dde58d9d8c4f29cbfdb7131e17ff8fe659356f3a 100644 --- a/MantidQt/CustomInterfaces/test/ReflSettingsPresenterTest.h +++ b/MantidQt/CustomInterfaces/test/ReflSettingsPresenterTest.h @@ -223,7 +223,7 @@ public: "1.006831,-0.011467,0.002244,-0.000095", "1.017526,-0.017183,0.003136,-0.000140", "0.917940,0.038265,-0.006645,0.000282", - "0.972762,0.001828,-0.000261,0.0", "1"}; + "0.972762,0.001828,-0.000261,0.0"}; EXPECT_CALL(mockView, setExpDefaults(defaults)).Times(1); presenter.notify(IReflSettingsPresenter::ExpDefaultsFlag); diff --git a/MantidQt/MantidWidgets/src/DataProcessorUI/DataProcessorGenerateNotebook.cpp b/MantidQt/MantidWidgets/src/DataProcessorUI/DataProcessorGenerateNotebook.cpp index 0b194aace1c19b48f69bf8cc963a8e5367abf838..3a37327cd554a1f16815fef4f47f14c9a61e1f9d 100644 --- a/MantidQt/MantidWidgets/src/DataProcessorUI/DataProcessorGenerateNotebook.cpp +++ b/MantidQt/MantidWidgets/src/DataProcessorUI/DataProcessorGenerateNotebook.cpp @@ -182,9 +182,9 @@ std::string plotsString(const std::vector<std::string> &output_ws, // 13462, 0 // 13463, 0 // output_ws will be: - // output_ws [0] = 'IvsQ_TOF_13460, IvsLam_TOF_13460' - // output_ws [1] = 'IvsQ_TOF_13462, IvsLam_TOF_13462' - // output_ws [3] = 'IvsQ_TOF_13463, IvsLam_TOF_13463' + // output_ws [0] = 'IvsQ_binned_TOF_13460, IvsQ_TOF_13460, IvsLam_TOF_13460' + // output_ws [1] = 'IvsQ_binned_TOF_13462, IvsQ_TOF_13462, IvsLam_TOF_13462' + // output_ws [3] = 'IvsQ_binned_TOF_13463, IvsQ_TOF_13463, IvsLam_TOF_13463' // As the reduction algorithm, ReflectometryReductionOneAuto, produces two // output workspaces // We need to group the 'IvsQ_' workspaces and the 'IvsLam_' workspaces diff --git a/MantidQt/MantidWidgets/test/DataProcessorUI/DataProcessorGenerateNotebookTest.h b/MantidQt/MantidWidgets/test/DataProcessorUI/DataProcessorGenerateNotebookTest.h index e411fe24dcaf46a3d2f5a8846f411dce334f5f7d..3069b5253cd716b1717dcec650932aaec4509c29 100644 --- a/MantidQt/MantidWidgets/test/DataProcessorUI/DataProcessorGenerateNotebookTest.h +++ b/MantidQt/MantidWidgets/test/DataProcessorUI/DataProcessorGenerateNotebookTest.h @@ -41,7 +41,7 @@ private: return DataProcessorProcessingAlgorithm( "ReflectometryReductionOneAuto", - std::vector<std::string>{"IvsQ_", "IvsLam_"}, + std::vector<std::string>{"IvsQ_binned_", "IvsQ_", "IvsLam_"}, std::set<std::string>{"ThetaIn", "ThetaOut", "InputWorkspace", "OutputWorkspace", "OutputWorkspaceWavelength", "FirstTransmissionRun", "SecondTransmissionRun"}); @@ -62,8 +62,8 @@ private: whitelist.addElement("Angle", "ThetaIn", ""); whitelist.addElement("Transmission Run(s)", "FirstTransmissionRun", "", true, "TRANS_"); - whitelist.addElement("Q min", "MomentumTransferMinimum", ""); - whitelist.addElement("Q max", "MomentumTransferMaximum", ""); + whitelist.addElement("Q min", "MomentumTransferMin", ""); + whitelist.addElement("Q max", "MomentumTransferMax", ""); whitelist.addElement("dQ/Q", "MomentumTransferStep", ""); whitelist.addElement("Scale", "ScaleFactor", ""); whitelist.addElement("Options", "Options", ""); @@ -316,11 +316,9 @@ public: const std::string result[] = { "TOF_12346 = Load(Filename = 'INSTRUMENT12346')", - "IvsQ_TOF_12346, IvsLam_TOF_12346, _ = " - "ReflectometryReductionOneAuto(InputWorkspace = 'TOF_12346', " - "ThetaIn = " - "1.5, MomentumTransferMinimum = 1.4, MomentumTransferMaximum = " - "2.9, " + "IvsQ_binned_TOF_12346, IvsQ_TOF_12346, IvsLam_TOF_12346 = " + "ReflectometryReductionOneAuto(InputWorkspace = 'TOF_12346', ThetaIn = " + "1.5, MomentumTransferMin = 1.4, MomentumTransferMax = 2.9, " "MomentumTransferStep = 0.04, ScaleFactor = 1)", ""}; @@ -329,7 +327,7 @@ public: int i = 0; for (const auto &line : notebookLines) { - TS_ASSERT_EQUALS(line, result[i++]) + TS_ASSERT_EQUALS(line, result[i++]); } } @@ -367,14 +365,16 @@ public: "RUN_1001 = Load(Filename = 'INST1001')", "RUN_1000_1001 = Plus(LHSWorkspace = 'RUN_1000_1001', RHSWorkspace = " "'RUN_1001', Property=prop)", - "IvsQ_1000_1001_angle_0.5, IvsLam_1000_1001_angle_0.5, _ = " + "IvsQ_binned_1000_1001_angle_0.5, IvsQ_1000_1001_angle_0.5, " + "IvsLam_1000_1001_angle_0.5 = " "ReflectometryReductionOneAuto(InputWorkspace = 'RUN_1000_1001', " "ThetaIn = 0.5)", ""}; // Check the names of the reduced workspaces - TS_ASSERT_EQUALS(boost::get<1>(output), - "IvsQ_1000_1001_angle_0.5, IvsLam_1000_1001_angle_0.5"); + TS_ASSERT_EQUALS(boost::get<1>(output), "IvsQ_binned_1000_1001_angle_0.5, " + "IvsQ_1000_1001_angle_0.5, " + "IvsLam_1000_1001_angle_0.5"); // Check the python code std::vector<std::string> notebookLines; @@ -400,13 +400,9 @@ public: reflProcessor(), emptyPreProcessingOptions, ""); const std::string result[] = { - "IvsQ_TOF_12346, IvsLam_TOF_12346, _ = " - "ReflectometryReductionOneAuto(InputWorkspace = " - "12346, " - "ThetaIn = " - "1.5, MomentumTransferMinimum = 1.4, " - "MomentumTransferMaximum = " - "2.9, " + "IvsQ_binned_TOF_12346, IvsQ_TOF_12346, IvsLam_TOF_12346 = " + "ReflectometryReductionOneAuto(InputWorkspace = 12346, ThetaIn = 1.5, " + "MomentumTransferMin = 1.4, MomentumTransferMax = 2.9, " "MomentumTransferStep = 0.04, ScaleFactor = 1)", ""}; @@ -515,10 +511,9 @@ public: "#Post-process workspaces", "IvsQ_TOF_12345_TOF_12346, _ = " "Stitch1DMany(InputWorkspaces = " - "'IvsQ_TOF_12345, IvsQ_TOF_12346', Params = " - "'0.1, -0.04, 2.9', StartOverlaps = '1.4, " - "0.1, " - "1.4', EndOverlaps = '1.6, 2.9, 1.6')", + "'IvsQ_binned_TOF_12345, IvsQ_binned_TOF_12346', Params = " + "'0.1, -0.04, 2.9', StartOverlaps = '1.4, 0.1, 1.4', EndOverlaps = " + "'1.6, 2.9, 1.6')", ""}; std::vector<std::string> notebookLines; @@ -540,10 +535,9 @@ public: result = {"#Post-process workspaces", "IvsQ_TOF_24681_TOF_24682, _ = " "Stitch1DMany(InputWorkspaces = " - "'IvsQ_TOF_24681, IvsQ_TOF_24682', Params = " - "'0.1, -0.04, 2.9', StartOverlaps = '1.4, " - "0.1, " - "1.4', EndOverlaps = '1.6, 2.9, 1.6')", + "'IvsQ_binned_TOF_24681, IvsQ_binned_TOF_24682', Params = '0.1, " + "-0.04, 2.9', StartOverlaps = '1.4, 0.1, 1.4', EndOverlaps = " + "'1.6, 2.9, 1.6')", ""}; boost::split(notebookLines, boost::get<0>(output), boost::is_any_of("\n")); @@ -571,8 +565,8 @@ public: void testPlotsString() { std::vector<std::string> unprocessed_ws; - unprocessed_ws.emplace_back("TEST_WS1_1, TEST_WS1_2"); - unprocessed_ws.emplace_back("TEST_WS2_1, TEST_WS2_2"); + unprocessed_ws.emplace_back("IvsQ_binned_1, IvsQ_1, IvsLam_1"); + unprocessed_ws.emplace_back("IvsQ_binned_2, IvsQ_2, IvsLam_2"); std::vector<std::string> postprocessed_ws; postprocessed_ws.emplace_back("TEST_WS3"); @@ -584,19 +578,20 @@ public: const std::string result[] = { "#Group workspaces to be plotted on same axes", - "IvsQ_groupWS = GroupWorkspaces(InputWorkspaces = 'TEST_WS1_1, " - "TEST_WS2_1')", - "IvsLam_groupWS = GroupWorkspaces(InputWorkspaces = 'TEST_WS1_2, " - "TEST_WS2_2')", - "#Plot workspaces", "fig = plots([IvsQ_groupWS, IvsLam_groupWS, " - "TEST_WS3_TEST_WS4], title=['IvsQ_groupWS', " - "'IvsLam_groupWS', 'TEST_WS3_TEST_WS4'], " - "legendLocation=[1, 1, 4])", + "IvsQ_binned_groupWS = GroupWorkspaces(InputWorkspaces = " + "'IvsQ_binned_1, IvsQ_binned_2')", + "IvsQ_groupWS = GroupWorkspaces(InputWorkspaces = 'IvsQ_1, IvsQ_2')", + "IvsLam_groupWS = GroupWorkspaces(InputWorkspaces = 'IvsLam_1, " + "IvsLam_2')", + "#Plot workspaces", + "fig = plots([IvsQ_binned_groupWS, IvsQ_groupWS, IvsLam_groupWS, " + "TEST_WS3_TEST_WS4], title=['IvsQ_binned_groupWS', 'IvsQ_groupWS', " + "'IvsLam_groupWS', 'TEST_WS3_TEST_WS4'], legendLocation=[1, 1, 4])", ""}; std::vector<std::string> notebookLines; boost::split(notebookLines, output, boost::is_any_of("\n")); - + std::cout << "\n"; int i = 0; for (const auto &line : notebookLines) { TS_ASSERT_EQUALS(line, result[i++]) @@ -606,8 +601,8 @@ public: void testPlotsStringNoPostprocessing() { // Reduced workspaces std::vector<std::string> unprocessed_ws; - unprocessed_ws.emplace_back("TEST_WS1_1, TEST_WS1_2"); - unprocessed_ws.emplace_back("TEST_WS2_1, TEST_WS2_2"); + unprocessed_ws.emplace_back("IvsQ_binned_1, IvsQ_1, IvsLam_1"); + unprocessed_ws.emplace_back("IvsQ_binned_2, IvsQ_2, IvsLam_2"); // Post-processed ws (empty) std::string postprocessed_ws; @@ -616,13 +611,15 @@ public: const std::string result[] = { "#Group workspaces to be plotted on same axes", - "IvsQ_groupWS = GroupWorkspaces(InputWorkspaces = 'TEST_WS1_1, " - "TEST_WS2_1')", - "IvsLam_groupWS = GroupWorkspaces(InputWorkspaces = 'TEST_WS1_2, " - "TEST_WS2_2')", - "#Plot workspaces", "fig = plots([IvsQ_groupWS, IvsLam_groupWS, ], " - "title=['IvsQ_groupWS', 'IvsLam_groupWS', ''], " - "legendLocation=[1, 1, 4])", + "IvsQ_binned_groupWS = GroupWorkspaces(InputWorkspaces = " + "'IvsQ_binned_1, IvsQ_binned_2')", + "IvsQ_groupWS = GroupWorkspaces(InputWorkspaces = 'IvsQ_1, IvsQ_2')", + "IvsLam_groupWS = GroupWorkspaces(InputWorkspaces = 'IvsLam_1, " + "IvsLam_2')", + "#Plot workspaces", + "fig = plots([IvsQ_binned_groupWS, IvsQ_groupWS, IvsLam_groupWS, ], " + "title=['IvsQ_binned_groupWS', 'IvsQ_groupWS', 'IvsLam_groupWS', ''], " + "legendLocation=[1, 1, 4])", ""}; std::vector<std::string> notebookLines; @@ -691,76 +688,75 @@ public: boost::split(notebookLines, generatedNotebook, boost::is_any_of("\n")); const std::string loadAndReduceStringFirstGroup = - " \"input\" : \"#Load and reduce\\n12345 = " - "Load(Filename = \'INTER12345\')\\nIvsQ_TOF_12345, " - "IvsLam_TOF_12345, _ = " - "ReflectometryReductionOneAuto(InputWorkspace = \'12345\', " - "ThetaIn = 0.5, MomentumTransferMinimum = 0.1, " - "MomentumTransferMaximum = 1.6, MomentumTransferStep = " - "0.04, ScaleFactor = 1, AnalysisMode = " - "MultiDetectorAnalysis)\\n#Load and reduce\\n12346 = " - "Load(Filename = \'INTER12346\')\\nIvsQ_TOF_12346, " - "IvsLam_TOF_12346, _ = " - "ReflectometryReductionOneAuto(InputWorkspace = \'12346\', " - "ThetaIn = 1.5, MomentumTransferMinimum = 1.4, " - "MomentumTransferMaximum = 2.9, MomentumTransferStep = " - "0.04, ScaleFactor = 1, AnalysisMode = " + " \"input\" : \"#Load and reduce\\n12345 = Load(Filename " + "= \'INTER12345\')\\nIvsQ_binned_TOF_12345, IvsQ_TOF_12345, " + "IvsLam_TOF_12345 = ReflectometryReductionOneAuto(InputWorkspace = " + "\'12345\', ThetaIn = 0.5, MomentumTransferMin = 0.1, " + "MomentumTransferMax = 1.6, MomentumTransferStep = 0.04, ScaleFactor = " + "1, AnalysisMode = MultiDetectorAnalysis)\\n#Load and reduce\\n12346 = " + "Load(Filename = \'INTER12346\')\\nIvsQ_binned_TOF_12346, " + "IvsQ_TOF_12346, IvsLam_TOF_12346 = " + "ReflectometryReductionOneAuto(InputWorkspace = \'12346\', ThetaIn = " + "1.5, MomentumTransferMin = 1.4, MomentumTransferMax = 2.9, " + "MomentumTransferStep = 0.04, ScaleFactor = 1, AnalysisMode = " "MultiDetectorAnalysis)\\n\","; TS_ASSERT_EQUALS(notebookLines[48], loadAndReduceStringFirstGroup); const std::string postProcessStringFirstGroup = " \"input\" : \"#Post-process " "workspaces\\nIvsQ_TOF_12345_TOF_12346, _ = " - "Stitch1DMany(InputWorkspaces = \'IvsQ_TOF_12345, IvsQ_TOF_12346\', " + "Stitch1DMany(InputWorkspaces = \'IvsQ_binned_TOF_12345, " + "IvsQ_binned_TOF_12346\', " "Params=0.04)\","; TS_ASSERT_EQUALS(notebookLines[56], postProcessStringFirstGroup); const std::string groupWorkspacesStringFirstGroup = " \"input\" : \"#Group workspaces to be plotted on same " - "axes\\nIvsQ_groupWS = GroupWorkspaces(InputWorkspaces = " - "\'IvsQ_TOF_12345, IvsQ_TOF_12346\')\\nIvsLam_groupWS = " - "GroupWorkspaces(InputWorkspaces = \'IvsLam_TOF_12345, " - "IvsLam_TOF_12346\')\\n#Plot workspaces\\nfig = plots([IvsQ_groupWS, " - "IvsLam_groupWS, IvsQ_TOF_12345_TOF_12346], title=[\'IvsQ_groupWS\', " - "\'IvsLam_groupWS\', \'IvsQ_TOF_12345_TOF_12346\'], legendLocation=" - "[1, 1, 4])\\n\","; + "axes\\nIvsQ_binned_groupWS = GroupWorkspaces(InputWorkspaces = " + "\'IvsQ_binned_TOF_12345, IvsQ_binned_TOF_12346\')\\nIvsQ_groupWS = " + "GroupWorkspaces(InputWorkspaces = \'IvsQ_TOF_12345, " + "IvsQ_TOF_12346\')\\nIvsLam_groupWS = GroupWorkspaces(InputWorkspaces " + "= \'IvsLam_TOF_12345, IvsLam_TOF_12346\')\\n#Plot workspaces\\nfig = " + "plots([IvsQ_binned_groupWS, IvsQ_groupWS, IvsLam_groupWS, " + "IvsQ_TOF_12345_TOF_12346], title=[\'IvsQ_binned_groupWS\', " + "\'IvsQ_groupWS\', \'IvsLam_groupWS\', \'IvsQ_TOF_12345_TOF_12346\'], " + "legendLocation=[1, 1, 4])\\n\","; ; TS_ASSERT_EQUALS(notebookLines[64], groupWorkspacesStringFirstGroup); const std::string loadAndReduceStringSecondGroup = - " \"input\" : \"#Load and reduce\\n24681 = " - "Load(Filename = \'INTER24681\')\\nIvsQ_TOF_24681, " - "IvsLam_TOF_24681, _ = " - "ReflectometryReductionOneAuto(InputWorkspace = \'24681\', " - "ThetaIn = 0.5, MomentumTransferMinimum = 0.1, " - "MomentumTransferMaximum = 1.6, MomentumTransferStep = " - "0.04, ScaleFactor = 1, AnalysisMode = " - "MultiDetectorAnalysis)\\n#Load and reduce\\n24682 = " - "Load(Filename = \'INTER24682\')\\nIvsQ_TOF_24682, " - "IvsLam_TOF_24682, _ = " - "ReflectometryReductionOneAuto(InputWorkspace = \'24682\', " - "ThetaIn = 1.5, MomentumTransferMinimum = 1.4, " - "MomentumTransferMaximum = 2.9, MomentumTransferStep = " - "0.04, ScaleFactor = 1, AnalysisMode = " + " \"input\" : \"#Load and reduce\\n24681 = Load(Filename " + "= \'INTER24681\')\\nIvsQ_binned_TOF_24681, IvsQ_TOF_24681, " + "IvsLam_TOF_24681 = ReflectometryReductionOneAuto(InputWorkspace = " + "\'24681\', ThetaIn = 0.5, MomentumTransferMin = 0.1, " + "MomentumTransferMax = 1.6, MomentumTransferStep = 0.04, ScaleFactor = " + "1, AnalysisMode = MultiDetectorAnalysis)\\n#Load and reduce\\n24682 = " + "Load(Filename = \'INTER24682\')\\nIvsQ_binned_TOF_24682, " + "IvsQ_TOF_24682, IvsLam_TOF_24682 = " + "ReflectometryReductionOneAuto(InputWorkspace = \'24682\', ThetaIn = " + "1.5, MomentumTransferMin = 1.4, MomentumTransferMax = 2.9, " + "MomentumTransferStep = 0.04, ScaleFactor = 1, AnalysisMode = " "MultiDetectorAnalysis)\\n\","; TS_ASSERT_EQUALS(notebookLines[77], loadAndReduceStringSecondGroup); const std::string postProcessStringSecondGroup = " \"input\" : \"#Post-process " "workspaces\\nIvsQ_TOF_24681_TOF_24682, _ = " - "Stitch1DMany(InputWorkspaces = \'IvsQ_TOF_24681, IvsQ_TOF_24682\', " - "Params=0.04)\","; + "Stitch1DMany(InputWorkspaces = \'IvsQ_binned_TOF_24681, " + "IvsQ_binned_TOF_24682\', Params=0.04)\","; TS_ASSERT_EQUALS(notebookLines[85], postProcessStringSecondGroup); const std::string groupWorkspacesStringSecondGroup = " \"input\" : \"#Group workspaces to be plotted on same " - "axes\\nIvsQ_groupWS = GroupWorkspaces(InputWorkspaces = " - "\'IvsQ_TOF_24681, IvsQ_TOF_24682\')\\nIvsLam_groupWS = " - "GroupWorkspaces(InputWorkspaces = \'IvsLam_TOF_24681, " - "IvsLam_TOF_24682\')\\n#Plot workspaces\\nfig = plots([IvsQ_groupWS, " - "IvsLam_groupWS, IvsQ_TOF_24681_TOF_24682], title=[\'IvsQ_groupWS\', " - "\'IvsLam_groupWS\', \'IvsQ_TOF_24681_TOF_24682\'], legendLocation=" - "[1, 1, 4])\\n\","; + "axes\\nIvsQ_binned_groupWS = GroupWorkspaces(InputWorkspaces = " + "\'IvsQ_binned_TOF_24681, IvsQ_binned_TOF_24682\')\\nIvsQ_groupWS = " + "GroupWorkspaces(InputWorkspaces = \'IvsQ_TOF_24681, " + "IvsQ_TOF_24682\')\\nIvsLam_groupWS = GroupWorkspaces(InputWorkspaces " + "= \'IvsLam_TOF_24681, IvsLam_TOF_24682\')\\n#Plot workspaces\\nfig = " + "plots([IvsQ_binned_groupWS, IvsQ_groupWS, IvsLam_groupWS, " + "IvsQ_TOF_24681_TOF_24682], title=[\'IvsQ_binned_groupWS\', " + "\'IvsQ_groupWS\', \'IvsLam_groupWS\', \'IvsQ_TOF_24681_TOF_24682\'], " + "legendLocation=[1, 1, 4])\\n\","; ; TS_ASSERT_EQUALS(notebookLines[93], groupWorkspacesStringSecondGroup); @@ -800,14 +796,12 @@ public: // First group std::string loadAndReduceString = - " \"input\" : \"#Load and reduce\\n12345 = " - "Load(Filename = \'INTER12345\')\\nIvsQ_TOF_12345, " - "IvsLam_TOF_12345, _ = " - "ReflectometryReductionOneAuto(InputWorkspace = \'12345\', " - "ThetaIn = 0.5, MomentumTransferMinimum = 0.1, " - "MomentumTransferMaximum = 1.6, MomentumTransferStep = " - "0.04, ScaleFactor = 1, AnalysisMode = " - "MultiDetectorAnalysis)\\n\","; + " \"input\" : \"#Load and reduce\\n12345 = Load(Filename " + "= \'INTER12345\')\\nIvsQ_binned_TOF_12345, IvsQ_TOF_12345, " + "IvsLam_TOF_12345 = ReflectometryReductionOneAuto(InputWorkspace = " + "\'12345\', ThetaIn = 0.5, MomentumTransferMin = 0.1, " + "MomentumTransferMax = 1.6, MomentumTransferStep = 0.04, ScaleFactor = " + "1, AnalysisMode = MultiDetectorAnalysis)\\n\","; TS_ASSERT_EQUALS(notebookLines[48], loadAndReduceString); std::string postProcessString = " \"input\" : \"\","; @@ -815,25 +809,25 @@ public: std::string groupWorkspacesString = " \"input\" : \"#Group workspaces to be plotted on same " - "axes\\nIvsQ_groupWS = GroupWorkspaces(InputWorkspaces = " + "axes\\nIvsQ_binned_groupWS = GroupWorkspaces(InputWorkspaces = " + "\'IvsQ_binned_TOF_12345\')\\nIvsQ_groupWS = " + "GroupWorkspaces(InputWorkspaces = " "\'IvsQ_TOF_12345\')\\nIvsLam_groupWS = " "GroupWorkspaces(InputWorkspaces = \'IvsLam_TOF_12345\')\\n#Plot " - "workspaces\\nfig = plots([IvsQ_groupWS, IvsLam_groupWS, ], " - "title=[\'IvsQ_groupWS\', \'IvsLam_groupWS\', \'\'], " - "legendLocation=[1, 1, 4])\\n\","; + "workspaces\\nfig = plots([IvsQ_binned_groupWS, IvsQ_groupWS, " + "IvsLam_groupWS, ], title=[\'IvsQ_binned_groupWS\', \'IvsQ_groupWS\', " + "\'IvsLam_groupWS\', \'\'], legendLocation=[1, 1, 4])\\n\","; TS_ASSERT_EQUALS(notebookLines[64], groupWorkspacesString); // Second group loadAndReduceString = - " \"input\" : \"#Load and reduce\\n12346 = " - "Load(Filename = \'INTER12346\')\\nIvsQ_TOF_12346, " - "IvsLam_TOF_12346, _ = " - "ReflectometryReductionOneAuto(InputWorkspace = \'12346\', " - "ThetaIn = 1.5, MomentumTransferMinimum = 1.4, " - "MomentumTransferMaximum = 2.9, MomentumTransferStep = " - "0.04, ScaleFactor = 1, AnalysisMode = " - "MultiDetectorAnalysis)\\n\","; + " \"input\" : \"#Load and reduce\\n12346 = Load(Filename " + "= \'INTER12346\')\\nIvsQ_binned_TOF_12346, IvsQ_TOF_12346, " + "IvsLam_TOF_12346 = ReflectometryReductionOneAuto(InputWorkspace = " + "\'12346\', ThetaIn = 1.5, MomentumTransferMin = 1.4, " + "MomentumTransferMax = 2.9, MomentumTransferStep = 0.04, ScaleFactor = " + "1, AnalysisMode = MultiDetectorAnalysis)\\n\","; TS_ASSERT_EQUALS(notebookLines[77], loadAndReduceString); postProcessString = " \"input\" : \"\","; @@ -841,12 +835,14 @@ public: groupWorkspacesString = " \"input\" : \"#Group workspaces to be plotted on same " - "axes\\nIvsQ_groupWS = GroupWorkspaces(InputWorkspaces = " + "axes\\nIvsQ_binned_groupWS = GroupWorkspaces(InputWorkspaces = " + "\'IvsQ_binned_TOF_12346\')\\nIvsQ_groupWS = " + "GroupWorkspaces(InputWorkspaces = " "\'IvsQ_TOF_12346\')\\nIvsLam_groupWS = " "GroupWorkspaces(InputWorkspaces = \'IvsLam_TOF_12346\')\\n#Plot " - "workspaces\\nfig = plots([IvsQ_groupWS, IvsLam_groupWS, ], " - "title=[\'IvsQ_groupWS\', \'IvsLam_groupWS\', \'\'], " - "legendLocation=[1, 1, 4])\\n\","; + "workspaces\\nfig = plots([IvsQ_binned_groupWS, IvsQ_groupWS, " + "IvsLam_groupWS, ], title=[\'IvsQ_binned_groupWS\', \'IvsQ_groupWS\', " + "\'IvsLam_groupWS\', \'\'], legendLocation=[1, 1, 4])\\n\","; TS_ASSERT_EQUALS(notebookLines[93], groupWorkspacesString); } }; diff --git a/MantidQt/MantidWidgets/test/DataProcessorUI/DataProcessorProcessingAlgorithmTest.h b/MantidQt/MantidWidgets/test/DataProcessorUI/DataProcessorProcessingAlgorithmTest.h index c0b5e1a7822cc31a66dddbfd8807e7f3e350687a..0abf18ed68cfb0336ddf912ac9f68107e85d4da2 100644 --- a/MantidQt/MantidWidgets/test/DataProcessorUI/DataProcessorProcessingAlgorithmTest.h +++ b/MantidQt/MantidWidgets/test/DataProcessorUI/DataProcessorProcessingAlgorithmTest.h @@ -57,28 +57,38 @@ public: std::string algName = "ReflectometryReductionOneAuto"; - // ReflectometryReductionOneAuto has two output ws properties - // We should provide two prefixes, one for each ws + // ReflectometryReductionOneAuto has three output ws properties + // We should provide three prefixes, one for each ws std::vector<std::string> prefixes; - prefixes.push_back("IvsQ_"); + prefixes.push_back("IvsQ_binned_"); // This should throw - TS_ASSERT_THROWS(DataProcessorProcessingAlgorithm(algName, prefixes), + TS_ASSERT_THROWS(DataProcessorProcessingAlgorithm(algName, prefixes, + std::set<std::string>()), + std::invalid_argument); + + prefixes.push_back("IvsQ_"); + // This should also throw + TS_ASSERT_THROWS(DataProcessorProcessingAlgorithm(algName, prefixes, + std::set<std::string>()), std::invalid_argument); // But this should be OK prefixes.push_back("IvsLam_"); - TS_ASSERT_THROWS_NOTHING( - DataProcessorProcessingAlgorithm(algName, prefixes)); + TS_ASSERT_THROWS_NOTHING(DataProcessorProcessingAlgorithm( + algName, prefixes, std::set<std::string>())); - auto alg = DataProcessorProcessingAlgorithm(algName, prefixes); + auto alg = DataProcessorProcessingAlgorithm(algName, prefixes, + std::set<std::string>()); TS_ASSERT_EQUALS(alg.name(), "ReflectometryReductionOneAuto"); - TS_ASSERT_EQUALS(alg.numberOfOutputProperties(), 2); - TS_ASSERT_EQUALS(alg.prefix(0), "IvsQ_"); - TS_ASSERT_EQUALS(alg.prefix(1), "IvsLam_"); + TS_ASSERT_EQUALS(alg.numberOfOutputProperties(), 3); + TS_ASSERT_EQUALS(alg.prefix(0), "IvsQ_binned_"); + TS_ASSERT_EQUALS(alg.prefix(1), "IvsQ_"); + TS_ASSERT_EQUALS(alg.prefix(2), "IvsLam_"); TS_ASSERT_EQUALS(alg.inputPropertyName(0), "InputWorkspace"); TS_ASSERT_EQUALS(alg.inputPropertyName(1), "FirstTransmissionRun"); TS_ASSERT_EQUALS(alg.inputPropertyName(2), "SecondTransmissionRun"); - TS_ASSERT_EQUALS(alg.outputPropertyName(0), "OutputWorkspace"); - TS_ASSERT_EQUALS(alg.outputPropertyName(1), "OutputWorkspaceWavelength"); + TS_ASSERT_EQUALS(alg.outputPropertyName(0), "OutputWorkspaceBinned"); + TS_ASSERT_EQUALS(alg.outputPropertyName(1), "OutputWorkspace"); + TS_ASSERT_EQUALS(alg.outputPropertyName(2), "OutputWorkspaceWavelength"); } // Add more tests for specific algorithms here diff --git a/MantidQt/MantidWidgets/test/DataProcessorUI/GenericDataProcessorPresenterTest.h b/MantidQt/MantidWidgets/test/DataProcessorUI/GenericDataProcessorPresenterTest.h index 3aeeb10f48c34cea04b3e1c0c329598cacd4728c..f4d24729d31c59fbc442a746abc6a63d18654af2 100644 --- a/MantidQt/MantidWidgets/test/DataProcessorUI/GenericDataProcessorPresenterTest.h +++ b/MantidQt/MantidWidgets/test/DataProcessorUI/GenericDataProcessorPresenterTest.h @@ -31,8 +31,8 @@ private: whitelist.addElement("Angle", "ThetaIn", ""); whitelist.addElement("Transmission Run(s)", "FirstTransmissionRun", "", true, "TRANS_"); - whitelist.addElement("Q min", "MomentumTransferMinimum", ""); - whitelist.addElement("Q max", "MomentumTransferMaximum", ""); + whitelist.addElement("Q min", "MomentumTransferMin", ""); + whitelist.addElement("Q max", "MomentumTransferMax", ""); whitelist.addElement("dQ/Q", "MomentumTransferStep", ""); whitelist.addElement("Scale", "ScaleFactor", ""); return whitelist; @@ -58,7 +58,7 @@ private: return DataProcessorProcessingAlgorithm( "ReflectometryReductionOneAuto", - std::vector<std::string>{"IvsQ_", "IvsLam_"}, + std::vector<std::string>{"IvsQ_binned_", "IvsQ_", "IvsLam_"}, std::set<std::string>{"ThetaIn", "ThetaOut", "InputWorkspace", "OutputWorkspace", "OutputWorkspaceWavelength", "FirstTransmissionRun", "SecondTransmissionRun"}); @@ -131,7 +131,7 @@ private: << "1.6" << "0.04" << "1" - << "ProcessingInstructions='0', CorrectDetectorPositions=0"; + << "ProcessingInstructions='0'"; row = ws->appendRow(); row << "0" << "12346" @@ -1037,9 +1037,13 @@ public: presenter.notify(DataProcessorPresenter::ProcessFlag); // Check output workspaces were created as expected + TS_ASSERT( + AnalysisDataService::Instance().doesExist("IvsQ_binned_TOF_12345")); TS_ASSERT(AnalysisDataService::Instance().doesExist("IvsQ_TOF_12345")); TS_ASSERT(AnalysisDataService::Instance().doesExist("IvsLam_TOF_12345")); TS_ASSERT(AnalysisDataService::Instance().doesExist("TOF_12345")); + TS_ASSERT( + AnalysisDataService::Instance().doesExist("IvsQ_binned_TOF_12346")); TS_ASSERT(AnalysisDataService::Instance().doesExist("IvsQ_TOF_12346")); TS_ASSERT(AnalysisDataService::Instance().doesExist("IvsLam_TOF_12346")); TS_ASSERT(AnalysisDataService::Instance().doesExist("TOF_12346")); @@ -1048,9 +1052,11 @@ public: // Tidy up AnalysisDataService::Instance().remove("TestWorkspace"); + AnalysisDataService::Instance().remove("IvsQ_binned_TOF_12345"); AnalysisDataService::Instance().remove("IvsQ_TOF_12345"); AnalysisDataService::Instance().remove("IvsLam_TOF_12345"); AnalysisDataService::Instance().remove("TOF_12345"); + AnalysisDataService::Instance().remove("IvsQ_binned_TOF_12346"); AnalysisDataService::Instance().remove("IvsQ_TOF_12346"); AnalysisDataService::Instance().remove("IvsLam_TOF_12346"); AnalysisDataService::Instance().remove("TOF_12346"); @@ -1072,7 +1078,7 @@ public: auto ws = createPrefilledWorkspace("TestWorkspace", presenter.getWhiteList()); - ws->String(0, QMinCol) = ""; + ws->String(0, ThetaCol) = ""; ws->String(1, ScaleCol) = ""; EXPECT_CALL(mockDataProcessorView, getWorkspaceToOpen()) .Times(1) @@ -1117,13 +1123,17 @@ public: TS_ASSERT_EQUALS(ws->rowCount(), 4); TS_ASSERT_EQUALS(ws->String(0, RunCol), "12345"); TS_ASSERT_EQUALS(ws->String(1, RunCol), "12346"); - TS_ASSERT(ws->String(0, QMinCol) != ""); + TS_ASSERT(ws->String(0, ThetaCol) != ""); TS_ASSERT(ws->String(1, ScaleCol) != ""); // Check output workspaces were created as expected + TS_ASSERT( + AnalysisDataService::Instance().doesExist("IvsQ_binned_TOF_12345")); TS_ASSERT(AnalysisDataService::Instance().doesExist("IvsQ_TOF_12345")); TS_ASSERT(AnalysisDataService::Instance().doesExist("IvsLam_TOF_12345")); TS_ASSERT(AnalysisDataService::Instance().doesExist("TOF_12345")); + TS_ASSERT( + AnalysisDataService::Instance().doesExist("IvsQ_binned_TOF_12346")); TS_ASSERT(AnalysisDataService::Instance().doesExist("IvsQ_TOF_12346")); TS_ASSERT(AnalysisDataService::Instance().doesExist("IvsLam_TOF_12346")); TS_ASSERT(AnalysisDataService::Instance().doesExist("TOF_12346")); @@ -1132,9 +1142,11 @@ public: // Tidy up AnalysisDataService::Instance().remove("TestWorkspace"); + AnalysisDataService::Instance().remove("IvsQ_binned_TOF_12345"); AnalysisDataService::Instance().remove("IvsQ_TOF_12345"); AnalysisDataService::Instance().remove("IvsLam_TOF_12345"); AnalysisDataService::Instance().remove("TOF_12345"); + AnalysisDataService::Instance().remove("IvsQ_binned_TOF_12346"); AnalysisDataService::Instance().remove("IvsQ_TOF_12346"); AnalysisDataService::Instance().remove("IvsLam_TOF_12346"); AnalysisDataService::Instance().remove("TOF_12346"); @@ -1198,9 +1210,13 @@ public: presenter.notify(DataProcessorPresenter::ProcessFlag); // Check output workspaces were created as expected + TS_ASSERT( + AnalysisDataService::Instance().doesExist("IvsQ_binned_TOF_12345")); TS_ASSERT(AnalysisDataService::Instance().doesExist("IvsQ_TOF_12345")); TS_ASSERT(AnalysisDataService::Instance().doesExist("IvsLam_TOF_12345")); TS_ASSERT(AnalysisDataService::Instance().doesExist("TOF_12345")); + TS_ASSERT( + AnalysisDataService::Instance().doesExist("IvsQ_binned_TOF_12346")); TS_ASSERT(AnalysisDataService::Instance().doesExist("IvsQ_TOF_12346")); TS_ASSERT(AnalysisDataService::Instance().doesExist("IvsLam_TOF_12346")); TS_ASSERT(AnalysisDataService::Instance().doesExist("TOF_12346")); @@ -1209,9 +1225,11 @@ public: // Tidy up AnalysisDataService::Instance().remove("TestWorkspace"); + AnalysisDataService::Instance().remove("IvsQ_binned_TOF_12345"); AnalysisDataService::Instance().remove("IvsQ_TOF_12345"); AnalysisDataService::Instance().remove("IvsLam_TOF_12345"); AnalysisDataService::Instance().remove("TOF_12345"); + AnalysisDataService::Instance().remove("IvsQ_binned_TOF_12346"); AnalysisDataService::Instance().remove("IvsQ_TOF_12346"); AnalysisDataService::Instance().remove("IvsLam_TOF_12346"); AnalysisDataService::Instance().remove("TOF_12346"); @@ -1222,6 +1240,7 @@ public: } void testProcessWithNotebook() { + NiceMock<MockDataProcessorView> mockDataProcessorView; NiceMock<MockProgressableView> mockProgress; NiceMock<MockMainPresenter> mockMainPresenter; @@ -1270,9 +1289,11 @@ public: // Tidy up AnalysisDataService::Instance().remove("TestWorkspace"); + AnalysisDataService::Instance().remove("IvsQ_binned_TOF_12345"); AnalysisDataService::Instance().remove("IvsQ_TOF_12345"); AnalysisDataService::Instance().remove("IvsLam_TOF_12345"); AnalysisDataService::Instance().remove("TOF_12345"); + AnalysisDataService::Instance().remove("IvsQ_binned_TOF_12346"); AnalysisDataService::Instance().remove("IvsQ_TOF_12346"); AnalysisDataService::Instance().remove("IvsLam_TOF_12346"); AnalysisDataService::Instance().remove("TOF_12346"); @@ -1307,7 +1328,7 @@ public: << "1.6" << "0.04" << "1" - << "ProcessingInstructions='0', CorrectDetectorPositions=0"; + << "ProcessingInstructions='0'"; row = ws->appendRow(); row << "1" << "dataB" @@ -1317,7 +1338,7 @@ public: << "2.9" << "0.04" << "1" - << "ProcessingInstructions='0', CorrectDetectorPositions=0"; + << "ProcessingInstructions='0'"; createTOFWorkspace("dataA"); createTOFWorkspace("dataB"); @@ -1353,6 +1374,10 @@ public: presenter.notify(DataProcessorPresenter::ProcessFlag); // Check output workspaces were created as expected + TS_ASSERT( + AnalysisDataService::Instance().doesExist("IvsQ_binned_TOF_dataA")); + TS_ASSERT( + AnalysisDataService::Instance().doesExist("IvsQ_binned_TOF_dataB")); TS_ASSERT(AnalysisDataService::Instance().doesExist("IvsQ_TOF_dataA")); TS_ASSERT(AnalysisDataService::Instance().doesExist("IvsQ_TOF_dataB")); TS_ASSERT(AnalysisDataService::Instance().doesExist("IvsLam_TOF_dataA")); @@ -1364,6 +1389,8 @@ public: AnalysisDataService::Instance().remove("TestWorkspace"); AnalysisDataService::Instance().remove("dataA"); AnalysisDataService::Instance().remove("dataB"); + AnalysisDataService::Instance().remove("IvsQ_binned_TOF_dataA"); + AnalysisDataService::Instance().remove("IvsQ_binned_TOF_dataB"); AnalysisDataService::Instance().remove("IvsQ_TOF_dataA"); AnalysisDataService::Instance().remove("IvsQ_TOF_dataB"); AnalysisDataService::Instance().remove("IvsLam_TOF_dataA"); @@ -2245,8 +2272,7 @@ public: rowlist[1].insert(1); const std::string expected = - "0\t12345\t0.5\t\t0.1\t1.6\t0.04\t1\tProcessingInstructions='0', " - "CorrectDetectorPositions=0\n" + "0\t12345\t0.5\t\t0.1\t1.6\t0.04\t1\tProcessingInstructions='0'\n" "0\t12346\t1.5\t\t1.4\t2.9\t0.04\t1\tProcessingInstructions='0'\n" "1\t24681\t0.5\t\t0.1\t1.6\t0.04\t1\t\n" "1\t24682\t1.5\t\t1.4\t2.9\t0.04\t1\t"; @@ -2328,8 +2354,7 @@ public: rowlist[1].insert(0); const std::string expected = - "0\t12345\t0.5\t\t0.1\t1.6\t0.04\t1\tProcessingInstructions='0', " - "CorrectDetectorPositions=0\n" + "0\t12345\t0.5\t\t0.1\t1.6\t0.04\t1\tProcessingInstructions='0'\n" "0\t12346\t1.5\t\t1.4\t2.9\t0.04\t1\tProcessingInstructions='0'\n" "1\t24681\t0.5\t\t0.1\t1.6\t0.04\t1\t"; @@ -2656,6 +2681,7 @@ public: } void testPlotRowWarn() { + NiceMock<MockDataProcessorView> mockDataProcessorView; MockProgressableView mockProgress; NiceMock<MockMainPresenter> mockMainPresenter; @@ -2695,6 +2721,7 @@ public: TS_ASSERT(Mock::VerifyAndClearExpectations(&mockDataProcessorView)); TS_ASSERT(Mock::VerifyAndClearExpectations(&mockMainPresenter)); } + void testPlotEmptyRow() { NiceMock<MockDataProcessorView> mockDataProcessorView; MockProgressableView mockProgress; @@ -3039,8 +3066,8 @@ public: .Times(1) .WillRepeatedly(Return("TestWorkspace")); presenter.notify(DataProcessorPresenter::OpenTableFlag); - createTOFWorkspace("IvsQ_TOF_12345", "12345"); - createTOFWorkspace("IvsQ_TOF_12346", "12346"); + createTOFWorkspace("IvsQ_binned_TOF_12345", "12345"); + createTOFWorkspace("IvsQ_binned_TOF_12346", "12346"); std::map<int, std::set<int>> rowlist; rowlist[0].insert(0); @@ -3058,18 +3085,17 @@ public: std::string pythonCode = "base_graph = None\nbase_graph = " - "plotSpectrum(\"IvsQ_TOF_12345\", 0, True, window = " - "base_graph)\nbase_graph = plotSpectrum(\"IvsQ_TOF_12346\", 0, " - "True, window = " - "base_graph)\nbase_graph.activeLayer().logLogAxes()\n"; + "plotSpectrum(\"IvsQ_binned_TOF_12345\", 0, True, window = " + "base_graph)\nbase_graph = plotSpectrum(\"IvsQ_binned_TOF_12346\", 0, " + "True, window = base_graph)\nbase_graph.activeLayer().logLogAxes()\n"; EXPECT_CALL(mockMainPresenter, runPythonAlgorithm(pythonCode)).Times(1); presenter.notify(DataProcessorPresenter::PlotRowFlag); // Tidy up AnalysisDataService::Instance().remove("TestWorkspace"); - AnalysisDataService::Instance().remove("IvsQ_TOF_12345"); - AnalysisDataService::Instance().remove("IvsQ_TOF_12346"); + AnalysisDataService::Instance().remove("IvsQ_binned_TOF_12345"); + AnalysisDataService::Instance().remove("IvsQ_binned_TOF_12346"); TS_ASSERT(Mock::VerifyAndClearExpectations(&mockDataProcessorView)); TS_ASSERT(Mock::VerifyAndClearExpectations(&mockMainPresenter)); @@ -3222,9 +3248,11 @@ public: // Tidy up AnalysisDataService::Instance().remove("TestWorkspace"); + AnalysisDataService::Instance().remove("IvsQ_binned_TOF_12345"); AnalysisDataService::Instance().remove("IvsQ_TOF_12345"); AnalysisDataService::Instance().remove("IvsLam_TOF_12345"); AnalysisDataService::Instance().remove("12345"); + AnalysisDataService::Instance().remove("IvsQ_binned_TOF_12346"); AnalysisDataService::Instance().remove("IvsQ_TOF_12346"); AnalysisDataService::Instance().remove("IvsLam_TOF_12346"); AnalysisDataService::Instance().remove("12346"); diff --git a/Testing/SystemTests/tests/analysis/OFFSPECReflRedOneAuto.py b/Testing/SystemTests/tests/analysis/OFFSPECReflRedOneAuto.py index e1c6be6a7b07c6b01df71d62c1bf11563639f4e2..7698184cbdbb3952aedcd428a126c9d8b2ea679c 100644 --- a/Testing/SystemTests/tests/analysis/OFFSPECReflRedOneAuto.py +++ b/Testing/SystemTests/tests/analysis/OFFSPECReflRedOneAuto.py @@ -19,17 +19,20 @@ class OFFSPECReflRedOneAuto(stresstesting.MantidStressTest): ivq_75, __, __ = ReflectometryReductionOneAuto(offspec75, ThetaIn=0.70,#2*th MomentumTransferStep=1e-3, - FirstTransmissionRun=offspec85) + FirstTransmissionRun=offspec85, + Version=1) ivq_76, __, __ = ReflectometryReductionOneAuto(offspec76, ThetaIn=2.00,#2*th MomentumTransferStep=1e-3, - FirstTransmissionRun=offspec85) + FirstTransmissionRun=offspec85, + Version=1) ivq_78, __, __ = ReflectometryReductionOneAuto(offspec78, ThetaIn=3.40,#2*th MomentumTransferStep=1e-3, - FirstTransmissionRun=offspec85) + FirstTransmissionRun=offspec85, + Version=1) ivq_75_76, __ = Stitch1D(ivq_75, ivq_76, Params="1e-3") #pylint: disable=unused-variable diff --git a/Testing/SystemTests/tests/analysis/OFFSPECReflRedOneAutoPolarizationCorrection.py b/Testing/SystemTests/tests/analysis/OFFSPECReflRedOneAutoPolarizationCorrection.py index 4ab38bb8d6b96c61521d044452346f633f02d61e..b4aaf1e46802965bff96694d9069b9289226984d 100644 --- a/Testing/SystemTests/tests/analysis/OFFSPECReflRedOneAutoPolarizationCorrection.py +++ b/Testing/SystemTests/tests/analysis/OFFSPECReflRedOneAutoPolarizationCorrection.py @@ -18,7 +18,7 @@ class OFFSPECReflRedOneAutoPolarizationCorrection(stresstesting.MantidStressTest transWorkspace = CreateTransmissionWorkspaceAuto(transmissionGroup, AnalysisMode="MultiDetectorAnalysis", ProcessingInstructions="110-120", - WavelengthMin=2.0, WavelengthMax=12.0) + WavelengthMin=2.0, WavelengthMax=12.0, Version=1) # set up our efficiency constants CRho=[1] CAlpha=[1] @@ -31,7 +31,7 @@ class OFFSPECReflRedOneAutoPolarizationCorrection(stresstesting.MantidStressTest ThetaIn="1.2",WavelengthMin=2.0, WavelengthMax=12.0,CorrectionAlgorithm='None', PolarizationAnalysis='PA', MomentumTransferStep=0.1, - CPp=CPp,CAp=CAp,CRho=CRho,CAlpha=CAlpha) + CPp=CPp,CAp=CAp,CRho=CRho,CAlpha=CAlpha, Version=1) return True def validate(self): diff --git a/Testing/SystemTests/tests/analysis/RROAutoFunctionalityTests.py b/Testing/SystemTests/tests/analysis/RROAutoFunctionalityTests.py deleted file mode 100644 index 523c83f1abcfdc9e36547d2cb55090edf4b4b5ba..0000000000000000000000000000000000000000 --- a/Testing/SystemTests/tests/analysis/RROAutoFunctionalityTests.py +++ /dev/null @@ -1,163 +0,0 @@ -#pylint: disable=invalid-name -import stresstesting -from algorithm_decorator import make_decorator -from mantid.simpleapi import * -import mantid.api - - -class RROAutoFunctionalityTest(stresstesting.MantidStressTest): - """ - This test is to check the functionality of ReflectometryReductionOneAuto. Data testing is done separately - """ - - def __init__(self): - super(RROAutoFunctionalityTest, self).__init__() - data_ws = Load('INTER00013460.nxs') - self.__data_ws = data_ws - trans_ws_1 = Load('INTER00013463.nxs') - self.__trans_ws_1 = trans_ws_1 - trans_ws_2 = Load('INTER00013464.nxs') - self.__trans_ws_2 = trans_ws_2 - line_detector_ws = Load('POLREF00004699.nxs') - self.__line_detector_ws = line_detector_ws - - def __del__(self): - DeleteWorkspace(self.__data_ws) - DeleteWorkspace(self.__trans_ws_1) - DeleteWorkspace(self.__trans_ws_2) - DeleteWorkspace(self.__self.__line_detector_ws) - - def construct_standard_algorithm(self): - alg = make_decorator(ReflectometryReductionOneAuto) - alg.set_WavelengthMin(1.0) - alg.set_WavelengthMax(2.0) - alg.set_I0MonitorIndex(0) - alg.set_ProcessingInstructions("0, 1") - alg.set_MonitorBackgroundWavelengthMin(0.0) - alg.set_MonitorBackgroundWavelengthMax(1.0) - alg.set_MonitorIntegrationWavelengthMin(0.0) - alg.set_MonitorIntegrationWavelengthMax(1.0) - alg.set_additional({'OutputWorkspaceWavelength': 'out_ws_wav'}) - return alg - - def test_point_detector_run_with_single_transmission_workspace(self): - alg = self.construct_standard_algorithm() - alg.set_InputWorkspace(self.__data_ws) - alg.set_ProcessingInstructions("3,4") - alg.set_FirstTransmissionRun(self.__trans_ws_1) - alg.set_ThetaIn(0.2) - - out_ws_q, out_ws_lam, theta = alg.execute() - self.assertEqual(0.2, theta, "Theta in and out should be the same") - - self.assertTrue(isinstance(out_ws_lam, mantid.api.MatrixWorkspace), "Should be a matrix workspace") - self.assertEqual("Wavelength", out_ws_lam.getAxis(0).getUnit().unitID()) - - self.assertTrue(isinstance(out_ws_q, mantid.api.MatrixWorkspace), "Should be a matrix workspace") - self.assertEqual("MomentumTransfer", out_ws_q.getAxis(0).getUnit().unitID()) - - self.assertEqual(2, out_ws_lam.getNumberHistograms()) - - def test_point_detector_run_with_two_transmission_workspaces(self): - alg = self.construct_standard_algorithm() - - alg.set_InputWorkspace(self.__data_ws) - alg.set_ProcessingInstructions("3,4") - alg.set_FirstTransmissionRun(self.__trans_ws_1) - alg.set_SecondTransmissionRun(self.__trans_ws_2) - alg.set_ThetaIn(0.2) - - out_ws_q, out_ws_lam, theta = alg.execute() - - def test_spectrum_map_mismatch_throws_when_strict(self): - alg = self.construct_standard_algorithm() - ''' - Here we convert the transmission run to Lam. The workspace will NOT have the same spectra map as the input workspace, - and strict checking is turned on, so this will throw upon execution. - ''' - trans_run1_lam = ConvertUnits(self.__trans_ws_1, Target='Wavelength') - trans_run1_lam = CropWorkspace(trans_run1_lam, EndWorkspaceIndex=1) - - alg.set_InputWorkspace(self.__data_ws) - alg.set_ProcessingInstructions("3,4") # This will make spectrum numbers in input workspace different from denominator - alg.set_FirstTransmissionRun(trans_run1_lam) - alg.set_StrictSpectrumChecking(True) - - self.assertRaises(Exception, alg.execute) # Should throw due to spectrum missmatch. - - def test_spectrum_map_mismatch_doesnt_throw_when_not_strict(self): - alg = self.construct_standard_algorithm() - - ''' - Here we convert the transmission run to Lam. The workspace will NOT have the same spectra map as the input workspace, - and strict checking is turned off, so this will NOT throw upon execution. - ''' - trans_run1_lam = ConvertUnits(self.__trans_ws_1, Target='Wavelength') - trans_run1_lam = CropWorkspace(trans_run1_lam, EndWorkspaceIndex=1) - - alg.set_InputWorkspace(self.__data_ws) - alg.set_ProcessingInstructions("3,4") # This will make spectrum numbers in input workspace different from denominator - alg.set_FirstTransmissionRun(trans_run1_lam) - alg.set_StrictSpectrumChecking(False) # Will not crash-out on spectrum checking. - - alg.execute()# Should not throw - - def test_multidetector_run(self): - alg = self.construct_standard_algorithm() - - alg.set_InputWorkspace(self.__line_detector_ws[0]) - alg.set_AnalysisMode("MultiDetectorAnalysis") - alg.set_DetectorComponentName('lineardetector') - alg.set_ProcessingInstructions("10") # Fictional values - alg.set_CorrectDetectorPositions(False) - alg.set_RegionOfDirectBeam("20, 30") # Fictional values - alg.set_ThetaIn(0.1) # Fictional values - - 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()) - - self.assertTrue(isinstance(out_ws_q, mantid.api.MatrixWorkspace), "Should be a matrix workspace") - self.assertEqual("MomentumTransfer", out_ws_q.getAxis(0).getUnit().unitID()) - - def test_multidetector_run_correct_positions(self): - alg = self.construct_standard_algorithm() - - alg.set_InputWorkspace(self.__line_detector_ws[0]) - alg.set_AnalysisMode("MultiDetectorAnalysis") - alg.set_DetectorComponentName('lineardetector') - alg.set_ProcessingInstructions("73") # Fictional values - alg.set_CorrectDetectorPositions(True) - alg.set_RegionOfDirectBeam("28, 29") # Fictional values - alg.set_ThetaIn(0.49) # Fictional values - - 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()) - - self.assertTrue(isinstance(out_ws_q, mantid.api.MatrixWorkspace), "Should be a matrix workspace") - self.assertEqual("MomentumTransfer", out_ws_q.getAxis(0).getUnit().unitID()) - - instrument = out_ws_lam.getInstrument() - detector_pos = instrument.getComponentByName("lineardetector").getPos() - - self.assertDelta(-0.05714, detector_pos.Z(), 0.0001) - - def runTest(self): - - self.test_point_detector_run_with_single_transmission_workspace() - - self.test_point_detector_run_with_two_transmission_workspaces() - - self.test_spectrum_map_mismatch_throws_when_strict() - - self.test_spectrum_map_mismatch_doesnt_throw_when_not_strict() - - self.test_multidetector_run() - - self.test_multidetector_run_correct_positions() - - def validate(self): - return True diff --git a/docs/source/algorithms/ConvertToReflectometryQ-v1.rst b/docs/source/algorithms/ConvertToReflectometryQ-v1.rst index 27d2ea2fc633bc7c123a44598fa5df6dd8084381..c355a7f8bfaeccc16db59096fd69f8dda3e09f06 100644 --- a/docs/source/algorithms/ConvertToReflectometryQ-v1.rst +++ b/docs/source/algorithms/ConvertToReflectometryQ-v1.rst @@ -9,6 +9,11 @@ Description ----------- +This algorithm transforms an input workspace in wavelength to Q or momentum space for +reflectometry workspaces. Prior to the transformation, the algorithm corrects the +detector position to an angle :math:`\theta_f`, where :math:`\theta_f` is extracted +from the log value :literal:`stheta`. + Prerequisites ############# @@ -17,11 +22,11 @@ The workspace spectrum axis should be converted to signed\_theta using converted to Wavelength using :ref:`algm-ConvertUnits` before running this algorithm. Histogram input workspaces are expected. -The algorithm will looks for a specific log value called *stheta*, which -contains the incident theta angle :math:`theta_i`. If the input +The algorithm will look for a specific log value called :literal:`stheta`, which +contains the incident theta angle :math:`\theta_i`. If the input workspace does not contain this value, or if you wish to override this -value you can do so by providing your own *IncidentTheta* property and -enabling *OverrideIncidentTheta*. +value you can do so by providing your own :literal:`IncidentTheta` property and +enabling :literal:`OverrideIncidentTheta`. The algorithm also has the ability to produce additional debugging information from the Tableworkspace that can be used to create a patch plot of results before any 2D fractional rebinning has happened. diff --git a/docs/source/algorithms/CreateTransmissionWorkspace-v1.rst b/docs/source/algorithms/CreateTransmissionWorkspace-v1.rst index fdf8292b9862067f59f36212770b9ee6ca732a31..912da132323649e6518303ee8635aa5688eab345 100644 --- a/docs/source/algorithms/CreateTransmissionWorkspace-v1.rst +++ b/docs/source/algorithms/CreateTransmissionWorkspace-v1.rst @@ -50,7 +50,8 @@ Usage MonitorBackgroundWavelengthMin = 15, MonitorBackgroundWavelengthMax = 17, MonitorIntegrationWavelengthMin = 4, - MonitorIntegrationWavelengthMax = 10) + MonitorIntegrationWavelengthMax = 10, + Version=1) print "The first four transWS Y values are:" for i in range (4): @@ -85,7 +86,8 @@ Output: MonitorBackgroundWavelengthMin = 15, MonitorBackgroundWavelengthMax = 17, MonitorIntegrationWavelengthMin = 4, - MonitorIntegrationWavelengthMax = 10) + MonitorIntegrationWavelengthMax = 10, + Version=1) print "The first four transWS Y values are:" for i in range (4): diff --git a/docs/source/algorithms/CreateTransmissionWorkspace-v2.rst b/docs/source/algorithms/CreateTransmissionWorkspace-v2.rst new file mode 100644 index 0000000000000000000000000000000000000000..0dd9126d80163c79aa44239437b8a742524d423f --- /dev/null +++ b/docs/source/algorithms/CreateTransmissionWorkspace-v2.rst @@ -0,0 +1,118 @@ +.. algorithm:: + +.. summary:: + +.. alias:: + +.. properties:: + +Description +----------- + +Creates a transmission run workspace given one or two TOF workspaces. +If two workspaces are provided, then the first workspace is considered +a low wavelength transmission run, and the second workspace is considered +a high wavelength transmission run. + +Both input workspaces must have X-units of TOF. They are first converted +to units of wavelength and then stitched together using :ref:`algm-Stitch1D`, +:literal:`Params`, :literal:`StartOverlap` and :literal:`EndOverlap`. A single +output workspace is generated with X-units of wavelength in angstroms. + + +.. diagram:: CreateTransmissionWorkspace_HighLvl-v2_wkflw.dot + +The diagram above illustrates the main steps in the algorithm. Below is a more +detailed diagram describing how transmission workspaces are converted to units +of wavelength and normalized by monitors. First, the input workspace is converted +to wavelength and :literal:`ProcessingInstructions` are used to extract +the detectors of interest. If :literal:`I0MonitorIndex`, :literal:`MonitorBackgroundWavelengthMin` +and :literal:`MonitorBackgroundWavelengthMax` are provided, the monitor will be +extracted from the input workspace and its background will be subtracted according +to :literal:`MonitorBackgroundWavelengthMin` and :literal:`MonitorBackgroundWavelengthMax`. +If :literal:`MonitorIntegrationWavelengthMin` and :literal:`MonitorIntegrationWavelengthMax` +are provided, monitors will be integrated according to that range. Finally, the +detector workspace will be normalized by the monitor workspace, and the resulting workspace +will be cropped according to :literal:`WavelengthMin` and :literal:`WavelengthMax`. +Note that monitor normalization is optional and only happens when all :literal:`I0MonitorIndex`, +:literal:`MonitorBackgroundWavelengthMin` and :literal:`MonitorBackgroundWavelengthMax` are +provided. + +.. diagram:: CreateTransmissionWorkspace_ConvertToWavelength-v2_wkflw.dot + +Previous Versions +----------------- + +This is version 2 of the algorithm. For version 1, please see `here. <CreateTransmissionWorkspace-v1.html>`_ + +Usage +----- + +.. include:: ../usagedata-note.txt + +**Example - Create a transmission run** + +.. testcode:: ExCreateTransWSSimple + + trans = Load(Filename='INTER00013463.nxs') + transWS = CreateTransmissionWorkspace(FirstTransmissionRun = trans, + I0MonitorIndex = 2, + ProcessingInstructions = '3,4', + WavelengthMin = 1, + WavelengthMax = 17, + MonitorBackgroundWavelengthMin = 15, + MonitorBackgroundWavelengthMax = 17, + MonitorIntegrationWavelengthMin = 4, + MonitorIntegrationWavelengthMax = 10) + + print "The first four transWS Y values are:" + for i in range (4): + print "%.4f" % transWS.readY(0)[i] + +Output: + +.. testoutput:: ExCreateTransWSSimple + + The first four transWS Y values are: + 0.0255 + 0.0759 + 0.1324 + 0.1424 + +**Example - Create a transmission run from two runs** + +.. testcode:: ExCreateTransWSTwo + + trans1 = Load(Filename='INTER00013463.nxs') + trans2 = Load(Filename='INTER00013464.nxs') + transWS = CreateTransmissionWorkspace(FirstTransmissionRun = trans1, + SecondTransmissionRun = trans2, + Params = [1.5,0.02,17], + StartOverlap = 10.0, + EndOverlap = 12.0, + I0MonitorIndex = 2, + ProcessingInstructions = '3,4', + WavelengthMin = 1, + WavelengthMax = 17, + MonitorBackgroundWavelengthMin = 15, + MonitorBackgroundWavelengthMax = 17, + MonitorIntegrationWavelengthMin = 4, + MonitorIntegrationWavelengthMax = 10) + + print "The first four transWS Y values are:" + for i in range (4): + print "%.4f" % transWS.readY(0)[i] + +Output: + +.. testoutput:: ExCreateTransWSTwo + + The first four transWS Y values are: + 0.0572 + 0.0575 + 0.0585 + 0.0585 + +.. categories:: + +.. sourcelink:: diff --git a/docs/source/algorithms/CreateTransmissionWorkspaceAuto-v1.rst b/docs/source/algorithms/CreateTransmissionWorkspaceAuto-v1.rst index 3d09e3330c9c3ddc746d4b9230c6fab8ac5cef64..6ec2d570b96239afdba5f448b5f356118a7cfd18 100644 --- a/docs/source/algorithms/CreateTransmissionWorkspaceAuto-v1.rst +++ b/docs/source/algorithms/CreateTransmissionWorkspaceAuto-v1.rst @@ -31,7 +31,7 @@ Usage trans = Load(Filename='INTER00013463.nxs') # Reduction overriding the default values for MonitorBackgroundWavelengthMin and MonitorBackgroundWavelengthMax which would otherwise be retirieved from the workspace - transWS = CreateTransmissionWorkspaceAuto(FirstTransmissionRun=trans) + transWS = CreateTransmissionWorkspaceAuto(FirstTransmissionRun=trans, Version=1) print "The first four transWS Y values are:" for i in range (4): @@ -55,7 +55,7 @@ Output: trans = Load(Filename='INTER00013463.nxs') # Reduction overriding the default values for MonitorBackgroundWavelengthMin and MonitorBackgroundWavelengthMax which would otherwise be retirieved from the workspace - transWS = CreateTransmissionWorkspaceAuto(FirstTransmissionRun=trans, MonitorBackgroundWavelengthMin=0.0, MonitorBackgroundWavelengthMax=1.0) + transWS = CreateTransmissionWorkspaceAuto(FirstTransmissionRun=trans, MonitorBackgroundWavelengthMin=0.0, MonitorBackgroundWavelengthMax=1.0, Version=1) print "The first four transWS Y values are:" for i in range (4): @@ -79,7 +79,7 @@ Output: trans1 = Load(Filename='INTER00013463.nxs') trans2 = Load(Filename='INTER00013464.nxs') # Reduction overriding the default values for MonitorBackgroundWavelengthMin and MonitorBackgroundWavelengthMax which would otherwise be retirieved from the workspace - transWS = CreateTransmissionWorkspaceAuto(FirstTransmissionRun=trans1, SecondTransmissionRun=trans2, Params=[1.5,0.02,17], StartOverlap=10.0, EndOverlap=12.0) + transWS = CreateTransmissionWorkspaceAuto(FirstTransmissionRun=trans1, SecondTransmissionRun=trans2, Params=[1.5,0.02,17], StartOverlap=10.0, EndOverlap=12.0, Version=1) print "The first four transWS Y values are:" for i in range (4): diff --git a/docs/source/algorithms/CreateTransmissionWorkspaceAuto-v2.rst b/docs/source/algorithms/CreateTransmissionWorkspaceAuto-v2.rst new file mode 100644 index 0000000000000000000000000000000000000000..b118f70ce8b3b917a1eb2f034edd69cc93404088 --- /dev/null +++ b/docs/source/algorithms/CreateTransmissionWorkspaceAuto-v2.rst @@ -0,0 +1,114 @@ +.. algorithm:: + +.. summary:: + +.. alias:: + +.. properties:: + +Description +----------- + +This algorithm is a facade over :ref:`algm-CreateTransmissionWorkspace`. It pulls numeric parameters +out of the instrument parameter file where possible. You can override any of these automatically applied +defaults by providing your own values. + +The first transmission run is the only mandatory property. If :literal:`ProcessingInstructions` is not set its value is inferred from other properties: + +* If :literal:`AnalysisMode = PointDetectorAnalaysis` and :literal:`PointDetectorStart = PointDetectorStop` then :literal:`ProcessingInstructions` is set to :literal:`PointDetectorStart`. +* If :literal:`AnalysisMode = PointDetectorAnalaysis` and :literal:`PointDetectorStart != PointDetectorStop` then :literal:`ProcessingInstructions` is set to :literal:`PointDetectorStart:PointDetectorStop`. +* If :literal:`AnalysisMode = MultiDetectorAnalaysis` then the spectrum range from :literal:`MultiDetectorStart` to the last spectrum in the input workspace is used. + +When :literal:`WavelengthMin` and/or :literal:`WavelengthMax` are not provided, the algorithm will +search for :literal:`LambdaMin` and :literal:`LambdaMax` in the parameter file. If monitor properties, +:literal:`I0MonitorIndex`, :literal:`MonitorBackgroundWavelengthMin`, :literal:`MonitorBackgroundWavelengthMax`, +:literal:`MonitorIntegrationWavelengthMin` and :literal:`MonitorIntegrationWavelengthMax`, are not set, the +algorithm will search for :literal:`I0MonitorIndex`, :literal:`MonitorBackgroundMin`, :literal:`MonitorBackgroundMax`, +:literal:`MonitorIntegralMin` and :literal:`MonitorIntegralMax` respectively. + +Finally, if a second transmission run is given, the algorithm will run :ref:`algm-CreateTransmissionWorkspace` using +:literal:`StartOverlap`, :literal:`EndOverlap` and :literal:`Params` if those have been set. + +See :ref:`algm-CreateTransmissionWorkspace` for more information on the wrapped algorithm. + +Previous Versions +----------------- + +This is version 2 of the algorithm. For version 1, please see `CreateTransmissionWorkspaceAuto-v1. <CreateTransmissionWorkspaceAuto-v1.html>`_ + +Usage +----- + +.. include:: ../usagedata-note.txt + +**Example - Create a transmission run** + +.. testcode:: ExCreateTransWSAutoSimple + + # Create a transmission run with input properties read from the parameter file + trans = Load(Filename='INTER00013463.nxs') + transWS = CreateTransmissionWorkspaceAuto(FirstTransmissionRun=trans) + + print "%.4f" % (transWS.readY(0)[26]) + print "%.4f" % (transWS.readY(0)[27]) + print "%.4f" % (transWS.readY(0)[28]) + print "%.4f" % (transWS.readY(0)[29]) + +Output: + +.. testoutput:: ExCreateTransWSAutoSimple + + 0.3671 + 0.3684 + 0.3640 + 0.3578 + + +**Example - Create a transmission run, overriding some default parameters** + +.. testcode:: ExCreateTransWSAutoOverload + + # Override the default values for MonitorBackgroundWavelengthMin and MonitorBackgroundWavelengthMax + trans = Load(Filename='INTER00013463.nxs') + transWS = CreateTransmissionWorkspaceAuto(FirstTransmissionRun=trans, MonitorBackgroundWavelengthMin=0.0, MonitorBackgroundWavelengthMax=1.0) + + print "%.4f" % (transWS.readY(0)[26]) + print "%.4f" % (transWS.readY(0)[27]) + print "%.4f" % (transWS.readY(0)[28]) + print "%.4f" % (transWS.readY(0)[29]) + +Output: + +.. testoutput:: ExCreateTransWSAutoOverload + + 0.3638 + 0.3651 + 0.3607 + 0.3546 + + +**Example - Create a transmission run from two runs** + +.. testcode:: ExCreateTransWSAutoTwo + + trans1 = Load(Filename='INTER00013463.nxs') + trans2 = Load(Filename='INTER00013464.nxs') + transWS = CreateTransmissionWorkspaceAuto(FirstTransmissionRun=trans1, SecondTransmissionRun=trans2, Params=[1.5,0.02,17], StartOverlap=10.0, EndOverlap=12.0) + + print "%.4f" % (transWS.readY(0)[26]) + print "%.4f" % (transWS.readY(0)[27]) + print "%.4f" % (transWS.readY(0)[28]) + print "%.4f" % (transWS.readY(0)[29]) + +Output: + +.. testoutput:: ExCreateTransWSAutoTwo + + 0.0825 + 0.0860 + 0.0879 + 0.0879 + +.. categories:: + +.. sourcelink:: diff --git a/docs/source/algorithms/ReflectometryReductionOne-v1.rst b/docs/source/algorithms/ReflectometryReductionOne-v1.rst index 22c25541d8d7c4786e282f4f36db3596b1c1abdf..6ecb0e331bdb48735d1447fc9bc7f5b65e20da98 100644 --- a/docs/source/algorithms/ReflectometryReductionOne-v1.rst +++ b/docs/source/algorithms/ReflectometryReductionOne-v1.rst @@ -225,7 +225,7 @@ Usage IvsQ, IvsLam, thetaOut = ReflectometryReductionOne(InputWorkspace=run, ThetaIn=0.7, I0MonitorIndex=2, ProcessingInstructions='3:4', WavelengthMin=1.0, WavelengthMax=17.0, MonitorBackgroundWavelengthMin=15.0, MonitorBackgroundWavelengthMax=17.0, - MonitorIntegrationWavelengthMin=4.0, MonitorIntegrationWavelengthMax=10.0 ) + MonitorIntegrationWavelengthMin=4.0, MonitorIntegrationWavelengthMax=10.0, Version=1) print "The first four IvsLam Y values are: [ %.4e, %.4e, %.4e, %.4e ]" % (IvsLam.readY(0)[0], IvsLam.readY(0)[1], IvsLam.readY(0)[2], IvsLam.readY(0)[3]) print "The first four IvsQ Y values are: [ %.4e, %.4e, %.4e, %.4e ]" % (IvsQ.readY(0)[0], IvsQ.readY(0)[1], IvsQ.readY(0)[2], IvsQ.readY(0)[3]) diff --git a/docs/source/algorithms/ReflectometryReductionOne-v2.rst b/docs/source/algorithms/ReflectometryReductionOne-v2.rst new file mode 100644 index 0000000000000000000000000000000000000000..3033e6d58b4c65a107a3a5e69fc171f5b4a69ca5 --- /dev/null +++ b/docs/source/algorithms/ReflectometryReductionOne-v2.rst @@ -0,0 +1,190 @@ +.. algorithm:: + +.. summary:: + +.. alias:: + +.. properties:: + +Description +----------- + +This algorithm is not meant to be used directly by users. Please see :ref:`algm-ReflectometryReductionOneAuto` +which is a facade over this algorithm. + +This algorithm reduces a single reflectometry run into a mod Q vs I/I0 workspace. +The mandatory input properties, :literal:`WavelengthMin`, :literal:`WavelengthMax` +and :literal:`ProcessingInstructions`, must be manually set by the user. In addition, for +the algorithm to be able to convert from wavelength to momentum transfer correctly, +instrument components, specially detectors, must be located at the correct positions. +The expected experimental setup for the algorithm to produce correct results is +shown below, where the angle between the beam direction and the sample-to-detector +vector must be :math:`2\theta`. + +.. figure:: /images/ReflectometryReductionOneDetectorPositions.png + :width: 400px + :align: center + + +The figure below displays a high-level workflow diagram illustrating the main +steps taking place in the reduction. + +.. diagram:: ReflectometryReductionOne_HighLvl-v2_wkflw.dot + + +Conversion to Wavelength +######################## + +First, the algorithm checks the X units of +the input workspace. If the input workspace is already in wavelength, normalization by +monitors and direct beam are not performed, as it is considered that the input run was +already reduced using this algorithm. If the input workspace is in TOF, it will be +converted to wavelength (note that :literal:`AlignBins` will be set to :literal:`True` for this in +:ref:`algm-ConvertUnits`) and the detectors +of interest, specified via :literal:`ProcessingInstructions`, will be grouped together using +:ref:`algm-GroupDetectors`. **Optionally**, the algorithm will perform direct beam +normalization (if :literal:`RegionOfDirectBeam` is specified) dividing the detectors of +interest by the direct beam, and monitor normalization (if :literal:`I0MonitorIndex` and +:literal:`MonitorBackgroundWavelengthMin` and :literal:`MonitorBackgroundWavelengthMax` are all specified), +in which case the detectors of interest will be divided by monitors. Detectors can be normalized +by integrated monitors by setting :literal:`NormalizeByIntegratedMonitors` to true, in which case +:literal:`MonitorIntegrationWavelengthMin` and :literal:`MonitorIntegrationWavelengthMax` will +be used as the integration range. Finally, the resulting workspace will be cropped according to +:literal:`WavelengthMin` and :literal:`WavelengthMax`, which are both mandatory properties. +A summary of the steps is shown in the workflow diagram below. + +.. diagram:: ReflectometryReductionOne_ConvertToWavelength-v2_wkflw.dot + + +Transmission Correction +####################### + +Transmission corrections can be optionally applied to the workspace resulting +from the previous step. Transmission corrections can be either specified via +transmission runs or specific correction algorithms. + +.. diagram:: ReflectometryReductionOne_TransmissionCorrection-v2_wkflw.dot + + +When normalizing by transmission runs, i.e. when one or two transmission runs +are given, the spectrum numbers in the +transmission workspaces must be the same as those in the input run +workspace. If spectrum numbers do not match, the algorithm will throw and exception +and execution of the algorithm will be stopped. This behaviour can be optionally +switched off by setting :literal:`StrictSpectrumChecking` to false, in which case +a warning message will be shown instead. + +When normalizing by transmission run, this algorithm will run +:ref:`algm-CreateTransmissionWorkspace` as a child algorithm, with properties :literal:`WavelengthMin`, +:literal:`WavelengthMax`, :literal:`I0MonitorIndex`, :literal:`MonitorBackgroundWavelengthMin`, +:literal:`MonitorBackgroundWavelengthMax`, :literal:`MonitorIntegrationWavelengthMin`, +:literal:`MonitorIntegrationWavelengthMax`, and :literal:`ProcessingInstructions`. +In addition, when both :literal:`FirstTransmissionRun` and :literal:`SecondTransmissionRun` +are provided the stitching parameters :literal:`Params`, as well as :literal:`StartOverlap` and +:literal:`EndOverlap` will be used by :ref:`algm-CreateTransmissionWorkspace` to create the +transmission workspace that will be used for the normalization. + +If no transmission runs are provided, then algorithmic corrections can be +performed instead by setting :literal:`CorrectionAlgorithm` to either +:literal:`PolynomialCorrection` or :literal:`ExponentialCorrection`, the two +possible types of corrections at the moment. If :literal:`PolynomialCorrection`, +is selected, :ref:`algm-PolynomialCorrection` algorithm will be run, with this +algorithm's :literal:`Polynomial` property used as its :literal:`Coefficients` +property. If the :literal:`CorrectionAlgorithm` property is set to +:literal:`ExponentialCorrection`, then the :Ref:`algm-ExponentialCorrection` +algorithm is used, with *C0* and *C1* taken from the :literal:`C0` and :literal:`C1` +properties. + +Conversion to Momentum Transfer (Q) +################################### + +Finally, the output workspace in wavelength is converted to momentum transfer (Q) using +:ref:`algm-ConvertUnits`. Note that the output workspace in Q is therefore a workspace +with native binning, and no rebin step is applied to it. + +.. diagram:: ReflectometryReductionOne_ConvertToMomentum-v2_wkflw.dot + +If you wish to obtain a rebinned workspace in Q you should consider using algorithm +:ref:`algm-ReflectometryReductionOneAuto` instead, which is a facade over this algorithm +and has two extra steps (:ref:`algm-Rebin` and :ref:`algm-Scale`) to produce an additional +workspace in Q with specified binning and scale factor. Please refer to :ref:`algm-ReflectometryReductionOneAuto` +for more information. + +Previous Versions +----------------- + +This is version 2 of the algorithm. For version 1, please see `here. <ReflectometryReductionOne-v1.html>`_ + +Usage +----- + +**Example - Reduce a run** + +.. testcode:: ExReflRedOneSimple + + run = Load(Filename='INTER00013460.nxs') + # Basic reduction with no transmission run + IvsQ, IvsLam = ReflectometryReductionOne(InputWorkspace=run, + WavelengthMin=1.0, + WavelengthMax=17.0, + ProcessingInstructions='3:4', + I0MonitorIndex=2, + MonitorBackgroundWavelengthMin=15.0, + MonitorBackgroundWavelengthMax=17.0, + MonitorIntegrationWavelengthMin=4.0, + MonitorIntegrationWavelengthMax=10.0) + + print "%.4f" % (IvsLam.readY(0)[173]) + print "%.4f" % (IvsLam.readY(0)[174]) + print "%.4f" % (IvsQ.readY(0)[2]) + print "%.4f" % (IvsQ.readY(0)[3]) + + +Output: + +.. testoutput:: ExReflRedOneSimple + + 0.0014 + 0.0014 + 0.0001 + 0.0001 + + +**Example - Reduce a run and normalize by transmission workspace** + +.. testcode:: ExReflRedOneTrans + + run = Load(Filename='INTER00013460.nxs') + trans1 = Load(Filename='INTER00013463.nxs') + trans2 = Load(Filename='INTER00013464.nxs') + # Basic reduction with two transmission runs + IvsQ, IvsLam = ReflectometryReductionOne(InputWorkspace=run, + WavelengthMin=1.0, + WavelengthMax=17.0, + ProcessingInstructions='3-4', + I0MonitorIndex=2, + MonitorBackgroundWavelengthMin=15.0, + MonitorBackgroundWavelengthMax=17.0, + MonitorIntegrationWavelengthMin=4.0, + MonitorIntegrationWavelengthMax=10.0, + FirstTransmissionRun=trans1, + SecondTransmissionRun=trans2) + + print "%.4f" % (IvsLam.readY(0)[170]) + print "%.4f" % (IvsLam.readY(0)[171]) + print "%.4f" % (IvsQ.readY(0)[107]) + print "%.4f" % (IvsQ.readY(0)[108]) + + +Output: + +.. testoutput:: ExReflRedOneTrans + + 0.4897 + 0.5468 + 0.6144 + 0.5943 + +.. categories:: + +.. sourcelink:: diff --git a/docs/source/algorithms/ReflectometryReductionOneAuto-v1.rst b/docs/source/algorithms/ReflectometryReductionOneAuto-v1.rst index d2ac5da76b004faf40ab6e32c5d0fb1620a062c8..0ffcea6393a7fe22494d5df44a10f7f976b4f61c 100644 --- a/docs/source/algorithms/ReflectometryReductionOneAuto-v1.rst +++ b/docs/source/algorithms/ReflectometryReductionOneAuto-v1.rst @@ -70,7 +70,7 @@ Usage run = Load(Filename='INTER00013460.nxs') # Basic reduction with no transmission run - IvsQ, IvsLam, thetaOut = ReflectometryReductionOneAuto(InputWorkspace=run, ThetaIn=0.7) + IvsQ, IvsLam, thetaOut = ReflectometryReductionOneAuto(InputWorkspace=run, ThetaIn=0.7, Version=1) print "The first four IvsLam Y values are: [ %.4e, %.4e, %.4e, %.4e ]" % (IvsLam.readY(0)[0], IvsLam.readY(0)[1], IvsLam.readY(0)[2], IvsLam.readY(0)[3]) print "The first four IvsQ Y values are: [ %.4e, %.4e, %.4e, %.4e ]" % (IvsQ.readY(0)[0], IvsQ.readY(0)[1], IvsQ.readY(0)[2], IvsQ.readY(0)[3]) @@ -91,7 +91,7 @@ Output: run = Load(Filename='INTER00013460.nxs') trans = Load(Filename='INTER00013463.nxs') # Basic reduction with a transmission run - IvsQ, IvsLam, thetaOut = ReflectometryReductionOneAuto(InputWorkspace=run, FirstTransmissionRun=trans, ThetaIn=0.7) + IvsQ, IvsLam, thetaOut = ReflectometryReductionOneAuto(InputWorkspace=run, FirstTransmissionRun=trans, ThetaIn=0.7, Version=1) print "The first four IvsLam Y values are: [ %.4e, %.4e, %.4e, %.4e ]" % (IvsLam.readY(0)[0], IvsLam.readY(0)[1], IvsLam.readY(0)[2], IvsLam.readY(0)[3]) print "The first four IvsQ Y values are: [ %.4e, %.4e, %.4e, %.4e ]" % (IvsQ.readY(0)[0], IvsQ.readY(0)[1], IvsQ.readY(0)[2], IvsQ.readY(0)[3]) @@ -111,7 +111,7 @@ Output: run = Load(Filename='INTER00013460.nxs') # Reduction overriding the default values for MonitorBackgroundWavelengthMin and MonitorBackgroundWavelengthMax which would otherwise be retirieved from the workspace - IvsQ, IvsLam, thetaOut = ReflectometryReductionOneAuto(InputWorkspace=run, ThetaIn=0.7, MonitorBackgroundWavelengthMin=0.0, MonitorBackgroundWavelengthMax=1.0) + IvsQ, IvsLam, thetaOut = ReflectometryReductionOneAuto(InputWorkspace=run, ThetaIn=0.7, MonitorBackgroundWavelengthMin=0.0, MonitorBackgroundWavelengthMax=1.0, Version=1) print "The first four IvsLam Y values are: [ %.4e, %.4e, %.4e, %.4e ]" % (IvsLam.readY(0)[0], IvsLam.readY(0)[1], IvsLam.readY(0)[2], IvsLam.readY(0)[3]) print "The first four IvsQ Y values are: [ %.4e, %.4e, %.4e, %.4e ]" % (IvsQ.readY(0)[0], IvsQ.readY(0)[1], IvsQ.readY(0)[2], IvsQ.readY(0)[3]) @@ -134,7 +134,7 @@ Output: SetInstrumentParameter(run, "correction", Value="polynomial") SetInstrumentParameter(run, "polynomial", Value="0,0.5,1,2,3") - IvsQ, IvsLam, thetaOut = ReflectometryReductionOneAuto(InputWorkspace=run, ThetaIn=0.7) + IvsQ, IvsLam, thetaOut = ReflectometryReductionOneAuto(InputWorkspace=run, ThetaIn=0.7, Version=1) def findByName(histories, name): return filter(lambda x: x.name() == name, histories)[0] diff --git a/docs/source/algorithms/ReflectometryReductionOneAuto-v2.rst b/docs/source/algorithms/ReflectometryReductionOneAuto-v2.rst new file mode 100644 index 0000000000000000000000000000000000000000..356a6c5f2a3bbceeda1f18319576398cec600256 --- /dev/null +++ b/docs/source/algorithms/ReflectometryReductionOneAuto-v2.rst @@ -0,0 +1,211 @@ +.. algorithm:: + +.. summary:: + +.. alias:: + +.. properties:: + +Description +----------- + +This algorithm is a facade over :ref:`algm-ReflectometryReductionOne` (see :ref:`algm-ReflectometryReductionOne` +for more information on the wrapped algorithm). It optionally corrects the detector position and then pulls numeric +parameters out of the instrument parameter file where possible. These automatically applied defaults +can be overriden by providing your own values. In addition, it outputs a rebinned workspace in Q, and it optionally +performs polarization analysis if the input workspace is a workspace group. + +First, if :literal:`ThetaIn` is given the algorithm will try to correct the detector position. For this, it uses +:literal:`ProcessingInstructions`, which corresponds to the grouping pattern of workspace indices that define the +detectors of interest. Only the detectors of interest will be corrected, the rest of the instrument components +will remain in the original position. Note that when :literal:`ProcessingInstructions` is not set, its value +is inferred from other properties, depending on the value of :literal:`AnalysisMode`: + +* If :literal:`AnalysisMode = PointDetectorAnalaysis` the algorithm will search for :literal:`PointDetectorStart` and :literal:`PointDetectorStep` in the parameter file, and :literal:`ProcessingInstructions` will be set to :literal:`PointDetectorStart:PointDetectorEnd`. +* If :literal:`AnalysisMode = MultiDetectorAnalaysis` the algorithm will search for :literal:`MultiDetectorStart` in the parameter file and all of the spectra from this value onwards will be used. + +Note that ProcessingInstructions are workspace indices, not detector IDs. The first few workspaces may correspond +to monitors, rather than detectors of interest. For the syntax of this property, see :ref:`algm-GroupDetectors`. + +Once the algorithm determines the detectors of interest it corrects their positions according to :literal:`ThetaIn`, +if given, for which it runs :ref:`algm-SpecularReflectionPositionCorrect`. If :literal:`ThetaIn` is not set, detectors +will not be corrected. However, it is recommended to use this option to ensure that :ref:`algm-ReflectometryReductionOne` +is able to convert from wavelength to momentum transfer properly. + +Next, the algorithm will try to populate input properties which have not been set. Specifically, it will search for +:literal:`LambdaMin`, :literal:`LambdaMax`, :literal:`I0MonitorIndex`, :literal:`MonitorBackgroundMin`, :literal:`MonitorBackgroundMax`, +:literal:`MonitorIntegralMin` and :literal:`MonitorIntegralMin` in the parameter file to populate :literal:`WavelengthMin`, +:literal:`WavelengthMax`, :literal:`I0MonitorIndex`, :literal:`MonitorBackgroundWavelengthMin`, :literal:`MonitorBackgroundWavelengthMax`, +:literal:`MonitorIntegrationWavelengthMin` and :literal:`MonitorIntegrationWavelengthMax` respectively. The first two properties +will be used by :ref:`algm-ReflectometryReductionOne` to crop the workspace in wavelength, whereas the rest of the properties +refer to monitors and are used to create a temporary monitor workspace by which the detectors of interest will be normalized. +Note that there is an additional property referring to monitors, :literal:`NormalizeByIntegratedMonitors`, which can be used +to specify whether or not integrated monitors should be considered. + +The rest of the input properties are not inferred from the parameter file, and must be specified manually. :literal:`RegionOfDirectBeam` is an optional +property that allows users to specify a region of direct beam that will be used to normalize +the detector signal. The region of direct beam is specified by workspace indices. For instance, :literal:`RegionOfDirectBeam='2-3'` +means that spectra with workspace indices :literal:`2` and :literal:`3` will be summed and the resulting +workspace will be used as the direct beam workspace. + +Transmission corrections can be optionally applied by providing either one or +two transmission runs or polynomial corrections. Polynomial correction is enabled by setting the +:literal:`CorrectionAlgorithm` property. If set to :literal:`AutoDetect`, the algorithm looks at the instrument +parameters for the :literal:`correction` parameter. If this parameter is set to +:literal:`polynomial`, then polynomial correction is performed using the +:ref:`algm-PolynomialCorrection` algorithm, with the polynomial string taken +from the instrument's :literal:`polystring` parameter. If the +:literal:`correction` parameter is set to :literal:`exponential` instead, then +the :Ref:`algm-ExponentialCorrection` algorithm is used, with C0 and C1 taken +from the instrument parameters, :literal:`C0` and :literal:`C1`. All these values +can be specified manually by setting the :literal:`CorrectionAlgorithm` to either +:literal:`PolynomialCorrection` or :literal:`ExponentialCorrection` and setting +:literal:`Polynomial` or :literal:`C0` and :literal:`C1` properties accordingly. +Note that when using a correction algorithm, monitors will not be integrated, even if +:literal:`NormalizeByIntegratedMonitors` was set to true. + +Finally, properties :literal:`MomentumTransferMin`, :literal:`MomentumTransferStep` and :literal:`MomentumTransferMax` are +used to rebin the output workspace in Q, and :literal:`ScaleFactor` is used to scale the rebinned workspace. When they +are not provided the algorithm will attempt to determine the bin width using :ref:`algm-CalculateResolution` (note that, for +the latter to run successfully, a :literal:`slit` component with a :literal:`vertical gap` must be defined in the +instrument definition file). + +See :ref:`algm-ReflectometryReductionOne` for more information +on how the input properties are used by the wrapped algorithm. + +Workspace Groups +################ + +If a workspace group is provided as input, each workspace in the group will be +reduced independently and sequentially using :ref:`algm-ReflectometryReductionOne`. Each of these +individual reductions will produce three output workspaces: an output workspace in +wavelength, an output workspace in Q with native binning, and a rebinned workspace in Q. +Output workspaces in wavelength will be grouped together to produce an output workspace group in wavelength, and output +workspaces in Q will be grouped together to produce an output workspace group in Q. +The diagram below illustrates this process (note that, for the sake of clarity, the rebinned output +workspace in Q, :literal:`OutputWorkspaceBinned`, is not represented but it is handled analogously to +:literal:`OutputWorkspace` and :literal:`OutputWorkspaceWavelength`): + +.. diagram:: ReflectometryReductionOneAuto-v2-Groups_noPA_wkflw.dot + +Polarization Analysis Off +~~~~~~~~~~~~~~~~~~~~~~~~~ + +If :literal:`PolarizationAnalysis = None` the reduction stops here. Note that if +transmission runs are given in the form of a workspace group, each member in the +transmission group will be associated to the corresponding member in the input +workspace group, i.e., the first item in the transmission group will be used as the +transmission run for the first workspace in the input workspace group, the second +element in the transmission group will be used as the transmission run for the +second workspace in the input workspace group, etc. This is also illustrated +in the diagram above, where :literal:`[0]` represents the first element in a +workspace group, :literal:`[1]` the second element, etc. If transmission runs +are provided as matrix workspaces the specified runs will be used for all members +of the input workspace group. + +Polarization Analysis On +~~~~~~~~~~~~~~~~~~~~~~~~ + +If :literal:`PolarizationAnalysis` is set to :literal:`PA` or :literal:`PNR` +the reduction continues and polarization corrections will be applied to +the output workspace in wavelength. The algorithm will use the properties :literal:`PolarizationAnalysis`, +:literal:`CPp`, :literal:`CAp`, :literal:`CRho` and :literal:`CAlpha` to run :ref:`algm-PolarizationCorrection`. +The result will be a new workspace in wavelength, which will override the previous one, that will +be used as input to :ref:`algm-ReflectometryReductionOne` to calculate the new output workspaces in Q, which +in turn will override the existing workspaces in Q. Note that if transmission runs are provided in the form of workspace +groups, the individual workspaces will be summed to produce a matrix workspace that will be used as the +transmission run for all items in the input workspace group, as illustrated in the diagram below +(note that, for the sake of clarity, the rebinned output workspace in Q, :literal:`OutputWorkspaceBinned`, is not +represented but it is handled analogously to :literal:`OutputWorkspace`). + +.. diagram:: ReflectometryReductionOneAuto-v2-Groups_PA_wkflw.dot + +Previous Versions +----------------- + +This is version 2 of the algorithm. For version 1, please see `here. <ReflectometryReductionOneAuto-v1.html>`_ + +Usage +----- + +.. include:: ../usagedata-note.txt + +**Example - Basic reduction with no transmission run, polynomial corrections will be automatically applied** + +.. testcode:: ExReflRedOneAutoSimple + + run = Load(Filename='INTER00013460.nxs') + IvsQ, IvsQ_unbinned, IvsLam = ReflectometryReductionOneAuto(InputWorkspace=run, ThetaIn=0.7) + + print "%.5f" % (IvsLam.readY(0)[175]) + print "%.5f" % (IvsLam.readY(0)[176]) + print "%.5f" % (IvsQ_unbinned.readY(0)[106]) + print "%.5f" % (IvsQ_unbinned.readY(0)[107]) + print "%.5f" % (IvsQ.readY(0)[106]) + print "%.5f" % (IvsQ.readY(0)[107]) + +Output: + +.. testoutput:: ExReflRedOneAutoSimple + + 0.56682 + 0.59735 + 0.57476 + 0.54633 + 0.00027 + 0.00027 + +**Example - Basic reduction with a transmission run** + +.. testcode:: ExReflRedOneAutoTrans + + run = Load(Filename='INTER00013460.nxs') + trans = Load(Filename='INTER00013463.nxs') + IvsQ, IvsQ_unbinned, IvsLam = ReflectometryReductionOneAuto(InputWorkspace=run, FirstTransmissionRun=trans, ThetaIn=0.7) + + print "%.5f" % (IvsLam.readY(0)[164]) + print "%.5f" % (IvsLam.readY(0)[164]) + print "%.5f" % (IvsQ_unbinned.readY(0)[96]) + print "%.5f" % (IvsQ_unbinned.readY(0)[97]) + print "%.5f" % (IvsQ.readY(0)[96]) + print "%.5f" % (IvsQ.readY(0)[97]) + +Output: + +.. testoutput:: ExReflRedOneAutoTrans + + 0.36906 + 0.36906 + 1.05389 + 1.02234 + 0.00074 + 0.00069 + +**Example - Reduction overriding some default values** + +.. testcode:: ExReflRedOneAutoOverload + + run = Load(Filename='INTER00013460.nxs') + IvsQ, IvsQ_unbinned, IvsLam = ReflectometryReductionOneAuto(InputWorkspace=run, ThetaIn=0.7, MonitorBackgroundWavelengthMin=0.0, MonitorBackgroundWavelengthMax=1.0) + + print "%.5f" % (IvsLam.readY(0)[175]) + print "%.5f" % (IvsLam.readY(0)[176]) + print "%.5f" % (IvsQ_unbinned.readY(0)[106]) + print "%.5f" % (IvsQ_unbinned.readY(0)[107]) + print "%.5f" % (IvsQ.readY(0)[106]) + print "%.5f" % (IvsQ.readY(0)[107]) + +Output: + +.. testoutput:: ExReflRedOneAutoOverload + + 0.50401 + 0.52599 + 0.51160 + 0.48843 + 0.00027 + 0.00027 + +.. categories:: + +.. sourcelink:: diff --git a/docs/source/algorithms/SpecularReflectionPositionCorrect-v1.rst b/docs/source/algorithms/SpecularReflectionPositionCorrect-v1.rst index b20da22b24d3ab81259c25dd926d8dbb5161d899..23ade33180525bef2772a2088a47eae99eb7942e 100644 --- a/docs/source/algorithms/SpecularReflectionPositionCorrect-v1.rst +++ b/docs/source/algorithms/SpecularReflectionPositionCorrect-v1.rst @@ -43,7 +43,7 @@ Usage MoveInstrumentComponent(ws, 'some-surface-holder',RelativePosition=False, X=0, Y= 0, Z=0) # Correct the detector position. Has a 45 degree incident beam angle. - corrected_ws = SpecularReflectionPositionCorrect(InputWorkspace=ws, DetectorComponentName='point-detector', AnalysisMode='PointDetectorAnalysis', TwoThetaIn=45.0) + corrected_ws = SpecularReflectionPositionCorrect(InputWorkspace=ws, DetectorComponentName='point-detector', AnalysisMode='PointDetectorAnalysis', TwoThetaIn=45.0, Version=1) # Get the detector position post correction. We expect that the vertical offset of the point detector == 1.0 inst = corrected_ws.getInstrument() diff --git a/docs/source/algorithms/SpecularReflectionPositionCorrect-v2.rst b/docs/source/algorithms/SpecularReflectionPositionCorrect-v2.rst new file mode 100644 index 0000000000000000000000000000000000000000..be5f1de144aab80247790520bc0b83740b98848d --- /dev/null +++ b/docs/source/algorithms/SpecularReflectionPositionCorrect-v2.rst @@ -0,0 +1,91 @@ +.. algorithm:: + +.. summary:: + +.. alias:: + +.. properties:: + +Description +----------- + +Moves the specified detector component vertically so that the angle between the beam and +the sample-to-detector vector is :literal:`TwoTheta`. The detector component is moved as a +block. The rest of the instrument components remain in the original position. + +Previous Versions +----------------- + +For version 1 of the algorithm, please see `SpecularReflectionPositionCorrect-v1. <SpecularReflectionPositionCorrect-v1.html>`_ + +Usage +----- + +.. include:: ../usagedata-note.txt + +**Example - Correct 'point-detector'** + +.. testcode:: SpecularReflectionPositionCorrectPointDetector + + polref = Load(Filename=r'POLREF00004699.raw', PeriodList=1) + polref = polref[0] + + instr = polref.getInstrument() + print instr.getComponentByName('point-detector').getPos() + + polref = SpecularReflectionPositionCorrect(polref, TwoTheta = 2*0.49, DetectorComponentName='point-detector') + instr = polref.getInstrument() + print instr.getComponentByName('point-detector').getPos() + +Output: + +.. testoutput:: SpecularReflectionPositionCorrectPointDetector + + [25.6,0,0.0444961] + [25.6,0,0.0444753] + +**Example - Correct 'lineardetector'** + +.. testcode:: SpecularReflectionPositionCorrectLinearDetector + + polref = Load(Filename=r'POLREF00004699.raw', PeriodList=1) + polref = polref[0] + + instr = polref.getInstrument() + print instr.getComponentByName('lineardetector').getPos() + + polref = SpecularReflectionPositionCorrect(polref, TwoTheta = 2*0.49, DetectorComponentName='lineardetector') + instr = polref.getInstrument() + print instr.getComponentByName('lineardetector').getPos() + +Output: + +.. testoutput:: SpecularReflectionPositionCorrectLinearDetector + + [26,0,0] + [26,0,0.0513177] + +**Example - Correct 'OSMOND'** + +.. testcode:: SpecularReflectionPositionCorrectOSMONDDetector + + polref = Load(Filename=r'POLREF00004699.raw', PeriodList=1) + polref = polref[0] + + instr = polref.getInstrument() + print instr.getComponentByName('OSMOND').getPos() + + polref = SpecularReflectionPositionCorrect(polref, TwoTheta = 2*0.49, DetectorComponentName='OSMOND') + instr = polref.getInstrument() + print instr.getComponentByName('OSMOND').getPos() + +Output: + +.. testoutput:: SpecularReflectionPositionCorrectOSMONDDetector + + [26,0,0] + [26,0,0.0513177] + +.. categories:: + +.. sourcelink:: diff --git a/docs/source/diagrams/CreateTransmissionWorkspace_ConvertToWavelength-v2_wkflw.dot b/docs/source/diagrams/CreateTransmissionWorkspace_ConvertToWavelength-v2_wkflw.dot new file mode 100644 index 0000000000000000000000000000000000000000..928d4c9ad09e17a88ca6a76368491159f68215aa --- /dev/null +++ b/docs/source/diagrams/CreateTransmissionWorkspace_ConvertToWavelength-v2_wkflw.dot @@ -0,0 +1,74 @@ +digraph CreateTransmissionWorkspaceWavelength { +label = "" +rankdir = TB; + +$global_style + +subgraph params { + $param_style + inputWS [label="TransmissionRun"] + procCommands [label="ProcessingCommands"] + wavMin [label="WavelengthMin", group=gwav] + wavMax [label="WavelengthMax", group=gwav] + monitorIndex [label="I0MonitorIndex"] + monIntWavMax [label="MonitorIntegration-\nWavelengthMax"] + monIntWavMin [label="MonitorIntegration-\nWavelengthMin"] + monBackWavMin [label="MonitorBackground-\nWavelengthMin"] + monBackWavMax [label="MonitorBackground-\nWavelengthMax"] +} + +subgraph decisions { + $decision_style +} + +subgraph algorithms { + $algorithm_style + convertWav [label="ConvertUnits\n(AlignBins = True)", group=g1] + groupDet [label="GroupDetectors"] + cropMonWS [label="CropWorkspace", group=g11] + calcFlatBg [label="CalculateFlatBackground", group=g11] + intMon [label="Integration", group=g11] + divideDetMon [label="Divide\n(Detectors / Monitors)", group=g1] + cropWav [label="CropWorkspace", group=g1] +} + +subgraph processes { + $process_style +} + +subgraph values { + $value_style + valWav [label="I(λ)", group=g1] + valWavOut [label="I(λ)", group=g1] +} + +inputWS -> convertWav +convertWav -> valWav +valWav -> groupDet [label="Detectors"] +procCommands -> groupDet + +valWav -> cropMonWS [label="Monitors"] +monitorIndex -> cropMonWS +cropMonWS -> calcFlatBg +monBackWavMin -> calcFlatBg +monBackWavMax -> calcFlatBg +calcFlatBg -> intMon +monIntWavMin -> intMon +monIntWavMax -> intMon + +groupDet -> divideDetMon +intMon -> divideDetMon +wavMin -> cropWav +divideDetMon -> cropWav +wavMax -> cropWav +cropWav -> valWavOut + +groupDet -> cropMonWS [style=invis] +groupDet -> intMon [style=invis] +monBackWavMin -> monIntWavMin [style=invis] +monBackWavMax -> monIntWavMax [style=invis] + +{rank=same; monIntWavMin; monIntWavMax} +{rank=same; monBackWavMin; monBackWavMax} +{rank=same; groupDet; cropMonWS} +} diff --git a/docs/source/diagrams/CreateTransmissionWorkspace_HighLvl-v2_wkflw.dot b/docs/source/diagrams/CreateTransmissionWorkspace_HighLvl-v2_wkflw.dot new file mode 100644 index 0000000000000000000000000000000000000000..9470de66e4ce72d912d667407c0b2f29a2501319 --- /dev/null +++ b/docs/source/diagrams/CreateTransmissionWorkspace_HighLvl-v2_wkflw.dot @@ -0,0 +1,53 @@ +digraph CreateTransmissionWorkspace { +label = "" + $global_style + +subgraph params { + $param_style + firstRun [label="FirstTransmissionRun", group=g1] + secondRun [label="SecondTransmissionRun", group=g2] + outputWS [label="OutputWorkspace"] + params [label="Params"] + startOv [label="StartOverlap"] + endOv [label="EndOverlap"] +} + +subgraph decisions { + $decision_style + checkSecondRun [label="SecondTransmissionRun?", group=g1] +} + +subgraph algorithms { + $algorithm_style + stitch [label="Stitch1D"] +} + +subgraph processes { + $process_style + convertFirst [label="Convert to λ and\nnormalize", group=g1] + convertSecond [label="Convert to λ and\nnormalize", group=g2] +} + +subgraph values { + $value_style + valFirst [label="I(λ)", group=g1] + valSecond [label="I(λ)", group=g2] +} + + firstRun -> convertFirst + convertFirst -> valFirst + valFirst -> checkSecondRun + checkSecondRun -> outputWS [label="No"] + checkSecondRun -> stitch [label="Yes"] + secondRun -> convertSecond + convertSecond -> valSecond + valSecond -> stitch + convertSecond -> params [style=invis] + startOv -> stitch + endOv -> stitch + stitch -> outputWS + params -> stitch + +{rank = same; valFirst; valSecond} +{rank = same; params; startOv; endOv} +} diff --git a/docs/source/diagrams/ReflectometryReductionOneAuto-v2-Groups_PA_wkflw.dot b/docs/source/diagrams/ReflectometryReductionOneAuto-v2-Groups_PA_wkflw.dot new file mode 100644 index 0000000000000000000000000000000000000000..1e6624e48347f2cfa75aa666bbbaa44650daa283 --- /dev/null +++ b/docs/source/diagrams/ReflectometryReductionOneAuto-v2-Groups_PA_wkflw.dot @@ -0,0 +1,70 @@ +digraph ReflectometryReductionOne { + label = "\n" + $global_style + + subgraph params { + $param_style + inputWorkspace [label="InputWorkspace"] + trans [label="FirstTransmissionRun"] + IvsLam_0 [label="OutputWorkspaceWavelength"] + IvsLam_1 [label="OutputWorkspaceWavelength"] + IvsLam_temp [label="OutputWorkspaceWavelength"] + IvsQ_0 [label="OutputWorkspace"] + IvsQ_1 [label="OutputWorkspace"] + IvsQ_temp [label="OutputWorkspace"] + IvsLam_final [label="OutputWorkspaceWavelength"] + IvsQ_2 [label="OutputWorkspace"] + IvsQ_3 [label="OutputWorkspace"] + IvsQ_final [label="OutputWorkspace"] + } + + subgraph algorithms { + $algorithm_style + reflRedOne_0 [label="ReflectometryReductionOne", group=g1] + reflRedOne_1 [label="ReflectometryReductionOne", group=g2] + groupIvsQ [label="GroupWorkspaces", group=g1] + groupIvsLam [label="GroupWorkspaces", group=g2] + polCorr [label="PolarizationCorrection", group=g1] + reflRedOne_2 [label="ReflectometryReductionOne"] + reflRedOne_3 [label="ReflectometryReductionOne"] + groupFinal [label="GroupWorkspaces", group=g1] + plus [label="Plus"] + } + + subgraph decisions { + $decision_style + } + + trans -> plus [label="[0] "] + trans -> plus [label="[1]"] + plus -> reflRedOne_0 + plus -> reflRedOne_1 + + inputWorkspace -> reflRedOne_0 [label="[0]"] + inputWorkspace -> reflRedOne_1 [label="[1]"] + reflRedOne_0 -> IvsLam_0 + reflRedOne_0 -> IvsQ_0 + reflRedOne_1 -> IvsLam_1 + reflRedOne_1 -> IvsQ_1 + + IvsQ_0 -> groupIvsQ + IvsQ_1 -> groupIvsQ + groupIvsQ -> IvsQ_temp + + IvsLam_0 -> groupIvsLam + IvsLam_1 -> groupIvsLam + groupIvsLam -> IvsLam_temp + + IvsLam_temp -> polCorr + polCorr -> IvsLam_final + IvsLam_final -> reflRedOne_2 [label="[0]"] + IvsLam_final -> reflRedOne_3 [label="[1]"] + reflRedOne_2 -> IvsQ_2 + reflRedOne_3 -> IvsQ_3 + IvsQ_2 -> groupFinal + IvsQ_3 -> groupFinal + groupFinal -> IvsQ_final + + {rank=same; IvsLam_temp; IvsQ_temp} + {rank=same; inputWorkspace; trans} +} diff --git a/docs/source/diagrams/ReflectometryReductionOneAuto-v2-Groups_noPA_wkflw.dot b/docs/source/diagrams/ReflectometryReductionOneAuto-v2-Groups_noPA_wkflw.dot new file mode 100644 index 0000000000000000000000000000000000000000..dc8c4af8718d770250ffa8e2259fe856d4b75c91 --- /dev/null +++ b/docs/source/diagrams/ReflectometryReductionOneAuto-v2-Groups_noPA_wkflw.dot @@ -0,0 +1,46 @@ +digraph ReflectometryReductionOne { + label = "\n" + $global_style + + subgraph params { + $param_style + inputWorkspace [label="InputWorkspace"] + trans [label="FirstTransmissionRun"] + IvsLam_0 [label="OutputWorkspaceWavelength"] + IvsLam_1 [label="OutputWorkspaceWavelength"] + IvsLam_temp [label="OutputWorkspaceWavelength"] + IvsQ_0 [label="OutputWorkspace"] + IvsQ_1 [label="OutputWorkspace"] + IvsQ_temp [label="OutputWorkspace"] + } + + subgraph algorithms { + $algorithm_style + reflRedOne_0 [label="ReflectometryReductionOne", group=g1] + reflRedOne_1 [label="ReflectometryReductionOne", group=g2] + groupIvsQ [label="GroupWorkspaces", group=g1] + groupIvsLam [label="GroupWorkspaces", group=g2] + } + + subgraph decisions { + $decision_style + } + + inputWorkspace -> reflRedOne_0 [label="[0]"] + trans -> reflRedOne_0 [label="[0]"] + inputWorkspace -> reflRedOne_1 [label="[1]"] + trans -> reflRedOne_1 [label="[1]"] + reflRedOne_0 -> IvsLam_0 + reflRedOne_0 -> IvsQ_0 + reflRedOne_1 -> IvsLam_1 + reflRedOne_1 -> IvsQ_1 + + IvsQ_0 -> groupIvsQ + IvsQ_1 -> groupIvsQ + groupIvsQ -> IvsQ_temp + + IvsLam_0 -> groupIvsLam + IvsLam_1 -> groupIvsLam + groupIvsLam -> IvsLam_temp + +} diff --git a/docs/source/diagrams/ReflectometryReductionOne_ConvertToMomentum-v2_wkflw.dot b/docs/source/diagrams/ReflectometryReductionOne_ConvertToMomentum-v2_wkflw.dot new file mode 100644 index 0000000000000000000000000000000000000000..451901553112e1a015d0f972b9329ac2b576f29e --- /dev/null +++ b/docs/source/diagrams/ReflectometryReductionOne_ConvertToMomentum-v2_wkflw.dot @@ -0,0 +1,30 @@ +digraph ReflectometryReductionOne { +label = "\n" + $global_style + +subgraph params { + $param_style + inputWorkspace [label="OutputWorkspaceWavelength", group=g1] + outputWorkspace [label="OutputWorkspace"] +} + +subgraph decisions { + $decision_style +} + +subgraph algorithms { + $algorithm_style + convertUnits [label="ConvertUnits\n(AlignBins=False)", group=g1] +} + +subgraph processes { + $process_style +} + +subgraph values { + $value_style +} + +inputWorkspace -> convertUnits +convertUnits -> outputWorkspace +} diff --git a/docs/source/diagrams/ReflectometryReductionOne_ConvertToWavelength-v2_wkflw.dot b/docs/source/diagrams/ReflectometryReductionOne_ConvertToWavelength-v2_wkflw.dot new file mode 100644 index 0000000000000000000000000000000000000000..8e07e7c4f846a96e5452685e116849eed1154155 --- /dev/null +++ b/docs/source/diagrams/ReflectometryReductionOne_ConvertToWavelength-v2_wkflw.dot @@ -0,0 +1,76 @@ +digraph ReflectometryReductionOne { +label = "\n" +rankdir = TB; + $global_style + +subgraph params { + $param_style + inputWS [label="InputWorkspace"] + outputWS [label="OutputWorkspaceWavelength"] + procCommands [label="ProcessingCommands"] + wavMin [label="WavelengthMin", group=gwav] + wavMax [label="WavelengthMax", group=gwav] + monitorIndex [label="I0MonitorIndex"] + regionOfDirectBeam [label="RegionOf-\nDirectBeam"] + monIntWavMax [label="MonitorIntegration-\nWavelengthMax"] + monIntWavMin [label="MonitorIntegration-\nWavelengthMin"] + monBackWavMin [label="MonitorBackground-\nWavelengthMin"] + monBackWavMax [label="MonitorBackground-\nWavelengthMax"] +} + +subgraph decisions { + $decision_style +} + +subgraph algorithms { + $algorithm_style + convertWav [label="ConvertUnits\n(AlignBins = True)"] + groupDet [label="GroupDetectors"] + cropMonWS [label="CropWorkspace", group=g11] + calcFlatBg [label="CalculateFlatBackground", group=g11] + intMon [label="Integration", group=g11] + groupDetRDB [label="GroupDetectors"] + divideDetMon [label="Divide\n(Detectors / Monitors)", group=g1] + divideDetRDB [label="Divide\n(Detectors / DirectBeam)", group=g1] + cropWav [label="CropWorkspace", group=g1] +} + +subgraph processes { + $process_style +} + +subgraph values { + $value_style + valWav [label="I(λ)"] +} + +inputWS -> convertWav +convertWav -> valWav +valWav -> groupDet [label="Detectors"] +procCommands -> groupDet + +valWav -> groupDetRDB [label="Direct Beam"] +regionOfDirectBeam -> groupDetRDB +groupDetRDB -> divideDetRDB +groupDet -> divideDetRDB + +valWav -> cropMonWS [label="Monitors"] +monitorIndex -> cropMonWS +cropMonWS -> calcFlatBg +monBackWavMin -> calcFlatBg +monBackWavMax -> calcFlatBg +calcFlatBg -> intMon +monIntWavMin -> intMon +monIntWavMax -> intMon + +divideDetRDB -> divideDetMon +intMon -> divideDetMon +wavMin -> cropWav +divideDetMon -> cropWav +wavMax -> cropWav +cropWav -> outputWS + +{rank=same; monIntWavMin; monIntWavMax} +{rank=same; divideDetRDB; intMon} +{rank=same; monBackWavMin; monBackWavMax} +} diff --git a/docs/source/diagrams/ReflectometryReductionOne_HighLvl-v2_wkflw.dot b/docs/source/diagrams/ReflectometryReductionOne_HighLvl-v2_wkflw.dot new file mode 100644 index 0000000000000000000000000000000000000000..caf0a9cd3a1abc708fa9a6d6586c48b05c9ddf52 --- /dev/null +++ b/docs/source/diagrams/ReflectometryReductionOne_HighLvl-v2_wkflw.dot @@ -0,0 +1,40 @@ +digraph ReflectometryReductionOne { +label = "\n" + $global_style + +subgraph params { + $param_style + inputWS [label="InputWorkspace"] + outputWSWL [label="OutputWorkspaceWavelength"] + outputWSFinal [label="OutputWorkspace"] +} + +subgraph decisions { + $decision_style + checkXUnit [label="X axis in λ?"] +} + +subgraph algorithms { + $algorithm_style +} + +subgraph processes { + $process_style + convertUnits [label="Convert to λ and\nnormalize\nby monitors"] + applyCorrTrans [label="Apply transmission\n corrections"] + convertMom [label="Convert to momentum\ntransfer"] +} + +subgraph values { + $value_style +} + +inputWS -> checkXUnit +checkXUnit -> applyCorrTrans [label="Yes"] +checkXUnit -> convertUnits [label="No"] +convertUnits -> applyCorrTrans +applyCorrTrans -> outputWSWL + +outputWSWL -> convertMom +convertMom -> outputWSFinal +} diff --git a/docs/source/diagrams/ReflectometryReductionOne_TransmissionCorrection-v2_wkflw.dot b/docs/source/diagrams/ReflectometryReductionOne_TransmissionCorrection-v2_wkflw.dot new file mode 100644 index 0000000000000000000000000000000000000000..4080a5b43296621ad0af51bd0aa624edbfa7c98f --- /dev/null +++ b/docs/source/diagrams/ReflectometryReductionOne_TransmissionCorrection-v2_wkflw.dot @@ -0,0 +1,63 @@ +digraph ReflectometryReductionOne { +label = "\n" + $global_style + +subgraph params { + $param_style + inputWorkspace [label="OutputWorkspaceWavelength"] + outputWorkspace [label="OutputWorkspaceWavelength"] + corrAlg [label="CorrectionAlgorithm"] + firstTransRun [label="FirstTransmissionRun"] + secondTransRun [label="SecondTransmissionRun"] + polynomial [label="Polynomial"] + c0 [label="C0"] + c1 [label="C1"] +} + +subgraph decisions { + $decision_style + checkTransRun [label="FirstTransmissionRun\ngiven?"] + checkCorrAlg [label="CorrectionAlgorithm?"] + checkTransRun [label="FirstTransmissionRun\ngiven?"] +} + +subgraph algorithms { + $algorithm_style + rebinByTransWS [label="RebinToWorkspace"] + polyCorr [label="PolynomialCorrection"] + expCorr [label="ExponentialCorrection"] + createTransWS [label="CreateTransmissionWorkspace"] + rebinByTransWS [label="RebinToWorkspace"] + divideTrans [label="Divide by\ntransmission run"] +} + +subgraph processes { + $process_style +} + +subgraph values { + $value_style +} + +inputWorkspace -> checkTransRun +checkTransRun -> checkCorrAlg [label="No"] +checkTransRun -> divideTrans [label="Yes"] +corrAlg -> checkCorrAlg +polynomial -> polyCorr +checkCorrAlg -> polyCorr [label="Polynomial"] +checkCorrAlg -> outputWorkspace [label="None"] +c0 -> expCorr +c1 -> expCorr +checkCorrAlg -> expCorr [label="Exponential"] +polyCorr -> outputWorkspace +expCorr -> outputWorkspace +firstTransRun -> createTransWS +secondTransRun -> createTransWS +createTransWS -> rebinByTransWS +inputWorkspace -> rebinByTransWS +rebinByTransWS -> divideTrans +divideTrans -> outputWorkspace + +{rank=same; checkCorrAlg; divideTrans} +{rank=same; inputWorkspace; firstTransRun; secondTransRun} +} diff --git a/docs/source/images/ReflectometryReductionOneDetectorPositions.png b/docs/source/images/ReflectometryReductionOneDetectorPositions.png new file mode 100644 index 0000000000000000000000000000000000000000..e7f2d9f15030c67df8f58ce7ae93930d874dd7af Binary files /dev/null and b/docs/source/images/ReflectometryReductionOneDetectorPositions.png differ diff --git a/docs/source/release/v3.9.0/reflectometry.rst b/docs/source/release/v3.9.0/reflectometry.rst index 96fc7b5b1d782a853f86eb0b261d40b625903efc..eff0ba6f19660fe253f590b8727438ea42dc2385 100644 --- a/docs/source/release/v3.9.0/reflectometry.rst +++ b/docs/source/release/v3.9.0/reflectometry.rst @@ -8,9 +8,31 @@ Reflectometry Changes Algorithms ---------- -- :ref:`algm-Stitch1D` documentation has been improved, it now includes a workflow diagram illustrating the different steps in the calculation and a note about how errors are propagated. -- :ref:`Stitch1DMany <algm-Stitch1DMany>` has a new property 'ScaleFactorFromPeriod' which enables it to apply scale factors from a particular period when stitching group workspaces. -- :ref:`algm-Stitch1DMany` documentation has been updated accordingly and improved, it includes more detail on algorithm properties and adds a workflow description and diagram. +* New versions of algorithms :ref:`algm-ReflectometryReductionOne` and :ref:`algm-CreateTransmissionWorkspace` + have been added to remove duplicate steps in the reduction. An improvement in performance of factor x3 has + been observed when the reduction is performed with no monitor normalization. + +* New versions of :ref:`algm-ReflectometryReductionOneAuto`, :ref:`algm-CreateTransmissionWorkspaceAuto` and + :ref:`algm-SpecularReflectionPositionCorrect` have been added. The new versions fix the following known issues: + + * When :literal:`CorrectionAlgorithm` was set to :literal:`AutoDetect` the algorithm was not able to find polynomial + corrections, as it was searching for :literal:`polynomial` instead of :literal:`polystring`. + * When an correction algorithm was applied, monitors were integrated if :literal:`NormalizeByIntegratedMonitors` + was set to true, which is the default. In the new version of the algorithms, monitors will never be integrated if a correction algorithm + is specified, even if :literal:`NormalizeByIntegratedMonitors` is set to true. + * Fix some problems when moving the detector components in the instrument. The new version uses :literal:`ProcessingInstructions` + to determine which detector components need to be moved. + * Monitor integration range was not being applied properly to CRISP data. The problem was that in the parameter + file the wavelength range used to crop the workspace in wavelength is [0.6, 6.5] and the monitor integration range is outside of these limits ([4, 10]). This was causing the algorithm to integrate over [0.6, 4]. + * :ref:`algm-ReflectometryReductionOneAuto` rebins and scales the output workspace and outputs a third output workspace, :literal:`OutputWorkspaceBinned`. + +* :ref:`algm-Stitch1D` documentation has been improved, it now includes a workflow diagram illustrating the different steps in the calculation and a note about how errors are propagated. + +* :ref:`Stitch1DMany <algm-Stitch1DMany>` has a new property 'ScaleFactorFromPeriod' which enables it to apply scale factors from a particular period when stitching group workspaces. + +* :ref:`algm-Stitch1DMany` documentation has been updated accordingly and improved, it includes more detail on algorithm properties and adds a workflow description and diagram. + +* :ref:`algm-ConvertToReflectometryQ` corrects the detector position before performing any type of calculation. Detectors are corrected to an angle theta read from the log value *stheta*. Reflectometry Reduction Interface --------------------------------- diff --git a/scripts/Interface/ui/reflectometer/refl_gui.py b/scripts/Interface/ui/reflectometer/refl_gui.py index 49a3674fa5a124bff7803ec7f9780af6b8c15c19..af36e1cd7f8468341aa39727c8e10989cac67864 100644 --- a/scripts/Interface/ui/reflectometer/refl_gui.py +++ b/scripts/Interface/ui/reflectometer/refl_gui.py @@ -987,13 +987,13 @@ class ReflGui(QtGui.QMainWindow, ui_refl_window.Ui_windowRefl): trans1 = converter.get_workspace_from_list(0) transmission_ws = CreateTransmissionWorkspaceAuto(FirstTransmissionRun=trans1, OutputWorkspace=out_ws_name, - Params=0.02, StartOverlap=10.0, EndOverlap=12.0) + Params=0.02, StartOverlap=10.0, EndOverlap=12.0, Version=1) elif size == 2: trans1 = converter.get_workspace_from_list(0) trans2 = converter.get_workspace_from_list(1) transmission_ws = CreateTransmissionWorkspaceAuto(FirstTransmissionRun=trans1, OutputWorkspace=out_ws_name, SecondTransmissionRun=trans2, Params=0.02, - StartOverlap=10.0, EndOverlap=12.0) + StartOverlap=10.0, EndOverlap=12.0, Version=1) else: raise RuntimeError("Up to 2 transmission runs can be specified. No more than that.") @@ -1032,7 +1032,8 @@ class ReflGui(QtGui.QMainWindow, ui_refl_window.Ui_windowRefl): thetaIn=angle, OutputWorkspace=runno+'_IvsQ_'+str(i+1), OutputWorkspaceWavelength=runno+'_IvsLam_'+str(i+1), ScaleFactor=factor,MomentumTransferStep=Qstep, - MomentumTransferMinimum=Qmin, MomentumTransferMaximum=Qmax) + MomentumTransferMinimum=Qmin, MomentumTransferMaximum=Qmax, + Version=1) wqGroup.append(wq) wlamGroup.append(wlam) thetaGroup.append(th) @@ -1045,7 +1046,8 @@ class ReflGui(QtGui.QMainWindow, ui_refl_window.Ui_windowRefl): thetaIn=angle, OutputWorkspace=runno+'_IvsQ', OutputWorkspaceWavelength=runno+'_IvsLam', ScaleFactor=factor,MomentumTransferStep=Qstep, - MomentumTransferMinimum=Qmin, MomentumTransferMaximum=Qmax) + MomentumTransferMinimum=Qmin, MomentumTransferMaximum=Qmax, + Version=1) cleanup() else: