Newer
Older
Russell Taylor
committed
#include "MantidGeometry/Instrument.h"
Gigg, Martyn Anthony
committed
#include "MantidKernel/V3D.h"
Gigg, Martyn Anthony
committed
#include "MantidKernel/Exception.h"
Michael Whitty
committed
#include "MantidGeometry/Instrument/ParameterMap.h"
#include "MantidGeometry/Instrument/ParComponentFactory.h"
Gigg, Martyn Anthony
committed
#include "MantidGeometry/Objects/BoundingBox.h"
#include "MantidGeometry/Instrument/CompAssembly.h"
Gigg, Martyn Anthony
committed
#include "MantidGeometry/Instrument/DetectorGroup.h"
#include "MantidGeometry/Instrument/ReferenceFrame.h"
Gigg, Martyn Anthony
committed
#include <algorithm>
#include <iostream>
Peterson, Peter
committed
#include <sstream>
#include <Poco/Path.h>
Gigg, Martyn Anthony
committed
using namespace Mantid::Kernel;
using Mantid::Kernel::Exception::NotFoundError;
using Mantid::Kernel::Exception::InstrumentDefinitionError;
Gigg, Martyn Anthony
committed
namespace Mantid
{
namespace Geometry
{
Kernel::Logger& Instrument::g_log = Kernel::Logger::get("Instrument");
/// Default constructor
Russell Taylor
committed
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)
Gigg, Martyn Anthony
committed
/// Constructor with name
Russell Taylor
committed
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)
Gigg, Martyn Anthony
committed
/** Constructor to create a parametrized instrument
Russell Taylor
committed
* @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)
Russell Taylor
committed
: 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),
Janik Zikovsky
committed
m_defaultViewAxis(instr->m_defaultViewAxis),
Russell Taylor
committed
m_instr(instr), m_map_nonconst(map),
m_ValidFrom(instr->m_ValidFrom), m_ValidTo(instr->m_ValidTo), m_referenceFrame(new ReferenceFrame)
Russell Taylor
committed
/** 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),
Russell Taylor
committed
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
Russell Taylor
committed
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
Russell Taylor
committed
if ( const IDetector* det = dynamic_cast<const Detector*>(it->get()) )
{
markAsDetector(det);
Russell Taylor
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()) )
Russell Taylor
committed
{
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() )
Russell Taylor
committed
{
markAsSource(obj);
Russell Taylor
committed
}
if ( objName == instr.m_sampleCache->getName() )
Russell Taylor
committed
{
markAsSamplePos(obj);
Russell Taylor
committed
}
for(size_t i = 0; i < instr.m_chopperPoints->size(); ++i)
{
if(objName == (*m_chopperPoints)[i]->getName())
{
markAsChopperPoint(obj);
break;
}
}
Russell Taylor
committed
}
}
}
/**
* Destructor
*/
Instrument::~Instrument()
{
if(!m_isParametrized)
{
m_chopperPoints->clear(); // CompAssembly will delete them
delete m_chopperPoints;
}
}
Russell Taylor
committed
/// Virtual copy constructor
Instrument* Instrument::clone() const
{
return new Instrument(*this);
}
/// Pointer to the 'real' instrument, for parametrized instruments
Russell Taylor
committed
Instrument_const_sptr Instrument::baseInstrument() const
{
if (m_isParametrized)
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
*/
Russell Taylor
committed
ParameterMap_sptr Instrument::getParameterMap() const
{
if (m_isParametrized)
return m_map_nonconst;
else
throw std::runtime_error("Instrument::getParameterMap() called for a non-parametrized instrument.");
}
Russell Taylor
committed
/** 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_isParametrized )
{
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();
}
}
else
{
return m_physicalInstrument;
}
}
Russell Taylor
committed
/** 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)
Russell Taylor
committed
{
if ( !m_isParametrized )
m_physicalInstrument = physInst;
else
throw std::runtime_error("Instrument::setPhysicalInstrument() called on a parametrized instrument.");
}
Gigg, Martyn Anthony
committed
Janik Zikovsky
committed
//------------------------------------------------------------------------------------------
Janik Zikovsky
committed
/** Fills a copy of the detector cache
Gigg, Martyn Anthony
committed
* @returns a map of the detectors hold by the instrument
*/
void Instrument::getDetectors(detid2det_map & out_map) const
Gigg, Martyn Anthony
committed
{
if (m_isParametrized)
{
//Get the base instrument detectors
Janik Zikovsky
committed
out_map.clear();
Russell Taylor
committed
const detid2det_map & in_dets = dynamic_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)
Janik Zikovsky
committed
{
out_map.insert(std::pair<detid_t, IDetector_sptr>
Janik Zikovsky
committed
(it->first, ParComponentFactory::createDetector(it->second.get(), m_map)));
}
}
else
{
//You can just return the detector cache directly.
Russell Taylor
committed
out_map = m_detectorCache;
}
Gigg, Martyn Anthony
committed
}
Janik Zikovsky
committed
Gigg, Martyn Anthony
committed
//------------------------------------------------------------------------------------------
Janik Zikovsky
committed
/** Return a vector of detector IDs in this instrument */
std::vector<detid_t> Instrument::getDetectorIDs(bool skipMonitors) const
Janik Zikovsky
committed
{
Janik Zikovsky
committed
if (m_isParametrized)
{
Russell Taylor
committed
const detid2det_map & in_dets = dynamic_cast<const Instrument*>(m_base)->m_detectorCache;
for(detid2det_map::const_iterator it=in_dets.begin();it!=in_dets.end();++it)
Janik Zikovsky
committed
if (!skipMonitors || !it->second->isMonitor())
out.push_back(it->first);
}
else
{
Russell Taylor
committed
const detid2det_map & in_dets = m_detectorCache;
for(detid2det_map::const_iterator it=in_dets.begin();it!=in_dets.end();++it)
Janik Zikovsky
committed
if (!skipMonitors || !it->second->isMonitor())
out.push_back(it->first);
}
return out;
}
/// @return The total number of detector IDs in the instrument */
std::size_t Instrument::getNumberDetectors(bool skipMonitors) const
{
std::size_t numDetIDs(0);
if (m_isParametrized)
{
numDetIDs = dynamic_cast<const Instrument*>(m_base)->m_detectorCache.size();
}
else
{
numDetIDs = m_detectorCache.size();
if (skipMonitors) // this slow, but gets the right answer
std::size_t monitors(0);
if (m_isParametrized)
{
const detid2det_map & in_dets = dynamic_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;
}
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_isParametrized)
in_dets = &dynamic_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;
}
Janik Zikovsky
committed
Janik Zikovsky
committed
//------------------------------------------------------------------------------------------
/** 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.
*/
Russell Taylor
committed
void Instrument::getDetectorsInBank(std::vector<IDetector_const_sptr> & dets, const std::string & bankName) const
Janik Zikovsky
committed
{
Russell Taylor
committed
boost::shared_ptr<const IComponent> comp = this->getComponentByName(bankName);
boost::shared_ptr<const ICompAssembly> bank = boost::dynamic_pointer_cast<const ICompAssembly>(comp);
Janik Zikovsky
committed
if (bank)
{
// Get a vector of children (recursively)
Russell Taylor
committed
std::vector<boost::shared_ptr<const IComponent> > children;
Janik Zikovsky
committed
bank->getChildren(children, true);
Russell Taylor
committed
std::vector<boost::shared_ptr<const IComponent> >::iterator it;
for (it = children.begin(); it != children.end(); ++it)
Janik Zikovsky
committed
{
Russell Taylor
committed
IDetector_const_sptr det = boost::dynamic_pointer_cast<const IDetector>(*it);
Janik Zikovsky
committed
if (det)
{
dets.push_back( det );
}
}
}
}
//------------------------------------------------------------------------------------------
Russell Taylor
committed
/** Gets a pointer to the source
* @returns a pointer to the source
*/
Russell Taylor
committed
IObjComponent_const_sptr Instrument::getSource() const
Gigg, Martyn Anthony
committed
{
Russell Taylor
committed
if ( !m_sourceCache )
Russell Taylor
committed
{
g_log.warning("In Instrument::getSource(). No source has been set.");
Russell Taylor
committed
return IObjComponent_const_sptr(m_sourceCache,NoDeleting());
Russell Taylor
committed
}
else if (m_isParametrized)
{
Russell Taylor
committed
return IObjComponent_const_sptr(new ObjComponent(dynamic_cast<const Instrument*>(m_base)->m_sourceCache,m_map));
}
else
{
Russell Taylor
committed
return IObjComponent_const_sptr(m_sourceCache,NoDeleting());
}
Gigg, Martyn Anthony
committed
}
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
/**
* 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();
}
Janik Zikovsky
committed
//------------------------------------------------------------------------------------------
Russell Taylor
committed
/** Gets a pointer to the Sample Position
* @returns a pointer to the Sample Position
*/
Russell Taylor
committed
IObjComponent_const_sptr Instrument::getSample() const
Gigg, Martyn Anthony
committed
{
Russell Taylor
committed
if ( !m_sampleCache )
Russell Taylor
committed
{
g_log.warning("In Instrument::getSamplePos(). No SamplePos has been set.");
Russell Taylor
committed
return IObjComponent_const_sptr(m_sampleCache,NoDeleting());
Russell Taylor
committed
}
else if (m_isParametrized)
{
Russell Taylor
committed
return IObjComponent_const_sptr(new ObjComponent(dynamic_cast<const Instrument*>(m_base)->m_sampleCache,m_map));
}
else
{
Russell Taylor
committed
return IObjComponent_const_sptr(m_sampleCache,NoDeleting());
}
Gigg, Martyn Anthony
committed
}
Russell Taylor
committed
/** 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;
}
Janik Zikovsky
committed
//------------------------------------------------------------------------------------------
/** Get a shared pointer to a component by its ID, const version
Janik Zikovsky
committed
* @param id :: ID
* @return A pointer to the component.
*/
Russell Taylor
committed
boost::shared_ptr<const IComponent> Instrument::getComponentByID(ComponentID id) const
const IComponent* base = (const IComponent*)(id);
if (m_isParametrized)
return ParComponentFactory::create(boost::shared_ptr<const IComponent>(base,NoDeleting()),m_map);
else
return boost::shared_ptr<const IComponent>(base, NoDeleting());
Russell Taylor
committed
}
/** 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
Russell Taylor
committed
{
boost::shared_ptr<const IComponent> node = boost::shared_ptr<const IComponent>(this, NoDeleting());
std::vector<boost::shared_ptr<const IComponent> > retVec;
Russell Taylor
committed
// 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;
Russell Taylor
committed
// 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);
Russell Taylor
committed
if( asmb )
{
nchildren = asmb->nelements();
}
for( int i = 0; i < nchildren; ++i )
{
boost::shared_ptr<const IComponent> comp = (*asmb)[i];
Russell Taylor
committed
if( comp->getName() == cname )
{
retVec.push_back(comp);
}
else
{
nodeQueue.push_back(comp);
}
}
}// while-end
// If we have reached here then the search failed
return retVec;
Gigg, Martyn Anthony
committed
}
/** Gets a pointer to the detector from its ID
* Note that for getting the detector associated with a spectrum, the MatrixWorkspace::getDetector
Gigg, Martyn Anthony
committed
* method should be used rather than this one because it takes account of the possibility of more
* than one detector contibuting 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
*/
Russell Taylor
committed
IDetector_const_sptr Instrument::getDetector(const detid_t &detector_id) const
Gigg, Martyn Anthony
committed
{
if (m_isParametrized)
Gigg, Martyn Anthony
committed
{
Russell Taylor
committed
IDetector_const_sptr baseDet = m_instr->getDetector(detector_id);
Gigg, Martyn Anthony
committed
return ParComponentFactory::createDetector(baseDet.get(), m_map);
Gigg, Martyn Anthony
committed
}
else
{
Russell Taylor
committed
detid2det_map::const_iterator it = m_detectorCache.find(detector_id);
if ( it == m_detectorCache.end() )
{
//FIXME: When ticket #4544 is fixed, re-enable this debug print:
//g_log.debug() << "Detector with ID " << detector_id << " not found." << std::endl;
std::stringstream readInt;
readInt << detector_id;
throw Kernel::Exception::NotFoundError("Instrument: Detector with ID " + readInt.str() + " not found.","");
}
return it->second;
Gigg, Martyn Anthony
committed
}
}
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
bool Instrument::isDetectorMasked(const std::set<detid_t> &detector_ids) const
{
if (detector_ids.empty())
for (std::set<detid_t>::const_iterator it = detector_ids.begin(); it != detector_ids.end(); ++it)
{
if (!this->isDetectorMasked(*it))
return false;
Gigg, Martyn Anthony
committed
/**
* 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
*/
Russell Taylor
committed
IDetector_const_sptr Instrument::getDetectorG(const std::vector<detid_t> &det_ids) const
Gigg, Martyn Anthony
committed
{
const size_t ndets(det_ids.size());
if( ndets == 1)
{
Russell Taylor
committed
return this->getDetector(det_ids[0]);
Gigg, Martyn Anthony
committed
}
else
{
Russell Taylor
committed
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);
}
return det_group;
}
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
/**
* Returns a list of Detectors for the given detectors ids
*
*/
Russell Taylor
committed
std::vector<IDetector_const_sptr> Instrument::getDetectors(const std::vector<detid_t> &det_ids) const
Gigg, Martyn Anthony
committed
{
Russell Taylor
committed
std::vector<IDetector_const_sptr> dets_ptr;
Gigg, Martyn Anthony
committed
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;
}
Janik Zikovsky
committed
/**
* Returns a list of Detectors for the given detectors ids
*
*/
Russell Taylor
committed
std::vector<IDetector_const_sptr> Instrument::getDetectors(const std::set<detid_t> &det_ids) const
Janik Zikovsky
committed
{
Russell Taylor
committed
std::vector<IDetector_const_sptr> dets_ptr;
Janik Zikovsky
committed
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;
}
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
/**
* 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");
}
IObjComponent_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
*/
Russell Taylor
committed
void Instrument::markAsSamplePos(const ObjComponent* comp)
Gigg, Martyn Anthony
committed
{
if (m_isParametrized)
throw std::runtime_error("Instrument::markAsSamplePos() called on a parametrized Instrument object.");
Russell Taylor
committed
if ( !m_sampleCache )
{
if ( comp->getName().empty() )
{
throw Exception::InstrumentDefinitionError("The sample component is required to have a name.");
}
Russell Taylor
committed
m_sampleCache = comp;
}
Gigg, Martyn Anthony
committed
else
{
Gigg, Martyn Anthony
committed
g_log.warning("Have already added samplePos component to the _sampleCache.");
}
Gigg, Martyn Anthony
committed
}
/** 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
*/
Russell Taylor
committed
void Instrument::markAsSource(const ObjComponent* comp)
Gigg, Martyn Anthony
committed
{
if (m_isParametrized)
throw std::runtime_error("Instrument::markAsSource() called on a parametrized Instrument object.");
Russell Taylor
committed
if ( !m_sourceCache )
{
if ( comp->getName().empty() )
{
throw Exception::InstrumentDefinitionError("The source component is required to have a name.");
}
Russell Taylor
committed
m_sourceCache = comp;
}
Gigg, Martyn Anthony
committed
else
{
Gigg, Martyn Anthony
committed
g_log.warning("Have already added source component to the _sourceCache.");
}
Gigg, Martyn Anthony
committed
}
/** 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.
*
Janik Zikovsky
committed
* @param det :: Component to be marked (stored for later retrievel) as a detector Component
Gigg, Martyn Anthony
committed
*
*/
Russell Taylor
committed
void Instrument::markAsDetector(const IDetector* det)
Gigg, Martyn Anthony
committed
{
if (m_isParametrized)
Michael Whitty
committed
throw std::runtime_error("Instrument::markAsDetector() called on a parametrized Instrument object.");
//Create a (non-deleting) shared pointer to it
Russell Taylor
committed
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) );
Gigg, Martyn Anthony
committed
}
/** Mark a Component which has already been added to the Instrument class
* as a monitor and add it to the detector cache.
*
Janik Zikovsky
committed
* @param det :: Component to be marked (stored for later retrieval) as a detector Component
Gigg, Martyn Anthony
committed
*
* @throw Exception::ExistsError if cannot add detector to cache
*/
Russell Taylor
committed
void Instrument::markAsMonitor(IDetector* det)
Gigg, Martyn Anthony
committed
{
if (m_isParametrized)
throw std::runtime_error("Instrument::markAsMonitor() called on a parametrized Instrument object.");
Gigg, Martyn Anthony
committed
// attempt to add monitor to instrument detector cache
markAsDetector(det);
// mark detector as a monitor
Russell Taylor
committed
Detector *d = dynamic_cast<Detector*>(det);
Gigg, Martyn Anthony
committed
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");
}
}
Russell Taylor
committed
/** Removes a detector from the instrument and from the detector cache.
* The object is deleted.
* @param det The detector to remove
*/
void Instrument::removeDetector(Detector* det)
{
if (m_isParametrized)
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);
Russell Taylor
committed
if ( it != m_monitorCache.end() ) m_monitorCache.erase(it);
}
// 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);
}
}
Gigg, Martyn Anthony
committed
/** This method returns monitor detector ids
*@return a vector holding detector ids of monitors
*/
const std::vector<detid_t> Instrument::getMonitors()const
Gigg, Martyn Anthony
committed
{
//Monitors cannot be parametrized. So just return the base.
if (m_isParametrized)
return dynamic_cast<const Instrument*>(m_base)->m_monitorCache;
else
return m_monitorCache;
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
/**
* Get the bounding box for this instrument. It is simply the sum of the bounding boxes of its children excluding the source
Janik Zikovsky
committed
* @param assemblyBox :: [Out] The resulting bounding box is stored here.
Gigg, Martyn Anthony
committed
*/
void Instrument::getBoundingBox(BoundingBox & assemblyBox) const
{
if (m_isParametrized)
Gigg, Martyn Anthony
committed
{
// Check cache for assembly
if( m_map->getCachedBoundingBox(this, assemblyBox ) )
{
return;
}
Gigg, Martyn Anthony
committed
// 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);
}
}
//Set the cache
m_map->setCachedBoundingBox(this, assemblyBox);
}
else
{
if( !m_cachedBoundingBox )
Gigg, Martyn Anthony
committed
{
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)
Gigg, Martyn Anthony
committed
{
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;
Gigg, Martyn Anthony
committed
}
}
Russell Taylor
committed
boost::shared_ptr<const std::vector<IObjComponent_const_sptr> > Instrument::getPlottable() const
Gigg, Martyn Anthony
committed
{
if (m_isParametrized)
{
// Get the 'base' plottable components
Russell Taylor
committed
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
Russell Taylor
committed
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)
{
Russell Taylor
committed
res[i] = boost::dynamic_pointer_cast<const Detector>(
ParComponentFactory::create(objs->at(i), m_map));
}
return objs;
}
else
{
// Base instrument
Russell Taylor
committed
boost::shared_ptr<std::vector<IObjComponent_const_sptr> > res( new std::vector<IObjComponent_const_sptr> );
Russell Taylor
committed
res->reserve(m_detectorCache.size()+10);
appendPlottable(*this,*res);
return res;
}
Gigg, Martyn Anthony
committed
}
Russell Taylor
committed
void Instrument::appendPlottable(const CompAssembly& ca,std::vector<IObjComponent_const_sptr>& lst) const
Gigg, Martyn Anthony
committed
{
for(int i=0;i<ca.nelements();i++)
{
Russell Taylor
committed
IComponent* c = ca[i].get();
CompAssembly* a = dynamic_cast<CompAssembly*>(c);
Gigg, Martyn Anthony
committed
if (a) appendPlottable(*a,lst);
else
{
Russell Taylor
committed
Detector* d = dynamic_cast<Detector*>(c);
ObjComponent* o = dynamic_cast<ObjComponent*>(c);
Gigg, Martyn Anthony
committed
if (d)
Russell Taylor
committed
lst.push_back(IObjComponent_const_sptr(d,NoDeleting()));
Gigg, Martyn Anthony
committed
else if (o)
Russell Taylor
committed
lst.push_back(IObjComponent_const_sptr(o,NoDeleting()));
Gigg, Martyn Anthony
committed
else
g_log.error()<<"Unknown comp type\n";
}
}
}
Gigg, Martyn Anthony
committed
const double CONSTANT = (PhysicalConstants::h * 1e10) / (2.0 * PhysicalConstants::NeutronMass * 1e6);
//-----------------------------------------------------------------------

Zhou, Wenduo
committed
/** 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,
Gigg, Martyn Anthony
committed
const Kernel::V3D &beamline,
const double beamline_norm,
Gigg, Martyn Anthony
committed
const Kernel::V3D &samplePos,
Russell Taylor
committed
const IDetector_const_sptr &det,

Zhou, Wenduo
committed
const double offset)
Peterson, Peter
committed
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());
}
// Get the sample-detector distance for this detector (in metres)
// The scattering angle for this detector (in radians).
Gigg, Martyn Anthony
committed
Kernel::V3D detPos;

Zhou, Wenduo
committed
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,
Gigg, Martyn Anthony
committed
const Kernel::V3D &beamline,
const double beamline_norm,
Gigg, Martyn Anthony
committed
const Kernel::V3D &samplePos,
const boost::shared_ptr<const Instrument> &instrument,

Zhou, Wenduo
committed
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.;
}
factor += calcConversion(l1, beamline, beamline_norm, samplePos,

Zhou, Wenduo
committed
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
*/
Gigg, Martyn Anthony
committed
void Instrument::getInstrumentParameters(double & l1, Kernel::V3D & beamline,
double & beamline_norm, Kernel::V3D & samplePos) const
{
// Get some positions
Russell Taylor
committed
const IObjComponent_const_sptr sourceObj = this->getSource();
if (sourceObj == NULL)
{
throw Exception::InstrumentDefinitionError("Failed to get source component from instrument");
}