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 +
10#include "MantidAPI/TableRow.h"
19
20using namespace Mantid::API;
21using namespace Mantid::Kernel;
22using namespace Mantid::DataObjects;
23using namespace Mantid::Geometry;
24
25namespace Mantid::Algorithms {
26// Register the algorithm into the AlgorithmFactory
27DECLARE_ALGORITHM(CreateDetectorTable)
28
29void CreateDetectorTable::init() {
30 declareProperty(std::make_unique<WorkspaceProperty<Workspace>>("InputWorkspace", "", Direction::Input),
31 "The name of the workspace to take as input.");
32
33 declareProperty(std::make_unique<ArrayProperty<int>>("WorkspaceIndices", Direction::Input),
34 "If left empty then all workspace indices are used.");
35 setPropertySettings("WorkspaceIndices",
36 std::make_unique<EnabledWhenWorkspaceIsType<MatrixWorkspace>>("InputWorkspace", true));
37
38 declareProperty("IncludeData", false, "Include the first value from each spectrum.");
39 setPropertySettings("IncludeData",
40 std::make_unique<EnabledWhenWorkspaceIsType<MatrixWorkspace>>("InputWorkspace", true));
41
42 declareProperty<bool>("IncludeDetectorPosition", false,
43 "Include the absolute position of the detector group for each spectrum.", Direction::Input);
44 setPropertySettings("IncludeDetectorPosition",
45 std::make_unique<EnabledWhenWorkspaceIsType<MatrixWorkspace>>("InputWorkspace", true));
46
47 declareProperty<bool>("PickOneDetectorID", false, "Populate the Detector ID column with only the first of the set.",
49 setPropertySettings("PickOneDetectorID",
50 std::make_unique<EnabledWhenWorkspaceIsType<MatrixWorkspace>>("InputWorkspace", true));
51
52 declareProperty(std::make_unique<WorkspaceProperty<TableWorkspace>>("DetectorTableWorkspace", "", Direction::Output,
54 "The name of the outputted detector table workspace, if left empty then "
55 "the input workspace name + \"-Detectors\" is used.");
56}
57
59 API::Workspace_sptr inputWs = getProperty("InputWorkspace");
60 includeData = getProperty("IncludeData");
61 workspaceIndices = getProperty("WorkspaceIndices");
62 includeDetectorPosition = getProperty("IncludeDetectorPosition");
63 PickOneDetectorID = getProperty("PickOneDetectorID");
64
65 if (auto peaks = std::dynamic_pointer_cast<IPeaksWorkspace>(inputWs)) {
66 table = peaks->createDetectorTable();
68 return;
69 }
70
71 if ((ws = std::dynamic_pointer_cast<MatrixWorkspace>(inputWs))) {
72 if (ws->getInstrument()->getSample() == nullptr) {
73 throw std::runtime_error("Matrix workspace has no instrument information");
74 }
75 setup();
79 return;
80 }
81
82 throw std::runtime_error("Detector table can only be created for matrix and peaks workspaces.");
83}
84
86 if (table == nullptr) {
87 throw std::runtime_error("Unknown error while creating detector table workspace");
88 }
89 API::Workspace_sptr inputWs = getProperty("InputWorkspace");
90 if (getPropertyValue("DetectorTableWorkspace") == "") {
91 setPropertyValue("DetectorTableWorkspace", inputWs->getName() + "-Detectors");
92 }
93 setProperty("DetectorTableWorkspace", table);
94}
95
96/*
97 * Validate the input parameters
98 * @returns map with keys corresponding to properties with errors and values
99 * containing the error messages.
100 */
101std::map<std::string, std::string> CreateDetectorTable::validateInputs() {
102 // create the map
103 std::map<std::string, std::string> validationOutput;
104
105 Workspace_sptr inputWS = getProperty("InputWorkspace");
106 const auto matrix = std::dynamic_pointer_cast<MatrixWorkspace>(inputWS);
107
108 if (matrix) {
109 const int numSpectra = static_cast<int>(matrix->getNumberHistograms());
110 const std::vector<int> indices = getProperty("WorkspaceIndices");
111
112 if (std::any_of(indices.cbegin(), indices.cend(),
113 [numSpectra](const auto index) { return (index >= numSpectra) || (index < 0); })) {
114 validationOutput["WorkspaceIndices"] = "One or more indices out of range of available spectra.";
115 }
116 }
117
118 return validationOutput;
119}
120
122
123 isScanning = ws->detectorInfo().isScanning();
124
125 spectrumInfo = &ws->spectrumInfo();
126
127 // check if efixed value is available
128 calcQ = true;
129 if (spectrumInfo->hasDetectors(0)) {
130 try {
131 std::shared_ptr<const IDetector> detector(&spectrumInfo->detector(0), Mantid::NoDeleting());
132 ws->getEFixed(detector);
133 } catch (std::invalid_argument &) {
134 calcQ = false;
135 } catch (std::runtime_error &) {
136 calcQ = false;
137 }
138 } else {
139 // No detectors available
140 calcQ = false;
141 }
142
143 hasDiffConstants = (ws->getEMode() == DeltaEMode::Elastic);
144
145 nrows = workspaceIndices.empty() ? static_cast<int>(ws->getNumberHistograms())
146 : static_cast<int>(workspaceIndices.size());
147
148 beamAxisIndex = ws->getInstrument()->getReferenceFrame()->pointingAlongBeam();
149 sampleDist = ws->getInstrument()->getSample()->getPos()[beamAxisIndex];
151 showSignedTwoTheta = false; // If true, signedVersion of the two theta
152 // value should be displayed
153 table = WorkspaceFactory::Instance().createTable("TableWorkspace");
154 table->setRowCount(nrows);
155}
156
158 std::vector<std::pair<std::string, std::string>> colNames;
159 colNames.emplace_back("int", "Index");
160 colNames.emplace_back("int", "Spectrum No");
161 if (PickOneDetectorID) {
162 colNames.emplace_back("int", "Detector ID(s)");
163 } else {
164 colNames.emplace_back("str", "Detector ID(s)");
165 }
166 if (isScanning)
167 colNames.emplace_back("str", "Time Indexes");
168 if (includeData) {
169 colNames.emplace_back("double", "Data Value");
170 colNames.emplace_back("double", "Data Error");
171 }
172
173 colNames.emplace_back("double", "R");
174 colNames.emplace_back("double", "Theta");
175 if (calcQ) {
176 colNames.emplace_back("double", "Q elastic");
177 }
178 colNames.emplace_back("double", "Phi");
179 colNames.emplace_back("str", "Monitor");
180 if (hasDiffConstants) {
181 colNames.emplace_back("double", "DIFA");
182 colNames.emplace_back("double", "DIFC");
183 colNames.emplace_back("double", "DIFC - Uncalibrated");
184 colNames.emplace_back("double", "TZERO");
185 }
187 colNames.emplace_back("V3D", "Position");
188 }
189
190 // Set the column names
191 for (size_t col = 0; col < colNames.size(); ++col) {
192 auto column = table->addColumn(colNames.at(col).first, colNames.at(col).second);
193 column->setPlotType(0);
194 }
195 return;
196}
197
200 for (int row = 0; row < nrows; ++row) {
201 TableRow colValues = table->getRow(row);
202 size_t wsIndex = workspaceIndices.empty() ? static_cast<size_t>(row) : workspaceIndices[row];
203 colValues << static_cast<int>(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
209 // Geometry
210 if (!spectrumInfo->hasDetectors(wsIndex))
211 throw std::runtime_error("No detectors found.");
213 const std::vector<std::string> &parameters =
214 spectrumInfo->detector(wsIndex).getStringParameter("show-signed-theta", true); // recursive
216 (!parameters.empty() && find(parameters.begin(), parameters.end(), "Always") != parameters.end());
218 }
219
220 double R{0.0}, theta{0.0}, phi{0.0};
221 // theta used as a dummy variable
222 // Note: phi is the angle around Z, not necessarily the beam direction.
223 spectrumInfo->position(wsIndex).getSpherical(R, theta, phi);
224 // R is actually L2 (same as R if sample is at (0,0,0)), except for
225 // monitors which are handled below.
226 R = spectrumInfo->l2(wsIndex);
227 // Theta is actually 'twoTheta' for detectors (twice the scattering
228 // angle), if Z is the beam direction this corresponds to theta in
229 // spherical coordinates.
230 // For monitors we follow historic behaviour and display theta
231 const bool isMonitor = spectrumInfo->isMonitor(wsIndex);
232 if (!isMonitor) {
233 try {
235 theta *= 180.0 / M_PI; // To degrees
236 } catch (const std::exception &ex) {
237 // Log the error and leave theta as it is
238 g_log.error(ex.what());
239 }
240 } else {
241 const auto dist = spectrumInfo->position(wsIndex)[beamAxisIndex];
242 theta = sampleDist > dist ? 180.0 : 0.0;
243 }
244 const std::string isMonitorDisplay = isMonitor ? "yes" : "no";
245
246 colValues << static_cast<int>(specNo);
247
248 const auto &ids = dynamic_cast<const std::set<int> &>(spectrum.getDetectorIDs());
249 if (PickOneDetectorID) {
250 // Populate detector column with first det id in set
251 colValues << static_cast<int>(*ids.begin());
252 } else {
253 // Populate detector column with a truncated string of all det ids
254 colValues << createTruncatedList(ids);
255 }
256 if (isScanning) {
257 std::set<int> timeIndexSet;
258 for (const auto &def : spectrumInfo->spectrumDefinition(wsIndex)) {
259 timeIndexSet.insert(int(def.second));
260 }
261
262 const std::string timeIndexes = createTruncatedList(timeIndexSet);
263 colValues << timeIndexes;
264 }
265 // Y/E
266 if (includeData) {
267 colValues << dataY0 << dataE0; // data
268 }
269 // If monitors are before the sample in the beam, DetectorInfo
270 // returns a negative l2 distance.
271 if (isMonitor) {
272 R = std::abs(R);
273 }
274 colValues << R << theta;
275
276 if (calcQ) {
277 if (isMonitor) {
278 // twoTheta is not defined for monitors.
279 colValues << std::nan("");
280 } else {
281 try {
282
283 // Get unsigned theta and efixed value
285 double efixed = ws->getEFixed(det);
286 double usignTheta = spectrumInfo->twoTheta(wsIndex) * 0.5;
287
288 double q = UnitConversion::convertToElasticQ(usignTheta, efixed);
289 colValues << q;
290 } catch (std::runtime_error &) {
291 // No Efixed
292 colValues << std::nan("");
293 }
294 }
295 }
296
297 colValues << phi // rtp
298 << isMonitorDisplay; // monitor
299
300 if (hasDiffConstants) {
301 if (isMonitor) {
302 colValues << 0. << 0. << 0. << 0.;
303 } else {
304 auto diffConsts = spectrumInfo->diffractometerConstants(wsIndex);
305 auto difcValueUncalibrated = spectrumInfo->difcUncalibrated(wsIndex);
306 // map will create an entry with zero value if not present already
307 colValues << diffConsts[UnitParams::difa] << diffConsts[UnitParams::difc] << difcValueUncalibrated
308 << diffConsts[UnitParams::tzero];
309 }
310 }
312 const auto &detectorPosition = spectrumInfo->position(wsIndex);
313 colValues << detectorPosition;
314 }
315 } catch (const std::exception &) {
316 colValues.row(row);
317 colValues << static_cast<int>(wsIndex);
318 // spectrumNo=-1, detID=0
319 colValues << -1;
320 if (PickOneDetectorID) {
321 colValues << 0;
322 } else {
323 colValues << "0";
324 }
325 // Y/E
326 if (includeData) {
327 colValues << dataY0 << dataE0; // data
328 }
329 colValues << 0.0 << 0.0; // rt
330 if (calcQ) {
331 colValues << 0.0; // efixed
332 }
333 colValues << 0.0 // rtp
334 << "n/a"; // monitor
335 if (hasDiffConstants) {
336 colValues << 0.0 << 0.0 << 0.0 << 0.0;
337 }
339 colValues << V3D(0.0, 0.0, 0.0);
340 }
341 } // End catch for no spectrum
342 }
343}
344
354std::string createTruncatedList(const std::set<int> &elements) {
355 std::string truncated;
356 size_t ndets = elements.size();
357 auto iter = elements.begin();
358 auto itEnd = elements.end();
359 if (ndets > 10) {
360 const Mantid::detid_t first{*iter++}, second{*iter++};
361 truncated = std::to_string(first) + "," + std::to_string(second) + "...(" + std::to_string(ndets - 4) + " more)...";
362 auto revIter = elements.rbegin();
363 const Mantid::detid_t last{*revIter++}, lastm1{*revIter++};
364 truncated += std::to_string(lastm1) + "," + std::to_string(last);
365 } else {
366 for (; iter != itEnd; ++iter) {
367 truncated += std::to_string(*iter) + ",";
368 }
369
370 if (!truncated.empty()) {
371 truncated.pop_back(); // Drop last comma
372 }
373 }
374
375 return truncated;
376}
377
378} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
std::map< DeltaEMode::Type, std::string > index
#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.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Kernel::Logger & g_log
Definition Algorithm.h:422
void setPropertyValue(const std::string &name, const std::string &value) override
Set the value of a property by string N.B.
Show a property as enabled when the workspace pointed to by another is of a given type.
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.
void setup()
Creates table workspace of detector information from a given workspace.
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.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void error(const std::string &msg)
Logs at error level.
Definition Logger.cpp:108
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.
Class for 3D vectors.
Definition V3D.h:34
void getSpherical(double &R, double &theta, double &phi) const noexcept
Return the vector's position in spherical coordinates.
Definition V3D.cpp:116
An object for constructing a shared_ptr that won't ever delete its pointee.
Definition IComponent.h:172
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
std::string createTruncatedList(const std::set< int > &elements)
Converts a list to a string, shortened if necessary.
std::shared_ptr< const Mantid::Geometry::IDetector > IDetector_const_sptr
Shared pointer to IDetector (const version)
Definition IDetector.h:102
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.
int32_t detid_t
Typedef for a detector ID.
int32_t specnum_t
Typedef for a spectrum Number.
Definition IDTypes.h:14
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