Mantid
Loading...
Searching...
No Matches
ConvertUnitsUsingDetectorTable.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
8
10#include "MantidAPI/ISpectrum.h"
18#include "MantidKernel/Unit.h"
20
21#include <boost/function.hpp>
22
23#include <algorithm>
24#include <cfloat>
25#include <numeric>
26
27namespace Mantid::Algorithms {
28
31using namespace Kernel;
32using namespace API;
33using namespace DataObjects;
34using namespace HistogramData;
35
36// Register the algorithm into the AlgorithmFactory
37DECLARE_ALGORITHM(ConvertUnitsUsingDetectorTable)
38
39
40const std::string ConvertUnitsUsingDetectorTable::name() const { return "ConvertUnitsUsingDetectorTable"; }
41
44
46const std::string ConvertUnitsUsingDetectorTable::category() const { return "Utility\\Development"; }
47
49const std::string ConvertUnitsUsingDetectorTable::summary() const {
50 return "Performs a unit change on the X values of a workspace";
51}
52
56 auto wsValidator = std::make_shared<CompositeValidator>();
57 wsValidator->add<API::WorkspaceUnitValidator>();
58 wsValidator->add<API::HistogramValidator>();
60 std::make_unique<WorkspaceProperty<API::MatrixWorkspace>>("InputWorkspace", "", Direction::Input, wsValidator),
61 "Name of the input workspace");
62 declareProperty(std::make_unique<WorkspaceProperty<API::MatrixWorkspace>>("OutputWorkspace", "", Direction::Output),
63 "Name of the output workspace, can be the same as the input");
64 declareProperty("Target", "", std::make_shared<StringListValidator>(UnitFactory::Instance().getConvertibleUnits()),
65 "The name of the units to convert to (must be one of those "
66 "registered in\n"
67 "the Unit Factory)");
68 declareProperty(std::make_unique<WorkspaceProperty<TableWorkspace>>("DetectorParameters", "", Direction::Input,
70 "Name of a TableWorkspace containing the detector parameters "
71 "to use instead of the IDF.");
72
73 declareProperty("AlignBins", false,
74 "If true (default is false), rebins after conversion to "
75 "ensure that all spectra in the output workspace\n"
76 "have identical bin boundaries. This option is not "
77 "recommended (see "
78 "http://www.mantidproject.org/ConvertUnits).");
79
80 declareProperty("ConvertFromPointData", true,
81 "When checked, if the Input Workspace contains Points\n"
82 "the algorithm ConvertToHistogram will be run to convert\n"
83 "the Points to Bins. The Output Workspace will contains Bins.");
84}
85
90 // do nothing here - don't store this value
91 UNUSED_ARG(outputWS);
92}
93
102 using namespace Geometry;
103
104 // Let's see if we are using a TableWorkspace to override parameters
105 TableWorkspace_sptr paramWS = getProperty("DetectorParameters");
106
107 // See if we have supplied a DetectorParameters Workspace
108 // TODO: Check if paramWS is NULL and if so throw an exception
109
110 // const std::string l1ColumnLabel("l1");
111
112 // Let's check all the columns exist and are readable
113 try {
114 auto spectraColumnTmp = paramWS->getColumn("spectra");
115 auto l1ColumnTmp = paramWS->getColumn("l1");
116 auto l2ColumnTmp = paramWS->getColumn("l2");
117 auto twoThetaColumnTmp = paramWS->getColumn("twotheta");
118 auto efixedColumnTmp = paramWS->getColumn("efixed");
119 auto emodeColumnTmp = paramWS->getColumn("emode");
120 } catch (...) {
121 throw Exception::InstrumentDefinitionError("DetectorParameter TableWorkspace is not defined correctly.");
122 }
123
124 // Now let's take a reference to the vectors.
125 const auto &l1Column = paramWS->getColVector<double>("l1");
126 const auto &l2Column = paramWS->getColVector<double>("l2");
127 const auto &twoThetaColumn = paramWS->getColVector<double>("twotheta");
128 const auto &efixedColumn = paramWS->getColVector<double>("efixed");
129 const auto &emodeColumn = paramWS->getColVector<int>("emode");
130 const auto &spectraColumn = paramWS->getColVector<int>("spectra");
131
132 Progress prog(this, 0.2, 1.0, m_numberOfSpectra);
133 auto numberOfSpectra_i = static_cast<int64_t>(m_numberOfSpectra); // cast to make openmp happy
134
135 // Get the unit object for each workspace
137 std::vector<double> emptyVec;
138 int failedDetectorCount = 0;
139
140 // Perform Sanity Validation before creating workspace
141 size_t checkIndex = 0;
142 int checkSpecNo = inputWS->getSpectrum(checkIndex).getSpectrumNo();
143 auto checkSpecIter = std::find(spectraColumn.begin(), spectraColumn.end(), checkSpecNo);
144 if (checkSpecIter != spectraColumn.end()) {
145 size_t detectorRow = std::distance(spectraColumn.begin(), checkSpecIter);
146 // copy the X values for the check
147 auto checkXValues = inputWS->readX(checkIndex);
148 // Convert the input unit to time-of-flight
149 auto checkFromUnit = std::unique_ptr<Unit>(fromUnit->clone());
150 auto checkOutputUnit = std::unique_ptr<Unit>(outputUnit->clone());
151 UnitParametersMap pmap{{UnitParams::l2, l2Column[detectorRow]},
152 {UnitParams::twoTheta, twoThetaColumn[detectorRow]},
153 {UnitParams::efixed, efixedColumn[detectorRow]}};
154 checkFromUnit->toTOF(checkXValues, emptyVec, l1Column[detectorRow], emodeColumn[detectorRow], pmap);
155 // Convert from time-of-flight to the desired unit
156 checkOutputUnit->fromTOF(checkXValues, emptyVec, l1Column[detectorRow], emodeColumn[detectorRow], pmap);
157 }
158
159 // create the output workspace
160 MatrixWorkspace_sptr outputWS = this->setupOutputWorkspace(inputWS);
161 EventWorkspace_sptr eventWS = std::dynamic_pointer_cast<EventWorkspace>(outputWS);
162 assert(static_cast<bool>(eventWS) == m_inputEvents); // Sanity check
163
164 auto &spectrumInfo = outputWS->mutableSpectrumInfo();
165
166 // Loop over the histograms (detector spectra)
167 for (int64_t i = 0; i < numberOfSpectra_i; ++i) {
168
169 // Lets find what row this spectrum Number appears in our detector table.
170
171 std::size_t wsid = i;
172
173 if (spectrumInfo.hasDetectors(i)) {
174 double deg2rad = M_PI / 180.;
175
176 auto &det = spectrumInfo.detector(i);
177 int specNo = det.getID();
178
179 // int spectraNumber = static_cast<int>(spectraColumn->toDouble(i));
180 // wsid = outputWS->getIndexFromSpectrumNumber(spectraNumber);
181 g_log.debug() << "###### Spectra #" << specNo << " ==> Workspace ID:" << wsid << '\n';
182
183 // Now we need to find the row that contains this spectrum
184 std::vector<int>::const_iterator specIter;
185
186 specIter = std::find(spectraColumn.begin(), spectraColumn.end(), specNo);
187 if (specIter != spectraColumn.end()) {
188 const size_t detectorRow = std::distance(spectraColumn.begin(), specIter);
189 const double l1 = l1Column[detectorRow];
190 const double l2 = l2Column[detectorRow];
191 const double twoTheta = twoThetaColumn[detectorRow] * deg2rad;
192 const double efixed = efixedColumn[detectorRow];
193 const int emode = emodeColumn[detectorRow];
194
195 if (g_log.is(Logger::Priority::PRIO_DEBUG)) {
196 g_log.debug() << "specNo from detector table = " << spectraColumn[detectorRow] << '\n';
197
198 g_log.debug() << "###### Spectra #" << specNo << " ==> Det Table Row:" << detectorRow << '\n';
199
200 g_log.debug() << "\tL1=" << l1 << ",L2=" << l2 << ",TT=" << twoTheta << ",EF=" << efixed << ",EM=" << emode
201 << '\n';
202 }
203
204 // Make local copies of the units. This allows running the loop in
205 // parallel
206 auto localFromUnit = std::unique_ptr<Unit>(fromUnit->clone());
207 auto localOutputUnit = std::unique_ptr<Unit>(outputUnit->clone());
209 std::vector<double> values(outputWS->x(wsid).begin(), outputWS->x(wsid).end());
210
211 UnitParametersMap pmap{{UnitParams::l2, l2}, {UnitParams::twoTheta, twoTheta}, {UnitParams::efixed, efixed}};
212 // Convert the input unit to time-of-flight
213 localFromUnit->toTOF(values, emptyVec, l1, emode, pmap);
214 // Convert from time-of-flight to the desired unit
215 localOutputUnit->fromTOF(values, emptyVec, l1, emode, pmap);
216
217 outputWS->mutableX(wsid) = values;
218
219 // EventWorkspace part, modifying the EventLists.
220 if (m_inputEvents) {
221 eventWS->getSpectrum(wsid).convertUnitsViaTof(localFromUnit.get(), localOutputUnit.get());
222 }
223
224 } else {
225 // Not found
226 failedDetectorCount++;
227 outputWS->getSpectrum(wsid).clearData();
228 if (spectrumInfo.hasDetectors(wsid))
229 spectrumInfo.setMasked(wsid, true);
230 }
231
232 } else {
233 // Get to here if exception thrown when calculating distance to detector
234 failedDetectorCount++;
235 // Since you usually (always?) get to here when there's no attached
236 // detectors, this call is
237 // the same as just zeroing out the data (calling clearData on the
238 // spectrum)
239 outputWS->getSpectrum(i).clearData();
240 }
241
242 prog.report("Convert to " + m_outputUnit->unitID());
243 } // loop over spectra
244
245 if (failedDetectorCount != 0) {
246 g_log.information() << "Something went wrong for " << failedDetectorCount << " spectra. Masking spectrum.\n";
247 }
248 if (m_inputEvents)
249 eventWS->clearMRU();
250
251 return outputWS;
252}
253
254} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
Definition: System.h:64
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
Definition: Algorithm.cpp:1913
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Definition: Algorithm.cpp:2076
A validator which checks that a workspace contains histogram data (the default) or point data as requ...
Helper class for reporting progress from algorithms.
Definition: Progress.h:25
A property class for workspaces.
A validator which checks that the unit of the workspace referred to by a WorkspaceProperty is the exp...
ConvertUnitsUsingDetectorTable : Converts the units in which a workspace is represented,...
const std::string summary() const override
Algorithm's summary for use in the GUI and help.
const std::string category() const override
Algorithm's category for identification.
void init() override
Initialize the algorithm's properties.
int version() const override
Algorithm's version for identification.
void storeEModeOnWorkspace(API::MatrixWorkspace_sptr outputWS) override
This implementation does NOT stores the emode in the provided workspace.
API::MatrixWorkspace_sptr convertViaTOF(Kernel::Unit_const_sptr fromUnit, API::MatrixWorkspace_const_sptr inputWS) override
Convert the workspace units using TOF as an intermediate step in the conversion.
bool m_inputEvents
to histogram workspaces.
Definition: ConvertUnits.h:109
Kernel::Unit_sptr m_outputUnit
The unit we're going to.
Definition: ConvertUnits.h:111
std::size_t m_numberOfSpectra
The number of spectra in the input workspace.
Definition: ConvertUnits.h:106
API::MatrixWorkspace_sptr setupOutputWorkspace(const API::MatrixWorkspace_const_sptr &inputWS)
Create an output workspace of the appropriate (histogram or event) type and copy over the data.
Exception for errors associated with the instrument definition.
Definition: Exception.h:220
void debug(const std::string &msg)
Logs at debug level.
Definition: Logger.cpp:114
bool is(int level) const
Returns true if at least the given log level is set.
Definition: Logger.cpp:146
void information(const std::string &msg)
Logs at information level.
Definition: Logger.cpp:105
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::shared_ptr< TableWorkspace > TableWorkspace_sptr
shared pointer to Mantid::DataObjects::TableWorkspace
std::shared_ptr< EventWorkspace > EventWorkspace_sptr
shared pointer to the EventWorkspace class
constexpr double deg2rad
Defines units/enum for Crystal work.
Definition: AngleUnits.h:20
std::unordered_map< UnitParams, double > UnitParametersMap
Definition: Unit.h:30
std::shared_ptr< const Unit > Unit_const_sptr
Shared pointer to the Unit base class (const version)
Definition: Unit.h:231
Generate a tableworkspace to store the calibration results.
STL namespace.
Describes the direction (within an algorithm) of a Property.
Definition: Property.h:50
@ Input
An input workspace.
Definition: Property.h:53
@ Output
An output workspace.
Definition: Property.h:54