Mantid
Loading...
Searching...
No Matches
SpectrumInfo.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 +
10#include "MantidBeamline/SpectrumInfo.h"
15#include "MantidKernel/Logger.h"
17#include "MantidTypes/SpectrumDefinition.h"
18
19#include <algorithm>
20#include <limits>
21#include <memory>
22
23using namespace Mantid::Kernel;
24
25namespace Mantid::API {
27Kernel::Logger g_log("ExperimentInfo");
28
29SpectrumInfo::SpectrumInfo(const Beamline::SpectrumInfo &spectrumInfo, const ExperimentInfo &experimentInfo,
30 Geometry::DetectorInfo &detectorInfo)
31 : m_experimentInfo(experimentInfo), m_detectorInfo(detectorInfo), m_spectrumInfo(spectrumInfo),
32 m_lastDetector(PARALLEL_GET_MAX_THREADS), m_lastIndex(PARALLEL_GET_MAX_THREADS, -1) {}
33
34// Defined as default in source for forward declaration with std::unique_ptr.
36
38size_t SpectrumInfo::size() const { return m_spectrumInfo.size(); }
39
40size_t SpectrumInfo::detectorCount() const { return m_spectrumInfo.detectorCount(); }
41
43const SpectrumDefinition &SpectrumInfo::spectrumDefinition(const size_t index) const {
45 return m_spectrumInfo.spectrumDefinition(index);
46}
47
49 for (size_t i = 0; i < size(); ++i)
51 return m_spectrumInfo.sharedSpectrumDefinitions();
52}
53
55bool SpectrumInfo::isMonitor(const size_t index) const {
56 const auto spectrumDef = checkAndGetSpectrumDefinition(index);
57 return std::all_of(spectrumDef.cbegin(), spectrumDef.cend(),
58 [this](const std::pair<size_t, size_t> &detIndex) { return m_detectorInfo.isMonitor(detIndex); });
59}
60
62bool SpectrumInfo::isMasked(const size_t index) const {
63 const auto spectrumDef = checkAndGetSpectrumDefinition(index);
64 return std::all_of(spectrumDef.cbegin(), spectrumDef.cend(),
65 [this](const std::pair<size_t, size_t> &detIndex) { return m_detectorInfo.isMasked(detIndex); });
66}
67
73double SpectrumInfo::l2(const size_t index) const {
74 const auto spectrumDef = checkAndGetSpectrumDefinition(index);
75 auto l2 = std::accumulate(
76 spectrumDef.cbegin(), spectrumDef.cend(), 0.0,
77 [this](double x, const std::pair<size_t, size_t> &detIndex) { return x + m_detectorInfo.l2(detIndex); });
78 return l2 / static_cast<double>(spectrumDef.size());
79}
80
86double SpectrumInfo::twoTheta(const size_t index) const {
87 const auto spectrumDef = checkAndGetSpectrumDefinition(index);
88 auto twoTheta = std::accumulate(
89 spectrumDef.cbegin(), spectrumDef.cend(), 0.0,
90 [this](double x, const std::pair<size_t, size_t> &detIndex) { return x + m_detectorInfo.twoTheta(detIndex); });
91 return twoTheta / static_cast<double>(spectrumDef.size());
92}
93
99double SpectrumInfo::signedTwoTheta(const size_t index) const {
100 const auto spectrumDef = checkAndGetSpectrumDefinition(index);
101 auto signedTwoTheta = std::accumulate(spectrumDef.cbegin(), spectrumDef.cend(), 0.0,
102 [this](double x, const std::pair<size_t, size_t> &detIndex) {
103 return x + m_detectorInfo.signedTwoTheta(detIndex);
104 });
105 return signedTwoTheta / static_cast<double>(spectrumDef.size());
106}
107
113double SpectrumInfo::azimuthal(const size_t index) const {
114 const auto spectrumDef = checkAndGetSpectrumDefinition(index);
115 auto phi = std::accumulate(
116 spectrumDef.cbegin(), spectrumDef.cend(), 0.0,
117 [this](double x, const std::pair<size_t, size_t> &detIndex) { return x + m_detectorInfo.azimuthal(detIndex); });
118 return phi / static_cast<double>(spectrumDef.size());
119}
120
125std::pair<double, double> SpectrumInfo::geographicalAngles(const size_t index) const {
126 double lat{0.0}, lon{0.0};
127 for (const auto &detIndex : checkAndGetSpectrumDefinition(index)) {
128 auto latlong = m_detectorInfo.geographicalAngles(detIndex);
129 lat += latlong.first;
130 lon += latlong.second;
131 }
132 return std::pair<double, double>(lat / static_cast<double>(spectrumDefinition(index).size()),
133 lon / static_cast<double>(spectrumDefinition(index).size()));
134}
135
138 const auto spectrumDef = checkAndGetSpectrumDefinition(index);
139 auto newPos = std::accumulate(spectrumDef.cbegin(), spectrumDef.cend(), Kernel::V3D(),
140 [this](const auto &x, const std::pair<size_t, size_t> &detIndex) {
141 return x + m_detectorInfo.position(detIndex);
142 });
143 return newPos / static_cast<double>(spectrumDef.size());
144}
145
155UnitParametersMap SpectrumInfo::diffractometerConstants(const size_t index, std::vector<detid_t> &warningDets) const {
157 throw std::runtime_error("Retrieval of diffractometer constants not "
158 "implemented for scanning instrument");
159 }
160 const auto &spectrumDef = checkAndGetSpectrumDefinition(index);
161 std::vector<size_t> detectorIndicesOnly;
162 std::vector<detid_t> calibratedDets;
163 std::vector<detid_t> uncalibratedDets;
164 std::transform(spectrumDef.cbegin(), spectrumDef.cend(), std::back_inserter(detectorIndicesOnly),
165 [](auto const &pair) { return pair.first; });
166 double difa{0.}, difc{0.}, tzero{0.};
167 for (const auto &detIndex : detectorIndicesOnly) {
168 const auto newDiffConstants = m_detectorInfo.diffractometerConstants(detIndex, calibratedDets, uncalibratedDets);
169 difa += std::get<0>(newDiffConstants);
170 difc += std::get<1>(newDiffConstants);
171 tzero += std::get<2>(newDiffConstants);
172 }
173
174 if (calibratedDets.size() > 0 && uncalibratedDets.size() > 0) {
175 warningDets.insert(warningDets.end(), uncalibratedDets.begin(), uncalibratedDets.end());
176 };
177 // if no calibration is found then return difc only based on the average
178 // of the detector L2 and twoThetas.
179 if (calibratedDets.size() == 0) {
180 return {{UnitParams::difc, difcUncalibrated(index)}};
181 }
182 const auto specDefSize = static_cast<double>(spectrumDefinition(index).size());
183 return {{UnitParams::difa, difa / specDefSize},
184 {UnitParams::difc, difc / specDefSize},
185 {UnitParams::tzero, tzero / specDefSize}};
186}
187
195 std::vector<int> warningDets;
196 return diffractometerConstants(index, warningDets);
197}
198
204double SpectrumInfo::difcUncalibrated(const size_t index) const {
205 // calculate difc based on the average of the detector L2 and twoThetas.
206 // This will be different to the average of the per detector difcs. This is
207 // for backwards compatibility because Mantid always used to calculate
208 // spectrum level difc's this way
210}
211
223void SpectrumInfo::getDetectorValues(const Kernel::Unit &inputUnit, const Kernel::Unit &outputUnit,
224 const Kernel::DeltaEMode::Type emode, const bool signedTheta, int64_t wsIndex,
225 UnitParametersMap &pmap) const {
226 if (!hasDetectors(wsIndex))
227 return;
228 pmap[UnitParams::l2] = l2(wsIndex);
229
230 if (!isMonitor(wsIndex)) {
231 // The scattering angle for this detector (in radians).
232 try {
233 if (signedTheta)
234 pmap[UnitParams::twoTheta] = signedTwoTheta(wsIndex);
235 else
236 pmap[UnitParams::twoTheta] = twoTheta(wsIndex);
237 } catch (const std::runtime_error &e) {
238 g_log.warning(e.what());
239 }
240 if (emode != Kernel::DeltaEMode::Elastic && pmap.find(UnitParams::efixed) == pmap.end()) {
241 std::shared_ptr<const Geometry::IDetector> det(&detector(wsIndex), Mantid::NoDeleting());
242 try {
243 pmap[UnitParams::efixed] = m_experimentInfo.getEFixedGivenEMode(det, emode);
244 g_log.debug() << "Detector: " << det->getID() << " EFixed: " << pmap[UnitParams::efixed] << "\n";
245 } catch (std::runtime_error &) {
246 // let the unit classes work out if this is a problem
247 }
248 }
249
250 try {
251 std::set<std::string> diffConstUnits = {"dSpacing", "MomentumTransfer", "Empty"};
252 if ((emode == Kernel::DeltaEMode::Elastic) &&
253 (diffConstUnits.count(inputUnit.unitID()) || diffConstUnits.count(outputUnit.unitID()))) {
254 std::vector<detid_t> warnDetIds;
255 auto diffConstsMap = diffractometerConstants(wsIndex, warnDetIds);
256 pmap.insert(diffConstsMap.begin(), diffConstsMap.end());
257 if (warnDetIds.size() > 0) {
258 createDetectorIdLogMessages(warnDetIds, wsIndex);
259 }
260 } else {
261 pmap[UnitParams::difc] = difcUncalibrated(wsIndex);
262 }
263 } catch (const std::runtime_error &e) {
264 g_log.warning(e.what());
265 }
266 } else {
267 pmap[UnitParams::twoTheta] = 0.0;
268 pmap[UnitParams::efixed] = std::numeric_limits<double>::min();
269 // Energy transfer is meaningless for a monitor, so set l2 to 0.
270 if (outputUnit.unitID().find("DeltaE") != std::string::npos) {
271 pmap[UnitParams::l2] = 0.0;
272 }
273 pmap[UnitParams::difc] = 0;
274 }
275}
276
277void SpectrumInfo::createDetectorIdLogMessages(const std::vector<detid_t> &detids, int64_t wsIndex) const {
278 std::string detIDstring;
279 auto iter = detids.begin();
280 auto itEnd = detids.end();
281 for (; iter != itEnd; ++iter) {
282 detIDstring += std::to_string(*iter) + ",";
283 }
284
285 if (!detIDstring.empty()) {
286 detIDstring.pop_back(); // Drop last comma
287 }
288 g_log.warning("Incomplete set of calibrated diffractometer constants found for "
289 "workspace index" +
290 std::to_string(wsIndex) + ". Using uncalibrated values for detectors " + detIDstring);
291}
292
295bool SpectrumInfo::hasDetectors(const size_t index) const {
296 // Workspaces can contain invalid detector IDs. Those IDs will be silently
297 // ignored here until this is fixed.
298 return spectrumDefinition(index).size() > 0;
299}
300
302bool SpectrumInfo::hasUniqueDetector(const size_t index) const {
303 // Workspaces can contain invalid detector IDs. Those IDs will be silently
304 // ignored here until this is fixed.
305 return spectrumDefinition(index).size() == 1;
306}
307
311void SpectrumInfo::setMasked(const size_t index, bool masked) {
312 for (const auto &detIndex : checkAndGetSpectrumDefinition(index))
313 m_detectorInfo.setMasked(detIndex, masked);
314}
315
318const Geometry::IDetector &SpectrumInfo::detector(const size_t index) const { return getDetector(index); }
319
322
325
327double SpectrumInfo::l1() const { return m_detectorInfo.l1(); }
328
330 auto thread = static_cast<size_t>(PARALLEL_THREAD_NUMBER);
331 if (m_lastIndex[thread] == index)
332 return *m_lastDetector[thread];
333
334 // Note: This function body has big overlap with the method
335 // MatrixWorkspace::getDetector(). The plan is to eventually remove the
336 // latter, once SpectrumInfo is in widespread use.
337 const auto &specDef = spectrumDefinition(index);
338 const size_t ndets = specDef.size();
339 if (ndets == 1) {
340 // If only 1 detector for the spectrum number, just return it
341 const auto detIndex = specDef[0].first;
342 m_lastDetector[thread] = m_detectorInfo.getDetectorPtr(detIndex);
343 } else if (ndets == 0) {
344 throw Kernel::Exception::NotFoundError("MatrixWorkspace::getDetector(): No "
345 "detectors for this workspace "
346 "index.",
348 } else {
349 // Else need to construct a DetectorGroup and use that
350 std::vector<std::shared_ptr<const Geometry::IDetector>> det_ptrs;
351 for (const auto &specDefIndex : specDef) {
352 const auto detIndex = specDefIndex.first;
353 det_ptrs.emplace_back(m_detectorInfo.getDetectorPtr(detIndex));
354 }
355 m_lastDetector[thread] = std::make_shared<Geometry::DetectorGroup>(det_ptrs);
356 }
357 m_lastIndex[thread] = index;
358 return *m_lastDetector[thread];
359}
360
361const SpectrumDefinition &SpectrumInfo::checkAndGetSpectrumDefinition(const size_t index) const {
362 if (spectrumDefinition(index).size() == 0)
363 throw Kernel::Exception::NotFoundError("SpectrumInfo: No detectors for this workspace index.",
366}
367
368// Begin method for iterator
370
371// End method for iterator
373
375
376// End method for iterator
378
379} // namespace Mantid::API
std::map< DeltaEMode::Type, std::string > index
#define PARALLEL_THREAD_NUMBER
#define PARALLEL_GET_MAX_THREADS
This class is shared by a few Workspace types and holds information related to a particular experimen...
void updateSpectrumDefinitionIfNecessary(const size_t index) const
double getEFixedGivenEMode(const std::shared_ptr< const Geometry::IDetector > &detector, const Kernel::DeltaEMode::Type emode) const
Easy access to the efixed value for this run & detector.
double signedTwoTheta(const size_t index) const
Returns the signed scattering angle 2 theta in radians (angle w.r.t.
SpectrumInfoIterator< SpectrumInfo > end()
bool isMonitor(const size_t index) const
Returns true if the detector(s) associated with the spectrum are monitors.
const Kernel::cow_ptr< std::vector< SpectrumDefinition > > & sharedSpectrumDefinitions() const
Kernel::V3D sourcePosition() const
Returns the source position.
const SpectrumInfoIterator< const SpectrumInfo > cbegin() const
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...
void setMasked(const size_t index, bool masked)
Set the mask flag of the spectrum with given index.
void createDetectorIdLogMessages(const std::vector< detid_t > &detids, int64_t wsIndex) const
Kernel::V3D samplePosition() const
Returns the sample position.
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).
double azimuthal(const size_t index) const
Returns the out-of-plane angle in radians (angle w.r.t.
bool isMasked(const size_t index) const
Returns true if the detector(s) associated with the spectrum are masked.
const SpectrumDefinition & checkAndGetSpectrumDefinition(const size_t index) const
SpectrumInfo(const Beamline::SpectrumInfo &spectrumInfo, const ExperimentInfo &experimentInfo, Geometry::DetectorInfo &detectorInfo)
bool hasUniqueDetector(const size_t index) const
Returns true if the spectrum is associated with exactly one detector.
const ExperimentInfo & m_experimentInfo
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.
size_t size() const
Returns the size of the SpectrumInfo, i.e., the number of spectra.
double l1() const
Returns L1 (distance from source to sample).
const SpectrumInfoIterator< const SpectrumInfo > cend() const
void getDetectorValues(const Kernel::Unit &inputUnit, const Kernel::Unit &outputUnit, const Kernel::DeltaEMode::Type emode, const bool signedTheta, int64_t wsIndex, Kernel::UnitParametersMap &pmap) const
Get the detector values relevant to unit conversion for a workspace index.
Geometry::DetectorInfo & m_detectorInfo
SpectrumInfoIterator< SpectrumInfo > begin()
std::pair< double, double > geographicalAngles(const size_t index) const
Calculate latitude and longitude for given spectrum index.
std::vector< std::shared_ptr< const Geometry::IDetector > > m_lastDetector
std::vector< size_t > m_lastIndex
const Geometry::IDetector & getDetector(const size_t index) const
const Beamline::SpectrumInfo & m_spectrumInfo
Geometry::DetectorInfo is an intermediate step towards a DetectorInfo that is part of Instrument-2....
Kernel::V3D samplePosition() const
Returns the sample position.
std::pair< double, double > geographicalAngles(const size_t index) const
void setMasked(const size_t index, bool masked)
Set the mask flag of the detector with given index. Not thread safe.
double l1() const
Returns L1 (distance from source to sample).
Kernel::V3D sourcePosition() const
Returns the source position.
std::tuple< double, double, double > diffractometerConstants(const size_t index, std::vector< detid_t > &calibratedDets, std::vector< detid_t > &uncalibratedDets) const
bool isScanning() const
Returns true if the beamline has scanning detectors.
std::shared_ptr< const Geometry::IDetector > getDetectorPtr(const size_t index) const
Helper used by SpectrumInfo.
Interface class for detector objects.
Definition IDetector.h:43
Exception for when an item is not found in a collection.
Definition Exception.h:145
The Logger class is in charge of the publishing messages from the framework through various channels.
Definition Logger.h:51
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
The base units (abstract) class.
Definition Unit.h:41
virtual const std::string unitID() const =0
The name of the unit.
Class for 3D vectors.
Definition V3D.h:34
Implements a copy on write data template.
Definition cow_ptr.h:41
An object for constructing a shared_ptr that won't ever delete its pointee.
Definition IComponent.h:172
Kernel::Logger g_log("ExperimentInfo")
static logger object
SpectrumInfoIterator< const SpectrumInfo > SpectrumInfoConstIt
SpectrumInfoIterator< SpectrumInfo > SpectrumInfoIt
MANTID_KERNEL_DLL double tofToDSpacingFactor(const double l1, const double l2, const double twoTheta, const double offset)
Calculate and return conversion factor from tof to d-spacing.
Definition Unit.cpp:589
std::unordered_map< UnitParams, double > UnitParametersMap
Definition Unit.h:30
Generate a tableworkspace to store the calibration results.
std::string to_string(const wide_integer< Bits, Signed > &n)
Type
Define the available energy transfer modes It is important to assign enums proper numbers,...
Definition DeltaEMode.h:29