diff --git a/Framework/Algorithms/CMakeLists.txt b/Framework/Algorithms/CMakeLists.txt index d513840a134f95c5ba095507bba5e1b684539c14..8bff60ceadf780e307ab42c681c8d8abd75b1439 100644 --- a/Framework/Algorithms/CMakeLists.txt +++ b/Framework/Algorithms/CMakeLists.txt @@ -288,6 +288,7 @@ set ( SRC_FILES src/SofQWCentre.cpp src/SofQWNormalisedPolygon.cpp src/SofQWPolygon.cpp + src/SofTwoThetaTOF.cpp src/SolidAngle.cpp src/SortEvents.cpp src/SortXAxis.cpp @@ -628,6 +629,7 @@ set ( INC_FILES inc/MantidAlgorithms/SofQWCentre.h inc/MantidAlgorithms/SofQWNormalisedPolygon.h inc/MantidAlgorithms/SofQWPolygon.h + inc/MantidAlgorithms/SofTwoThetaTOF.h inc/MantidAlgorithms/SolidAngle.h inc/MantidAlgorithms/SortEvents.h inc/MantidAlgorithms/SortXAxis.h @@ -957,6 +959,7 @@ set ( TEST_FILES SofQWNormalisedPolygonTest.h SofQWPolygonTest.h SofQWTest.h + SofTwoThetaTOFTest.h SolidAngleTest.h SortEventsTest.h SortXAxisTest.h diff --git a/Framework/Algorithms/inc/MantidAlgorithms/SofTwoThetaTOF.h b/Framework/Algorithms/inc/MantidAlgorithms/SofTwoThetaTOF.h new file mode 100644 index 0000000000000000000000000000000000000000..5fc799e910a5e1fac23a87dd514fe198f5a76b3b --- /dev/null +++ b/Framework/Algorithms/inc/MantidAlgorithms/SofTwoThetaTOF.h @@ -0,0 +1,43 @@ +// Mantid Repository : https://github.com/mantidproject/mantid +// +// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI, +// NScD Oak Ridge National Laboratory, European Spallation Source +// & Institut Laue - Langevin +// SPDX - License - Identifier: GPL - 3.0 + +#ifndef MANTID_ALGORITHMS_SOFTWOTHETATOF_H_ +#define MANTID_ALGORITHMS_SOFTWOTHETATOF_H_ + +#include "MantidAPI/Algorithm.h" +#include "MantidAlgorithms/DllConfig.h" + +namespace Mantid { +namespace Algorithms { + +/** SofTwoThetaTOF : Convert a S(spectrum number, TOF) workspace to + * S(twoTheta, TOF) workspace. + */ +class MANTID_ALGORITHMS_DLL SofTwoThetaTOF : public API::Algorithm { +public: + const std::string name() const override; + int version() const override; + const std::string category() const override; + const std::string summary() const override; + +private: + void init() override; + void exec() override; + double clarifyAngleStep(API::MatrixWorkspace const &ws); + API::MatrixWorkspace_sptr convertToConstantL2(API::MatrixWorkspace_sptr &ws); + API::MatrixWorkspace_sptr convertToTwoTheta(API::MatrixWorkspace_sptr &ws); + API::MatrixWorkspace_sptr groupByTwoTheta(API::MatrixWorkspace_sptr &ws, + double const twoThetaStep); + API::MatrixWorkspace_sptr + maskEmptyBins(API::MatrixWorkspace_sptr &maskable, + API::MatrixWorkspace_sptr &comparison); + API::MatrixWorkspace_sptr rebinToNonRagged(API::MatrixWorkspace_sptr &ws); +}; + +} // namespace Algorithms +} // namespace Mantid + +#endif /* MANTID_ALGORITHMS_SOFTWOTHETATOF_H_ */ diff --git a/Framework/Algorithms/src/ConvertToConstantL2.cpp b/Framework/Algorithms/src/ConvertToConstantL2.cpp index 47f37b4d0c749e6f327438e9e352a6b19a5ab138..6817490d4a212da87742a5d9491b928758aa1942 100644 --- a/Framework/Algorithms/src/ConvertToConstantL2.cpp +++ b/Framework/Algorithms/src/ConvertToConstantL2.cpp @@ -148,7 +148,8 @@ double ConvertToConstantL2::getRunProperty(std::string s) { Mantid::Kernel::Property *prop = run.getProperty(s); double val; if (!Strings::convert(prop->value(), val)) { - const std::string mesg = "Cannot convert sample log '" + s + "' to a number."; + const std::string mesg = + "Cannot convert sample log '" + s + "' to a number."; throw std::runtime_error(mesg); } return val; diff --git a/Framework/Algorithms/src/SofTwoThetaTOF.cpp b/Framework/Algorithms/src/SofTwoThetaTOF.cpp new file mode 100644 index 0000000000000000000000000000000000000000..70fd77250bb6ef3ae29fca57b144cb2937c57ee1 --- /dev/null +++ b/Framework/Algorithms/src/SofTwoThetaTOF.cpp @@ -0,0 +1,249 @@ +// Mantid Repository : https://github.com/mantidproject/mantid +// +// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI, +// NScD Oak Ridge National Laboratory, European Spallation Source +// & Institut Laue - Langevin +// SPDX - License - Identifier: GPL - 3.0 + +#include "MantidAlgorithms/SofTwoThetaTOF.h" + +#include "MantidAPI/FileProperty.h" +#include "MantidAPI/HistogramValidator.h" +#include "MantidAPI/InstrumentValidator.h" +#include "MantidAPI/WorkspaceUnitValidator.h" +#include "MantidGeometry/Instrument.h" +#include "MantidGeometry/Instrument/ParameterMap.h" +#include "MantidKernel/BoundedValidator.h" +#include "MantidKernel/CompositeValidator.h" + +#include "boost/filesystem.hpp" + +namespace { +/// Constants for the algorithm's property names. +namespace Prop { +std::string const ANGLE_STEP{"AngleStep"}; +std::string const FILENAME{"GroupingFilename"}; +std::string const INPUT_WS{"InputWorkspace"}; +std::string const OUTPUT_WS{"OutputWorkspace"}; +} // namespace Prop + +/// A temporary file resource lifetime manager +struct RemoveFileAtScopeExit { + std::string name; + ~RemoveFileAtScopeExit() { + if (!name.empty()) { + auto const path = boost::filesystem::path(name); + if (boost::filesystem::exists(path)) { + boost::filesystem::remove(path); + } + } + } +}; + +/// A holder of minimum and maximum values. +struct MinMax { + double min{std::numeric_limits<double>::max()}; + double max{std::numeric_limits<double>::lowest()}; +}; + +/** + * Return the minimum and maximum X over all histograms + * @param ws a workspace + * @return the minimum and maximum X + */ +MinMax minMaxX(Mantid::API::MatrixWorkspace const &ws) { + auto const nHisto = ws.getNumberHistograms(); + MinMax mm; + for (size_t i = 0; i < nHisto; ++i) { + auto const &x = ws.x(i); + mm.min = std::min(mm.min, x.front()); + mm.max = std::max(mm.max, x.back()); + } + return mm; +} + +/** + * Return the width of the first bin in the first histogram. + * @param ws a workspace + * @return the bin width + */ +double binWidth(Mantid::API::MatrixWorkspace const &ws) { + auto const &x = ws.x(0); + return x[1] - x[0]; +} + +/** + * Append .xml to filename if needed. + * @param filename a filename + * @return a suitable name for an XML file + */ +std::string ensureXMLExtension(std::string const &filename) { + std::string name = filename; + auto const path = boost::filesystem::path(filename); + if (path.extension() != ".xml") { + name += ".xml"; + } + return name; +} +} // namespace + +namespace Mantid { +namespace Algorithms { + +// Register the algorithm into the AlgorithmFactory +DECLARE_ALGORITHM(SofTwoThetaTOF) + +/// Algorithms name for identification. @see Algorithm::name +const std::string SofTwoThetaTOF::name() const { return "SofTwoThetaTOF"; } + +/// Algorithm's version for identification. @see Algorithm::version +int SofTwoThetaTOF::version() const { return 1; } + +/// Algorithm's category for identification. @see Algorithm::category +const std::string SofTwoThetaTOF::category() const { + return "Inelastic;ILL\\Direct"; +} + +/// Algorithm's summary for use in the GUI and help. @see Algorithm::summary +const std::string SofTwoThetaTOF::summary() const { + return "Calculates the intensity as a function of scattering angle and time " + "of flight."; +} + +/** Initialize the algorithm's properties. + */ +void SofTwoThetaTOF::init() { + auto histogrammedTOF = boost::make_shared<Kernel::CompositeValidator>(); + histogrammedTOF->add(boost::make_shared<API::WorkspaceUnitValidator>("TOF")); + histogrammedTOF->add(boost::make_shared<API::HistogramValidator>()); + histogrammedTOF->add(boost::make_shared<API::InstrumentValidator>()); + declareProperty( + Kernel::make_unique<API::WorkspaceProperty<>>( + Prop::INPUT_WS, "", Kernel::Direction::Input, histogrammedTOF), + "A workspace to be converted."); + declareProperty(Kernel::make_unique<API::WorkspaceProperty<>>( + Prop::OUTPUT_WS, "", Kernel::Direction::Output), + "A workspace with (2theta, TOF) units."); + auto positiveDouble = boost::make_shared<Kernel::BoundedValidator<double>>(); + positiveDouble->setLowerExclusive(0.); + declareProperty(Prop::ANGLE_STEP, EMPTY_DBL(), positiveDouble, + "The angle step for detector grouping, in degrees."); + declareProperty(Kernel::make_unique<API::FileProperty>( + Prop::FILENAME, "", API::FileProperty::OptionalSave, + std::vector<std::string>{".xml"}), + "A grouping file that will be created; a corresponding .par " + "file wille be created as well."); +} + +/** Execute the algorithm. + */ +void SofTwoThetaTOF::exec() { + API::MatrixWorkspace_sptr in = getProperty(Prop::INPUT_WS); + auto ragged = convertToConstantL2(in); + auto equalBinning = rebinToNonRagged(ragged); + auto ws = maskEmptyBins(equalBinning, ragged); + ws = groupByTwoTheta(ws, clarifyAngleStep(*in)); + ws = convertToTwoTheta(ws); + setProperty(Prop::OUTPUT_WS, ws); +} + +double SofTwoThetaTOF::clarifyAngleStep(API::MatrixWorkspace const &ws) { + if (!isDefault(Prop::ANGLE_STEP)) { + return getProperty(Prop::ANGLE_STEP); + } else { + auto instrument = ws.getInstrument(); + if (!instrument) { + throw std::invalid_argument("Missing " + Prop::ANGLE_STEP); + } + auto const ¶mMap = ws.constInstrumentParameters(); + auto const paramValues = + paramMap.getDouble(instrument->getName(), "natural-angle-step"); + if (paramValues.empty()) { + throw std::invalid_argument("Missing " + Prop::ANGLE_STEP + + " or 'natural-angle-step' not defined in " + "instrument parameters file."); + } + return paramValues.front(); + } +} + +API::MatrixWorkspace_sptr +SofTwoThetaTOF::convertToConstantL2(API::MatrixWorkspace_sptr &ws) { + auto toConstantL2 = createChildAlgorithm("ConvertToConstantL2", 0., 0.2); + toConstantL2->setProperty("InputWorkspace", ws); + toConstantL2->setPropertyValue("OutputWorkspace", "out"); + toConstantL2->execute(); + return toConstantL2->getProperty("OutputWorkspace"); +} + +API::MatrixWorkspace_sptr +SofTwoThetaTOF::convertToTwoTheta(API::MatrixWorkspace_sptr &ws) { + auto convertAxis = createChildAlgorithm("ConvertSpectrumAxis", 0.9, 1.0); + convertAxis->setProperty("InputWorkspace", ws); + convertAxis->setProperty("OutputWorkspace", "out"); + convertAxis->setProperty("Target", "Theta"); + convertAxis->execute(); + return convertAxis->getProperty("OutputWorkspace"); +} + +API::MatrixWorkspace_sptr +SofTwoThetaTOF::groupByTwoTheta(API::MatrixWorkspace_sptr &ws, + double const twoThetaStep) { + auto generateGrouping = + createChildAlgorithm("GenerateGroupingPowder", 0.2, 0.5); + generateGrouping->setProperty("InputWorkspace", ws); + generateGrouping->setProperty("AngleStep", twoThetaStep); + std::string filename; + RemoveFileAtScopeExit deleteThisLater; + if (isDefault(Prop::FILENAME)) { + auto tempPath = boost::filesystem::temp_directory_path(); + tempPath /= boost::filesystem::unique_path( + "detector-grouping-%%%%-%%%%-%%%%-%%%%.xml"); + filename = tempPath.c_str(); + generateGrouping->setProperty("GenerateParFile", false); + // Make sure the file gets deleted at scope exit. + deleteThisLater.name = filename; + } else { + filename = static_cast<std::string>(getProperty(Prop::FILENAME)); + filename = ensureXMLExtension(filename); + } + generateGrouping->setProperty("GroupingFilename", filename); + generateGrouping->execute(); + auto groupDetectors = createChildAlgorithm("GroupDetectors", 0.7, 0.9); + groupDetectors->setProperty("InputWorkspace", ws); + groupDetectors->setProperty("OutputWorkspace", "out"); + groupDetectors->setProperty("MapFile", filename); + groupDetectors->setProperty("Behaviour", "Average"); + groupDetectors->execute(); + return groupDetectors->getProperty("OutputWorkspace"); +} + +API::MatrixWorkspace_sptr +SofTwoThetaTOF::maskEmptyBins(API::MatrixWorkspace_sptr &maskable, + API::MatrixWorkspace_sptr &comparison) { + auto maskNonOverlapping = + createChildAlgorithm("MaskNonOverlappingBins", 0.6, 0.7); + maskNonOverlapping->setProperty("InputWorkspace", maskable); + maskNonOverlapping->setProperty("OutputWorkspace", "out"); + maskNonOverlapping->setProperty("ComparisonWorkspace", comparison); + maskNonOverlapping->setProperty("MaskPartiallyOverlapping", true); + maskNonOverlapping->setProperty("RaggedInputs", "Ragged"); + maskNonOverlapping->setProperty("CheckSortedX", false); + maskNonOverlapping->execute(); + return maskNonOverlapping->getProperty("OutputWorkspace"); +} + +API::MatrixWorkspace_sptr +SofTwoThetaTOF::rebinToNonRagged(API::MatrixWorkspace_sptr &ws) { + auto const xRange = minMaxX(*ws); + std::vector<double> const rebinParams{xRange.min, binWidth(*ws), xRange.max}; + auto rebin = createChildAlgorithm("Rebin", 0.5, 0.6); + rebin->setProperty("InputWorkspace", ws); + rebin->setProperty("OutputWorkspace", "out"); + rebin->setProperty("Params", rebinParams); + rebin->setProperty("FullBinsOnly", true); + rebin->execute(); + return rebin->getProperty("OutputWorkspace"); +} + +} // namespace Algorithms +} // namespace Mantid diff --git a/Framework/Algorithms/test/SofTwoThetaTOFTest.h b/Framework/Algorithms/test/SofTwoThetaTOFTest.h new file mode 100644 index 0000000000000000000000000000000000000000..8ae43575d0e1561493e7b148acadfabad5071869 --- /dev/null +++ b/Framework/Algorithms/test/SofTwoThetaTOFTest.h @@ -0,0 +1,164 @@ +// Mantid Repository : https://github.com/mantidproject/mantid +// +// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI, +// NScD Oak Ridge National Laboratory, European Spallation Source +// & Institut Laue - Langevin +// SPDX - License - Identifier: GPL - 3.0 + +#ifndef MANTID_ALGORITHMS_SOFTWOTHETATOFTEST_H_ +#define MANTID_ALGORITHMS_SOFTWOTHETATOFTEST_H_ + +#include <cxxtest/TestSuite.h> + +#include "MantidAPI/Axis.h" +#include "MantidAPI/SpectrumInfo.h" +#include "MantidAlgorithms/SofTwoThetaTOF.h" +#include "MantidGeometry/Crystal/AngleUnits.h" +#include "MantidGeometry/Instrument.h" +#include "MantidTestHelpers/WorkspaceCreationHelper.h" + +#include <boost/filesystem.hpp> + +using namespace Mantid; +using Mantid::Geometry::deg2rad; +using Mantid::Geometry::rad2deg; + +class SofTwoThetaTOFTest : public CxxTest::TestSuite { +public: + // This pair of boilerplate methods prevent the suite being created statically + // This means the constructor isn't called when running other tests + static SofTwoThetaTOFTest *createSuite() { return new SofTwoThetaTOFTest(); } + static void destroySuite(SofTwoThetaTOFTest *suite) { delete suite; } + + void test_init() { + Algorithms::SofTwoThetaTOF alg; + TS_ASSERT_THROWS_NOTHING(alg.initialize()) + TS_ASSERT(alg.isInitialized()) + } + + void test_twoThetaGrouping() { + constexpr int numBanks{1}; + constexpr int bankSize{6}; + constexpr int numBins{13}; + constexpr double angleStep{0.1}; + API::MatrixWorkspace_sptr inputWS = + WorkspaceCreationHelper::create2DWorkspaceWithRectangularInstrument( + numBanks, bankSize, numBins); + inputWS->getAxis(0)->setUnit("TOF"); + inputWS->mutableRun().addProperty("wavelength", 1.0); + auto ¶mMap = inputWS->instrumentParameters(); + paramMap.addString(inputWS->getInstrument().get(), "l2", + std::to_string(5.)); + Algorithms::SofTwoThetaTOF alg; + alg.setChild(true); + alg.setRethrows(true); + TS_ASSERT_THROWS_NOTHING(alg.initialize()) + TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspace", inputWS)); + TS_ASSERT_THROWS_NOTHING( + alg.setProperty("OutputWorkspace", "_unused_for_child")); + TS_ASSERT_THROWS_NOTHING(alg.setProperty("AngleStep", angleStep)) + TS_ASSERT_THROWS_NOTHING(alg.execute()) + TS_ASSERT(alg.isExecuted()) + API::MatrixWorkspace_const_sptr outputWS = + alg.getProperty("OutputWorkspace"); + TS_ASSERT(outputWS) + auto const &spectrumInfo = outputWS->spectrumInfo(); + auto const nHist = spectrumInfo.size(); + TS_ASSERT_LESS_THAN(1, nHist) + auto angleBinEdge = + std::floor(spectrumInfo.twoTheta(0) / (angleStep * deg2rad)); + for (size_t i = 0; i < nHist; ++i) { + auto const twoTheta = spectrumInfo.twoTheta(i); + TS_ASSERT_LESS_THAN(angleBinEdge, twoTheta) + angleBinEdge += angleStep * deg2rad; + TS_ASSERT_LESS_THAN(twoTheta, angleBinEdge) + } + } + + void test_grouping_file_and_par_file_creation() { + constexpr int numBanks{1}; + constexpr int bankSize{6}; + constexpr int numBins{13}; + constexpr double angleStep{0.1}; + API::MatrixWorkspace_sptr inputWS = + WorkspaceCreationHelper::create2DWorkspaceWithRectangularInstrument( + numBanks, bankSize, numBins); + inputWS->getAxis(0)->setUnit("TOF"); + inputWS->mutableRun().addProperty("wavelength", 1.0); + auto ¶mMap = inputWS->instrumentParameters(); + paramMap.addString(inputWS->getInstrument().get(), "l2", + std::to_string(5.)); + Algorithms::SofTwoThetaTOF alg; + alg.setChild(true); + alg.setRethrows(true); + TS_ASSERT_THROWS_NOTHING(alg.initialize()) + TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspace", inputWS)); + TS_ASSERT_THROWS_NOTHING( + alg.setProperty("OutputWorkspace", "_unused_for_child")); + TS_ASSERT_THROWS_NOTHING(alg.setProperty("AngleStep", angleStep)) + auto tempXml = boost::filesystem::temp_directory_path(); + tempXml /= boost::filesystem::unique_path("SofTwoThetaTest-%%%%%%%%.xml"); + TS_ASSERT_THROWS_NOTHING( + alg.setProperty("GroupingFilename", tempXml.c_str())) + TS_ASSERT_THROWS_NOTHING(alg.execute()) + TS_ASSERT(alg.isExecuted()) + auto const xmlExists = boost::filesystem::exists(tempXml); + TS_ASSERT(xmlExists) + if (xmlExists) { + boost::filesystem::remove(tempXml); + } + auto tempPar = tempXml; + tempPar.replace_extension(".par"); + auto const parExists = boost::filesystem::exists(tempPar); + TS_ASSERT(parExists) + if (parExists) { + boost::filesystem::remove(tempPar); + } + } + + void test_averaging() { + constexpr int numBanks{1}; + constexpr int bankSize{6}; + constexpr int numBins{13}; + constexpr double angleStep{0.1}; + API::MatrixWorkspace_sptr inputWS = + WorkspaceCreationHelper::create2DWorkspaceWithRectangularInstrument( + numBanks, bankSize, numBins); + inputWS->getAxis(0)->setUnit("TOF"); + inputWS->mutableRun().addProperty("wavelength", 1.0); + auto ¶mMap = inputWS->instrumentParameters(); + paramMap.addString(inputWS->getInstrument().get(), "l2", + std::to_string(5.)); + Algorithms::SofTwoThetaTOF alg; + alg.setChild(true); + alg.setRethrows(true); + TS_ASSERT_THROWS_NOTHING(alg.initialize()) + TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspace", inputWS)); + TS_ASSERT_THROWS_NOTHING( + alg.setProperty("OutputWorkspace", "_unused_for_child")); + TS_ASSERT_THROWS_NOTHING(alg.setProperty("AngleStep", angleStep)) + TS_ASSERT_THROWS_NOTHING(alg.execute()) + TS_ASSERT(alg.isExecuted()) + API::MatrixWorkspace_const_sptr outputWS = + alg.getProperty("OutputWorkspace"); + TS_ASSERT(outputWS) + for (size_t i = 0; i < outputWS->getNumberHistograms(); ++i) { + auto const &Ys = outputWS->y(i); + auto const &Es = outputWS->e(i); + for (size_t j = 0; j < Ys.size(); ++j) { + if (Ys[j] == 0.) + std::cout << "i: " << i << " j: " << j << '\n'; + if (j == 0 && i != 6) { + // These bins are known to be zero. + TS_ASSERT_EQUALS(Ys[j], 0.) + TS_ASSERT_EQUALS(Es[j], 0.) + } else { + TS_ASSERT_DELTA(Ys[j], 2., 1e-12) + TS_ASSERT_LESS_THAN(0., Es[j]) + TS_ASSERT_LESS_THAN_EQUALS(Es[j], std::sqrt(2)) + } + } + } + } +}; + +#endif /* MANTID_ALGORITHMS_SOFTWOTHETATOFTEST_H_ */ diff --git a/Framework/DataHandling/test/GenerateGroupingPowderTest.h b/Framework/DataHandling/test/GenerateGroupingPowderTest.h index 343cc491cceb69fe68e61c78cbf78a00388eb0f2..7521e0a1c4c0266fe40444f42eb49e505d7037bf 100644 --- a/Framework/DataHandling/test/GenerateGroupingPowderTest.h +++ b/Framework/DataHandling/test/GenerateGroupingPowderTest.h @@ -154,6 +154,7 @@ public: boost::filesystem::remove(parFile); } } + private: std::string parFilename(const std::string &xmlFilename) { std::string parFile = xmlFilename; diff --git a/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp b/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp index b0e962e69aed9ed295f4cd10c4a0049e13d8bb4d..7e297083364ed7cc5fad74643efd540073053fab 100644 --- a/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp +++ b/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp @@ -443,7 +443,7 @@ MatrixWorkspace_sptr create2DDetectorScanWorkspaceWithFullInstrument( * @param numBanks :: number of rectangular banks * @param numPixels :: each bank will be numPixels*numPixels * @param numBins :: each spectrum will have this # of bins - * @return The EventWorkspace + * @return The Workspace2D */ Mantid::DataObjects::Workspace2D_sptr create2DWorkspaceWithRectangularInstrument(int numBanks, int numPixels, diff --git a/docs/source/algorithms/SofTwoThetaTOF-v1.rst b/docs/source/algorithms/SofTwoThetaTOF-v1.rst new file mode 100644 index 0000000000000000000000000000000000000000..1736d0940b66ce7200c934eaa96d399cdbf1952c --- /dev/null +++ b/docs/source/algorithms/SofTwoThetaTOF-v1.rst @@ -0,0 +1,53 @@ + +.. algorithm:: + +.. summary:: + +.. relatedalgorithms:: + +.. properties:: + +Description +----------- + +This algorithm converts a workspace from (spectrum number, TOF) coordinates to (:math:`2\theta`, TOF). The latter view is useful for visualization and diagnostics purposes of direct geometry spectrometers with large PSD arrays. The algorithm performs the following steps: + +#. Equalize the sample-to-detector distances using :ref:`ConvertToConstantL2 <algm-ConvertToConstantL2>` +#. :ref:`Rebin <algm-Rebin>` the ragged workspace to same binning over all histograms. The bin width is taken from the first bin of the first histogram. This will introduce zero padding to the histograms. +#. Mask the zero padding using :ref:`MaskNonOverlappingBins <algm-MaskNonOverlappingBins>`. +#. Group the detectors to given :math:`2\theta` bins using :ref:`GenerateGroupingPowder <algm-GenerateGroupingPowder>` and :ref:`GroupDetectors <algm-GroupDetectors>`. +#. Convert the spectrum axis from spectrum numbers to :math:`2\theta` using :ref:`ConvertSpectrumAxis <algm-ConvertSpectrumAxis>` + +A default ``AngleStep`` can be defined in the :ref:`instrument parameters <InstrumentParameterFile>`. The parameter is called ``natural-angle-step``; its type should be ``float`` and value the desired ``AngleStep`` in degrees. + +The instrument should have an ``l2`` parameter defined which is the nominal sample to detector distance. Also, sample logs should include a ``wavelength`` entry (in Angstroms). See :ref:`ConvertToConstantL2 <algm-ConvertToConstantL2>` for more details. + +By default, the ``.xml`` and ``.par`` files generated by :ref:`GenerateGroupingPowder <algm-GenerateGroupingPowder>` are stored in a temporary location and deleted when the algorithm finishes. If these files are needed afterwards, a name for the ``.xml`` file can be given by ``GroupingFilename``. The ``.par`` file will have the same name except for the file extension which is changed from ``.xml`` to ``.par``. Note that this algorithm forces the ``.xml`` extension to ``GroupingFilename``. + + +Usage +----- + +**Example - Applying SofTwoThetaTOF and plotting the result** + +.. plot:: + :include-source: + + from mantid.simpleapi import * + import directtools as dt + ws = CreateSampleWorkspace(Function='Quasielastic Tunnelling', NumBanks=1, BankPixelWidth=20) + AddSampleLog(ws, 'wavelength', '6.26', 'Number', 'Angstrom') + SetInstrumentParameter(ws, ParameterName='l2', ParameterType='String', Value='5') + SofTT = SofTwoThetaTOF(ws, AngleStep=1) + fig, axes = dt.subplots() + axes.pcolor(SofTT) + axes.set_xlim(0.) + # Uncomment the line below to show the plot. + #fig.show() + mtd.clear() + + +.. categories:: + +.. sourcelink:: + diff --git a/docs/source/release/v3.14.0/direct_inelastic.rst b/docs/source/release/v3.14.0/direct_inelastic.rst index fb474c020a68c13f6f8f06f1d23de59d7b9d0363..4203e18ee381db05201d1b69f96111f839bd6e90 100644 --- a/docs/source/release/v3.14.0/direct_inelastic.rst +++ b/docs/source/release/v3.14.0/direct_inelastic.rst @@ -17,6 +17,7 @@ New Algorithms ############## - Added a new algorithm to ILL's reduction workflow: :ref:`DirectILLTubeBackground <algm-DirectILLTubeBackground>` which can be used to calculate the time-independent backgrounds for instruments with PSD detectors such as IN5. +- The new algorithm :ref:`SofTwoThetaTOF <algm-SofTwoThetaTOF>` can be used to convert a workspace from (spectrum number, TOF) units to (:math:`2\theta`, TOF) averaging the intensities over constant scattering angles. Improvements ############ diff --git a/instrument/IN5_Parameters.xml b/instrument/IN5_Parameters.xml index eb1d90293afe47ba3adf4933a011f6e8d8a20252..4eb0ad4c8519fe3b9920d54de22e0289ed4f1ce0 100644 --- a/instrument/IN5_Parameters.xml +++ b/instrument/IN5_Parameters.xml @@ -12,7 +12,9 @@ <parameter name="l2" type="string"> <value val="4.0" /> </parameter> - + <parameter name="natural-angle-step" type="float"> + <value val="0.3724" /> + </parameter> <!-- formula for Detector efficiency calculation. Algorithm: DetectorEfficiencyCorUser See http://muparser.sourceforge.net/mup_features.html#idDef2 for available operators -->