Mantid
Loading...
Searching...
No Matches
CreateDetectorTable.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2019 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
9using namespace Mantid::API;
10using namespace Mantid::Kernel;
11using namespace Mantid::DataObjects;
12using namespace Mantid::Geometry;
13
14namespace Mantid::Algorithms {
15// Register the algorithm into the AlgorithmFactory
16DECLARE_ALGORITHM(CreateDetectorTable)
17
18void CreateDetectorTable::init() {
19 declareProperty(std::make_unique<WorkspaceProperty<Workspace>>("InputWorkspace", "", Direction::Input),
20 "The name of the workspace to take as input.");
21
22 declareProperty(std::make_unique<ArrayProperty<int>>("WorkspaceIndices", Direction::Input),
23 "If left empty then all workspace indices are used.");
24 setPropertySettings("WorkspaceIndices",
25 std::make_unique<EnabledWhenWorkspaceIsType<MatrixWorkspace>>("InputWorkspace", true));
26
27 declareProperty("IncludeData", false, "Include the first value from each spectrum.");
28 setPropertySettings("IncludeData",
29 std::make_unique<EnabledWhenWorkspaceIsType<MatrixWorkspace>>("InputWorkspace", true));
30
31 declareProperty(std::make_unique<WorkspaceProperty<TableWorkspace>>("DetectorTableWorkspace", "", Direction::Output,
33 "The name of the outputted detector table workspace, if left empty then "
34 "the input workspace name + \"-Detectors\" is used.");
35}
36
38 Workspace_sptr inputWS = getProperty("InputWorkspace");
39 bool includeData = getProperty("IncludeData");
40 std::vector<int> indices = getProperty("WorkspaceIndices");
41
42 ITableWorkspace_sptr detectorTable;
43 // Standard MatrixWorkspace
44 auto matrix = std::dynamic_pointer_cast<MatrixWorkspace>(inputWS);
45 if (matrix) {
46 detectorTable = createDetectorTableWorkspace(matrix, indices, includeData, g_log);
47
48 if (detectorTable == nullptr) {
49 throw std::runtime_error("The instrument has no sample.");
50 }
51 } else {
52 auto peaks = std::dynamic_pointer_cast<IPeaksWorkspace>(inputWS);
53 if (peaks) {
54 detectorTable = peaks->createDetectorTable();
55 }
56 }
57
58 if (detectorTable == nullptr) {
59 throw std::runtime_error("Detector table can only be created for matrix and peaks workspaces.");
60 }
61
62 if (getPropertyValue("DetectorTableWorkspace") == "") {
63 setPropertyValue("DetectorTableWorkspace", inputWS->getName() + "-Detectors");
64 }
65
66 setProperty("DetectorTableWorkspace", detectorTable);
67}
68
69/*
70 * Validate the input parameters
71 * @returns map with keys corresponding to properties with errors and values
72 * containing the error messages.
73 */
74std::map<std::string, std::string> CreateDetectorTable::validateInputs() {
75 // create the map
76 std::map<std::string, std::string> validationOutput;
77
78 Workspace_sptr inputWS = getProperty("InputWorkspace");
79 const auto matrix = std::dynamic_pointer_cast<MatrixWorkspace>(inputWS);
80
81 if (matrix) {
82 const int numSpectra = static_cast<int>(matrix->getNumberHistograms());
83 const std::vector<int> indices = getProperty("WorkspaceIndices");
84
85 if (std::any_of(indices.cbegin(), indices.cend(),
86 [numSpectra](const auto index) { return (index >= numSpectra) || (index < 0); })) {
87 validationOutput["WorkspaceIndices"] = "One or more indices out of range of available spectra.";
88 }
89 }
90
91 return validationOutput;
92}
93
105 const bool includeData, Logger &logger) {
106
107 IComponent_const_sptr sample = ws->getInstrument()->getSample();
108 if (!sample) {
109 return nullptr;
110 }
111
112 // check if efixed value is available
113 bool calcQ{true};
114
115 // check if we have a scanning workspace
116 const bool isScanning = ws->detectorInfo().isScanning();
117
118 const auto &spectrumInfo = ws->spectrumInfo();
119 if (spectrumInfo.hasDetectors(0)) {
120 try {
121 std::shared_ptr<const IDetector> detector(&spectrumInfo.detector(0), Mantid::NoDeleting());
122 ws->getEFixed(detector);
123 } catch (std::runtime_error &) {
124 calcQ = false;
125 }
126 } else {
127 // No detectors available
128 calcQ = false;
129 }
130
131 bool hasDiffConstants{false};
132 auto emode = ws->getEMode();
133 if (emode == DeltaEMode::Elastic) {
134 hasDiffConstants = true;
135 }
136
137 // Prepare column names
138 auto colNames = createColumns(isScanning, includeData, calcQ, hasDiffConstants);
139
140 const int ncols = static_cast<int>(colNames.size());
141 const int nrows = indices.empty() ? static_cast<int>(ws->getNumberHistograms()) : static_cast<int>(indices.size());
142
143 auto t = WorkspaceFactory::Instance().createTable("TableWorkspace");
144
145 // Set the column names
146 for (int col = 0; col < ncols; ++col) {
147 auto column = t->addColumn(colNames.at(col).first, colNames.at(col).second);
148 column->setPlotType(0);
149 }
150
151 t->setRowCount(nrows);
152
153 // Cache some frequently used values
154 const auto beamAxisIndex = ws->getInstrument()->getReferenceFrame()->pointingAlongBeam();
155 const auto sampleDist = sample->getPos()[beamAxisIndex];
156 bool signedThetaParamRetrieved{false}, showSignedTwoTheta{false}; // If true, signedVersion of the two theta
157 // value should be displayed
158
159 populateTable(t, ws, nrows, indices, spectrumInfo, signedThetaParamRetrieved, showSignedTwoTheta, beamAxisIndex,
160 sampleDist, isScanning, includeData, calcQ, hasDiffConstants, logger);
161
162 return t;
163}
164
165std::vector<std::pair<std::string, std::string>> createColumns(const bool isScanning, const bool includeData,
166 const bool calcQ, const bool hasDiffConstants) {
167 std::vector<std::pair<std::string, std::string>> colNames;
168 colNames.emplace_back("double", "Index");
169 colNames.emplace_back("int", "Spectrum No");
170 colNames.emplace_back("str", "Detector ID(s)");
171 if (isScanning)
172 colNames.emplace_back("str", "Time Indexes");
173 if (includeData) {
174 colNames.emplace_back("double", "Data Value");
175 colNames.emplace_back("double", "Data Error");
176 }
177
178 colNames.emplace_back("double", "R");
179 colNames.emplace_back("double", "Theta");
180 if (calcQ) {
181 colNames.emplace_back("double", "Q elastic");
182 }
183 colNames.emplace_back("double", "Phi");
184 colNames.emplace_back("str", "Monitor");
185 if (hasDiffConstants) {
186 colNames.emplace_back("double", "DIFA");
187 colNames.emplace_back("double", "DIFC");
188 colNames.emplace_back("double", "DIFC - Uncalibrated");
189 colNames.emplace_back("double", "TZERO");
190 }
191 return colNames;
192}
193
195 const std::vector<int> &indices, const SpectrumInfo &spectrumInfo, bool signedThetaParamRetrieved,
196 bool showSignedTwoTheta, const PointingAlong &beamAxisIndex, const double sampleDist,
197 const bool isScanning, const bool includeData, const bool calcQ, const bool includeDiffConstants,
198 Logger &logger) {
200 for (int row = 0; row < nrows; ++row) {
201 TableRow colValues = t->getRow(row);
202 size_t wsIndex = indices.empty() ? static_cast<size_t>(row) : indices[row];
203 colValues << static_cast<double>(wsIndex);
204 const double dataY0{ws->y(wsIndex)[0]}, dataE0{ws->e(wsIndex)[0]};
205 try {
206 auto &spectrum = ws->getSpectrum(wsIndex);
207 Mantid::specnum_t specNo = spectrum.getSpectrumNo();
208 const auto &ids = dynamic_cast<const std::set<int> &>(spectrum.getDetectorIDs());
209 std::string detIds = createTruncatedList(ids);
210
211 // Geometry
212 if (!spectrumInfo.hasDetectors(wsIndex))
213 throw std::runtime_error("No detectors found.");
214 if (!signedThetaParamRetrieved) {
215 const std::vector<std::string> &parameters =
216 spectrumInfo.detector(wsIndex).getStringParameter("show-signed-theta", true); // recursive
217 showSignedTwoTheta =
218 (!parameters.empty() && find(parameters.begin(), parameters.end(), "Always") != parameters.end());
219 signedThetaParamRetrieved = true;
220 }
221
222 double R{0.0}, theta{0.0}, phi{0.0};
223 // theta used as a dummy variable
224 // Note: phi is the angle around Z, not necessarily the beam direction.
225 spectrumInfo.position(wsIndex).getSpherical(R, theta, phi);
226 // R is actually L2 (same as R if sample is at (0,0,0)), except for
227 // monitors which are handled below.
228 R = spectrumInfo.l2(wsIndex);
229 // Theta is actually 'twoTheta' for detectors (twice the scattering
230 // angle), if Z is the beam direction this corresponds to theta in
231 // spherical coordinates.
232 // For monitors we follow historic behaviour and display theta
233 const bool isMonitor = spectrumInfo.isMonitor(wsIndex);
234 if (!isMonitor) {
235 try {
236 theta = showSignedTwoTheta ? spectrumInfo.signedTwoTheta(wsIndex) : spectrumInfo.twoTheta(wsIndex);
237 theta *= 180.0 / M_PI; // To degrees
238 } catch (const std::exception &ex) {
239 // Log the error and leave theta as it is
240 logger.error(ex.what());
241 }
242 } else {
243 const auto dist = spectrumInfo.position(wsIndex)[beamAxisIndex];
244 theta = sampleDist > dist ? 180.0 : 0.0;
245 }
246 const std::string isMonitorDisplay = isMonitor ? "yes" : "no";
247 colValues << static_cast<int>(specNo) << detIds;
248 if (isScanning) {
249 std::set<int> timeIndexSet;
250 for (auto def : spectrumInfo.spectrumDefinition(wsIndex)) {
251 timeIndexSet.insert(int(def.second));
252 }
253
254 std::string timeIndexes = createTruncatedList(timeIndexSet);
255 colValues << timeIndexes;
256 }
257 // Y/E
258 if (includeData) {
259 colValues << dataY0 << dataE0; // data
260 }
261 // If monitors are before the sample in the beam, DetectorInfo
262 // returns a negative l2 distance.
263 if (isMonitor) {
264 R = std::abs(R);
265 }
266 colValues << R << theta;
267
268 if (calcQ) {
269 if (isMonitor) {
270 // twoTheta is not defined for monitors.
271 colValues << std::nan("");
272 } else {
273 try {
274
275 // Get unsigned theta and efixed value
276 IDetector_const_sptr det{&spectrumInfo.detector(wsIndex), Mantid::NoDeleting()};
277 double efixed = ws->getEFixed(det);
278 double usignTheta = spectrumInfo.twoTheta(wsIndex) * 0.5;
279
280 double q = UnitConversion::convertToElasticQ(usignTheta, efixed);
281 colValues << q;
282 } catch (std::runtime_error &) {
283 // No Efixed
284 colValues << std::nan("");
285 }
286 }
287 }
288
289 colValues << phi // rtp
290 << isMonitorDisplay; // monitor
291
292 if (includeDiffConstants) {
293 if (isMonitor) {
294 colValues << 0. << 0. << 0. << 0.;
295 } else {
296 auto diffConsts = spectrumInfo.diffractometerConstants(wsIndex);
297 auto difcValueUncalibrated = spectrumInfo.difcUncalibrated(wsIndex);
298 // map will create an entry with zero value if not present already
299 colValues << diffConsts[UnitParams::difa] << diffConsts[UnitParams::difc] << difcValueUncalibrated
300 << diffConsts[UnitParams::tzero];
301 }
302 }
303 } catch (const std::exception &) {
304 colValues.row(row);
305 colValues << static_cast<double>(wsIndex);
306 // spectrumNo=-1, detID=0
307 colValues << -1 << "0";
308 // Y/E
309 if (includeData) {
310 colValues << dataY0 << dataE0; // data
311 }
312 colValues << 0.0 << 0.0; // rt
313 if (calcQ) {
314 colValues << 0.0; // efixed
315 }
316 colValues << 0.0 // rtp
317 << "n/a"; // monitor
318 if (includeDiffConstants) {
319 colValues << 0.0 << 0.0 << 0.0 << 0.0;
320 }
321 } // End catch for no spectrum
322 }
323}
324
334std::string createTruncatedList(const std::set<int> &elements) {
335 std::string truncated;
336 size_t ndets = elements.size();
337 auto iter = elements.begin();
338 auto itEnd = elements.end();
339 if (ndets > 10) {
340 const Mantid::detid_t first{*iter++}, second{*iter++};
341 truncated = std::to_string(first) + "," + std::to_string(second) + "...(" + std::to_string(ndets - 4) + " more)...";
342 auto revIter = elements.rbegin();
343 const Mantid::detid_t last{*revIter++}, lastm1{*revIter++};
344 truncated += std::to_string(lastm1) + "," + std::to_string(last);
345 } else {
346 for (; iter != itEnd; ++iter) {
347 truncated += std::to_string(*iter) + ",";
348 }
349
350 if (!truncated.empty()) {
351 truncated.pop_back(); // Drop last comma
352 }
353 }
354
355 return truncated;
356}
357
358} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
std::map< DeltaEMode::Type, std::string > index
Definition: DeltaEMode.cpp:19
#define PARALLEL_FOR_IF(condition)
Empty definitions - to enable set your complier to enable openMP.
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
Definition: Algorithm.cpp:2026
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Definition: Algorithm.cpp:2076
Kernel::Logger & g_log
Definition: Algorithm.h:451
void setPropertyValue(const std::string &name, const std::string &value) override
Set the value of a property by string N.B.
Definition: Algorithm.cpp:1975
Show a property as enabled when the workspace pointed to by another is of a given type.
API::SpectrumInfo is an intermediate step towards a SpectrumInfo that is part of Instrument-2....
Definition: SpectrumInfo.h:53
double signedTwoTheta(const size_t index) const
Returns the signed scattering angle 2 theta in radians (angle w.r.t.
bool isMonitor(const size_t index) const
Returns true if the detector(s) associated with the spectrum are monitors.
Kernel::UnitParametersMap diffractometerConstants(const size_t index, std::vector< detid_t > &uncalibratedDets) const
Calculate average diffractometer constants (DIFA, DIFC, TZERO) of detectors associated with this spec...
bool hasDetectors(const size_t index) const
Returns true if the spectrum is associated with detectors in the instrument.
double twoTheta(const size_t index) const
Returns the scattering angle 2 theta in radians (angle w.r.t.
double difcUncalibrated(const size_t index) const
Calculate average uncalibrated DIFC value of detectors associated with this spectrum.
Kernel::V3D position(const size_t index) const
Returns the position of the spectrum with given index.
double l2(const size_t index) const
Returns L2 (distance from sample to spectrum).
const SpectrumDefinition & spectrumDefinition(const size_t index) const
Returns a const reference to the SpectrumDefinition of the spectrum.
const Geometry::IDetector & detector(const size_t index) const
Return a const reference to the detector or detector group of the spectrum with given index.
TableRow represents a row in a TableWorkspace.
Definition: TableRow.h:39
size_t row() const
Returns the row number of the TableRow.
Definition: TableRow.h:43
A property class for workspaces.
std::map< std::string, std::string > validateInputs() override
Method checking errors on ALL the inputs, before execution.
virtual std::vector< std::string > getStringParameter(const std::string &pname, bool recursive=true) const =0
Get a parameter defined as a string.
Support for a property that holds an array of values.
Definition: ArrayProperty.h:28
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
The Logger class is in charge of the publishing messages from the framework through various channels.
Definition: Logger.h:52
void error(const std::string &msg)
Logs at error level.
Definition: Logger.cpp:77
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
static double convertToElasticQ(const double theta, const double efixed)
Convert to ElasticQ from Energy.
void getSpherical(double &R, double &theta, double &phi) const noexcept
Return the vector's position in spherical coordinates.
Definition: V3D.cpp:117
An object for constructing a shared_ptr that won't ever delete its pointee.
Definition: IComponent.h:166
std::shared_ptr< ITableWorkspace > ITableWorkspace_sptr
shared pointer to Mantid::API::ITableWorkspace
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
Definition: Workspace_fwd.h:20
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::string createTruncatedList(const std::set< int > &elements)
Converts a list to a string, shortened if necessary.
API::ITableWorkspace_sptr createDetectorTableWorkspace(const API::MatrixWorkspace_sptr &ws, const std::vector< int > &indices, const bool includeData, Kernel::Logger &logger)
Creates table workspace of detector information from a given workspace.
std::vector< std::pair< std::string, std::string > > createColumns(const bool isScanning, const bool includeData, const bool calcQ, const bool hasDiffConstants)
void populateTable(Mantid::API::ITableWorkspace_sptr &t, const Mantid::API::MatrixWorkspace_sptr &ws, const int nrows, const std::vector< int > &indices, const Mantid::API::SpectrumInfo &spectrumInfo, bool signedThetaParamRetrieved, bool showSignedTwoTheta, const Mantid::Geometry::PointingAlong &beamAxisIndex, const double sampleDist, const bool isScanning, const bool include_data, const bool calcQ, const bool includeDiffConstants, Kernel::Logger &logger)
std::shared_ptr< const IComponent > IComponent_const_sptr
Typdef of a shared pointer to a const IComponent.
Definition: IComponent.h:161
std::shared_ptr< const Mantid::Geometry::IDetector > IDetector_const_sptr
Shared pointer to IDetector (const version)
Definition: IDetector.h:102
PointingAlong
Type to describe pointing along options.
std::enable_if< std::is_pointer< Arg >::value, bool >::type threadSafe(Arg workspace)
Thread-safety check Checks the workspace to ensure it is suitable for multithreaded access.
Definition: MultiThreaded.h:22
int32_t detid_t
Typedef for a detector ID.
Definition: SpectrumInfo.h:21
int32_t specnum_t
Typedef for a spectrum Number.
Definition: IDTypes.h:16
std::string to_string(const wide_integer< Bits, Signed > &n)
@ Input
An input workspace.
Definition: Property.h:53
@ Output
An output workspace.
Definition: Property.h:54