Mantid
Loading...
Searching...
No Matches
Instrument.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#include "MantidBeamline/ComponentInfo.h"
9#include "MantidBeamline/DetectorInfo.h"
25#include "MantidKernel/Logger.h"
27#include "MantidKernel/Unit.h"
28#include "MantidNexus/NexusFile.h"
29
30#include <algorithm>
31#include <memory>
32#include <queue>
33#include <utility>
34
35using namespace Mantid::Kernel;
38
39namespace Mantid::Geometry {
40
41namespace {
42Kernel::Logger g_log("Instrument");
43
44void raiseDuplicateDetectorError(const size_t detectorId) {
45 std::stringstream sstream;
46 sstream << "Instrument Definition corrupt. Detector with ID " << detectorId << " already exists.";
47 throw Exception::InstrumentDefinitionError(sstream.str());
48}
49
51size_t componentObjectSize(const IComponent *comp) {
52 size_t result;
53 if (dynamic_cast<const RectangularDetector *>(comp))
54 result = sizeof(RectangularDetector);
55 else if (const auto *sd = dynamic_cast<const StructuredDetector *>(comp))
56 result = sizeof(StructuredDetector) + sd->getXValues().capacity() * sizeof(double) +
57 sd->getYValues().capacity() * sizeof(double);
58 else if (dynamic_cast<const GridDetectorPixel *>(comp))
59 result = sizeof(GridDetectorPixel);
60 else if (dynamic_cast<const GridDetector *>(comp))
61 result = sizeof(GridDetector);
62 else if (dynamic_cast<const Detector *>(comp))
63 result = sizeof(Detector);
64 else if (dynamic_cast<const ObjCompAssembly *>(comp))
65 result = sizeof(ObjCompAssembly);
66 else if (dynamic_cast<const ObjComponent *>(comp))
67 result = sizeof(ObjComponent);
68 else if (dynamic_cast<const CompAssembly *>(comp))
69 result = sizeof(CompAssembly);
70 else
71 result = sizeof(Component);
72 return result;
73}
74} // namespace
75
78 : CompAssembly(), m_detectorCache(), m_sourceCache(nullptr), m_sampleCache(nullptr), m_defaultView("3D"),
79 m_defaultViewAxis("Z+"), m_referenceFrame(new ReferenceFrame) {}
80
82Instrument::Instrument(const std::string &name)
83 : CompAssembly(name), m_detectorCache(), m_sourceCache(nullptr), m_sampleCache(nullptr), m_defaultView("3D"),
84 m_defaultViewAxis("Z+"), m_referenceFrame(new ReferenceFrame) {}
85
90Instrument::Instrument(const std::shared_ptr<const Instrument> &instr, const std::shared_ptr<ParameterMap> &map)
91 : CompAssembly(instr.get(), map.get()), m_sourceCache(instr->m_sourceCache), m_sampleCache(instr->m_sampleCache),
92 m_defaultView(instr->m_defaultView), m_defaultViewAxis(instr->m_defaultViewAxis), m_instr(instr),
93 m_map_nonconst(map), m_ValidFrom(instr->m_ValidFrom), m_ValidTo(instr->m_ValidTo),
94 m_referenceFrame(new ReferenceFrame) {
95 // Note that we do not copy m_detectorInfo and m_componentInfo into the parametrized instrument since the ParameterMap
96 // will make a copy, if applicable.
97}
98
104 : CompAssembly(instr), m_sourceCache(nullptr), m_sampleCache(nullptr), /* Should only be temporarily null */
105 m_logfileCache(instr.m_logfileCache), m_logfileUnit(instr.m_logfileUnit), m_defaultView(instr.m_defaultView),
106 m_defaultViewAxis(instr.m_defaultViewAxis), m_instr(), m_map_nonconst(), /* Should not be parameterized */
107 m_ValidFrom(instr.m_ValidFrom), m_ValidTo(instr.m_ValidTo), m_referenceFrame(instr.m_referenceFrame) {
108 // Note that we do not copy m_detectorInfo and m_componentInfo into the new instrument since they are only non-NULL
109 // for the base instrument, which should usually not be copied.
110
111 // Now we need to fill the detector, source and sample caches with pointers into the new instrument
112 std::vector<IComponent_const_sptr> children;
113 getChildren(children, true);
114 std::vector<IComponent_const_sptr>::const_iterator it;
115 for (it = children.begin(); it != children.end(); ++it) {
116 // First check if the current component is a detector and add to cache if it is
117 if (const IDetector *det = dynamic_cast<const Detector *>(it->get())) {
118 if (instr.isMonitor(det->getID()))
119 markAsMonitor(det);
120 else
121 markAsDetector(det);
122 continue;
123 }
124 // Now check whether the current component is the source or sample.
125 // As the majority of components will be detectors, we will rarely get to here
126 if (const auto *obj = dynamic_cast<const Component *>(it->get())) {
127 const std::string objName = obj->getName();
128 // This relies on the source and sample having a unique name. I think the way our instrument definition files work
129 // ensures this is the case.
130 if (objName == instr.m_sourceCache->getName()) {
132 continue;
133 }
134 if (objName == instr.m_sampleCache->getName()) {
136 continue;
137 }
138 }
139 }
140}
141
149Instrument::Instrument(const Instrument &instr, bool copyCache)
150 : CompAssembly(), m_sourceCache(nullptr), m_sampleCache(nullptr), /* Should only be temporarily null */
151 m_logfileCache(instr.m_logfileCache), m_logfileUnit(instr.m_logfileUnit), m_defaultView(instr.m_defaultView),
152 m_defaultViewAxis(instr.m_defaultViewAxis), m_instr(), m_map_nonconst(), /* Should not be parameterized */
153 m_ValidFrom(instr.m_ValidFrom), m_ValidTo(instr.m_ValidTo), m_referenceFrame(instr.m_referenceFrame) {
154 UNUSED_ARG(copyCache);
155 setName(instr.getName() + "_clone");
156 // add in the sample and the source
157 auto sampleComp = instr.getSample();
158 auto sourceComp = instr.getSource();
159 if (!sampleComp || !sourceComp) {
160 throw std::runtime_error("Cannot copy instrument: source instrument must have valid sample and source components");
161 }
162 auto sample = sampleComp->clone();
163 auto source = sourceComp->clone();
164 add(sample);
165 add(source);
166 markAsSource(source);
167 markAsSamplePos(sample);
168 // also add in the monitors
169 std::vector<IComponent_const_sptr> children;
170 instr.getChildren(children, true);
171 for (auto const &child : children) {
172 if (IDetector const *det = dynamic_cast<Detector const *>(child.get())) {
173 if (instr.isMonitor(det->getID())) {
174 auto dclone = dynamic_cast<IDetector *>(det->clone());
175 add(dclone);
176 markAsMonitor(dclone);
177 }
178 }
179 }
180}
181
183Instrument *Instrument::clone() const { return new Instrument(*this); }
184
187 if (m_map)
188 return m_instr;
189 else
190 throw std::runtime_error("Instrument::baseInstrument() called for a "
191 "non-parametrized instrument.");
192}
193
200 if (m_map)
201 return m_map_nonconst;
202 else
203 throw std::runtime_error("Instrument::getParameterMap() called for a "
204 "non-parametrized instrument.");
205}
206
214 if (m_map) {
215 if (m_instr->getPhysicalInstrument()) {
216 // A physical instrument should use the same parameter map as the 'main'
217 // instrument. This constructor automatically sets the instrument as the
218 // owning instrument in the ParameterMap. We need to undo this immediately
219 // since the ParameterMap must always be owned by the neutronic
220 // instrument.
221 return std::make_shared<Instrument>(m_instr->getPhysicalInstrument(), m_map_nonconst);
222 } else {
223 return Instrument_const_sptr();
224 }
225 } else {
227 }
228}
229
235void Instrument::setPhysicalInstrument(std::unique_ptr<Instrument> physInst) {
236 if (!m_map) {
237 physInst->m_isPhysicalInstrument = true;
238 m_physicalInstrument = std::move(physInst);
239 } else
240 throw std::runtime_error("Instrument::setPhysicalInstrument() called on a "
241 "parametrized instrument.");
242}
243
244//------------------------------------------------------------------------------------------
248 out_map.clear();
249 auto it = out_map.end();
250 if (m_map) {
251 // Get the base instrument detectors
252 const auto &in_dets = m_instr->m_detectorCache;
253 // And turn them into parametrized versions
254 for (const auto &in_det : in_dets) {
255 it = out_map.emplace_hint(it, in_det.id(), ParComponentFactory::createDetector(in_det.detector().get(), m_map));
256 }
257 } else {
258 // You can just return the detector cache directly.
259 for (const auto &in_det : m_detectorCache) {
260 it = out_map.emplace_hint(it, in_det.id(), in_det.detector());
261 }
262 }
263}
264
265//------------------------------------------------------------------------------------------
267std::vector<detid_t> Instrument::getDetectorIDs(bool skipMonitors) const {
268 const auto &in_dets = m_map ? m_instr->m_detectorCache : m_detectorCache;
269 std::vector<detid_t> out;
270 out.reserve(in_dets.size());
271 for (const auto &in_det : in_dets) {
272 if (!skipMonitors || !in_det.isMonitor()) {
273 out.emplace_back(in_det.id());
274 }
275 }
276 return out;
277}
278
282std::vector<detid_t> Instrument::getMonitorIDs() const {
283 // Monitors cannot be parametrized. So just return the base.
284 if (m_map)
285 return m_instr->getMonitorIDs();
286
287 std::vector<detid_t> mons;
288 for (const auto &item : m_detectorCache)
289 if (item.isMonitor())
290 mons.emplace_back(item.id());
291 return mons;
292}
293
295std::size_t Instrument::getNumberDetectors(bool skipMonitors) const {
296 const auto &in_dets = m_map ? m_instr->m_detectorCache : m_detectorCache;
297
298 if (skipMonitors) {
299 const std::size_t monitors =
300 std::count_if(in_dets.cbegin(), in_dets.cend(), [](const auto &in_det) { return in_det.isMonitor(); });
301 return (in_dets.size() - monitors);
302 } else {
303 return in_dets.size();
304 }
305}
306
314 const auto &in_dets = m_map ? m_instr->m_detectorCache : m_detectorCache;
315 // ensure there are detectors
316 if (in_dets.empty())
317 throw std::runtime_error("No detectors on this instrument. Can't find min/max ids");
318 // ensure the cache is finalized
319 if (!in_dets.isFinalized())
320 throw std::runtime_error("Instrument definition is not finalized. Can't find min/max ids");
321 min = in_dets.minID();
322 max = in_dets.maxID();
323}
324
334void Instrument::getDetectorsInBank(std::vector<IDetector_const_sptr> &dets, const IComponent &comp) const {
335 const auto bank = dynamic_cast<const ICompAssembly *>(&comp);
336 if (bank) {
337 // Get a vector of children (recursively)
338 std::vector<std::shared_ptr<const IComponent>> children;
339 bank->getChildren(children, true);
340 std::vector<std::shared_ptr<const IComponent>>::iterator it;
341 for (it = children.begin(); it != children.end(); ++it) {
342 IDetector_const_sptr det = std::dynamic_pointer_cast<const IDetector>(*it);
343 if (det) {
344 dets.emplace_back(det);
345 }
346 }
347 }
348}
349
360void Instrument::getDetectorsInBank(std::vector<IDetector_const_sptr> &dets, const std::string &bankName) const {
361 std::shared_ptr<const IComponent> comp = this->getComponentByName(bankName);
362 if (!comp) {
363 throw Kernel::Exception::NotFoundError("Instrument: Could not find component", bankName);
364 }
365 getDetectorsInBank(dets, *comp);
366}
367
368std::set<detid_t> Instrument::getDetectorIDsInBank(const std::string &bankName) const {
369 std::set<detid_t> detIDs;
370 std::vector<IDetector_const_sptr> detectors;
371 getDetectorsInBank(detectors, bankName);
372
373 for (const auto &det : detectors) {
374 detIDs.emplace(det->getID());
375 }
376 return detIDs;
377}
378
382bool Instrument::hasSource() const { return m_sourceCache; }
383
387bool Instrument::hasSample() const { return m_sampleCache; }
388
393 if (!m_sourceCache) {
394 g_log.warning("In Instrument::getSource(). No source has been set.");
396 } else if (m_map) {
397 auto sourceCache = static_cast<const Instrument *>(m_base)->m_sourceCache;
398 if (dynamic_cast<const ObjComponent *>(sourceCache))
399 return IComponent_const_sptr(new ObjComponent(sourceCache, m_map));
400 else if (dynamic_cast<const CompAssembly *>(sourceCache))
401 return IComponent_const_sptr(new CompAssembly(sourceCache, m_map));
402 else if (dynamic_cast<const Component *>(sourceCache))
403 return IComponent_const_sptr(new Component(sourceCache, m_map));
404 else {
405 g_log.error("In Instrument::getSource(). Source is not a recognised "
406 "component type.");
407 g_log.error("Try to assume it is a Component.");
408 return IComponent_const_sptr(new ObjComponent(sourceCache, m_map));
409 }
410 } else {
412 }
413}
414
419 if (!m_sampleCache) {
420 g_log.warning("In Instrument::getSamplePos(). No SamplePos has been set.");
422 } else if (m_map) {
423 auto sampleCache = static_cast<const Instrument *>(m_base)->m_sampleCache;
424 if (dynamic_cast<const ObjComponent *>(sampleCache))
425 return IComponent_const_sptr(new ObjComponent(sampleCache, m_map));
426 else if (dynamic_cast<const CompAssembly *>(sampleCache))
427 return IComponent_const_sptr(new CompAssembly(sampleCache, m_map));
428 else if (dynamic_cast<const Component *>(sampleCache))
429 return IComponent_const_sptr(new Component(sampleCache, m_map));
430 else {
431 g_log.error("In Instrument::getSamplePos(). SamplePos is not a "
432 "recognised component type.");
433 g_log.error("Try to assume it is a Component.");
434 return IComponent_const_sptr(new ObjComponent(sampleCache, m_map));
435 }
436 } else {
438 }
439}
440
446
447//------------------------------------------------------------------------------------------
452std::shared_ptr<const IComponent> Instrument::getComponentByID(const IComponent *id) const {
453 const auto *base = static_cast<const IComponent *>(id);
454 if (m_map)
455 return ParComponentFactory::create(std::shared_ptr<const IComponent>(base, NoDeleting()), m_map);
456 else
457 return std::shared_ptr<const IComponent>(base, NoDeleting());
458}
459
468std::vector<std::shared_ptr<const IComponent>> Instrument::getAllComponentsWithName(const std::string &cname) const {
469 std::shared_ptr<const IComponent> node = std::shared_ptr<const IComponent>(this, NoDeleting());
470 std::vector<std::shared_ptr<const IComponent>> retVec;
471 // Check the instrument name first
472 if (this->getName() == cname) {
473 retVec.emplace_back(node);
474 }
475 // Same algorithm as used in getComponentByName() but searching the full tree
476 std::deque<std::shared_ptr<const IComponent>> nodeQueue;
477 // Need to be able to enter the while loop
478 nodeQueue.emplace_back(node);
479 while (!nodeQueue.empty()) {
480 node = nodeQueue.front();
481 nodeQueue.pop_front();
482 int nchildren(0);
483 std::shared_ptr<const ICompAssembly> asmb = std::dynamic_pointer_cast<const ICompAssembly>(node);
484 if (asmb) {
485 nchildren = asmb->nelements();
486 }
487 for (int i = 0; i < nchildren; ++i) {
488 std::shared_ptr<const IComponent> comp = (*asmb)[i];
489 if (comp->getName() == cname) {
490 retVec.emplace_back(comp);
491 } else {
492 nodeQueue.emplace_back(comp);
493 }
494 }
495 } // while-end
496
497 // If we have reached here then the search failed
498 return retVec;
499}
500
509Instrument::DetectorCache::iterator Instrument::DetectorCache::lower_bound(detid_t id) {
510 if (!isFinalized()) {
511 throw std::runtime_error("lower_bound() called on non-finalized DetectorCache");
512 }
513 return std::lower_bound(begin(), end(), id,
514 [](DetectorCacheEntry const &entry, detid_t id) { return entry.id() < id; });
515}
516
526Instrument::DetectorCache::const_iterator Instrument::DetectorCache::lower_bound(detid_t id) const {
527 if (!isFinalized()) {
528 throw std::runtime_error("lower_bound() called on non-finalized DetectorCache");
529 }
530 return std::lower_bound(cbegin(), cend(), id,
531 [](DetectorCacheEntry const &entry, detid_t id) { return entry.id() < id; });
532}
533
541Instrument::DetectorCache::iterator Instrument::DetectorCache::find(detid_t id) {
542 if (!isFinalized()) {
543 throw std::runtime_error("find() called on non-finalized DetectorCache");
544 }
545 auto it = lower_bound(id);
546 if (it != end() && it->id() == id) {
547 return it;
548 } else {
549 return end();
550 }
551}
552
560Instrument::DetectorCache::const_iterator Instrument::DetectorCache::find(detid_t id) const {
561 if (!isFinalized()) {
562 throw std::runtime_error("find() called on non-finalized DetectorCache");
563 }
564 auto const it = lower_bound(id);
565 if (it != cend() && it->id() == id) {
566 return it;
567 } else {
568 return cend();
569 }
570}
571
581 // ensure instrument is finalized
582 if (!isFinalized())
583 throw std::runtime_error("Instrument definition is not finalized. Can't search for detector ID " +
584 std::to_string(detector_id));
585
586 const auto &in_dets = m_map ? m_instr->m_detectorCache : m_detectorCache;
587 const auto it = in_dets.find(detector_id);
588 if (it == in_dets.end()) {
589 std::stringstream readInt;
590 readInt << detector_id;
591 throw Kernel::Exception::NotFoundError("Instrument: Detector with ID " + readInt.str() + " not found.", "");
592 }
593 IDetector_const_sptr baseDet = it->detector();
594
595 if (!m_map)
596 return baseDet;
597
598 auto det = ParComponentFactory::createDetector(baseDet.get(), m_map);
599 return det;
600}
601
607const IDetector *Instrument::getBaseDetector(const detid_t &detector_id) const {
608 // ensure instrument is finalized
609 if (!m_map)
610 throw std::runtime_error("Instrument::getBaseDetector() called on a non-parametrized instrument.");
611 if (!isFinalized())
612 throw std::runtime_error("Instrument definition is not finalized. Can't find base detector ID " +
613 std::to_string(detector_id));
614
615 auto it = m_instr->m_detectorCache.find(detector_id);
616 if (it == m_instr->m_detectorCache.end()) {
617 return nullptr;
618 }
619 return it->detector().get();
620}
621
622bool Instrument::isMonitor(const detid_t &detector_id) const {
623 // ensure instrument is finalized
624 if (!isFinalized())
625 throw std::runtime_error("Instrument definition is not finalized. Can't search for monitor ID " +
626 std::to_string(detector_id));
627
628 const auto &in_dets = m_map ? m_instr->m_detectorCache : m_detectorCache;
629 const auto it = in_dets.find(detector_id);
630 if (it == in_dets.end())
631 return false;
632 return it->isMonitor();
633}
634
635bool Instrument::isMonitor(const std::set<detid_t> &detector_ids) const {
636 if (detector_ids.empty())
637 return false;
638
639 return std::any_of(detector_ids.cbegin(), detector_ids.cend(),
640 [this](const auto detector_id) { return isMonitor(detector_id); });
641}
642
649IDetector_const_sptr Instrument::getDetectorG(const std::set<detid_t> &det_ids) const {
650 const size_t ndets(det_ids.size());
651 if (ndets == 1) {
652 return this->getDetector(*det_ids.begin());
653 } else {
654 std::shared_ptr<DetectorGroup> det_group = std::make_shared<DetectorGroup>();
655 for (const auto detID : det_ids) {
656 det_group->addDetector(this->getDetector(detID));
657 }
658 return det_group;
659 }
660}
661
666std::vector<IDetector_const_sptr> Instrument::getDetectors(const std::vector<detid_t> &det_ids) const {
667 std::vector<IDetector_const_sptr> dets_ptr;
668 dets_ptr.reserve(det_ids.size());
669 std::vector<detid_t>::const_iterator it;
670 for (it = det_ids.begin(); it != det_ids.end(); ++it) {
671 dets_ptr.emplace_back(this->getDetector(*it));
672 }
673 return dets_ptr;
674}
675
680std::vector<IDetector_const_sptr> Instrument::getDetectors(const std::set<detid_t> &det_ids) const {
681 std::vector<IDetector_const_sptr> dets_ptr;
682 dets_ptr.reserve(det_ids.size());
683 std::set<detid_t>::const_iterator it;
684 for (it = det_ids.begin(); it != det_ids.end(); ++it) {
685 dets_ptr.emplace_back(this->getDetector(*it));
686 }
687 return dets_ptr;
688}
689
701 if (m_map)
702 throw std::runtime_error("Instrument::markAsSamplePos() called on a "
703 "parametrized Instrument object.");
704
705 auto objComp = dynamic_cast<const IObjComponent *>(comp);
706 if (objComp) {
707 throw std::runtime_error("Instrument::markAsSamplePos() called on an IObjComponent "
708 "object that supports shape definition. Sample is prevented from "
709 "being this type because the shape must only be stored in "
710 "ExperimentInfo::m_sample.");
711 }
712
713 if (!m_sampleCache) {
714 if (comp->getName().empty()) {
715 throw Exception::InstrumentDefinitionError("The sample component is required to have a name.");
716 }
717 m_sampleCache = comp;
718 } else {
719 g_log.warning("Have already added samplePos component to the _sampleCache.");
720 }
721}
722
734 if (m_map)
735 throw std::runtime_error("Instrument::markAsSource() called on a "
736 "parametrized Instrument object.");
737
738 if (!m_sourceCache) {
739 if (comp->getName().empty()) {
740 throw Exception::InstrumentDefinitionError("The source component is required to have a name.");
741 }
742 m_sourceCache = comp;
743 } else {
744 g_log.warning("Have already added source component to the _sourceCache.");
745 }
746}
747
757 if (m_map)
758 throw std::runtime_error("Instrument::markAsDetector() called on a "
759 "parametrized Instrument object.");
760 // ensure instrument is finalized
761 if (!isFinalized())
762 throw std::runtime_error("Instrument definition is not finalized. Add detector with markAsDetectorIncomplete, "
763 "then call markAsDetectorFinalized when finished.");
764
765 // Duplicate detector ids are forbidden
766 auto it = m_detectorCache.lower_bound(det->getID());
767 if ((it != m_detectorCache.end()) && (it->id() == det->getID())) {
768 raiseDuplicateDetectorError(det->getID());
769 }
770 // Create a (non-deleting) shared pointer to it
772 m_detectorCache.emplace(it, det->getID(), det_sptr, false);
773}
774
778 if (m_map)
779 throw std::runtime_error("Instrument::markAsDetector() called on a "
780 "parametrized Instrument object.");
781
783 // Create a (non-deleting) shared pointer to it
785 m_detectorCache.emplace_back(det->getID(), det_sptr, false);
786}
787
791 // We're already finalized! We can't finalize any further!
792 if (isFinalized())
793 return;
794
795 // Detectors (even when different objects) are NOT allowed to have duplicate
796 // ids. This method establishes the presence of duplicates.
797 std::sort(m_detectorCache.begin(), m_detectorCache.end(),
798 [](DetectorCacheEntry const &a, DetectorCacheEntry const &b) -> bool { return a.id() < b.id(); });
799
800 auto resultIt = std::adjacent_find(
801 m_detectorCache.begin(), m_detectorCache.end(),
802 [](DetectorCacheEntry const &a, DetectorCacheEntry const &b) -> bool { return a.id() == b.id(); });
803 if (resultIt != m_detectorCache.end()) {
804 raiseDuplicateDetectorError(resultIt->id());
805 } else {
807 }
808}
809
819 if (m_map)
820 throw std::runtime_error("Instrument::markAsMonitor() called on a "
821 "parametrized Instrument object.");
822 if (!isFinalized()) {
823 throw std::runtime_error("Instrument definition is not finalized. Add monitor with markAsMonitorIncomplete, then "
824 "call markAsDetectorFinalized when finished.");
825 }
826
827 // attempt to add monitor to instrument detector cache
828 markAsDetector(det);
829
830 // mark detector as a monitor
831 auto it = m_detectorCache.find(det->getID());
832 it->setIsMonitor(true);
833}
834
842 if (m_map)
843 throw std::runtime_error("Instrument::markAsMonitorIncomplete() called on a "
844 "parametrized Instrument object.");
845
847 // Create a (non-deleting) shared pointer to it
849 m_detectorCache.emplace_back(det->getID(), det_sptr, true);
850}
851
858 if (m_map)
859 throw std::runtime_error("Instrument::removeDetector() called on a "
860 "parameterized Instrument object.");
861 if (!isFinalized())
862 throw std::runtime_error("Instrument definition is not finalized. Can't remove detector with ID " +
863 std::to_string(det->getID()));
864
865 const detid_t id = det->getID();
866 // Remove the detector from the detector cache
867 const auto it = m_detectorCache.find(id);
868 // NOTE this operation is O(N) for the vector cache
869 m_detectorCache.erase(it);
870
871 // Remove it from the parent assembly (and thus the instrument).
872 // Evilness required here unfortunately.
873 auto *parentAssembly = dynamic_cast<CompAssembly *>(const_cast<IComponent *>(det->getBareParent()));
874 if (parentAssembly) // Should always be true, but check just in case
875 {
876 parentAssembly->remove(det);
877 }
878}
879
888 if (m_map)
889 throw std::runtime_error("Instrument::removeDetectorIncomplete() called on a "
890 "parameterized Instrument object.");
892 if (m_detectorCache.m_toRemove.empty()) {
894 }
895 m_detectorCache.m_toRemove.insert(det);
896}
897
903 if (m_map)
904 throw std::runtime_error("Instrument::removeDetectorFinalize() called on a "
905 "parameterized Instrument object.");
906
907 if (isFinalized()) {
909 return;
910 }
911
912 // Remove from the cache all the ones to be removed
913 auto newEnd = std::remove_if(m_detectorCache.begin(), m_detectorCache.end(), [this](const auto &entry) {
914 return m_detectorCache.m_toRemove.contains(entry.detector().get());
915 });
916 m_detectorCache.erase(newEnd, m_detectorCache.end());
917
918 // clear the removal set and finalize the cache
921}
922
928void Instrument::getBoundingBox(BoundingBox &assemblyBox) const {
929 if (m_map) {
930
931 if (m_map->hasComponentInfo(this->baseInstrument().get())) {
932 assemblyBox = m_map->componentInfo().boundingBox(index(), &assemblyBox);
933 return;
934 }
935
936 // Loop over the children and define a box large enough for all of them
937 ComponentID sourceID = getSource()->getComponentID();
938 assemblyBox = BoundingBox(); // this makes the instrument BB always axis aligned
939 int nchildren = nelements();
940 for (int i = 0; i < nchildren; ++i) {
941 IComponent_sptr comp = this->getChild(i);
942 if (comp && comp->getComponentID() != sourceID) {
943 BoundingBox compBox;
944 comp->getBoundingBox(compBox);
945 assemblyBox.grow(compBox);
946 }
947 }
948 } else {
949
950 if (!m_cachedBoundingBox) {
952 ComponentID sourceID = getSource()->getComponentID();
953 // Loop over the children and define a box large enough for all of them
954 for (const auto component : m_children) {
955 BoundingBox compBox;
956 if (component && component->getComponentID() != sourceID) {
957 component->getBoundingBox(compBox);
958 m_cachedBoundingBox->grow(compBox);
959 }
960 }
961 }
962 // Use cached box
963 assemblyBox = *m_cachedBoundingBox;
964 }
965}
966
967std::shared_ptr<const std::vector<IObjComponent_const_sptr>> Instrument::getPlottable() const {
968 if (m_map) {
969 // Get the 'base' plottable components
970 std::shared_ptr<const std::vector<IObjComponent_const_sptr>> objs = m_instr->getPlottable();
971
972 // Get a reference to the underlying vector, casting away the constness so that we
973 // can modify it to get our result rather than creating another long vector
974 auto &res = const_cast<std::vector<IObjComponent_const_sptr> &>(*objs);
975 const std::vector<IObjComponent_const_sptr>::size_type total = res.size();
976 for (std::vector<IObjComponent_const_sptr>::size_type i = 0; i < total; ++i) {
977 res[i] = std::dynamic_pointer_cast<const Detector>(ParComponentFactory::create(objs->at(i), m_map));
978 }
979 return objs;
980
981 } else {
982 // Base instrument
983 auto res = std::make_shared<std::vector<IObjComponent_const_sptr>>();
984 res->reserve(m_detectorCache.size() + 10);
985 appendPlottable(*this, *res);
986 return res;
987 }
988}
989
990void Instrument::appendPlottable(const CompAssembly &ca, std::vector<IObjComponent_const_sptr> &lst) const {
991 for (int i = 0; i < ca.nelements(); i++) {
992 IComponent *c = ca[i].get();
993 const auto *a = dynamic_cast<CompAssembly *>(c);
994 if (a)
995 appendPlottable(*a, lst);
996 else {
997 auto *d = dynamic_cast<Detector *>(c);
998 auto *o = dynamic_cast<ObjComponent *>(c);
999 if (d)
1000 lst.emplace_back(IObjComponent_const_sptr(d, NoDeleting()));
1001 else if (o)
1002 lst.emplace_back(IObjComponent_const_sptr(o, NoDeleting()));
1003 else
1004 g_log.error() << "Unknown comp type\n";
1005 }
1006 }
1007}
1008
1009//------------------------------------------------------------------------------------------------
1018void Instrument::getInstrumentParameters(double &l1, Kernel::V3D &beamline, double &beamline_norm,
1019 Kernel::V3D &samplePos) const {
1020 // Get some positions
1021 const IComponent_const_sptr sourceObj = this->getSource();
1022 if (sourceObj == nullptr) {
1023 throw Exception::InstrumentDefinitionError("Failed to get source component from instrument");
1024 }
1025 const Kernel::V3D sourcePos = sourceObj->getPos();
1026 samplePos = this->getSample()->getPos();
1027 beamline = samplePos - sourcePos;
1028 beamline_norm = 2.0 * beamline.norm();
1029
1030 // Get the distance between the source and the sample (assume in metres)
1031 IComponent_const_sptr sample = this->getSample();
1032 try {
1033 l1 = this->getSource()->getDistance(*sample);
1034 } catch (Exception::NotFoundError &) {
1035 throw Exception::InstrumentDefinitionError("Unable to calculate source-sample distance ", this->getName());
1036 }
1037}
1038
1039//--------------------------------------------------------------------------------------------
1042void Instrument::setFilename(const std::string &filename) {
1043 if (m_map)
1044 m_instr->m_filename = filename;
1045 else
1046 m_filename = filename;
1047}
1048
1051const std::string &Instrument::getFilename() const {
1052 if (m_map)
1053 return m_instr->getFilename();
1054 else
1055 return m_filename;
1056}
1057
1059void Instrument::setXmlText(const std::string &XmlText) {
1060 if (m_map)
1061 m_instr->m_xmlText = XmlText;
1062 else
1063 m_xmlText = XmlText;
1064}
1065
1067const std::string &Instrument::getXmlText() const {
1068 if (m_map)
1069 return m_instr->getXmlText();
1070 else
1071 return m_xmlText;
1072}
1073
1074//--------------------------------------------------------------------------------------------
1083void Instrument::saveNexus(Nexus::File *file, const std::string &group) const {
1084 file->makeGroup(group, "NXinstrument", true);
1085 file->putAttr("version", 1);
1086
1087 file->writeData("name", getName());
1088
1089 // XML contents of instrument, as a NX note
1090 file->makeGroup("instrument_xml", "NXnote", true);
1091 const std::string &xmlText = getXmlText();
1092 if (xmlText.empty())
1093 g_log.warning() << "Saving Instrument with no XML data. If this was "
1094 "instrument data you may not be able to load this data "
1095 "back into Mantid, for fitted/analysed data this "
1096 "warning can be ignored.\n";
1097 file->writeData("data", xmlText);
1098 file->writeData("type", "text/xml"); // mimetype
1099 file->writeData("description", "XML contents of the instrument IDF file.");
1100 file->closeGroup();
1101
1102 // Now the parameter map, as a NXnote via its saveNexus method
1103 if (isParametrized()) {
1104 // Map with data extracted from DetectorInfo -> legacy compatible files.
1105 const auto &params = makeLegacyParameterMap();
1106 params->saveNexus(file, "instrument_parameter_map");
1107 }
1108
1109 // Add physical detector data
1110 auto detectorIDs = getDetectorIDs(true);
1111 if (!detectorIDs.empty()) {
1112 // Add detectors group
1113 file->makeGroup("physical_detectors", "NXdetector", true);
1114 file->writeData("number_of_detectors", uint64_t(detectorIDs.size()));
1115 saveDetectorSetInfoToNexus(file, detectorIDs);
1116 file->closeGroup(); // detectors
1117 }
1118
1119 // Add monitor data
1120 auto monitorIDs = getMonitorIDs();
1121 if (!monitorIDs.empty()) {
1122 // Add Monitors group
1123 file->makeGroup("physical_monitors", "NXmonitor", true);
1124 file->writeData("number_of_monitors", uint64_t(monitorIDs.size()));
1125 saveDetectorSetInfoToNexus(file, monitorIDs);
1126 file->closeGroup(); // monitors
1127 }
1128
1129 file->closeGroup();
1130}
1131
1132/* A private helper function so save information about a set of detectors to
1133 * Nexus
1134 * @param file :: open Nexus file ready to recieve the info about the set of
1135 * detectors
1136 * a group must be open that has only one call of this function.
1137 * @param detIDs :: the dectector IDs of the detectors belonging to the set
1138 */
1139void Instrument::saveDetectorSetInfoToNexus(Nexus::File *file, const std::vector<detid_t> &detIDs) const {
1140
1141 size_t nDets = detIDs.size();
1142 if (nDets == 0)
1143 return;
1144 auto detectors = getDetectors(detIDs);
1145
1147 Kernel::V3D sample_pos;
1148 if (sample)
1149 sample_pos = sample->getPos();
1150
1151 std::vector<double> a_angles(nDets);
1152 std::vector<double> p_angles(nDets);
1153 std::vector<double> distances(nDets);
1154
1155 for (size_t i = 0; i < nDets; i++) {
1156 if (sample) {
1157 Kernel::V3D pos = detectors[i]->getPos() - sample_pos;
1158 pos.getSpherical(distances[i], p_angles[i], a_angles[i]);
1159 } else {
1160 a_angles[i] = detectors[i]->getPhi() * 180.0 / M_PI;
1161 }
1162 }
1163 file->writeData("detector_number", detIDs);
1164 file->writeData("azimuthal_angle", a_angles);
1165 file->openData("azimuthal_angle");
1166 file->putAttr("units", "degree");
1167 file->closeData();
1168 if (sample) {
1169 file->writeData("polar_angle", p_angles);
1170 file->openData("polar_angle");
1171 file->putAttr("units", "degree");
1172 file->closeData();
1173 file->writeData("distance", distances);
1174 file->openData("distance");
1175 file->putAttr("units", "metre");
1176 file->closeData();
1177 }
1178}
1179
1180//--------------------------------------------------------------------------------------------
1185void Instrument::loadNexus(Nexus::File *file, const std::string &group) {
1186 file->openGroup(group, "NXinstrument");
1187 file->closeGroup();
1188}
1189
1194void Instrument::setReferenceFrame(std::shared_ptr<ReferenceFrame> frame) { m_referenceFrame = std::move(frame); }
1195
1200std::shared_ptr<const ReferenceFrame> Instrument::getReferenceFrame() const {
1201 if (m_map) {
1202 return m_instr->getReferenceFrame();
1203 } else {
1204 return m_referenceFrame;
1205 }
1206}
1207
1216void Instrument::setDefaultView(const std::string &type) {
1217 std::string typeUC(type);
1218 std::transform(typeUC.begin(), typeUC.end(), typeUC.begin(), toupper);
1219 if (typeUC == "3D" || typeUC == "CYLINDRICAL_X" || typeUC == "CYLINDRICAL_Y" || typeUC == "CYLINDRICAL_Z" ||
1220 typeUC == "SPHERICAL_X" || typeUC == "SPHERICAL_Y" || typeUC == "SPHERICAL_Z") {
1221 m_defaultView = typeUC;
1222 } else {
1223 m_defaultView = "3D";
1224 g_log.warning() << type << " is not allowed as an instrument view type. Default to \"3D\"" << '\n';
1225 }
1226}
1227
1232void Instrument::setValidFromDate(const Types::Core::DateAndTime &val) {
1233 Types::Core::DateAndTime earliestAllowedDate("1900-01-31 23:59:01");
1234 if (val < earliestAllowedDate) {
1236 "The valid-from <instrument> tag date must be from 1900-01-31 23:59:01 "
1237 "or later",
1238 m_filename);
1239 }
1240 m_ValidFrom = val;
1241}
1242
1244 std::queue<IComponent_const_sptr> compQueue; // Search queue
1246
1247 bool foundRect = false;
1248 bool foundNonRect = false;
1249
1251
1252 while (!compQueue.empty() && !(foundRect && foundNonRect)) {
1253 comp = compQueue.front();
1254 compQueue.pop();
1255
1256 if (!validateComponentProperties(comp))
1257 continue;
1258
1259 if (dynamic_cast<const RectangularDetector *>(comp.get())) {
1260 foundRect = true;
1261 } // If component isn't a ComponentAssembly, we know it is a non-rectangular detector. Otherwise check its children
1262 else if (!addAssemblyChildrenToQueue(compQueue, comp)) {
1263 foundNonRect = true;
1264 }
1265 }
1266
1267 // Found both
1268 if (foundRect && foundNonRect)
1270 // Found only rectangular
1271 else if (foundRect)
1273 // Found only non-rectangular
1274 else
1276}
1277
1279 // Skip source, if has one
1280 if (m_sourceCache && m_sourceCache->getComponentID() == component->getComponentID())
1281 return false;
1282
1283 // Skip sample, if has one
1284 if (m_sampleCache && m_sampleCache->getComponentID() == component->getComponentID())
1285 return false;
1286
1287 // Skip monitors
1288 IDetector_const_sptr detector = std::dynamic_pointer_cast<const IDetector>(component);
1289 if (detector && isMonitor(detector->getID()))
1290 return false;
1291
1292 // skip choppers, slits and supermirrors - HACK!
1293 const auto &name = component->getName();
1294 if (name == "chopper-position" || name.substr(0, 4) == "slit" || name == "supermirror") {
1295 return false;
1296 }
1297
1298 return true;
1299}
1300
1301void Instrument::addInstrumentChildrenToQueue(std::queue<IComponent_const_sptr> &queue) const {
1302 // Add all the direct children of the instrument
1303 for (int i = 0; i < nelements(); i++)
1304 queue.push(getChild(i));
1305}
1306
1309bool Instrument::addAssemblyChildrenToQueue(std::queue<IComponent_const_sptr> &queue,
1310 IComponent_const_sptr component) const {
1311 if (auto const assembly = std::dynamic_pointer_cast<const ICompAssembly>(component)) {
1312 for (int i = 0; i < assembly->nelements(); i++)
1313 queue.push(assembly->getChild(i));
1314 return true;
1315 }
1316 return false;
1317}
1318
1320bool Instrument::isMonitorViaIndex(const size_t index) const {
1321 const auto &in_dets = m_map ? m_instr->m_detectorCache : m_detectorCache;
1322 if (!in_dets.isFinalized())
1323 throw std::runtime_error("Instrument::isMonitorViaIndex: detector cache is not finalized");
1324 if (index >= in_dets.size())
1325 throw std::out_of_range("Instrument::isMonitorViaIndex: index out of range");
1326 return in_dets[index].isMonitor();
1327}
1328
1329bool Instrument::isEmptyInstrument() const { return this->nelements() == 0; }
1330
1332size_t Instrument::detectorIndex(const detid_t detID) const {
1333 if (!isFinalized())
1334 throw std::runtime_error("Instrument definition is not finalized. Can't get detector index for ID " +
1335 std::to_string(detID));
1336
1337 const auto &in_dets = m_map ? m_instr->m_detectorCache : m_detectorCache;
1338 const auto it = in_dets.find(detID);
1339 return std::distance(in_dets.cbegin(), it);
1340}
1341
1344std::shared_ptr<ParameterMap> Instrument::makeLegacyParameterMap() const {
1345 if (!isFinalized())
1346 throw std::runtime_error("Instrument definition is not finalized. Can't create legacy ParameterMap.");
1347
1348 auto pmap = std::make_shared<ParameterMap>(*getParameterMap());
1349 // Instrument is only needed for DetectorInfo access so it is not needed. This
1350 // also clears DetectorInfo and ComponentInfo (information will be stored
1351 // directly in pmap so we do not need them).
1352 pmap->setInstrument(nullptr);
1353
1354 const auto &baseInstr = m_map ? *m_instr : *this;
1355
1356 if (!getParameterMap()->hasComponentInfo(&baseInstr))
1357 return pmap;
1358
1359 // Tolerance 1e-9 m with rotation center at a distance of L = 1000 m as in
1360 // Beamline::DetectorInfo::isEquivalent.
1361 constexpr double d_max = 1e-9;
1362 constexpr double L = 1000.0;
1363 constexpr double safety_factor = 2.0;
1364 const double imag_norm_max = sin(d_max / (2.0 * L * safety_factor));
1365
1366 auto transformation = Eigen::Affine3d::Identity();
1367 int64_t oldParentIndex = -1;
1368
1369 const auto &componentInfo = getParameterMap()->componentInfo();
1370 const auto &detectorInfo = getParameterMap()->detectorInfo();
1371 for (size_t i = 0; i < componentInfo.size(); ++i) {
1372
1373 const int64_t parentIndex = componentInfo.parent(i);
1374 const bool makeTransform = parentIndex != oldParentIndex;
1375 bool isDetFixedInBank = false;
1376
1377 if (makeTransform) {
1378 oldParentIndex = parentIndex;
1379 const auto parentPos = toVector3d(componentInfo.position(parentIndex));
1380 const auto invParentRot = toQuaterniond(componentInfo.rotation(parentIndex)).conjugate();
1381
1382 transformation = invParentRot;
1383 transformation.translate(-parentPos);
1384 }
1385
1386 if (componentInfo.isDetector(i)) {
1387 isDetFixedInBank = ComponentInfoBankHelpers::isDetectorFixedInBank(componentInfo, i);
1388 if (detectorInfo.isMasked(i)) {
1389 auto const &baseDet = baseInstr.m_detectorCache[i].detector();
1390 pmap->forceUnsafeSetMasked(baseDet.get(), true);
1391 }
1392
1393 if (makeTransform) {
1394 // Special case: scaling for GridDetectorPixel.
1395 if (isDetFixedInBank) {
1396
1397 size_t panelIndex = componentInfo.parent(parentIndex);
1398 const auto panelID = componentInfo.componentID(panelIndex);
1399
1400 Eigen::Vector3d scale(1, 1, 1);
1401 if (auto scalex = pmap->get(panelID, "scalex"))
1402 scale[0] = 1.0 / scalex->value<double>();
1403 if (auto scaley = pmap->get(panelID, "scaley"))
1404 scale[1] = 1.0 / scaley->value<double>();
1405 transformation.prescale(scale);
1406 }
1407 }
1408 }
1409
1410 const auto componentId = componentInfo.componentID(i);
1411 const IComponent *baseComponent = componentId->getBaseComponent();
1412 // Generic sca scale factors
1413 const auto newScaleFactor = Kernel::toVector3d(componentInfo.scaleFactor(i));
1414 if ((newScaleFactor - toVector3d(baseComponent->getScaleFactor())).norm() >= 1e-9) {
1415 pmap->addV3D(componentId, ParameterMap::scale(), componentInfo.scaleFactor(i));
1416 }
1417
1418 // Undo parent transformation to obtain relative position/rotation.
1419 Eigen::Vector3d relPos = transformation * toVector3d(componentInfo.position(i));
1420 Eigen::Quaterniond relRot = toQuaterniond(componentInfo.relativeRotation(i));
1421
1422 // Tolerance 1e-9 m as in Beamline::DetectorInfo::isEquivalent.
1423 if ((relPos - toVector3d(baseComponent->getRelativePos())).norm() >= 1e-9) {
1424 if (isDetFixedInBank) {
1425 throw std::runtime_error(
1426 "Cannot create legacy ParameterMap: Position parameters for GridDetectorPixel are not supported");
1427 }
1428 pmap->addV3D(componentId, ParameterMap::pos(), Kernel::toV3D(relPos));
1429 }
1430 if ((relRot * toQuaterniond(baseComponent->getRelativeRot()).conjugate()).vec().norm() >= imag_norm_max) {
1431 pmap->addQuat(componentId, ParameterMap::rot(), Kernel::toQuat(relRot));
1432 }
1433 }
1434
1435 return pmap;
1436}
1437
1445 if (isParametrized())
1446 throw std::logic_error(
1447 "Instrument::parseTreeAndCacheBeamline must be called with the base instrument, not a parametrized instrument");
1449}
1450
1456std::pair<std::unique_ptr<ComponentInfo>, std::unique_ptr<DetectorInfo>>
1458 // If we have source and it has Beamline objects just copy them
1459 if (source && source->hasComponentInfo(this)) {
1460 return makeWrappers(pmap, source->componentInfo(), source->detectorInfo());
1461 }
1462 // If pmap is empty and base instrument has Beamline objects just copy them
1463 if (pmap.empty() && m_componentInfo) {
1465 }
1466 // pmap not empty and/or no cached Beamline objects found
1467 return InstrumentVisitor::makeWrappers(*this, &pmap);
1468}
1469
1474std::pair<std::unique_ptr<ComponentInfo>, std::unique_ptr<DetectorInfo>>
1478
1480std::pair<std::unique_ptr<ComponentInfo>, std::unique_ptr<DetectorInfo>>
1482 const DetectorInfo &detectorInfo) const {
1483 auto compInfo = componentInfo.cloneWithoutDetectorInfo();
1484 auto detInfo = std::make_unique<DetectorInfo>(detectorInfo);
1485 compInfo->m_componentInfo->setDetectorInfo(detInfo->m_detectorInfo.get());
1486 const auto parInstrument = ParComponentFactory::createInstrument(
1487 std::shared_ptr<const Instrument>(this, NoDeleting()), std::shared_ptr<ParameterMap>(&pmap, NoDeleting()));
1488 detInfo->m_instrument = parInstrument;
1489 return {std::move(compInfo), std::move(detInfo)};
1490}
1491
1496 // A parametrized instrument is a thin wrapper around a base instrument: it holds a shared_ptr to
1497 // the base (m_instr) but owns none of the component tree, detector cache, or beamline objects.
1498 // Delegate to the base and add only the ParameterMap overhead.
1499 if (m_instr) {
1500 const size_t paramMapMem = m_map_nonconst ? m_map_nonconst->getMemorySize() : 0;
1501 return sizeof(*this) + m_instr->getMemorySize() + paramMapMem;
1502 }
1503
1504 // Each std::map node carries ~4 pointers of red-black-tree overhead beyond the stored value_type.
1505 const size_t mapNodeOverhead = 4 * sizeof(void *);
1506
1507 const size_t logfileCacheMem =
1508 m_logfileCache.size() * (sizeof(InstrumentParameterCache::value_type) + mapNodeOverhead);
1509 const size_t logfileUnitMem = m_logfileUnit.size() * (sizeof(decltype(m_logfileUnit)::value_type) + mapNodeOverhead);
1510
1511 const size_t detectorInfoMem = m_detectorInfo ? m_detectorInfo->getMemorySize() : 0;
1512 const size_t componentInfoMem = m_componentInfo ? m_componentInfo->getMemorySize() : 0;
1513
1514 // BFS over the component tree. The Instrument root is already counted via sizeof(*this),
1515 // so start the traversal from the root and add each child's type-accurate object size plus
1516 // the IComponent* slot it occupies in its parent's m_children buffer.
1517 size_t componentTreeMem = 0;
1518 std::queue<const ICompAssembly *> bfsQueue;
1519 bfsQueue.push(this);
1520 while (!bfsQueue.empty()) {
1521 const auto *assembly = bfsQueue.front();
1522 bfsQueue.pop();
1523 const int n = assembly->nelements();
1524 componentTreeMem += static_cast<size_t>(n) * sizeof(IComponent *);
1525 for (int i = 0; i < n; ++i) {
1526 auto child = assembly->getChild(i);
1527 const IComponent *raw = child.get();
1528 componentTreeMem += componentObjectSize(raw);
1529 if (const auto *sub = dynamic_cast<const ICompAssembly *>(raw))
1530 bfsQueue.push(sub);
1531 }
1532 }
1533
1534 // m_referenceFrame: heap-allocated ReferenceFrame object
1535 const size_t referenceFrameMem = m_referenceFrame ? sizeof(ReferenceFrame) : 0;
1536
1537 // Indirect-geometry instruments hold a second full instrument for the physical geometry.
1538 const size_t physicalInstrumentMem = m_physicalInstrument ? m_physicalInstrument->getMemorySize() : 0;
1539
1540 return sizeof(*this) + componentTreeMem + m_detectorCache.capacity() * sizeof(DetectorCacheEntry) + logfileCacheMem +
1541 logfileUnitMem + m_defaultView.capacity() + m_defaultViewAxis.capacity() + m_xmlText.capacity() +
1542 m_filename.capacity() + detectorInfoMem + componentInfoMem + referenceFrameMem + physicalInstrumentMem;
1543}
1544
1545namespace Conversion {
1546
1555double tofToDSpacingFactor(const double l1, const double l2, const double twoTheta, const double offset) {
1556 return Kernel::Units::tofToDSpacingFactor(l1, l2, twoTheta, offset);
1557}
1558
1559double calculateDIFCCorrection(const double l1, const double l2, const double twoTheta, const double offset,
1560 const double binWidth) {
1561 return Kernel::Units::calculateDIFCCorrection(l1, l2, twoTheta, offset, binWidth);
1562}
1563
1564} // namespace Conversion
1565} // namespace Mantid::Geometry
std::string name
Definition Run.cpp:60
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
Definition System.h:44
double obj
the value of the quadratic function
A simple structure that defines an axis-aligned cuboid shaped bounding box for a geometrical object.
Definition BoundingBox.h:33
void grow(const BoundingBox &other)
Grow the bounding box so that it also encompasses the given box.
Class for Assembly of geometric components.
std::vector< IComponent * > m_children
the group of child components
void getChildren(std::vector< IComponent_const_sptr > &outVector, bool recursive) const override
Returns a vector of all children contained.
BoundingBox * m_cachedBoundingBox
A cached bounding box.
int add(IComponent *) override
Add a component to the assembly.
std::shared_ptr< const IComponent > getComponentByName(const std::string &cname, int nlevels=0) const override
Returns a pointer to the first component of assembly encountered with the given name.
int remove(IComponent *)
Remove a component from the assembly.
Kernel::V3D getPos() const override
Gets the absolute position of the Parametrized CompAssembly This attempts to read the cached position...
CompAssembly()
Empty constructor.
int nelements() const override
Return the number of elements in the assembly.
ComponentInfo : Provides a component centric view on to the instrument.
BoundingBox boundingBox(const size_t componentIndex, const BoundingBox *reference=nullptr, const bool excludeMonitors=false) const
Compute the bounding box for the component with componentIndex taking into account all sub components...
std::unique_ptr< ComponentInfo > cloneWithoutDetectorInfo() const
Clone current instance but not the DetectorInfo non-owned parts.
Component is a wrapper for a Component which can modify some of its parameters, e....
Definition Component.h:42
const ParameterMap * m_map
A pointer to const ParameterMap containing the parameters.
Definition Component.h:316
size_t index() const
Helper for legacy access mode. Returns the index of the component.
void setName(const std::string &) override
Set the IComponent name.
const IComponent * base() const
Returns the address of the base component.
Definition Component.h:289
bool isParametrized() const override
Return true if the Component is, in fact, parametrized (that is - it has a valid parameter map)
Definition Component.cpp:75
std::string getName() const override
Get the IComponent name.
const Component * m_base
The base component - this is the unmodified component (without the parameters).
Definition Component.h:314
Geometry::DetectorInfo is an intermediate step towards a DetectorInfo that is part of Instrument-2....
This class represents a detector - i.e.
Definition Detector.h:30
GridrDetectorPixel: a sub-class of Detector that is one pixel inside a GridDetector.
GridDetector is a type of CompAssembly, an assembly of components.
Class for Assembly of geometric components.
virtual void getChildren(std::vector< IComponent_const_sptr > &outVector, bool recursive) const =0
Get all children.
base class for Geometric IComponent
Definition IComponent.h:53
virtual IComponent const * getBaseComponent() const =0
Returns const pointer to base component if this component is parametrized.
virtual Kernel::V3D getScaleFactor() const
Gets the scaling factor of the object for the Object Component.
Definition IComponent.h:124
virtual ComponentID getComponentID() const =0
Returns the ComponentID - a unique identifier of the component.
virtual Kernel::Quat getRelativeRot() const =0
Get the relative Orientation.
virtual Kernel::V3D getRelativePos() const =0
Get the position relative to the parent IComponent (absolute if no parent)
virtual const IComponent * getBareParent() const =0
Returns the bare pointer to the IComponent parent.
virtual std::string getName() const =0
Get the IComponent name.
Interface class for detector objects.
Definition IDetector.h:43
virtual detid_t getID() const =0
Get the detector ID.
Object Component class, this class brings together the physical attributes of the component to the po...
std::pair< std::unique_ptr< ComponentInfo >, std::unique_ptr< DetectorInfo > > makeWrappers() const
Base Instrument Class.
Definition Instrument.h:49
ContainsState containsRectDetectors() const
Check whether instrument contains rectangular detectors.
std::string m_filename
Path to the original IDF .xml file that was loaded for this instrument.
Definition Instrument.h:367
std::vector< std::shared_ptr< const IComponent > > getAllComponentsWithName(const std::string &cname) const
Returns pointers to all components encountered with the given name.
void markAsSamplePos(const IComponent *)
mark a Component which has already been added to the Instrument (as a child comp.) to be 'the' sample...
std::size_t getNumberDetectors(bool skipMonitors=false) const
IComponent_const_sptr getSource() const
Gets a pointer to the source.
std::string m_defaultViewAxis
Stores from which side the instrument will be viewed from, initially in the instrument viewer,...
Definition Instrument.h:353
void removeDetectorIncomplete(IDetector const *)
Efficiently remove multiple detectors.
std::string m_xmlText
Contents of the IDF .xml file that was loaded for this instrument.
Definition Instrument.h:370
std::shared_ptr< const IComponent > getComponentByID(const IComponent *id) const
Returns a shared pointer to a component.
bool validateComponentProperties(IComponent_const_sptr component) const
const IComponent * m_sampleCache
Purpose to hold copy of samplePos component.
Definition Instrument.h:330
void getInstrumentParameters(double &l1, Kernel::V3D &beamline, double &beamline_norm, Kernel::V3D &samplePos) const
Get several instrument parameters used in tof to D-space conversion.
std::pair< std::unique_ptr< ComponentInfo >, std::unique_ptr< DetectorInfo > > makeWrappers(ParameterMap &pmap, const ComponentInfo &componentInfo, const DetectorInfo &detectorInfo) const
Sets up links between m_detectorInfo, m_componentInfo, and m_instrument.
void markAsMonitorIncomplete(IDetector const *)
Mark a Component which has already been added to the Instrument class as a monitor and add it to the ...
const IDetector * getBaseDetector(const detid_t &detector_id) const
Gets a pointer to the base (non-parametrized) detector from its ID returns null if the detector has n...
std::shared_ptr< const Instrument > baseInstrument() const
Pointer to the 'real' instrument, for parametrized instruments.
Instrument()
Default constructor.
size_t getMemorySize() const
Get the footprint in memory in bytes.
ContainsState
To determine whether the instrument contains elements of some type.
Definition Instrument.h:203
void parseTreeAndCacheBeamline()
Parse the instrument tree and create ComponentInfo and DetectorInfo.
std::shared_ptr< const Instrument > getPhysicalInstrument() const
INDIRECT GEOMETRY INSTRUMENTS ONLY: Returns the physical instrument, if one has been specified as dis...
std::shared_ptr< const Instrument > m_instr
Pointer to the "real" instrument, for parametrized Instrument.
Definition Instrument.h:356
std::set< detid_t > getDetectorIDsInBank(const std::string &bankName) const
void markAsDetector(const IDetector *)
mark a Component which has already been added to the Instrument (as a child comp.) to be a Detector c...
std::pair< std::unique_ptr< ComponentInfo >, std::unique_ptr< DetectorInfo > > makeBeamlineNew(ParameterMap &pmap) const
Return ComponentInfo and DetectorInfo for instrument given by pmap.
std::string m_defaultView
Stores the default type of the instrument view: 3D or one of the "unwrapped".
Definition Instrument.h:350
std::pair< std::unique_ptr< ComponentInfo >, std::unique_ptr< DetectorInfo > > makeBeamline(ParameterMap &pmap, const ParameterMap *source=nullptr) const
Return ComponentInfo and DetectorInfo for instrument given by pmap.
std::shared_ptr< const DetectorInfo > m_detectorInfo
Pointer to the DetectorInfo object. May be NULL.
Definition Instrument.h:380
std::vector< detid_t > getMonitorIDs() const
Returns a list containing the detector ids of monitors.
std::vector< IDetector_const_sptr > getDetectors(const std::vector< detid_t > &det_ids) const
Returns a list of Detectors for the given detectors ids.
std::map< std::string, std::string > m_logfileUnit
Store units used by users to specify angles in IDFs and associated parameter files.
Definition Instrument.h:346
std::shared_ptr< ParameterMap > makeLegacyParameterMap() const
Returns a legacy ParameterMap, containing information that is now stored in DetectorInfo (masking,...
size_t detectorIndex(const detid_t detID) const
Returns the index for a detector ID. Used for accessing DetectorInfo.
void setValidFromDate(const Types::Core::DateAndTime &val)
Set the date from which the instrument definition begins to be valid.
void setXmlText(const std::string &XmlText)
Set the Contents of the IDF .xml file that was loaded for this instrument.
Instrument * clone() const override
Virtual copy constructor.
bool isMonitor(const detid_t &detector_id) const
const std::string & getFilename() const
bool isMonitorViaIndex(const size_t index) const
Temporary helper for refactoring. Argument is index, not ID!
void setPhysicalInstrument(std::unique_ptr< Instrument >)
INDIRECT GEOMETRY INSTRUMENTS ONLY: Sets the physical instrument.
std::shared_ptr< ParameterMap > getParameterMap() const
Pointer to the NOT const ParameterMap holding the parameters of the modified instrument components.
void markAsMonitor(IDetector const *)
mark a Component which has already been added to the Instrument (as a child comp.) to be a monitor an...
std::shared_ptr< IComponent > getChild(const int i) const override
Get a pointer to the ith component within the assembly. Easier to use than.
bool hasSample() const
Checks to see if the Instrument has a sample.
Kernel::V3D getBeamDirection() const
Gets the beam direction (i.e.
const IComponent * m_sourceCache
Purpose to hold copy of source component.
Definition Instrument.h:326
void saveNexus(Nexus::File *file, const std::string &group) const
Save the instrument to an open NeXus file.
void appendPlottable(const CompAssembly &ca, std::vector< IObjComponent_const_sptr > &lst) const
Add a plottable component.
std::string type() const override
String description of the type of component.
Definition Instrument.h:52
void markAsDetectorIncomplete(const IDetector *)
As markAsDetector but without the required sorting.
const std::string & getXmlText() const
std::vector< detid_t > getDetectorIDs(bool skipMonitors=false) const
Returns a list containing the detector ids of all detectors, optionally skipping monitors.
void getBoundingBox(BoundingBox &assemblyBox) const override
Get the bounding box for this component and store it in the given argument.
std::shared_ptr< const ComponentInfo > m_componentInfo
Pointer to the ComponentInfo object. May be NULL.
Definition Instrument.h:383
std::shared_ptr< const Instrument > m_physicalInstrument
Pointer to the physical instrument, where this differs from the 'neutronic' one (indirect geometry)
Definition Instrument.h:374
Mantid::Geometry::Instrument::DetectorCache m_detectorCache
std::shared_ptr< const std::vector< IObjComponent_const_sptr > > getPlottable() const
Get pointers to plottable components.
void saveDetectorSetInfoToNexus(Nexus::File *file, const std::vector< detid_t > &detIDs) const
Save information about a set of detectors to Nexus.
IDetector_const_sptr getDetectorG(const std::set< detid_t > &det_ids) const
Returns a pointer to the geometrical object for the given set of IDs.
void getDetectorsInBank(std::vector< IDetector_const_sptr > &dets, const IComponent &comp) const
Fill a vector with all the detectors contained (at any depth) in a named component.
void markAsSource(const IComponent *)
mark a Component which has already been added to the Instrument (as a child comp.) to be 'the' source...
bool hasSource() const
Checks to see if the Instrument has a source.
void setReferenceFrame(std::shared_ptr< ReferenceFrame > frame)
Set reference Frame.
void getMinMaxDetectorIDs(detid_t &min, detid_t &max) const
Get the minimum and maximum (inclusive) detector IDs.
std::shared_ptr< ParameterMap > m_map_nonconst
Non-const pointer to the parameter map.
Definition Instrument.h:359
InstrumentParameterCache m_logfileCache
To store info about the parameters defined in IDF.
Definition Instrument.h:335
void setDefaultView(const std::string &type)
Set the default type of the instrument view.
void removeDetectorFinalize()
Remove all detectors that have been marked for removal with removeDetectorIncomplete() from the detec...
std::shared_ptr< const ReferenceFrame > getReferenceFrame() const
Get refernce Frame.
void markAsDetectorFinalize()
Sorts the detector cache.
bool addAssemblyChildrenToQueue(std::queue< IComponent_const_sptr > &queue, IComponent_const_sptr component) const
If component is a ComponentAssembly, we add its children to the queue to check if they're Rectangular...
std::shared_ptr< ReferenceFrame > m_referenceFrame
Pointer to the reference frame object.
Definition Instrument.h:377
IDetector_const_sptr getDetector(const detid_t &detector_id) const
Gets a pointer to the detector from its ID Note that for getting the detector associated with a spect...
Types::Core::DateAndTime m_ValidFrom
the date from which the instrument definition begins to be valid.
Definition Instrument.h:362
void setFilename(const std::string &filename)
Set the path to the original IDF .xml file that was loaded for this instrument.
IComponent_const_sptr getSample() const
Gets a pointer to the Sample Position.
void addInstrumentChildrenToQueue(std::queue< IComponent_const_sptr > &queue) const
void loadNexus(Nexus::File *file, const std::string &group)
Load the object from an open NeXus file.
void removeDetector(IDetector *)
Remove a detector from the instrument.
Class for Assembly of geometric components.
Object Component class, this class brings together the physical attributes of the component to the po...
static std::shared_ptr< IComponent > create(const std::shared_ptr< const IComponent > &base, const ParameterMap *map)
Create a parameterized component from the given base component and ParameterMap.
static std::shared_ptr< Instrument > createInstrument(const std::shared_ptr< const Instrument > &base, const std::shared_ptr< ParameterMap > &map)
Create a parameterized instrument from the given base and ParameterMap.
static std::shared_ptr< IDetector > createDetector(const IDetector *base, const ParameterMap *map)
Create a parameterized detector from the given base component and ParameterMap and return a shared_pt...
const Geometry::DetectorInfo & detectorInfo() const
Only for use by ExperimentInfo. Returns a reference to the DetectorInfo.
static const std::string & scale()
static const std::string & rot()
static const std::string & pos()
Return string to be used in the map.
bool hasComponentInfo(const Instrument *instrument) const
Only for use by ExperimentInfo.
const Geometry::ComponentInfo & componentInfo() const
Only for use by ExperimentInfo. Returns a reference to the ComponentInfo.
RectangularDetector is a type of CompAssembly, an assembly of components.
ReferenceFrame : Holds reference frame information from the geometry description file.
StructuredDetector is a type of CompAssembly, an assembly of components.
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
The Logger class is in charge of the publishing messages from the framework through various channels.
Definition Logger.h:51
void error(const std::string &msg)
Logs at error level.
Definition Logger.cpp:108
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
Class for 3D vectors.
Definition V3D.h:34
double norm() const noexcept
Definition V3D.h:269
void getSpherical(double &R, double &theta, double &phi) const noexcept
Return the vector's position in spherical coordinates.
Definition V3D.cpp:116
This functor is used as the deleter object of a shared_ptr to effectively erase ownership Raw pointer...
Definition IComponent.h:173
MANTID_GEOMETRY_DLL bool isDetectorFixedInBank(const ComponentInfo &compInfo, const size_t detIndex)
Tests whether or not the detector is within a fixed bank.
MANTID_GEOMETRY_DLL double calculateDIFCCorrection(const double l1, const double l2, const double twoTheta, const double offset, const double binWidth)
MANTID_GEOMETRY_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.
std::shared_ptr< const IComponent > IComponent_const_sptr
Typdef of a shared pointer to a const IComponent.
Definition IComponent.h:167
std::shared_ptr< IComponent > IComponent_sptr
Typedef of a shared pointer to a IComponent.
Definition IComponent.h:165
Mantid::Kernel::Logger g_log("Goniometer")
std::shared_ptr< const IObjComponent > IObjComponent_const_sptr
Shared pointer to IObjComponent (const version)
std::shared_ptr< ParameterMap > ParameterMap_sptr
ParameterMap shared pointer typedef.
std::shared_ptr< const Mantid::Geometry::IDetector > IDetector_const_sptr
Shared pointer to IDetector (const version)
Definition IDetector.h:102
std::shared_ptr< const Instrument > Instrument_const_sptr
Shared pointer to an const instrument object.
Kernel::Quat toQuat(const Eigen::Quaterniond &quat)
Converts Eigen::Quaterniond to Kernel::Quat.
Eigen::Vector3d toVector3d(const Kernel::V3D &vec)
Converts Kernel::V3D to Eigen::Vector3d.
Kernel::V3D toV3D(const Eigen::Vector3d &vec)
This header provides conversion helpers between vector and rotation types in MantidKernel and equival...
MANTID_KERNEL_DLL V3D normalize(V3D v)
Normalizes a V3D.
Definition V3D.h:352
Eigen::Quaterniond toQuaterniond(const Kernel::Quat &quat)
Converts Kernel::Quat to Eigen::Quaterniond.
int32_t detid_t
Typedef for a detector ID.
std::map< detid_t, Geometry::IDetector_const_sptr > detid2det_map
Typedef of a map from detector ID to detector shared pointer.
Definition Instrument.h:28
Generate a tableworkspace to store the calibration results.
adjust instrument component position and orientation
: detector size scale at y-direction
std::string to_string(const wide_integer< Bits, Signed > &n)
Tuple which holds detector-IDs and pointers to detector components, and monitor flags.
Definition Instrument.h:276
DetectorCache::iterator lower_bound(detid_t id)
Perform a lower bound search on the detector cache, for the element with the given ID.
std::unordered_set< IDetector const * > m_toRemove
Definition Instrument.h:313
DetectorCache::iterator find(detid_t id)
Find the element in the detector cache with the given ID.
void setFinalized(bool const flag=true)
Definition Instrument.h:294