Mantid
Loading...
Searching...
No Matches
PreprocessDetectorsToMD.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 +
12#include "MantidAPI/Run.h"
19
20using namespace Mantid;
21using namespace Mantid::API;
22using namespace Mantid::DataObjects;
23
24namespace Mantid::MDAlgorithms {
25// Register the algorithm into the AlgorithmFactory
26DECLARE_ALGORITHM(PreprocessDetectorsToMD)
27
28PreprocessDetectorsToMD::PreprocessDetectorsToMD() : m_getEFixed(false), m_getIsMasked(false) {}
29
32 auto ws_valid = std::make_shared<Kernel::CompositeValidator>();
33 // workspace needs instrument
34 ws_valid->add<API::InstrumentValidator>();
35 // the validator which checks if the workspace has axis and any units
36 // ws_valid->add<API::WorkspaceUnitValidator>("");
37
38 declareProperty(std::make_unique<WorkspaceProperty<API::MatrixWorkspace>>("InputWorkspace", "",
39 Kernel::Direction::Input, ws_valid),
40 "Name of an input Matrix Workspace with instrument.");
41
42 declareProperty(std::make_unique<WorkspaceProperty<TableWorkspace>>("OutputWorkspace", "", Kernel::Direction::Output),
43 "Name of the output Table workspace with pre-processed "
44 "detectors data. If the workspace exists, it will be "
45 "replaced.");
46
47 declareProperty(std::make_unique<Kernel::PropertyWithValue<bool>>("GetMaskState", true, Kernel::Direction::Input),
48 "Returns masked state of the detectors. If this option is "
49 "false, the masked detectors are just dropped from the "
50 "resulting workspace and spectra-to detectors map has to be "
51 "used to analyse the spectra. This is temporary parameter "
52 "and logic necessary until Mantid masks signal by 0 rather "
53 "then NaN.");
54
55 declareProperty(std::make_unique<Kernel::PropertyWithValue<bool>>("UpdateMasksInfo", false, Kernel::Direction::Input),
56 "If target workspace already exists as the result of "
57 "previous deployment of this algorithm, the algorithm just "
58 "updated masks states column instead of calculating the "
59 "whole target workspace. The target workspace has to be "
60 "appropriate for the source workspace This is temporary "
61 "parameter and logic necessary until Mantid masks signal by "
62 "0 rather then NaN.");
63
65 "This option makes sense for Indirect instrument, where each "
66 "detector can have its own energy, defined by correspondent "
67 "crystal-analyzer position.\n"
68 "If this option is selected for other instrument types, the "
69 "value of eFixed is taken from workspace property "
70 "Ei"
71 " or "
72 "eFixed"
73 " if "
74 "Ei"
75 "\n"
76 "is missing and is set to NaN if no such properties are "
77 "defined on the input workspace.");
78
79 // declareProperty(new
80 // PropertyWithValue<bool>("FakeDetectors",false,Kernel::Direction::Input),
81 // "If selected, generates table workspace with fake detectors, all allocated
82 // in a monitor position.\n"
83 // "Number of detectors is equal to number of spectra and real detectors, if
84 // present are ignored ");
85}
86
87//----------------------------------------------------------------------------------------------
88/* Execute the algorithm. */
90 // -------- get Input workspace
91 MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace");
92
93 // verify if we want to preprocess real workspace or just update the state of
94 // workspace masks
96 bool updateMasks(false);
97 if (this->getProperty("GetMaskState") && this->getProperty("UpdateMasksInfo")) {
98 std::string wsName = this->getPointerToProperty("OutputWorkspace")->value();
99 if (API::AnalysisDataService::Instance().doesExist(wsName)) {
100 targWS =
101 std::dynamic_pointer_cast<DataObjects::TableWorkspace>(API::AnalysisDataService::Instance().retrieve(wsName));
102 if (targWS) {
103 auto *pMasksArray = targWS->getColDataArray<int>("detMask");
104 if (pMasksArray)
105 updateMasks = true;
106 // was this workspace calculated without eFixed and now we need one?
107 if (this->getProperty("GetEFixed") && !targWS->getColDataArray<float>("eFixed"))
108 updateMasks = false;
109 }
110 }
111 }
112
113 if (updateMasks) // just update masks
114 this->updateMasksState(inputWS, targWS);
115 else // -------- build target workspace:
116 targWS = createTableWorkspace(inputWS);
117
118 if (this->isDetInfoLost(inputWS))
119 this->buildFakeDetectorsPositions(inputWS, targWS);
120 else // process real detectors positions
121 this->processDetectorsPositions(inputWS, targWS);
122
123 // set up target workspace
124 setProperty("OutputWorkspace", targWS);
125}
126
128std::shared_ptr<DataObjects::TableWorkspace>
130 const size_t nHist = inputWS->getNumberHistograms();
131
132 // set the target workspace
133 auto targWS = std::make_shared<TableWorkspace>(nHist);
134 // detectors positions
135 targWS->addColumn("V3D", "DetDirections");
136 // sample-detector distance;
137 targWS->addColumn("double", "L2");
138 // Diffraction angle
139 targWS->addColumn("double", "TwoTheta");
140 targWS->addColumn("double", "Azimuthal");
141 // the detector ID;
142 targWS->addColumn("int", "DetectorID");
143 // stores spectra index which corresponds to a valid detector index;
144 targWS->addColumn("size_t", "detIDMap");
145 // stores detector index which corresponds to the workspace index;
146 targWS->addColumn("size_t", "spec2detMap");
147
148 m_getIsMasked = this->getProperty("GetMaskState");
149 if (m_getIsMasked) // as bool is presented in vectors as a class, we are using
150 // int instead of bool
151 targWS->addColumn("int", "detMask");
152
153 // check if one wants to obtain detector's efixed"
154 m_getEFixed = this->getProperty("GetEFixed");
155 if (m_getEFixed)
156 targWS->addColumn("float", "eFixed");
157 targWS->addColumn("double", "DIFA");
158 targWS->addColumn("double", "DIFC");
159 targWS->addColumn("double", "TZERO");
160
161 // will see about that
162 // sin^2(Theta)
163 // std::vector<double> SinThetaSq;
164
165 double Efi = getEi(inputWS);
166 targWS->logs()->addProperty<double>("Ei", Efi, true);
167
168 return targWS;
169}
170
177 g_log.information() << "Preprocessing detector locations in a target reciprocal space\n";
178 //
179 Geometry::Instrument_const_sptr instrument = inputWS->getInstrument();
180 Geometry::IComponent_const_sptr source = instrument->getSource();
181 Geometry::IComponent_const_sptr sample = instrument->getSample();
182 if ((!source) || (!sample)) {
183 g_log.error() << " Instrument is not fully defined. Can not identify "
184 "source or sample\n";
186 "Instrument not sufficiently defined: failed to get source and/or "
187 "sample");
188 }
189
190 // L1
191 try {
192 double L1 = source->getDistance(*sample);
193 targWS->logs()->addProperty<double>("L1", L1, true);
194 g_log.debug() << "Source-sample distance: " << L1 << '\n';
196 throw Kernel::Exception::InstrumentDefinitionError("Unable to calculate source-sample distance for workspace",
197 inputWS->getTitle());
198 }
199 // Instrument name
200 std::string InstrName = inputWS->getInstrumentName();
201 targWS->logs()->addProperty<std::string>("InstrumentName", InstrName,
202 true); // "The name which should unique identify current instrument");
203 targWS->logs()->addProperty<bool>("FakeDetectors", false, true);
204
205 // get access to the workspace memory
206 auto &sp2detMap = targWS->getColVector<size_t>("spec2detMap");
207 auto &detId = targWS->getColVector<int32_t>("DetectorID");
208 auto &detIDMap = targWS->getColVector<size_t>("detIDMap");
209 auto &L2 = targWS->getColVector<double>("L2");
210 auto &TwoTheta = targWS->getColVector<double>("TwoTheta");
211 auto &Azimuthal = targWS->getColVector<double>("Azimuthal");
212 auto &detDir = targWS->getColVector<Kernel::V3D>("DetDirections");
213 auto &DIFA = targWS->getColVector<double>("DIFA");
214 auto &DIFC = targWS->getColVector<double>("DIFC");
215 auto &TZERO = targWS->getColVector<double>("TZERO");
216
217 // Efixed; do we need one and does one exist?
218 auto Efi = targWS->getLogs()->getPropertyValueAsType<double>("Ei");
219 float *pEfixedArray(nullptr);
220 const auto &componentInfo = inputWS->componentInfo();
221 const auto &detectorInfo = inputWS->detectorInfo();
222 if (m_getEFixed)
223 pEfixedArray = targWS->getColDataArray<float>("eFixed");
224
225 // check if one needs to generate masked detectors column.
226 int *pMasksArray(nullptr);
227 if (m_getIsMasked)
228 pMasksArray = targWS->getColDataArray<int>("detMask");
229
231 size_t div = 100;
232 size_t nHist = targWS->rowCount();
233 Mantid::API::Progress theProgress(this, 0.0, 1.0, nHist);
235 uint32_t liveDetectorsCount(0);
236 const auto &spectrumInfo = inputWS->spectrumInfo();
237 for (size_t i = 0; i < nHist; i++) {
238 sp2detMap[i] = std::numeric_limits<uint64_t>::quiet_NaN();
239 detId[i] = std::numeric_limits<int32_t>::quiet_NaN();
240 detIDMap[i] = std::numeric_limits<uint64_t>::quiet_NaN();
241 L2[i] = std::numeric_limits<double>::quiet_NaN();
242 DIFC[i] = std::numeric_limits<double>::quiet_NaN();
243 TwoTheta[i] = std::numeric_limits<double>::quiet_NaN();
244 Azimuthal[i] = std::numeric_limits<double>::quiet_NaN();
245 // detMask[i] = true;
246
247 if (!spectrumInfo.hasDetectors(i) || spectrumInfo.isMonitor(i))
248 continue;
249
250 // if masked detectors state is not used, masked detectors just ignored;
251 bool maskDetector = spectrumInfo.isMasked(i);
252 if (m_getIsMasked)
253 *(pMasksArray + liveDetectorsCount) = maskDetector ? 1 : 0;
254 else if (maskDetector)
255 continue;
256
257 // The first detector, for a spectrum of several
258 const auto firstDetIndex = spectrumInfo.firstDetectorIndex(i);
259
260 // calculate the requested values;
261 sp2detMap[i] = liveDetectorsCount;
262 detId[liveDetectorsCount] = int32_t(detectorInfo.detid(firstDetIndex));
263 detIDMap[liveDetectorsCount] = i;
264 L2[liveDetectorsCount] = spectrumInfo.l2(i);
265
266 double polar = spectrumInfo.twoTheta(i);
267 double azim = spectrumInfo.phi(i);
268 TwoTheta[liveDetectorsCount] = polar;
269 Azimuthal[liveDetectorsCount] = azim;
270
271 std::vector<int> warningDets;
272 auto diffConsts = spectrumInfo.diffractometerConstants(i, warningDets);
273 // map will create an entry with zero value if not present already
274 DIFA[liveDetectorsCount] = diffConsts[Kernel::UnitParams::difa];
275 DIFC[liveDetectorsCount] = diffConsts[Kernel::UnitParams::difc];
276 TZERO[liveDetectorsCount] = diffConsts[Kernel::UnitParams::tzero];
277
278 double sPhi = sin(polar);
279 double ez = cos(polar);
280 double ex = sPhi * cos(azim);
281 double ey = sPhi * sin(azim);
282
283 detDir[liveDetectorsCount].setX(ex);
284 detDir[liveDetectorsCount].setY(ey);
285 detDir[liveDetectorsCount].setZ(ez);
286
287 // double sinTheta=sin(0.5*polar);
288 // this->SinThetaSq[liveDetectorsCount] = sinTheta*sinTheta;
289
290 // specific code which should work and makes sense
291 // for indirect instrument but may be deployed on any code with Ei property
292 // defined;
293 if (pEfixedArray) {
294 // A spectrum of several detectors has no parameters of its own
295 if (spectrumInfo.hasUniqueDetector(i)) {
296 try {
297 const auto eFixed = componentInfo.getNumberParameter(firstDetIndex, "eFixed");
298 if (!eFixed.empty())
299 Efi = eFixed.front();
300 } catch (std::runtime_error &) {
301 }
302 }
303 // set efixed for each existing detector
304 *(pEfixedArray + liveDetectorsCount) = static_cast<float>(Efi);
305 }
306
307 liveDetectorsCount++;
308 if (i % div == 0)
309 theProgress.report(i, "Preprocessing detectors");
310 }
311 targWS->logs()->addProperty<uint32_t>("ActualDetectorsNum", liveDetectorsCount, true);
312
313 theProgress.report();
314 g_log.information() << "Finished preprocessing detector locations. Found: " << liveDetectorsCount
315 << " detectors out of: " << nHist << " histograms\n";
316}
323 auto *pMasksArray = targWS->getColDataArray<int>("detMask");
324 if (!pMasksArray)
325 throw std::invalid_argument("target workspace " + targWS->getName() +
326 " does not have defined masks column to update");
327
328 size_t nHist = targWS->rowCount();
329 const size_t nRows = inputWS->getNumberHistograms();
330 if (nHist != nRows)
331 throw std::invalid_argument(" source workspace " + inputWS->getName() + " and target workspace " +
332 targWS->getName() + " are inconsistent as have different numner of detectors");
333
334 uint32_t liveDetectorsCount(0);
335 const auto &spectrumInfo = inputWS->spectrumInfo();
336 for (size_t i = 0; i < nHist; i++) {
337 if (!spectrumInfo.hasDetectors(i) || spectrumInfo.isMonitor(i))
338 continue;
339
340 // if masked detectors state is not used, masked detectors just ignored;
341 bool maskDetector = spectrumInfo.isMasked(i);
342 *(pMasksArray + liveDetectorsCount) = maskDetector ? 1 : 0;
343
344 liveDetectorsCount++;
345 }
346}
347
352 UNUSED_ARG(inputWS);
353 // set sample-detector position equal to 1;
354 targWS->logs()->addProperty<double>("L1", 1., true);
355 //
356 targWS->logs()->addProperty<std::string>("InstrumentName", "FakeInstrument", true);
357 targWS->logs()->addProperty<bool>("FakeDetectors", true, true);
358
359 // get access to the workspace memory
360 auto &sp2detMap = targWS->getColVector<size_t>("spec2detMap");
361 auto &detId = targWS->getColVector<int32_t>("DetectorID");
362 auto &detIDMap = targWS->getColVector<size_t>("detIDMap");
363 auto &L2 = targWS->getColVector<double>("L2");
364 auto &TwoTheta = targWS->getColVector<double>("TwoTheta");
365 auto &Azimuthal = targWS->getColVector<double>("Azimuthal");
366 auto &detDir = targWS->getColVector<Kernel::V3D>("DetDirections");
367 // auto &detMask = targWS->getColVector<bool>("detMask");
368
370 size_t nHist = targWS->rowCount();
371 targWS->logs()->addProperty<uint32_t>("ActualDetectorsNum", uint32_t(nHist), true);
372
373 double polar(0);
374 // Loop over the spectra
375 for (size_t i = 0; i < nHist; i++) {
376 sp2detMap[i] = i;
377 detId[i] = static_cast<detid_t>(i);
378 detIDMap[i] = i;
379 L2[i] = 1;
380
381 TwoTheta[i] = polar;
382 Azimuthal[i] = 0;
383 // this->SinThetaSq[i]= 0;
384
385 double ez = 1.;
386 double ex = 0.;
387 double ey = 0.;
388
389 detDir[i].setX(ex);
390 detDir[i].setY(ey);
391 detDir[i].setZ(ez);
392 }
393 //
394}
395
399 auto const *pYAxis = dynamic_cast<API::NumericAxis const *>(inWS2D->getAxis(1));
400 // if this is numeric axis, then the detector's information has been lost:
401 return pYAxis != nullptr;
402}
403
417 double Efi = std::numeric_limits<double>::quiet_NaN();
418
419 // is Ei on workspace properties? (it can be defined for some reason if
420 // detectors do not have one, and then it would exist as Ei)
421 bool EiFound(false);
422 try {
423 Efi = inputWS->run().getPropertyValueAsType<double>("Ei");
424 EiFound = true;
426 }
427 // try to get Efixed as property on a workspace, obtained for indirect
428 // instrument
429 bool eFixedFound(false);
430 if (!EiFound) {
431 try {
432 Efi = inputWS->run().getPropertyValueAsType<double>("eFixed");
433 eFixedFound = true;
435 }
436 }
437
438 if (!(EiFound || eFixedFound))
439 g_log.debug() << " Ei/eFixed requested but have not been found\n";
440
441 return Efi;
442}
443} // namespace Mantid::MDAlgorithms
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:547
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
Definition System.h:44
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
Kernel::Property * getPointerToProperty(const std::string &name) const override
Get a property by name.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Kernel::Logger & g_log
Definition Algorithm.h:426
A validator which checks that a workspace has a valid instrument.
Class to represent a numeric axis of a workspace.
Definition NumericAxis.h:30
Helper class for reporting progress from algorithms.
Definition Progress.h:25
A property class for workspaces.
Exception for errors associated with the instrument definition.
Definition Exception.h:220
Exception for when an item is not found in a collection.
Definition Exception.h:145
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
void error(const std::string &msg)
Logs at error level.
Definition Logger.cpp:108
void information(const std::string &msg)
Logs at information level.
Definition Logger.cpp:136
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
The concrete, templated class for properties.
virtual std::string value() const =0
Returns the value of the property as a string.
Class for 3D vectors.
Definition V3D.h:35
This is helper algorithm used to preprocess detector's positions namely to perform generic part of th...
bool isDetInfoLost(const Mantid::API::MatrixWorkspace_const_sptr &inWS2D) const
function checks if source workspace still has information about detectors.
void updateMasksState(const API::MatrixWorkspace_const_sptr &inputWS, DataObjects::TableWorkspace_sptr &targWS)
Method updates the column, which describes if current detector/spectra is masked It is used if one tr...
void buildFakeDetectorsPositions(const API::MatrixWorkspace_const_sptr &inputWS, DataObjects::TableWorkspace_sptr &targWS)
method calculates fake detectors positions in the situation when real detector information has been l...
std::shared_ptr< DataObjects::TableWorkspace > createTableWorkspace(const API::MatrixWorkspace_const_sptr &inputWS)
helper method to create resulting table workspace
bool m_getIsMasked
the variable specifies if one needs to return the state of detector mask e.g if the detector is maske...
double getEi(const API::MatrixWorkspace_const_sptr &inputWS) const
Method returns the efixed or Ei value stored in properties of the input workspace.
bool m_getEFixed
the variable specifies if one needs to calculate efixed for detectors (make sense for indirect instru...
void init() override
Initialize the algorithm's properties.
void processDetectorsPositions(const API::MatrixWorkspace_const_sptr &inputWS, DataObjects::TableWorkspace_sptr &targWS)
method does preliminary calculations of the detectors positions to convert results into k-dE space ; ...
void exec() override
Virtual method - must be overridden by concrete algorithm.
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
std::shared_ptr< TableWorkspace > TableWorkspace_sptr
shared pointer to Mantid::DataObjects::TableWorkspace
std::shared_ptr< const IComponent > IComponent_const_sptr
Typdef of a shared pointer to a const IComponent.
Definition IComponent.h:165
std::shared_ptr< const Instrument > Instrument_const_sptr
Shared pointer to an const instrument object.
Helper class which provides the Collimation Length for SANS instruments.
int32_t detid_t
Typedef for a detector ID.
@ Input
An input workspace.
Definition Property.h:54
@ Output
An output workspace.
Definition Property.h:55