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"
27#include "MantidKernel/Logger.h"
29#include "MantidKernel/Unit.h"
30#include "MantidNexus/NexusFile.h"
31
32#include <algorithm>
33#include <memory>
34#include <queue>
35#include <utility>
36
37using namespace Mantid::Kernel;
40
41namespace Mantid::Geometry {
42
43namespace {
44Kernel::Logger g_log("Instrument");
45
46void raiseDuplicateDetectorError(const size_t detectorId) {
47 std::stringstream sstream;
48 sstream << "Instrument Definition corrupt. Detector with ID " << detectorId << " already exists.";
49 throw Exception::InstrumentDefinitionError(sstream.str());
50}
51
53size_t componentObjectSize(const IComponent *comp) {
54 size_t result;
55 if (dynamic_cast<const RectangularDetector *>(comp))
56 result = sizeof(RectangularDetector);
57 else if (const auto *sd = dynamic_cast<const StructuredDetector *>(comp))
58 result = sizeof(StructuredDetector) + sd->getXValues().capacity() * sizeof(double) +
59 sd->getYValues().capacity() * sizeof(double);
60 else if (dynamic_cast<const GridDetectorPixel *>(comp))
61 result = sizeof(GridDetectorPixel);
62 else if (dynamic_cast<const GridDetector *>(comp))
63 result = sizeof(GridDetector);
64 else if (dynamic_cast<const Detector *>(comp))
65 result = sizeof(Detector);
66 else if (dynamic_cast<const ObjCompAssembly *>(comp))
67 result = sizeof(ObjCompAssembly);
68 else if (dynamic_cast<const ObjComponent *>(comp))
69 result = sizeof(ObjComponent);
70 else if (dynamic_cast<const CompAssembly *>(comp))
71 result = sizeof(CompAssembly);
72 else
73 result = sizeof(Component);
74 return result;
75}
76} // namespace
77
80 : CompAssembly(), m_detectorCache(), m_sourceCache(nullptr), m_sampleCache(nullptr), m_defaultView("3D"),
81 m_defaultViewAxis("Z+"), m_referenceFrame(new ReferenceFrame) {}
82
84Instrument::Instrument(const std::string &name)
85 : CompAssembly(name), m_detectorCache(), m_sourceCache(nullptr), m_sampleCache(nullptr), m_defaultView("3D"),
86 m_defaultViewAxis("Z+"), m_referenceFrame(new ReferenceFrame) {}
87
92Instrument::Instrument(const std::shared_ptr<const Instrument> &instr, const std::shared_ptr<ParameterMap> &map)
93 : CompAssembly(instr.get(), map.get()), m_sourceCache(instr->m_sourceCache), m_sampleCache(instr->m_sampleCache),
94 m_defaultView(instr->m_defaultView), m_defaultViewAxis(instr->m_defaultViewAxis), m_instr(instr),
95 m_map_nonconst(map), m_ValidFrom(instr->m_ValidFrom), m_ValidTo(instr->m_ValidTo),
96 m_referenceFrame(new ReferenceFrame) {
97 // Note that we do not copy m_detectorInfo and m_componentInfo into the parametrized instrument since the ParameterMap
98 // will make a copy, if applicable.
99}
100
106 : CompAssembly(instr), m_sourceCache(nullptr), m_sampleCache(nullptr), /* Should only be temporarily null */
107 m_logfileCache(instr.m_logfileCache), m_logfileUnit(instr.m_logfileUnit), m_defaultView(instr.m_defaultView),
108 m_defaultViewAxis(instr.m_defaultViewAxis), m_instr(), m_map_nonconst(), /* Should not be parameterized */
109 m_ValidFrom(instr.m_ValidFrom), m_ValidTo(instr.m_ValidTo), m_referenceFrame(instr.m_referenceFrame) {
110 // Note that we do not copy m_detectorInfo and m_componentInfo into the new instrument since they are only non-NULL
111 // for the base instrument, which should usually not be copied.
112
113 // Now we need to fill the detector, source and sample caches with pointers into the new instrument
114 std::vector<IComponent_const_sptr> children;
115 getChildren(children, true);
116 std::vector<IComponent_const_sptr>::const_iterator it;
117 for (it = children.begin(); it != children.end(); ++it) {
118 // First check if the current component is a detector and add to cache if it is
119 if (const IDetector *det = dynamic_cast<const Detector *>(it->get())) {
120 if (instr.isMonitor(det->getID()))
121 markAsMonitor(det);
122 else
123 markAsDetector(det);
124 continue;
125 }
126 // Now check whether the current component is the source or sample.
127 // As the majority of components will be detectors, we will rarely get to here
128 if (const auto *obj = dynamic_cast<const Component *>(it->get())) {
129 const std::string objName = obj->getName();
130 // This relies on the source and sample having a unique name. I think the way our instrument definition files work
131 // ensures this is the case.
132 if (objName == instr.m_sourceCache->getName()) {
134 continue;
135 }
136 if (objName == instr.m_sampleCache->getName()) {
138 continue;
139 }
140 }
141 }
142}
143
151Instrument::Instrument(const Instrument &instr, bool copyCache)
152 : CompAssembly(), m_sourceCache(nullptr), m_sampleCache(nullptr), /* Should only be temporarily null */
153 m_logfileCache(instr.m_logfileCache), m_logfileUnit(instr.m_logfileUnit), m_defaultView(instr.m_defaultView),
154 m_defaultViewAxis(instr.m_defaultViewAxis), m_instr(), m_map_nonconst(), /* Should not be parameterized */
155 m_ValidFrom(instr.m_ValidFrom), m_ValidTo(instr.m_ValidTo), m_referenceFrame(instr.m_referenceFrame) {
156 UNUSED_ARG(copyCache);
157 setName(instr.getName() + "_clone");
158 // add in the sample and the source
159 auto sampleComp = instr.getSample();
160 auto sourceComp = instr.getSource();
161 if (!sampleComp || !sourceComp) {
162 throw std::runtime_error("Cannot copy instrument: source instrument must have valid sample and source components");
163 }
164 auto sample = sampleComp->clone();
165 auto source = sourceComp->clone();
166 add(sample);
167 add(source);
168 markAsSource(source);
169 markAsSamplePos(sample);
170 // also add in the monitors
171 std::vector<IComponent_const_sptr> children;
172 instr.getChildren(children, true);
173 for (auto const &child : children) {
174 if (IDetector const *det = dynamic_cast<Detector const *>(child.get())) {
175 if (instr.isMonitor(det->getID())) {
176 auto dclone = dynamic_cast<IDetector *>(det->clone());
177 add(dclone);
178 markAsMonitor(dclone);
179 }
180 }
181 }
182}
183
185Instrument *Instrument::clone() const { return new Instrument(*this); }
186
189 if (m_map)
190 return m_instr;
191 else
192 throw std::runtime_error("Instrument::baseInstrument() called for a "
193 "non-parametrized instrument.");
194}
195
202 if (m_map)
203 return m_map_nonconst;
204 else
205 throw std::runtime_error("Instrument::getParameterMap() called for a "
206 "non-parametrized instrument.");
207}
208
216 if (m_map) {
217 if (m_instr->getPhysicalInstrument()) {
218 // A physical instrument should use the same parameter map as the 'main'
219 // instrument. This constructor automatically sets the instrument as the
220 // owning instrument in the ParameterMap. We need to undo this immediately
221 // since the ParameterMap must always be owned by the neutronic
222 // instrument.
223 return std::make_shared<Instrument>(m_instr->getPhysicalInstrument(), m_map_nonconst);
224 } else {
225 return Instrument_const_sptr();
226 }
227 } else {
229 }
230}
231
237void Instrument::setPhysicalInstrument(std::unique_ptr<Instrument> physInst) {
238 if (!m_map) {
239 physInst->m_isPhysicalInstrument = true;
240 m_physicalInstrument = std::move(physInst);
241 } else
242 throw std::runtime_error("Instrument::setPhysicalInstrument() called on a "
243 "parametrized instrument.");
244}
245
246//------------------------------------------------------------------------------------------
250 out_map.clear();
251 auto it = out_map.end();
252 if (m_map) {
253 // Get the base instrument detectors
254 const auto &in_dets = m_instr->m_detectorCache;
255 // And turn them into parametrized versions
256 for (const auto &in_det : in_dets) {
257 it = out_map.emplace_hint(it, in_det.id(), ParComponentFactory::createDetector(in_det.detector().get(), m_map));
258 }
259 } else {
260 // You can just return the detector cache directly.
261 for (const auto &in_det : m_detectorCache) {
262 it = out_map.emplace_hint(it, in_det.id(), in_det.detector());
263 }
264 }
265}
266
267//------------------------------------------------------------------------------------------
269std::vector<detid_t> Instrument::getDetectorIDs(bool skipMonitors) const {
270 const auto &in_dets = m_map ? m_instr->m_detectorCache : m_detectorCache;
271 std::vector<detid_t> out;
272 out.reserve(in_dets.size());
273 for (const auto &in_det : in_dets) {
274 if (!skipMonitors || !in_det.isMonitor()) {
275 out.emplace_back(in_det.id());
276 }
277 }
278 return out;
279}
280
284std::vector<detid_t> Instrument::getMonitorIDs() const {
285 // Monitors cannot be parametrized. So just return the base.
286 if (m_map)
287 return m_instr->getMonitorIDs();
288
289 std::vector<detid_t> mons;
290 for (const auto &item : m_detectorCache)
291 if (item.isMonitor())
292 mons.emplace_back(item.id());
293 return mons;
294}
295
297std::size_t Instrument::getNumberDetectors(bool skipMonitors) const {
298 const auto &in_dets = m_map ? m_instr->m_detectorCache : m_detectorCache;
299
300 if (skipMonitors) {
301 const std::size_t monitors =
302 std::count_if(in_dets.cbegin(), in_dets.cend(), [](const auto &in_det) { return in_det.isMonitor(); });
303 return (in_dets.size() - monitors);
304 } else {
305 return in_dets.size();
306 }
307}
308
316 const auto &in_dets = m_map ? m_instr->m_detectorCache : m_detectorCache;
317 // ensure there are detectors
318 if (in_dets.empty())
319 throw std::runtime_error("No detectors on this instrument. Can't find min/max ids");
320 // ensure the cache is finalized
321 if (!in_dets.isFinalized())
322 throw std::runtime_error("Instrument definition is not finalized. Can't find min/max ids");
323 min = in_dets.minID();
324 max = in_dets.maxID();
325}
326
336void Instrument::getDetectorsInBank(std::vector<IDetector_const_sptr> &dets, const IComponent &comp) const {
337 const auto bank = dynamic_cast<const ICompAssembly *>(&comp);
338 if (bank) {
339 // Get a vector of children (recursively)
340 std::vector<std::shared_ptr<const IComponent>> children;
341 bank->getChildren(children, true);
342 std::vector<std::shared_ptr<const IComponent>>::iterator it;
343 for (it = children.begin(); it != children.end(); ++it) {
344 IDetector_const_sptr det = std::dynamic_pointer_cast<const IDetector>(*it);
345 if (det) {
346 dets.emplace_back(det);
347 }
348 }
349 }
350}
351
362void Instrument::getDetectorsInBank(std::vector<IDetector_const_sptr> &dets, const std::string &bankName) const {
363 std::shared_ptr<const IComponent> comp = this->getComponentByName(bankName);
364 if (!comp) {
365 throw Kernel::Exception::NotFoundError("Instrument: Could not find component", bankName);
366 }
367 getDetectorsInBank(dets, *comp);
368}
369
370std::set<detid_t> Instrument::getDetectorIDsInBank(const std::string &bankName) const {
371 std::set<detid_t> detIDs;
372 std::vector<IDetector_const_sptr> detectors;
373 getDetectorsInBank(detectors, bankName);
374
375 for (const auto &det : detectors) {
376 detIDs.emplace(det->getID());
377 }
378 return detIDs;
379}
380
384bool Instrument::hasSource() const { return m_sourceCache; }
385
389bool Instrument::hasSample() const { return m_sampleCache; }
390
395 if (!m_sourceCache) {
396 g_log.warning("In Instrument::getSource(). No source has been set.");
398 } else if (m_map) {
399 auto sourceCache = static_cast<const Instrument *>(m_base)->m_sourceCache;
400 if (dynamic_cast<const ObjComponent *>(sourceCache))
401 return IComponent_const_sptr(new ObjComponent(sourceCache, m_map));
402 else if (dynamic_cast<const CompAssembly *>(sourceCache))
403 return IComponent_const_sptr(new CompAssembly(sourceCache, m_map));
404 else if (dynamic_cast<const Component *>(sourceCache))
405 return IComponent_const_sptr(new Component(sourceCache, m_map));
406 else {
407 g_log.error("In Instrument::getSource(). Source is not a recognised "
408 "component type.");
409 g_log.error("Try to assume it is a Component.");
410 return IComponent_const_sptr(new ObjComponent(sourceCache, m_map));
411 }
412 } else {
414 }
415}
416
421 if (!m_sampleCache) {
422 g_log.warning("In Instrument::getSamplePos(). No SamplePos has been set.");
424 } else if (m_map) {
425 auto sampleCache = static_cast<const Instrument *>(m_base)->m_sampleCache;
426 if (dynamic_cast<const ObjComponent *>(sampleCache))
427 return IComponent_const_sptr(new ObjComponent(sampleCache, m_map));
428 else if (dynamic_cast<const CompAssembly *>(sampleCache))
429 return IComponent_const_sptr(new CompAssembly(sampleCache, m_map));
430 else if (dynamic_cast<const Component *>(sampleCache))
431 return IComponent_const_sptr(new Component(sampleCache, m_map));
432 else {
433 g_log.error("In Instrument::getSamplePos(). SamplePos is not a "
434 "recognised component type.");
435 g_log.error("Try to assume it is a Component.");
436 return IComponent_const_sptr(new ObjComponent(sampleCache, m_map));
437 }
438 } else {
440 }
441}
442
448
449//------------------------------------------------------------------------------------------
454std::shared_ptr<const IComponent> Instrument::getComponentByID(const IComponent *id) const {
455 const auto *base = static_cast<const IComponent *>(id);
456 if (m_map)
457 return ParComponentFactory::create(std::shared_ptr<const IComponent>(base, NoDeleting()), m_map);
458 else
459 return std::shared_ptr<const IComponent>(base, NoDeleting());
460}
461
470std::vector<std::shared_ptr<const IComponent>> Instrument::getAllComponentsWithName(const std::string &cname) const {
471 std::shared_ptr<const IComponent> node = std::shared_ptr<const IComponent>(this, NoDeleting());
472 std::vector<std::shared_ptr<const IComponent>> retVec;
473 // Check the instrument name first
474 if (this->getName() == cname) {
475 retVec.emplace_back(node);
476 }
477 // Same algorithm as used in getComponentByName() but searching the full tree
478 std::deque<std::shared_ptr<const IComponent>> nodeQueue;
479 // Need to be able to enter the while loop
480 nodeQueue.emplace_back(node);
481 while (!nodeQueue.empty()) {
482 node = nodeQueue.front();
483 nodeQueue.pop_front();
484 int nchildren(0);
485 std::shared_ptr<const ICompAssembly> asmb = std::dynamic_pointer_cast<const ICompAssembly>(node);
486 if (asmb) {
487 nchildren = asmb->nelements();
488 }
489 for (int i = 0; i < nchildren; ++i) {
490 std::shared_ptr<const IComponent> comp = (*asmb)[i];
491 if (comp->getName() == cname) {
492 retVec.emplace_back(comp);
493 } else {
494 nodeQueue.emplace_back(comp);
495 }
496 }
497 } // while-end
498
499 // If we have reached here then the search failed
500 return retVec;
501}
502
511Instrument::DetectorCache::iterator Instrument::DetectorCache::lower_bound(detid_t id) {
512 if (!isFinalized()) {
513 throw std::runtime_error("lower_bound() called on non-finalized DetectorCache");
514 }
515 return std::lower_bound(begin(), end(), id,
516 [](DetectorCacheEntry const &entry, detid_t id) { return entry.id() < id; });
517}
518
528Instrument::DetectorCache::const_iterator Instrument::DetectorCache::lower_bound(detid_t id) const {
529 if (!isFinalized()) {
530 throw std::runtime_error("lower_bound() called on non-finalized DetectorCache");
531 }
532 return std::lower_bound(cbegin(), cend(), id,
533 [](DetectorCacheEntry const &entry, detid_t id) { return entry.id() < id; });
534}
535
543Instrument::DetectorCache::iterator Instrument::DetectorCache::find(detid_t id) {
544 if (!isFinalized()) {
545 throw std::runtime_error("find() called on non-finalized DetectorCache");
546 }
547 auto it = lower_bound(id);
548 if (it != end() && it->id() == id) {
549 return it;
550 } else {
551 return end();
552 }
553}
554
562Instrument::DetectorCache::const_iterator Instrument::DetectorCache::find(detid_t id) const {
563 if (!isFinalized()) {
564 throw std::runtime_error("find() called on non-finalized DetectorCache");
565 }
566 auto const it = lower_bound(id);
567 if (it != cend() && it->id() == id) {
568 return it;
569 } else {
570 return cend();
571 }
572}
573
583 // ensure instrument is finalized
584 if (!isFinalized())
585 throw std::runtime_error("Instrument definition is not finalized. Can't search for detector ID " +
586 std::to_string(detector_id));
587
588 const auto &in_dets = m_map ? m_instr->m_detectorCache : m_detectorCache;
589 const auto it = in_dets.find(detector_id);
590 if (it == in_dets.end()) {
591 std::stringstream readInt;
592 readInt << detector_id;
593 throw Kernel::Exception::NotFoundError("Instrument: Detector with ID " + readInt.str() + " not found.", "");
594 }
595 IDetector_const_sptr baseDet = it->detector();
596
597 if (!m_map)
598 return baseDet;
599
600 auto det = ParComponentFactory::createDetector(baseDet.get(), m_map);
601 return det;
602}
603
609const IDetector *Instrument::getBaseDetector(const detid_t &detector_id) const {
610 // ensure instrument is finalized
611 if (!m_map)
612 throw std::runtime_error("Instrument::getBaseDetector() called on a non-parametrized instrument.");
613 if (!isFinalized())
614 throw std::runtime_error("Instrument definition is not finalized. Can't find base detector ID " +
615 std::to_string(detector_id));
616
617 auto it = m_instr->m_detectorCache.find(detector_id);
618 if (it == m_instr->m_detectorCache.end()) {
619 return nullptr;
620 }
621 return it->detector().get();
622}
623
624bool Instrument::isMonitor(const detid_t &detector_id) const {
625 // ensure instrument is finalized
626 if (!isFinalized())
627 throw std::runtime_error("Instrument definition is not finalized. Can't search for monitor ID " +
628 std::to_string(detector_id));
629
630 const auto &in_dets = m_map ? m_instr->m_detectorCache : m_detectorCache;
631 const auto it = in_dets.find(detector_id);
632 if (it == in_dets.end())
633 return false;
634 return it->isMonitor();
635}
636
637bool Instrument::isMonitor(const std::set<detid_t> &detector_ids) const {
638 if (detector_ids.empty())
639 return false;
640
641 return std::any_of(detector_ids.cbegin(), detector_ids.cend(),
642 [this](const auto detector_id) { return isMonitor(detector_id); });
643}
644
651IDetector_const_sptr Instrument::getDetectorG(const std::set<detid_t> &det_ids) const {
652 const size_t ndets(det_ids.size());
653 if (ndets == 1) {
654 return this->getDetector(*det_ids.begin());
655 } else {
656 std::shared_ptr<DetectorGroup> det_group = std::make_shared<DetectorGroup>();
657 for (const auto detID : det_ids) {
658 det_group->addDetector(this->getDetector(detID));
659 }
660 return det_group;
661 }
662}
663
668std::vector<IDetector_const_sptr> Instrument::getDetectors(const std::vector<detid_t> &det_ids) const {
669 std::vector<IDetector_const_sptr> dets_ptr;
670 dets_ptr.reserve(det_ids.size());
671 std::vector<detid_t>::const_iterator it;
672 for (it = det_ids.begin(); it != det_ids.end(); ++it) {
673 dets_ptr.emplace_back(this->getDetector(*it));
674 }
675 return dets_ptr;
676}
677
682std::vector<IDetector_const_sptr> Instrument::getDetectors(const std::set<detid_t> &det_ids) const {
683 std::vector<IDetector_const_sptr> dets_ptr;
684 dets_ptr.reserve(det_ids.size());
685 std::set<detid_t>::const_iterator it;
686 for (it = det_ids.begin(); it != det_ids.end(); ++it) {
687 dets_ptr.emplace_back(this->getDetector(*it));
688 }
689 return dets_ptr;
690}
691
703 if (m_map)
704 throw std::runtime_error("Instrument::markAsSamplePos() called on a "
705 "parametrized Instrument object.");
706
707 auto objComp = dynamic_cast<const IObjComponent *>(comp);
708 if (objComp) {
709 throw std::runtime_error("Instrument::markAsSamplePos() called on an IObjComponent "
710 "object that supports shape definition. Sample is prevented from "
711 "being this type because the shape must only be stored in "
712 "ExperimentInfo::m_sample.");
713 }
714
715 if (!m_sampleCache) {
716 if (comp->getName().empty()) {
717 throw Exception::InstrumentDefinitionError("The sample component is required to have a name.");
718 }
719 m_sampleCache = comp;
720 } else {
721 g_log.warning("Have already added samplePos component to the _sampleCache.");
722 }
723}
724
736 if (m_map)
737 throw std::runtime_error("Instrument::markAsSource() called on a "
738 "parametrized Instrument object.");
739
740 if (!m_sourceCache) {
741 if (comp->getName().empty()) {
742 throw Exception::InstrumentDefinitionError("The source component is required to have a name.");
743 }
744 m_sourceCache = comp;
745 } else {
746 g_log.warning("Have already added source component to the _sourceCache.");
747 }
748}
749
759 if (m_map)
760 throw std::runtime_error("Instrument::markAsDetector() called on a "
761 "parametrized Instrument object.");
762 // ensure instrument is finalized
763 if (!isFinalized())
764 throw std::runtime_error("Instrument definition is not finalized. Add detector with markAsDetectorIncomplete, "
765 "then call markAsDetectorFinalized when finished.");
766
767 // Duplicate detector ids are forbidden
768 auto it = m_detectorCache.lower_bound(det->getID());
769 if ((it != m_detectorCache.end()) && (it->id() == det->getID())) {
770 raiseDuplicateDetectorError(det->getID());
771 }
772 // Create a (non-deleting) shared pointer to it
774 m_detectorCache.emplace(it, det->getID(), det_sptr, false);
775}
776
780 if (m_map)
781 throw std::runtime_error("Instrument::markAsDetector() called on a "
782 "parametrized Instrument object.");
783
785 // Create a (non-deleting) shared pointer to it
787 m_detectorCache.emplace_back(det->getID(), det_sptr, false);
788}
789
793 // We're already finalized! We can't finalize any further!
794 if (isFinalized())
795 return;
796
797 // Detectors (even when different objects) are NOT allowed to have duplicate
798 // ids. This method establishes the presence of duplicates.
799 std::sort(m_detectorCache.begin(), m_detectorCache.end(),
800 [](DetectorCacheEntry const &a, DetectorCacheEntry const &b) -> bool { return a.id() < b.id(); });
801
802 auto resultIt = std::adjacent_find(
803 m_detectorCache.begin(), m_detectorCache.end(),
804 [](DetectorCacheEntry const &a, DetectorCacheEntry const &b) -> bool { return a.id() == b.id(); });
805 if (resultIt != m_detectorCache.end()) {
806 raiseDuplicateDetectorError(resultIt->id());
807 } else {
809 }
810}
811
821 if (m_map)
822 throw std::runtime_error("Instrument::markAsMonitor() called on a "
823 "parametrized Instrument object.");
824 if (!isFinalized()) {
825 throw std::runtime_error("Instrument definition is not finalized. Add monitor with markAsMonitorIncomplete, then "
826 "call markAsDetectorFinalized when finished.");
827 }
828
829 // attempt to add monitor to instrument detector cache
830 markAsDetector(det);
831
832 // mark detector as a monitor
833 auto it = m_detectorCache.find(det->getID());
834 it->setIsMonitor(true);
835}
836
844 if (m_map)
845 throw std::runtime_error("Instrument::markAsMonitorIncomplete() called on a "
846 "parametrized Instrument object.");
847
849 // Create a (non-deleting) shared pointer to it
851 m_detectorCache.emplace_back(det->getID(), det_sptr, true);
852}
853
860 if (m_map)
861 throw std::runtime_error("Instrument::removeDetector() called on a "
862 "parameterized Instrument object.");
863 if (!isFinalized())
864 throw std::runtime_error("Instrument definition is not finalized. Can't remove detector with ID " +
865 std::to_string(det->getID()));
866
867 const detid_t id = det->getID();
868 // Remove the detector from the detector cache
869 const auto it = m_detectorCache.find(id);
870 // NOTE this operation is O(N) for the vector cache
871 m_detectorCache.erase(it);
872
873 // Remove it from the parent assembly (and thus the instrument).
874 // Evilness required here unfortunately.
875 auto *parentAssembly = dynamic_cast<CompAssembly *>(const_cast<IComponent *>(det->getBareParent()));
876 if (parentAssembly) // Should always be true, but check just in case
877 {
878 parentAssembly->remove(det);
879 }
880}
881
890 if (m_map)
891 throw std::runtime_error("Instrument::removeDetectorIncomplete() called on a "
892 "parameterized Instrument object.");
894 if (m_detectorCache.m_toRemove.empty()) {
896 }
897 m_detectorCache.m_toRemove.insert(det);
898}
899
905 if (m_map)
906 throw std::runtime_error("Instrument::removeDetectorFinalize() called on a "
907 "parameterized Instrument object.");
908
909 if (isFinalized()) {
911 return;
912 }
913
914 // Remove from the cache all the ones to be removed
915 auto newEnd = std::remove_if(m_detectorCache.begin(), m_detectorCache.end(), [this](const auto &entry) {
916 return m_detectorCache.m_toRemove.contains(entry.detector().get());
917 });
918 m_detectorCache.erase(newEnd, m_detectorCache.end());
919
920 // clear the removal set and finalize the cache
923}
924
930void Instrument::getBoundingBox(BoundingBox &assemblyBox) const {
931 if (m_map) {
932
933 if (m_map->hasComponentInfo(m_instr.get())) {
934 assemblyBox = m_map->componentInfo().boundingBox(index(), &assemblyBox);
935 return;
936 }
937
938 // Loop over the children and define a box large enough for all of them
939 ComponentID sourceID = getSource()->getComponentID();
940 assemblyBox = BoundingBox(); // this makes the instrument BB always axis aligned
941 int nchildren = nelements();
942 for (int i = 0; i < nchildren; ++i) {
943 IComponent_sptr comp = this->getChild(i);
944 if (comp && comp->getComponentID() != sourceID) {
945 BoundingBox compBox;
946 comp->getBoundingBox(compBox);
947 assemblyBox.grow(compBox);
948 }
949 }
950 } else {
951
952 if (!m_cachedBoundingBox) {
954 ComponentID sourceID = getSource()->getComponentID();
955 // Loop over the children and define a box large enough for all of them
956 for (const auto component : m_children) {
957 BoundingBox compBox;
958 if (component && component->getComponentID() != sourceID) {
959 component->getBoundingBox(compBox);
960 m_cachedBoundingBox->grow(compBox);
961 }
962 }
963 }
964 // Use cached box
965 assemblyBox = *m_cachedBoundingBox;
966 }
967}
968
969std::shared_ptr<const std::vector<IObjComponent_const_sptr>> Instrument::getPlottable() const {
970 if (m_map) {
971 // Get the 'base' plottable components
972 std::shared_ptr<const std::vector<IObjComponent_const_sptr>> objs = m_instr->getPlottable();
973
974 // Get a reference to the underlying vector, casting away the constness so that we
975 // can modify it to get our result rather than creating another long vector
976 auto &res = const_cast<std::vector<IObjComponent_const_sptr> &>(*objs);
977 const std::vector<IObjComponent_const_sptr>::size_type total = res.size();
978 for (std::vector<IObjComponent_const_sptr>::size_type i = 0; i < total; ++i) {
979 res[i] = std::dynamic_pointer_cast<const Detector>(ParComponentFactory::create(objs->at(i), m_map));
980 }
981 return objs;
982
983 } else {
984 // Base instrument
985 auto res = std::make_shared<std::vector<IObjComponent_const_sptr>>();
986 res->reserve(m_detectorCache.size() + 10);
987 appendPlottable(*this, *res);
988 return res;
989 }
990}
991
992void Instrument::appendPlottable(const CompAssembly &ca, std::vector<IObjComponent_const_sptr> &lst) const {
993 for (int i = 0; i < ca.nelements(); i++) {
994 IComponent *c = ca[i].get();
995 const auto *a = dynamic_cast<CompAssembly *>(c);
996 if (a)
997 appendPlottable(*a, lst);
998 else {
999 auto *d = dynamic_cast<Detector *>(c);
1000 auto *o = dynamic_cast<ObjComponent *>(c);
1001 if (d)
1002 lst.emplace_back(IObjComponent_const_sptr(d, NoDeleting()));
1003 else if (o)
1004 lst.emplace_back(IObjComponent_const_sptr(o, NoDeleting()));
1005 else
1006 g_log.error() << "Unknown comp type\n";
1007 }
1008 }
1009}
1010
1011//------------------------------------------------------------------------------------------------
1020void Instrument::getInstrumentParameters(double &l1, Kernel::V3D &beamline, double &beamline_norm,
1021 Kernel::V3D &samplePos) const {
1022 // Get some positions
1023 const IComponent_const_sptr sourceObj = this->getSource();
1024 if (sourceObj == nullptr) {
1025 throw Exception::InstrumentDefinitionError("Failed to get source component from instrument");
1026 }
1027 const Kernel::V3D sourcePos = sourceObj->getPos();
1028 samplePos = this->getSample()->getPos();
1029 beamline = samplePos - sourcePos;
1030 beamline_norm = 2.0 * beamline.norm();
1031
1032 // Get the distance between the source and the sample (assume in metres)
1033 IComponent_const_sptr sample = this->getSample();
1034 try {
1035 l1 = this->getSource()->getDistance(*sample);
1036 } catch (Exception::NotFoundError &) {
1037 throw Exception::InstrumentDefinitionError("Unable to calculate source-sample distance ", this->getName());
1038 }
1039}
1040
1041//--------------------------------------------------------------------------------------------
1044void Instrument::setFilename(const std::string &filename) {
1045 if (m_map)
1046 m_instr->m_filename = filename;
1047 else
1048 m_filename = filename;
1049}
1050
1053const std::string &Instrument::getFilename() const {
1054 if (m_map)
1055 return m_instr->getFilename();
1056 else
1057 return m_filename;
1058}
1059
1061void Instrument::setXmlText(const std::string &XmlText) {
1062 if (m_map)
1063 m_instr->m_xmlText = XmlText;
1064 else
1065 m_xmlText = XmlText;
1066}
1067
1069const std::string &Instrument::getXmlText() const {
1070 if (m_map)
1071 return m_instr->getXmlText();
1072 else
1073 return m_xmlText;
1074}
1075
1076//--------------------------------------------------------------------------------------------
1085void Instrument::saveNexus(Nexus::File *file, const std::string &group) const {
1086 file->makeGroup(group, "NXinstrument", true);
1087 file->putAttr("version", 1);
1088
1089 file->writeData("name", getName());
1090
1091 // XML contents of instrument, as a NX note
1092 file->makeGroup("instrument_xml", "NXnote", true);
1093 const std::string &xmlText = getXmlText();
1094 if (xmlText.empty())
1095 g_log.warning() << "Saving Instrument with no XML data. If this was "
1096 "instrument data you may not be able to load this data "
1097 "back into Mantid, for fitted/analysed data this "
1098 "warning can be ignored.\n";
1099 file->writeData("data", xmlText);
1100 file->writeData("type", "text/xml"); // mimetype
1101 file->writeData("description", "XML contents of the instrument IDF file.");
1102 file->closeGroup();
1103
1104 // Now the parameter map, as a NXnote via its saveNexus method
1105 if (isParametrized()) {
1106 // Map with data extracted from DetectorInfo -> legacy compatible files.
1107 const auto &pmap = *getParameterMap();
1108 const auto parameters = legacyParameters();
1109 ParameterMap::saveNexus(file, "instrument_parameter_map",
1110 parameters.empty()
1111 ? std::string()
1112 : ParameterMap::asString(parameters, pmap.componentInfo(), pmap.detectorInfo()));
1113 }
1114
1115 // Add physical detector data
1116 auto detectorIDs = getDetectorIDs(true);
1117 if (!detectorIDs.empty()) {
1118 // Add detectors group
1119 file->makeGroup("physical_detectors", "NXdetector", true);
1120 file->writeData("number_of_detectors", uint64_t(detectorIDs.size()));
1121 saveDetectorSetInfoToNexus(file, detectorIDs);
1122 file->closeGroup(); // detectors
1123 }
1124
1125 // Add monitor data
1126 auto monitorIDs = getMonitorIDs();
1127 if (!monitorIDs.empty()) {
1128 // Add Monitors group
1129 file->makeGroup("physical_monitors", "NXmonitor", true);
1130 file->writeData("number_of_monitors", uint64_t(monitorIDs.size()));
1131 saveDetectorSetInfoToNexus(file, monitorIDs);
1132 file->closeGroup(); // monitors
1133 }
1134
1135 file->closeGroup();
1136}
1137
1138/* A private helper function so save information about a set of detectors to
1139 * Nexus
1140 * @param file :: open Nexus file ready to recieve the info about the set of
1141 * detectors
1142 * a group must be open that has only one call of this function.
1143 * @param detIDs :: the dectector IDs of the detectors belonging to the set
1144 */
1145void Instrument::saveDetectorSetInfoToNexus(Nexus::File *file, const std::vector<detid_t> &detIDs) const {
1146
1147 size_t nDets = detIDs.size();
1148 if (nDets == 0)
1149 return;
1150 auto detectors = getDetectors(detIDs);
1151
1153 Kernel::V3D sample_pos;
1154 if (sample)
1155 sample_pos = sample->getPos();
1156
1157 std::vector<double> a_angles(nDets);
1158 std::vector<double> p_angles(nDets);
1159 std::vector<double> distances(nDets);
1160
1161 for (size_t i = 0; i < nDets; i++) {
1162 if (sample) {
1163 Kernel::V3D pos = detectors[i]->getPos() - sample_pos;
1164 pos.getSpherical(distances[i], p_angles[i], a_angles[i]);
1165 } else {
1166 a_angles[i] = detectors[i]->getPhi() * 180.0 / M_PI;
1167 }
1168 }
1169 file->writeData("detector_number", detIDs);
1170 file->writeData("azimuthal_angle", a_angles);
1171 file->openData("azimuthal_angle");
1172 file->putAttr("units", "degree");
1173 file->closeData();
1174 if (sample) {
1175 file->writeData("polar_angle", p_angles);
1176 file->openData("polar_angle");
1177 file->putAttr("units", "degree");
1178 file->closeData();
1179 file->writeData("distance", distances);
1180 file->openData("distance");
1181 file->putAttr("units", "metre");
1182 file->closeData();
1183 }
1184}
1185
1186//--------------------------------------------------------------------------------------------
1191void Instrument::loadNexus(Nexus::File *file, const std::string &group) {
1192 file->openGroup(group, "NXinstrument");
1193 file->closeGroup();
1194}
1195
1200void Instrument::setReferenceFrame(std::shared_ptr<ReferenceFrame> frame) { m_referenceFrame = std::move(frame); }
1201
1206std::shared_ptr<const ReferenceFrame> Instrument::getReferenceFrame() const {
1207 if (m_map) {
1208 return m_instr->getReferenceFrame();
1209 } else {
1210 return m_referenceFrame;
1211 }
1212}
1213
1222void Instrument::setDefaultView(const std::string &type) {
1223 std::string typeUC(type);
1224 std::transform(typeUC.begin(), typeUC.end(), typeUC.begin(), toupper);
1225 if (typeUC == "3D" || typeUC == "CYLINDRICAL_X" || typeUC == "CYLINDRICAL_Y" || typeUC == "CYLINDRICAL_Z" ||
1226 typeUC == "SPHERICAL_X" || typeUC == "SPHERICAL_Y" || typeUC == "SPHERICAL_Z") {
1227 m_defaultView = typeUC;
1228 } else {
1229 m_defaultView = "3D";
1230 g_log.warning() << type << " is not allowed as an instrument view type. Default to \"3D\"" << '\n';
1231 }
1232}
1233
1238void Instrument::setValidFromDate(const Types::Core::DateAndTime &val) {
1239 Types::Core::DateAndTime earliestAllowedDate("1900-01-31 23:59:01");
1240 if (val < earliestAllowedDate) {
1242 "The valid-from <instrument> tag date must be from 1900-01-31 23:59:01 "
1243 "or later",
1244 m_filename);
1245 }
1246 m_ValidFrom = val;
1247}
1248
1250 std::queue<IComponent_const_sptr> compQueue; // Search queue
1252
1253 bool foundRect = false;
1254 bool foundNonRect = false;
1255
1257
1258 while (!compQueue.empty() && !(foundRect && foundNonRect)) {
1259 comp = compQueue.front();
1260 compQueue.pop();
1261
1262 if (!validateComponentProperties(comp))
1263 continue;
1264
1265 if (dynamic_cast<const RectangularDetector *>(comp.get())) {
1266 foundRect = true;
1267 } // If component isn't a ComponentAssembly, we know it is a non-rectangular detector. Otherwise check its children
1268 else if (!addAssemblyChildrenToQueue(compQueue, comp)) {
1269 foundNonRect = true;
1270 }
1271 }
1272
1273 // Found both
1274 if (foundRect && foundNonRect)
1276 // Found only rectangular
1277 else if (foundRect)
1279 // Found only non-rectangular
1280 else
1282}
1283
1285 // Skip source, if has one
1286 if (m_sourceCache && m_sourceCache->getComponentID() == component->getComponentID())
1287 return false;
1288
1289 // Skip sample, if has one
1290 if (m_sampleCache && m_sampleCache->getComponentID() == component->getComponentID())
1291 return false;
1292
1293 // Skip monitors
1294 IDetector_const_sptr detector = std::dynamic_pointer_cast<const IDetector>(component);
1295 if (detector && isMonitor(detector->getID()))
1296 return false;
1297
1298 // skip choppers, slits and supermirrors - HACK!
1299 const auto &name = component->getName();
1300 if (name == "chopper-position" || name.substr(0, 4) == "slit" || name == "supermirror") {
1301 return false;
1302 }
1303
1304 return true;
1305}
1306
1307void Instrument::addInstrumentChildrenToQueue(std::queue<IComponent_const_sptr> &queue) const {
1308 // Add all the direct children of the instrument
1309 for (int i = 0; i < nelements(); i++)
1310 queue.push(getChild(i));
1311}
1312
1315bool Instrument::addAssemblyChildrenToQueue(std::queue<IComponent_const_sptr> &queue,
1316 IComponent_const_sptr component) const {
1317 if (auto const assembly = std::dynamic_pointer_cast<const ICompAssembly>(component)) {
1318 for (int i = 0; i < assembly->nelements(); i++)
1319 queue.push(assembly->getChild(i));
1320 return true;
1321 }
1322 return false;
1323}
1324
1326bool Instrument::isMonitorViaIndex(const size_t index) const {
1327 const auto &in_dets = m_map ? m_instr->m_detectorCache : m_detectorCache;
1328 if (!in_dets.isFinalized())
1329 throw std::runtime_error("Instrument::isMonitorViaIndex: detector cache is not finalized");
1330 if (index >= in_dets.size())
1331 throw std::out_of_range("Instrument::isMonitorViaIndex: index out of range");
1332 return in_dets[index].isMonitor();
1333}
1334
1335bool Instrument::isEmptyInstrument() const { return this->nelements() == 0; }
1336
1338size_t Instrument::detectorIndex(const detid_t detID) const {
1339 if (!isFinalized())
1340 throw std::runtime_error("Instrument definition is not finalized. Can't get detector index for ID " +
1341 std::to_string(detID));
1342
1343 const auto &in_dets = m_map ? m_instr->m_detectorCache : m_detectorCache;
1344 const auto it = in_dets.find(detID);
1345 return std::distance(in_dets.cbegin(), it);
1346}
1347
1350std::vector<ParameterMap::Entry> Instrument::legacyParameters() const {
1351 if (!isFinalized())
1352 throw std::runtime_error("Instrument definition is not finalized. Can't create legacy parameters.");
1353
1354 const auto &pmap = *getParameterMap();
1355 const auto &baseInstr = m_map ? *m_instr : *this;
1356
1357 if (!pmap.hasComponentInfo(&baseInstr))
1358 return pmap.entries();
1359
1360 // Start from a copy of the instrument's parameters. add() replaces a parameter of the same name.
1361 ParameterInfo legacy(*pmap.sharedParameterInfo());
1362 auto const makeParameter = [](const std::string &type, const std::string &name, auto const &value) {
1363 auto parameter = ParameterFactory::create(type, name);
1364 parameter->set(value);
1365 return parameter;
1366 };
1367
1368 // Tolerance 1e-9 m with rotation center at a distance of L = 1000 m as in
1369 // Beamline::DetectorInfo::isEquivalent.
1370 constexpr double d_max = 1e-9;
1371 constexpr double L = 1000.0;
1372 constexpr double safety_factor = 2.0;
1373 const double imag_norm_max = sin(d_max / (2.0 * L * safety_factor));
1374
1375 auto transformation = Eigen::Affine3d::Identity();
1376 int64_t oldParentIndex = -1;
1377
1378 const auto &componentInfo = pmap.componentInfo();
1379 const auto &detectorInfo = pmap.detectorInfo();
1380 for (size_t i = 0; i < componentInfo.size(); ++i) {
1381
1382 const int64_t parentIndex = componentInfo.parent(i);
1383 const bool makeTransform = parentIndex != oldParentIndex;
1384 bool isDetFixedInBank = false;
1385
1386 if (makeTransform) {
1387 oldParentIndex = parentIndex;
1388 const auto parentPos = toVector3d(componentInfo.position(parentIndex));
1389 const auto invParentRot = toQuaterniond(componentInfo.rotation(parentIndex)).conjugate();
1390
1391 transformation = invParentRot;
1392 transformation.translate(-parentPos);
1393 }
1394
1395 if (componentInfo.isDetector(i)) {
1396 isDetFixedInBank = ComponentInfoBankHelpers::isDetectorFixedInBank(componentInfo, i);
1397 if (detectorInfo.isMasked(i)) {
1398 // insert() rather than add(), as ParameterMap::forceUnsafeSetMasked() does
1399 legacy.insert(i, makeParameter(ParameterMap::pBool(), "masked", true));
1400 }
1401
1402 if (makeTransform) {
1403 // Special case: scaling for GridDetectorPixel.
1404 if (isDetFixedInBank) {
1405
1406 size_t panelIndex = componentInfo.parent(parentIndex);
1407
1408 Eigen::Vector3d scale(1, 1, 1);
1409 if (auto scalex = legacy.get(panelIndex, "scalex"))
1410 scale[0] = 1.0 / scalex->value<double>();
1411 if (auto scaley = legacy.get(panelIndex, "scaley"))
1412 scale[1] = 1.0 / scaley->value<double>();
1413 transformation.prescale(scale);
1414 }
1415 }
1416 }
1417
1418 const IComponent *baseComponent = componentInfo.componentID(i)->getBaseComponent();
1419 // Generic sca scale factors
1420 const auto newScaleFactor = Kernel::toVector3d(componentInfo.scaleFactor(i));
1421 if ((newScaleFactor - toVector3d(baseComponent->getScaleFactor())).norm() >= 1e-9) {
1422 legacy.add(i, makeParameter(ParameterMap::pV3D(), ParameterMap::scale(), componentInfo.scaleFactor(i)));
1423 }
1424
1425 // Undo parent transformation to obtain relative position/rotation.
1426 Eigen::Vector3d relPos = transformation * toVector3d(componentInfo.position(i));
1427 Eigen::Quaterniond relRot = toQuaterniond(componentInfo.relativeRotation(i));
1428
1429 // Tolerance 1e-9 m as in Beamline::DetectorInfo::isEquivalent.
1430 if ((relPos - toVector3d(baseComponent->getRelativePos())).norm() >= 1e-9) {
1431 if (isDetFixedInBank) {
1432 throw std::runtime_error(
1433 "Cannot create legacy parameters: Position parameters for GridDetectorPixel are not supported");
1434 }
1435 legacy.add(i, makeParameter(ParameterMap::pV3D(), ParameterMap::pos(), Kernel::toV3D(relPos)));
1436 }
1437 if ((relRot * toQuaterniond(baseComponent->getRelativeRot()).conjugate()).vec().norm() >= imag_norm_max) {
1438 legacy.add(i, makeParameter(ParameterMap::pQuat(), ParameterMap::rot(), Kernel::toQuat(relRot)));
1439 }
1440 }
1441
1442 std::vector<ParameterMap::Entry> result;
1443 result.reserve(legacy.size());
1444 for (auto const &[index, parameters] : legacy) {
1445 for (auto const &[parameterName, parameter] : parameters) {
1446 static_cast<void>(parameterName);
1447 result.emplace_back(index, parameter);
1448 }
1449 }
1450 return result;
1451}
1452
1460 if (isParametrized())
1461 throw std::logic_error(
1462 "Instrument::parseTreeAndCacheBeamline must be called with the base instrument, not a parametrized instrument");
1464}
1465
1471std::pair<std::unique_ptr<ComponentInfo>, std::unique_ptr<DetectorInfo>>
1473 // If we have source and it has Beamline objects just copy them
1474 if (source && source->hasComponentInfo(this)) {
1475 return makeWrappers(pmap, source->componentInfo(), source->detectorInfo());
1476 }
1477 // If pmap is empty and base instrument has Beamline objects just copy them
1478 if (pmap.empty() && m_componentInfo) {
1480 }
1481 // pmap not empty and/or no cached Beamline objects found
1482 return InstrumentVisitor::makeWrappers(*this, &pmap);
1483}
1484
1489std::pair<std::unique_ptr<ComponentInfo>, std::unique_ptr<DetectorInfo>>
1493
1495std::pair<std::unique_ptr<ComponentInfo>, std::unique_ptr<DetectorInfo>>
1497 const DetectorInfo &detectorInfo) const {
1498 auto compInfo = componentInfo.cloneWithoutDetectorInfo();
1499 auto detInfo = std::make_unique<DetectorInfo>(detectorInfo);
1500 compInfo->m_componentInfo->setDetectorInfo(detInfo->m_detectorInfo.get());
1501 // Point the clone at THIS map's parameter store, attaching the map to the clone's index domain if
1502 // it is not already: the map is either empty or a copy of one attached to that domain.
1503 compInfo->m_parameterInfo = pmap.rekey(compInfo->m_componentIds, compInfo->m_compIDToIndex);
1504 detInfo->m_parameterInfo = compInfo->m_parameterInfo;
1505 // Take the frame from the instrument rather than the cached copy, in case it was set after the cache was built.
1506 compInfo->m_referenceFrame = getReferenceFrame();
1507 detInfo->m_referenceFrame = compInfo->m_referenceFrame;
1508 const auto parInstrument = ParComponentFactory::createInstrument(
1509 std::shared_ptr<const Instrument>(this, NoDeleting()), std::shared_ptr<ParameterMap>(&pmap, NoDeleting()));
1510 detInfo->m_instrument = parInstrument;
1511 return {std::move(compInfo), std::move(detInfo)};
1512}
1513
1518 // A parametrized instrument is a thin wrapper around a base instrument: it holds a shared_ptr to
1519 // the base (m_instr) but owns none of the component tree, detector cache, or beamline objects.
1520 // Delegate to the base and add only the ParameterMap overhead.
1521 if (m_instr) {
1522 const size_t paramMapMem = m_map_nonconst ? m_map_nonconst->getMemorySize() : 0;
1523 return sizeof(*this) + m_instr->getMemorySize() + paramMapMem;
1524 }
1525
1526 // Each std::map node carries ~4 pointers of red-black-tree overhead beyond the stored value_type.
1527 const size_t mapNodeOverhead = 4 * sizeof(void *);
1528
1529 const size_t logfileCacheMem =
1530 m_logfileCache.size() * (sizeof(InstrumentParameterCache::value_type) + mapNodeOverhead);
1531 const size_t logfileUnitMem = m_logfileUnit.size() * (sizeof(decltype(m_logfileUnit)::value_type) + mapNodeOverhead);
1532
1533 const size_t detectorInfoMem = m_detectorInfo ? m_detectorInfo->getMemorySize() : 0;
1534 const size_t componentInfoMem = m_componentInfo ? m_componentInfo->getMemorySize() : 0;
1535
1536 // BFS over the component tree. The Instrument root is already counted via sizeof(*this),
1537 // so start the traversal from the root and add each child's type-accurate object size plus
1538 // the IComponent* slot it occupies in its parent's m_children buffer.
1539 size_t componentTreeMem = 0;
1540 std::queue<const ICompAssembly *> bfsQueue;
1541 bfsQueue.push(this);
1542 while (!bfsQueue.empty()) {
1543 const auto *assembly = bfsQueue.front();
1544 bfsQueue.pop();
1545 const int n = assembly->nelements();
1546 componentTreeMem += static_cast<size_t>(n) * sizeof(IComponent *);
1547 for (int i = 0; i < n; ++i) {
1548 auto child = assembly->getChild(i);
1549 const IComponent *raw = child.get();
1550 componentTreeMem += componentObjectSize(raw);
1551 if (const auto *sub = dynamic_cast<const ICompAssembly *>(raw))
1552 bfsQueue.push(sub);
1553 }
1554 }
1555
1556 // m_referenceFrame: heap-allocated ReferenceFrame object
1557 const size_t referenceFrameMem = m_referenceFrame ? sizeof(ReferenceFrame) : 0;
1558
1559 // Indirect-geometry instruments hold a second full instrument for the physical geometry.
1560 const size_t physicalInstrumentMem = m_physicalInstrument ? m_physicalInstrument->getMemorySize() : 0;
1561
1562 return sizeof(*this) + componentTreeMem + m_detectorCache.capacity() * sizeof(DetectorCacheEntry) + logfileCacheMem +
1563 logfileUnitMem + m_defaultView.capacity() + m_defaultViewAxis.capacity() + m_xmlText.capacity() +
1564 m_filename.capacity() + detectorInfoMem + componentInfoMem + referenceFrameMem + physicalInstrumentMem;
1565}
1566
1567namespace Conversion {
1568
1577double tofToDSpacingFactor(const double l1, const double l2, const double twoTheta, const double offset) {
1578 return Kernel::Units::tofToDSpacingFactor(l1, l2, twoTheta, offset);
1579}
1580
1581double calculateDIFCCorrection(const double l1, const double l2, const double twoTheta, const double offset,
1582 const double binWidth) {
1583 return Kernel::Units::calculateDIFCCorrection(l1, l2, twoTheta, offset, binWidth);
1584}
1585
1586} // namespace Conversion
1587} // namespace Mantid::Geometry
std::string name
Definition Run.cpp:60
double value
The value of the point.
Definition FitMW.cpp:51
#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.
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:318
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:291
Kernel::V3D getPos() const override
Get the position of the IComponent. Tree structure is traverse through the.
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:316
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:37
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
Make the wrappers from the data collected by walkInstrument(), which must be called first.
Base Instrument Class.
Definition Instrument.h:50
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:370
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:356
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:373
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:333
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:205
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:359
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:353
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:383
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:349
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:329
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::vector< std::pair< size_t, std::shared_ptr< Parameter > > > legacyParameters() const
The parameters in their legacy form, by component index, as ParameterMap::Entry.
std::string type() const override
String description of the type of component.
Definition Instrument.h:53
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:386
std::shared_ptr< const Instrument > m_physicalInstrument
Pointer to the physical instrument, where this differs from the 'neutronic' one (indirect geometry)
Definition Instrument.h:377
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:362
InstrumentParameterCache m_logfileCache
To store info about the parameters defined in IDF.
Definition Instrument.h:338
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:380
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:365
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...
static std::shared_ptr< Parameter > create(const std::string &className, const std::string &name, const std::string &visible="true")
Creates an instance of a parameter.
Definition Parameter.cpp:86
ParameterInfo : the named parameters of an instrument, addressed by component index.
void insert(size_t const componentIndex, std::shared_ptr< Parameter > const &parameter)
Insert a parameter without add()'s add-or-replace deduplication.
size_t size() const
The total number of parameters across all components.
std::shared_ptr< Parameter > get(size_t const componentIndex, std::string const &name, std::string const &type="") const
The named parameter on this component, or a null shared pointer if there is none.
void add(size_t const componentIndex, std::shared_ptr< Parameter > const &parameter)
Add a parameter, replacing any existing parameter of the same name on the same component.
Parameter map iterator typedef.
const Geometry::DetectorInfo & detectorInfo() const
Only for use by ExperimentInfo. Returns a reference to the DetectorInfo.
static const std::string & pQuat()
static const std::string & scale()
static const std::string & rot()
static const std::string & pBool()
static const std::string & pV3D()
static void saveNexus(Nexus::File *file, const std::string &group, const std::string &contents)
Persist a representation of a Parameter map, as given by asString(), to the open Nexus file.
static const std::string & pos()
Return string to be used in the map.
std::string asString() const
Returns a string with all component names, parameter names and values.
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:35
double norm() const noexcept
Definition V3D.h:270
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:171
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:165
std::shared_ptr< IComponent > IComponent_sptr
Typedef of a shared pointer to a IComponent.
Definition IComponent.h:163
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:96
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:353
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:279
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:316
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:297