Newer
Older
Russell Taylor
committed
#include "MantidGeometry/Instrument.h"
#include "MantidGeometry/Instrument/ParComponentFactory.h"
Gigg, Martyn Anthony
committed
#include "MantidGeometry/Instrument/DetectorGroup.h"
#include "MantidGeometry/Instrument/ReferenceFrame.h"
#include "MantidGeometry/Instrument/RectangularDetector.h"
Gigg, Martyn Anthony
committed
using namespace Mantid::Kernel;
using Mantid::Kernel::Exception::NotFoundError;
using Mantid::Kernel::Exception::InstrumentDefinitionError;
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
namespace Mantid {
namespace Geometry {
namespace {
Kernel::Logger g_log("Instrument");
}
/// Default constructor
Instrument::Instrument()
: CompAssembly(), m_detectorCache(), m_sourceCache(0),
m_chopperPoints(new std::vector<const ObjComponent *>), m_sampleCache(0),
m_defaultView("3D"), m_defaultViewAxis("Z+"),
m_referenceFrame(new ReferenceFrame) {}
/// Constructor with name
Instrument::Instrument(const std::string &name)
: CompAssembly(name), m_detectorCache(), m_sourceCache(0),
m_chopperPoints(new std::vector<const ObjComponent *>), m_sampleCache(0),
m_defaultView("3D"), m_defaultViewAxis("Z+"),
m_referenceFrame(new ReferenceFrame) {}
/** Constructor to create a parametrized instrument
* @param instr :: instrument for parameter inclusion
* @param map :: parameter map to include
*/
Instrument::Instrument(const boost::shared_ptr<const Instrument> instr,
boost::shared_ptr<ParameterMap> map)
: CompAssembly(instr.get(), map.get()), m_sourceCache(instr->m_sourceCache),
m_chopperPoints(instr->m_chopperPoints),
m_sampleCache(instr->m_sampleCache), m_defaultView(instr->m_defaultView),
m_defaultViewAxis(instr->m_defaultViewAxis), m_instr(instr),
m_map_nonconst(map), m_ValidFrom(instr->m_ValidFrom),
m_ValidTo(instr->m_ValidTo), m_referenceFrame(new ReferenceFrame) {}
/** Copy constructor
* This method was added to deal with having distinct neutronic and physical
* positions
* in indirect instruments.
*/
Instrument::Instrument(const Instrument &instr)
: CompAssembly(instr), m_sourceCache(NULL),
m_chopperPoints(new std::vector<const ObjComponent *>),
m_sampleCache(NULL), /* Should only be temporarily null */
m_logfileCache(instr.m_logfileCache), m_logfileUnit(instr.m_logfileUnit),
m_monitorCache(instr.m_monitorCache), m_defaultView(instr.m_defaultView),
m_defaultViewAxis(instr.m_defaultViewAxis), m_instr(),
m_map_nonconst(), /* Should not be parameterized */
m_ValidFrom(instr.m_ValidFrom), m_ValidTo(instr.m_ValidTo),
m_referenceFrame(instr.m_referenceFrame) {
// Now we need to fill the detector, source and sample caches with pointers
// into the new instrument
std::vector<IComponent_const_sptr> children;
getChildren(children, true);
std::vector<IComponent_const_sptr>::const_iterator it;
for (it = children.begin(); it != children.end(); ++it) {
// First check if the current component is a detector and add to cache if it
// is
// N.B. The list of monitors should remain unchanged. As the cache holds
// detector id
// numbers rather than pointers, there's no need for special handling
if (const IDetector *det = dynamic_cast<const Detector *>(it->get())) {
markAsDetector(det);
continue;
Janik Zikovsky
committed
}
// Now check whether the current component is the source or sample.
// As the majority of components will be detectors, we will rarely get to
// here
if (const ObjComponent *obj =
dynamic_cast<const ObjComponent *>(it->get())) {
const std::string objName = obj->getName();
// This relies on the source and sample having a unique name.
// I think the way our instrument definition files work ensures this is
// the case.
if (objName == instr.m_sourceCache->getName()) {
markAsSource(obj);
continue;
if (objName == instr.m_sampleCache->getName()) {
markAsSamplePos(obj);
continue;
for (size_t i = 0; i < instr.m_chopperPoints->size(); ++i) {
if (objName == (*m_chopperPoints)[i]->getName()) {
markAsChopperPoint(obj);
break;
}
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
}
}
/**
* Destructor
*/
Instrument::~Instrument() {
if (!m_map) {
m_chopperPoints->clear(); // CompAssembly will delete them
delete m_chopperPoints;
}
}
/// Virtual copy constructor
Instrument *Instrument::clone() const { return new Instrument(*this); }
/// Pointer to the 'real' instrument, for parametrized instruments
Instrument_const_sptr Instrument::baseInstrument() const {
if (m_map)
return m_instr;
else
throw std::runtime_error("Instrument::baseInstrument() called for a "
"non-parametrized instrument.");
}
/**
* Pointer to the ParameterMap holding the parameters of the modified instrument
* components.
* @return parameter map from modified instrument components
*/
ParameterMap_sptr Instrument::getParameterMap() const {
if (m_map)
return m_map_nonconst;
else
throw std::runtime_error("Instrument::getParameterMap() called for a "
"non-parametrized instrument.");
}
/** INDIRECT GEOMETRY INSTRUMENTS ONLY: Returns the physical instrument,
* if one has been specified as distinct from the 'neutronic' one.
* Otherwise (and most commonly) returns a null pointer, meaning that the
* holding
* instrument is already the physical instrument.
*/
Instrument_const_sptr Instrument::getPhysicalInstrument() const {
if (m_map) {
if (m_instr->getPhysicalInstrument()) {
// A physical instrument should use the same parameter map as the 'main'
// instrument
return Instrument_const_sptr(
new Instrument(m_instr->getPhysicalInstrument(), m_map_nonconst));
} else {
return Instrument_const_sptr();
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
} else {
return m_physicalInstrument;
}
}
/** INDIRECT GEOMETRY INSTRUMENTS ONLY: Sets the physical instrument.
* The holding instrument is then the 'neutronic' one, and is used in all
* algorithms.
* @param physInst A pointer to the physical instrument object.
*/
void Instrument::setPhysicalInstrument(
boost::shared_ptr<const Instrument> physInst) {
if (!m_map)
m_physicalInstrument = physInst;
else
throw std::runtime_error("Instrument::setPhysicalInstrument() called on a "
"parametrized instrument.");
}
//------------------------------------------------------------------------------------------
/** Fills a copy of the detector cache
* @returns a map of the detectors hold by the instrument
*/
void Instrument::getDetectors(detid2det_map &out_map) const {
if (m_map) {
// Get the base instrument detectors
out_map.clear();
const detid2det_map &in_dets =
static_cast<const Instrument *>(m_base)->m_detectorCache;
// And turn them into parametrized versions
for (detid2det_map::const_iterator it = in_dets.begin();
it != in_dets.end(); ++it) {
out_map.insert(std::pair<detid_t, IDetector_sptr>(
it->first,
ParComponentFactory::createDetector(it->second.get(), m_map)));
Janik Zikovsky
committed
}
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
} else {
// You can just return the detector cache directly.
out_map = m_detectorCache;
}
}
//------------------------------------------------------------------------------------------
/** Return a vector of detector IDs in this instrument */
std::vector<detid_t> Instrument::getDetectorIDs(bool skipMonitors) const {
std::vector<detid_t> out;
if (m_map) {
const detid2det_map &in_dets =
static_cast<const Instrument *>(m_base)->m_detectorCache;
for (detid2det_map::const_iterator it = in_dets.begin();
it != in_dets.end(); ++it)
if (!skipMonitors || !it->second->isMonitor())
out.push_back(it->first);
} else {
const detid2det_map &in_dets = m_detectorCache;
for (detid2det_map::const_iterator it = in_dets.begin();
it != in_dets.end(); ++it)
if (!skipMonitors || !it->second->isMonitor())
out.push_back(it->first);
}
return out;
}
Janik Zikovsky
committed
/// @return The total number of detector IDs in the instrument */
std::size_t Instrument::getNumberDetectors(bool skipMonitors) const {
std::size_t numDetIDs(0);
Janik Zikovsky
committed
if (m_map) {
numDetIDs = static_cast<const Instrument *>(m_base)->m_detectorCache.size();
} else {
numDetIDs = m_detectorCache.size();
}
Gigg, Martyn Anthony
committed
if (skipMonitors) // this slow, but gets the right answer
{
std::size_t monitors(0);
if (m_map) {
const detid2det_map &in_dets =
static_cast<const Instrument *>(m_base)->m_detectorCache;
for (detid2det_map::const_iterator it = in_dets.begin();
it != in_dets.end(); ++it)
if (it->second->isMonitor())
monitors += 1;
} else {
const detid2det_map &in_dets = m_detectorCache;
for (detid2det_map::const_iterator it = in_dets.begin();
it != in_dets.end(); ++it)
if (it->second->isMonitor())
monitors += 1;
}
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
return (numDetIDs - monitors);
} else {
return numDetIDs;
}
}
/** Get the minimum and maximum (inclusive) detector IDs
*
* @param min :: set to the min detector ID
* @param max :: set to the max detector ID
*/
void Instrument::getMinMaxDetectorIDs(detid_t &min, detid_t &max) const {
const detid2det_map *in_dets;
if (m_map)
in_dets = &(static_cast<const Instrument *>(m_base)->m_detectorCache);
else
in_dets = &this->m_detectorCache;
if (in_dets->empty())
throw std::runtime_error(
"No detectors on this instrument. Can't find min/max ids");
// Maps are sorted by key. So it is easy to find
min = in_dets->begin()->first;
max = in_dets->rbegin()->first;
}
//------------------------------------------------------------------------------------------
/** Fill a vector with all the detectors contained (at any depth) in a named
*component. For example,
* you might have a bank10 with 4 tubes with 100 pixels each; this will return
*the
* 400 contained Detector objects.
*
* @param[out] dets :: vector filled with detector pointers
* @param bankName :: name of the parent component assembly that contains
*detectors.
* The name must be unique, otherwise the first matching component
*(getComponentByName)
* is used.
*/
void Instrument::getDetectorsInBank(std::vector<IDetector_const_sptr> &dets,
const std::string &bankName) const {
boost::shared_ptr<const IComponent> comp = this->getComponentByName(bankName);
boost::shared_ptr<const ICompAssembly> bank =
boost::dynamic_pointer_cast<const ICompAssembly>(comp);
if (bank) {
// Get a vector of children (recursively)
std::vector<boost::shared_ptr<const IComponent>> children;
bank->getChildren(children, true);
std::vector<boost::shared_ptr<const IComponent>>::iterator it;
for (it = children.begin(); it != children.end(); ++it) {
IDetector_const_sptr det =
boost::dynamic_pointer_cast<const IDetector>(*it);
if (det) {
dets.push_back(det);
}
Gigg, Martyn Anthony
committed
}
}
}
//------------------------------------------------------------------------------------------
/** Gets a pointer to the source
* @returns a pointer to the source
*/
IComponent_const_sptr Instrument::getSource() const {
if (!m_sourceCache) {
g_log.warning("In Instrument::getSource(). No source has been set.");
return IComponent_const_sptr(m_sourceCache, NoDeleting());
} else if (m_map) {
auto sourceCache = static_cast<const Instrument *>(m_base)->m_sourceCache;
if (dynamic_cast<const ObjComponent *>(sourceCache))
return IComponent_const_sptr(new ObjComponent(sourceCache, m_map));
else if (dynamic_cast<const CompAssembly *>(sourceCache))
return IComponent_const_sptr(new CompAssembly(sourceCache, m_map));
else if (dynamic_cast<const Component *>(sourceCache))
return IComponent_const_sptr(new Component(sourceCache, m_map));
else {
g_log.error("In Instrument::getSource(). Source is not a recognised "
"component type.");
g_log.error("Try to assume it is a Component.");
return IComponent_const_sptr(new ObjComponent(sourceCache, m_map));
Russell Taylor
committed
}
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
} else {
return IComponent_const_sptr(m_sourceCache, NoDeleting());
}
}
/**
* Returns the chopper at the given index. Index 0 is defined as closest to the
* source
* If there are no choppers defined or the index is out of range then an
* invalid_argument
* exception is thrown.
* @param index :: Defines which chopper to pick, 0 being closest to the source
* [Default = 0]
* @return A pointer to the chopper
*/
IObjComponent_const_sptr Instrument::getChopperPoint(const size_t index) const {
if (index >= getNumberOfChopperPoints()) {
std::ostringstream os;
os << "Instrument::getChopperPoint - No chopper point at index '" << index
<< "' defined. Instrument has only " << getNumberOfChopperPoints()
<< " chopper points defined.";
throw std::invalid_argument(os.str());
}
return IObjComponent_const_sptr(m_chopperPoints->at(index), NoDeleting());
}
/**
* @return The number of chopper points defined by this instrument
*/
size_t Instrument::getNumberOfChopperPoints() const {
return m_chopperPoints->size();
}
//------------------------------------------------------------------------------------------
/** Gets a pointer to the Sample Position
* @returns a pointer to the Sample Position
*/
IComponent_const_sptr Instrument::getSample() const {
if (!m_sampleCache) {
g_log.warning("In Instrument::getSamplePos(). No SamplePos has been set.");
return IComponent_const_sptr(m_sampleCache, NoDeleting());
} else if (m_map) {
auto sampleCache = static_cast<const Instrument *>(m_base)->m_sampleCache;
if (dynamic_cast<const ObjComponent *>(sampleCache))
return IComponent_const_sptr(new ObjComponent(sampleCache, m_map));
else if (dynamic_cast<const CompAssembly *>(sampleCache))
return IComponent_const_sptr(new CompAssembly(sampleCache, m_map));
else if (dynamic_cast<const Component *>(sampleCache))
return IComponent_const_sptr(new Component(sampleCache, m_map));
else {
g_log.error("In Instrument::getSamplePos(). SamplePos is not a "
"recognised component type.");
g_log.error("Try to assume it is a Component.");
return IComponent_const_sptr(new ObjComponent(sampleCache, m_map));
Russell Taylor
committed
}
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
} else {
return IComponent_const_sptr(m_sampleCache, NoDeleting());
}
}
/** Gets the beam direction (i.e. source->sample direction).
* Not virtual because it relies the getSample() & getPos() virtual functions
* @returns A unit vector denoting the direction of the beam
*/
Kernel::V3D Instrument::getBeamDirection() const {
V3D retval = getSample()->getPos() - getSource()->getPos();
retval.normalize();
return retval;
}
//------------------------------------------------------------------------------------------
/** Get a shared pointer to a component by its ID, const version
* @param id :: ID
* @return A pointer to the component.
*/
boost::shared_ptr<const IComponent>
Instrument::getComponentByID(ComponentID id) const {
const IComponent *base = (const IComponent *)(id);
if (m_map)
return ParComponentFactory::create(
boost::shared_ptr<const IComponent>(base, NoDeleting()), m_map);
else
return boost::shared_ptr<const IComponent>(base, NoDeleting());
}
/** Find all components in an Instrument Definition File (IDF) with a given
* name. If you know a component
* has a unique name use instead getComponentByName(), which is as fast or
* faster for retrieving a uniquely
* named component.
* @param cname :: The name of the component. If there are multiple matches,
* the first one found is returned.
* @returns Pointers to components
*/
std::vector<boost::shared_ptr<const IComponent>>
Instrument::getAllComponentsWithName(const std::string &cname) const {
boost::shared_ptr<const IComponent> node =
boost::shared_ptr<const IComponent>(this, NoDeleting());
std::vector<boost::shared_ptr<const IComponent>> retVec;
// Check the instrument name first
if (this->getName() == cname) {
retVec.push_back(node);
}
// Same algorithm as used in getComponentByName() but searching the full tree
std::deque<boost::shared_ptr<const IComponent>> nodeQueue;
// Need to be able to enter the while loop
nodeQueue.push_back(node);
while (!nodeQueue.empty()) {
node = nodeQueue.front();
nodeQueue.pop_front();
int nchildren(0);
boost::shared_ptr<const ICompAssembly> asmb =
boost::dynamic_pointer_cast<const ICompAssembly>(node);
if (asmb) {
nchildren = asmb->nelements();
Gigg, Martyn Anthony
committed
}
for (int i = 0; i < nchildren; ++i) {
boost::shared_ptr<const IComponent> comp = (*asmb)[i];
if (comp->getName() == cname) {
retVec.push_back(comp);
} else {
nodeQueue.push_back(comp);
Gigg, Martyn Anthony
committed
}
}
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
} // while-end
// If we have reached here then the search failed
return retVec;
}
/** Gets a pointer to the detector from its ID
* Note that for getting the detector associated with a spectrum, the
* MatrixWorkspace::getDetector
* method should be used rather than this one because it takes account of the
* possibility of more
* than one detector contributing to a single spectrum
* @param detector_id The requested detector ID
* @returns A pointer to the detector object
* @throw NotFoundError If no detector is found for the detector ID given
*/
IDetector_const_sptr Instrument::getDetector(const detid_t &detector_id) const {
if (m_map) {
IDetector_const_sptr baseDet = m_instr->getDetector(detector_id);
return ParComponentFactory::createDetector(baseDet.get(), m_map);
} else {
detid2det_map::const_iterator it = m_detectorCache.find(detector_id);
if (it == m_detectorCache.end()) {
std::stringstream readInt;
readInt << detector_id;
throw Kernel::Exception::NotFoundError(
"Instrument: Detector with ID " + readInt.str() + " not found.", "");
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
/** Gets a pointer to the base (non-parametrized) detector from its ID
* returns null if the detector has not been found
* @param detector_id The requested detector ID
* @returns A const pointer to the detector object
*/
const IDetector *Instrument::getBaseDetector(const detid_t &detector_id) const {
detid2det_map::const_iterator it = m_instr->m_detectorCache.find(detector_id);
if (it == m_instr->m_detectorCache.end()) {
return NULL;
}
return it->second.get();
}
bool Instrument::isMonitor(const detid_t &detector_id) const {
// Find the (base) detector object in the map.
detid2det_map::const_iterator it = m_instr->m_detectorCache.find(detector_id);
if (it == m_instr->m_detectorCache.end())
return false;
// This is the detector
const Detector *det = dynamic_cast<const Detector *>(it->second.get());
if (det == NULL)
return false;
return det->isMonitor();
}
bool Instrument::isMonitor(const std::set<detid_t> &detector_ids) const {
if (detector_ids.empty())
return false;
for (std::set<detid_t>::const_iterator it = detector_ids.begin();
it != detector_ids.end(); ++it) {
if (this->isMonitor(*it))
return true;
}
return false;
}
//--------------------------------------------------------------------------
/** Is the detector with the given ID masked?
*
* @param detector_id :: detector ID to look for.
* @return true if masked; false if not masked or if the detector was not found.
*/
bool Instrument::isDetectorMasked(const detid_t &detector_id) const {
// With no parameter map, then no detector is EVER masked
if (!isParametrized())
return false;
// Find the (base) detector object in the map.
detid2det_map::const_iterator it = m_instr->m_detectorCache.find(detector_id);
if (it == m_instr->m_detectorCache.end())
return false;
// This is the detector
const Detector *det = dynamic_cast<const Detector *>(it->second.get());
if (det == NULL)
return false;
// Access the parameter map directly.
Parameter_sptr maskedParam = m_map->get(det, "masked");
if (!maskedParam)
return false;
// If the parameter is defined, then yes, it is masked.
return maskedParam->value<bool>();
}
//--------------------------------------------------------------------------
/** Is this group of detectors masked?
*
* This returns true (masked) if ALL of the detectors listed are masked.
* It returns false (not masked) if there are no detectors in the list
* It returns false (not masked) if any of the detectors are NOT masked.
*
* @param detector_ids :: set of detector IDs
* @return true if masked.
*/
bool Instrument::isDetectorMasked(const std::set<detid_t> &detector_ids) const {
if (detector_ids.empty())
return false;
for (std::set<detid_t>::const_iterator it = detector_ids.begin();
it != detector_ids.end(); ++it) {
if (!this->isDetectorMasked(*it))
}
return true;
}
/**
* Returns a pointer to the geometrical object for the given set of IDs
* @param det_ids :: A list of detector ids
* @returns A pointer to the detector object
* @throw NotFoundError If no detector is found for the detector ID given
*/
IDetector_const_sptr
Instrument::getDetectorG(const std::vector<detid_t> &det_ids) const {
const size_t ndets(det_ids.size());
if (ndets == 1) {
return this->getDetector(det_ids[0]);
} else {
boost::shared_ptr<DetectorGroup> det_group(new DetectorGroup());
bool warn(false);
for (size_t i = 0; i < ndets; ++i) {
det_group->addDetector(this->getDetector(det_ids[i]), warn);
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
return det_group;
}
}
/**
* Returns a list of Detectors for the given detectors ids
*
*/
std::vector<IDetector_const_sptr>
Instrument::getDetectors(const std::vector<detid_t> &det_ids) const {
std::vector<IDetector_const_sptr> dets_ptr;
dets_ptr.reserve(det_ids.size());
std::vector<detid_t>::const_iterator it;
for (it = det_ids.begin(); it != det_ids.end(); ++it) {
dets_ptr.push_back(this->getDetector(*it));
}
return dets_ptr;
}
/**
* Returns a list of Detectors for the given detectors ids
*
*/
std::vector<IDetector_const_sptr>
Instrument::getDetectors(const std::set<detid_t> &det_ids) const {
std::vector<IDetector_const_sptr> dets_ptr;
dets_ptr.reserve(det_ids.size());
std::set<detid_t>::const_iterator it;
for (it = det_ids.begin(); it != det_ids.end(); ++it) {
dets_ptr.push_back(this->getDetector(*it));
}
return dets_ptr;
}
/**
* Adds a Component which already exists in the instrument to the chopper cache.
* If
* the component is not a chopper or it has no name then an invalid_argument
* expection is thrown
* @param comp :: A pointer to the component
*/
void Instrument::markAsChopperPoint(const ObjComponent *comp) {
const std::string name = comp->getName();
if (name.empty()) {
throw std::invalid_argument(
"Instrument::markAsChopper - Chopper component must have a name");
}
IComponent_const_sptr source = getSource();
if (!source) {
throw Exception::InstrumentDefinitionError("Instrument::markAsChopper - No "
"source is set, cannot defined "
"chopper positions.");
}
auto insertPos = m_chopperPoints->begin();
const double newChopperSourceDist = m_sourceCache->getDistance(*comp);
for (; insertPos != m_chopperPoints->end(); ++insertPos) {
const double sourceToChopDist = m_sourceCache->getDistance(**insertPos);
if (newChopperSourceDist < sourceToChopDist) {
break; // Found the insertion point
}
m_chopperPoints->insert(insertPos, comp);
}
/** Mark a component which has already been added to the Instrument (as a child
*component)
* to be 'the' samplePos component. NOTE THOUGH THAT THIS METHOD DOES NOT
*VERIFY THAT THIS
* IS THE CASE. It is assumed that we have at only one of these.
* The component is required to have a name.
*
* @param comp :: Component to be marked (stored for later retrieval) as a
*"SamplePos" Component
*/
void Instrument::markAsSamplePos(const IComponent *comp) {
if (m_map)
throw std::runtime_error("Instrument::markAsSamplePos() called on a "
"parametrized Instrument object.");
if (!m_sampleCache) {
if (comp->getName().empty()) {
throw Exception::InstrumentDefinitionError(
"The sample component is required to have a name.");
Gigg, Martyn Anthony
committed
}
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
m_sampleCache = comp;
} else {
g_log.warning(
"Have already added samplePos component to the _sampleCache.");
}
}
/** Mark a component which has already been added to the Instrument (as a child
*component)
* to be 'the' source component.NOTE THOUGH THAT THIS METHOD DOES NOT VERIFY
*THAT THIS
* IS THE CASE. It is assumed that we have at only one of these.
* The component is required to have a name.
*
* @param comp :: Component to be marked (stored for later retrieval) as a
*"source" Component
*/
void Instrument::markAsSource(const IComponent *comp) {
if (m_map)
throw std::runtime_error("Instrument::markAsSource() called on a "
"parametrized Instrument object.");
if (!m_sourceCache) {
if (comp->getName().empty()) {
throw Exception::InstrumentDefinitionError(
"The source component is required to have a name.");
Janik Zikovsky
committed
}
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
m_sourceCache = comp;
} else {
g_log.warning("Have already added source component to the _sourceCache.");
}
}
/** Mark a Component which has already been added to the Instrument (as a child
*component)
* to be a Detector by adding it to a detector cache.
*
* @param det :: Component to be marked (stored for later retrieval) as a
*detector Component
*
*/
void Instrument::markAsDetector(const IDetector *det) {
if (m_map)
throw std::runtime_error("Instrument::markAsDetector() called on a "
"parametrized Instrument object.");
// Create a (non-deleting) shared pointer to it
IDetector_const_sptr det_sptr = IDetector_const_sptr(det, NoDeleting());
std::map<int, IDetector_const_sptr>::iterator it = m_detectorCache.end();
m_detectorCache.insert(it, std::map<int, IDetector_const_sptr>::value_type(
det->getID(), det_sptr));
}
/** Mark a Component which has already been added to the Instrument class
* as a monitor and add it to the detector cache.
*
* @param det :: Component to be marked (stored for later retrieval) as a
*detector Component
*
* @throw Exception::ExistsError if cannot add detector to cache
*/
void Instrument::markAsMonitor(IDetector *det) {
if (m_map)
throw std::runtime_error("Instrument::markAsMonitor() called on a "
"parametrized Instrument object.");
// attempt to add monitor to instrument detector cache
markAsDetector(det);
// mark detector as a monitor
Detector *d = dynamic_cast<Detector *>(det);
if (d) {
d->markAsMonitor();
m_monitorCache.push_back(det->getID());
} else {
throw std::invalid_argument(
"The IDetector pointer does not point to a Detector object");
}
}
/** Removes a detector from the instrument and from the detector cache.
* The object is deleted.
* @param det The detector to remove
*/
void Instrument::removeDetector(IDetector *det) {
if (m_map)
throw std::runtime_error("Instrument::removeDetector() called on a "
"parameterized Instrument object.");
const detid_t id = det->getID();
// Remove the detector from the detector cache
m_detectorCache.erase(id);
// Also need to remove from monitor cache if appropriate
if (det->isMonitor()) {
std::vector<detid_t>::iterator it =
std::find(m_monitorCache.begin(), m_monitorCache.end(), id);
if (it != m_monitorCache.end())
m_monitorCache.erase(it);
}
Janik Zikovsky
committed
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
// Remove it from the parent assembly (and thus the instrument). Evilness
// required here unfortunately.
CompAssembly *parentAssembly = dynamic_cast<CompAssembly *>(
const_cast<IComponent *>(det->getBareParent()));
if (parentAssembly) // Should always be true, but check just in case
{
parentAssembly->remove(det);
}
}
/** This method returns monitor detector ids
* @return a vector holding detector ids of monitors
*/
std::vector<detid_t> Instrument::getMonitors() const {
// Monitors cannot be parametrized. So just return the base.
if (m_map)
return static_cast<const Instrument *>(m_base)->m_monitorCache;
else
return m_monitorCache;
}
/**
* Returns the number of monitors attached to this instrument
* @returns The number of monitors within the instrument
*/
size_t Instrument::numMonitors() const {
if (m_map) {
return static_cast<const Instrument *>(m_base)->m_monitorCache.size();
} else {
return m_monitorCache.size();
}
}
/**
* Get the bounding box for this instrument. It is simply the sum of the
* bounding boxes of its children excluding the source
* @param assemblyBox :: [Out] The resulting bounding box is stored here.
*/
void Instrument::getBoundingBox(BoundingBox &assemblyBox) const {
if (m_map) {
// Check cache for assembly
if (m_map->getCachedBoundingBox(this, assemblyBox)) {
return;
}
// Loop over the children and define a box large enough for all of them
ComponentID sourceID = getSource()->getComponentID();
assemblyBox =
BoundingBox(); // this makes the instrument BB always axis aligned
int nchildren = nelements();
for (int i = 0; i < nchildren; ++i) {
IComponent_sptr comp = this->getChild(i);
if (comp && comp->getComponentID() != sourceID) {
BoundingBox compBox;
comp->getBoundingBox(compBox);
assemblyBox.grow(compBox);
}
Gigg, Martyn Anthony
committed
}
// Set the cache
m_map->setCachedBoundingBox(this, assemblyBox);
} else {
if (!m_cachedBoundingBox) {
m_cachedBoundingBox = new BoundingBox();
ComponentID sourceID = getSource()->getComponentID();
// Loop over the children and define a box large enough for all of them
for (const_comp_it it = m_children.begin(); it != m_children.end();
++it) {
BoundingBox compBox;
IComponent *component = *it;
if (component && component->getComponentID() != sourceID) {
component->getBoundingBox(compBox);
m_cachedBoundingBox->grow(compBox);
}
}
Gigg, Martyn Anthony
committed
}
// Use cached box
assemblyBox = *m_cachedBoundingBox;
}
}
boost::shared_ptr<const std::vector<IObjComponent_const_sptr>>
Instrument::getPlottable() const {
if (m_map) {
// Get the 'base' plottable components
boost::shared_ptr<const std::vector<IObjComponent_const_sptr>> objs =
m_instr->getPlottable();
// Get a reference to the underlying vector, casting away the constness so
// that we
// can modify it to get our result rather than creating another long vector
std::vector<IObjComponent_const_sptr> &res =
const_cast<std::vector<IObjComponent_const_sptr> &>(*objs);
const std::vector<IObjComponent_const_sptr>::size_type total = res.size();
for (std::vector<IObjComponent_const_sptr>::size_type i = 0; i < total;
++i) {
res[i] = boost::dynamic_pointer_cast<const Detector>(
ParComponentFactory::create(objs->at(i), m_map));
Gigg, Martyn Anthony
committed
}
return objs;
} else {
// Base instrument
boost::shared_ptr<std::vector<IObjComponent_const_sptr>> res(
new std::vector<IObjComponent_const_sptr>);
res->reserve(m_detectorCache.size() + 10);
appendPlottable(*this, *res);
return res;
}
}
void Instrument::appendPlottable(
const CompAssembly &ca, std::vector<IObjComponent_const_sptr> &lst) const {
for (int i = 0; i < ca.nelements(); i++) {
IComponent *c = ca[i].get();
CompAssembly *a = dynamic_cast<CompAssembly *>(c);
if (a)
appendPlottable(*a, lst);
else {
Detector *d = dynamic_cast<Detector *>(c);
ObjComponent *o = dynamic_cast<ObjComponent *>(c);
Gigg, Martyn Anthony
committed
if (d)
lst.push_back(IObjComponent_const_sptr(d, NoDeleting()));
else if (o)
lst.push_back(IObjComponent_const_sptr(o, NoDeleting()));
Gigg, Martyn Anthony
committed
else
g_log.error() << "Unknown comp type\n";
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
}
}
const double CONSTANT = (PhysicalConstants::h * 1e10) /
(2.0 * PhysicalConstants::NeutronMass * 1e6);
//-----------------------------------------------------------------------
/** Calculate the conversion factor (tof -> d-spacing) for a single pixel, i.e.,
*1/DIFC for that pixel.
*
* @param l1 :: Primary flight path.
* @param beamline: vector = samplePos-sourcePos = a vector pointing from the
*source to the sample,
* the length of the distance between the two.
* @param beamline_norm: (source to sample distance) * 2.0 (apparently)
* @param samplePos: position of the sample
* @param det: Geometry object representing the detector (position of the pixel)
* @param offset: value (close to zero) that changes the factor := factor *
*(1+offset).
*/
double Instrument::calcConversion(const double l1, const Kernel::V3D &beamline,
const double beamline_norm,
const Kernel::V3D &samplePos,
const IDetector_const_sptr &det,
const double offset) {
if (offset <=
-1.) // not physically possible, means result is negative d-spacing
{
std::stringstream msg;
msg << "Encountered offset of " << offset
<< " which converts data to negative d-spacing\n";
throw std::logic_error(msg.str());
}
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
// Get the sample-detector distance for this detector (in metres)
// The scattering angle for this detector (in radians).
Kernel::V3D detPos;
detPos = det->getPos();
// Now detPos will be set with respect to samplePos
detPos -= samplePos;
// 0.5*cos(2theta)
double l2 = detPos.norm();
double halfcosTwoTheta = detPos.scalar_prod(beamline) / (l2 * beamline_norm);
// This is sin(theta)
double sinTheta = sqrt(0.5 - halfcosTwoTheta);
const double numerator = (1.0 + offset);
sinTheta *= (l1 + l2);
return (numerator * CONSTANT) / sinTheta;
}
//-----------------------------------------------------------------------
/** Calculate the conversion factor (tof -> d-spacing)
* for a LIST of detectors assigned to a single spectrum.
*/
double Instrument::calcConversion(
const double l1, const Kernel::V3D &beamline, const double beamline_norm,
const Kernel::V3D &samplePos,
const boost::shared_ptr<const Instrument> &instrument,
const std::vector<detid_t> &detectors,
const std::map<detid_t, double> &offsets) {
double factor = 0.;
double offset;
for (std::vector<detid_t>::const_iterator iter = detectors.begin();
iter != detectors.end(); ++iter) {
std::map<detid_t, double>::const_iterator off_iter = offsets.find(*iter);
if (off_iter != offsets.end()) {
offset = offsets.find(*iter)->second;
} else {
offset = 0.;
Janik Zikovsky
committed
}
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
factor += calcConversion(l1, beamline, beamline_norm, samplePos,
instrument->getDetector(*iter), offset);
}
return factor / static_cast<double>(detectors.size());
}
//------------------------------------------------------------------------------------------------
/** Get several instrument parameters used in tof to D-space conversion
*
* @param l1 :: primary flight path (source-sample distance)
* @param beamline :: vector of the direction and length of the beam (source to
*samepl)
* @param beamline_norm :: 2 * the length of beamline
* @param samplePos :: vector of the position of the sample
*/
void Instrument::getInstrumentParameters(double &l1, Kernel::V3D &beamline,
double &beamline_norm,
Kernel::V3D &samplePos) const {
// Get some positions
const IComponent_const_sptr sourceObj = this->getSource();
if (sourceObj == NULL) {
throw Exception::InstrumentDefinitionError(
"Failed to get source component from instrument");
}
const Kernel::V3D sourcePos = sourceObj->getPos();
samplePos = this->getSample()->getPos();
beamline = samplePos - sourcePos;
beamline_norm = 2.0 * beamline.norm();
// Get the distance between the source and the sample (assume in metres)
IComponent_const_sptr sample = this->getSample();
try {