Mantid
Loading...
Searching...
No Matches
InstrumentDefinitionParser.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 +
7#include <fstream>
8#include <sstream>
9
22#include "MantidKernel/Logger.h"
26#include "MantidTypes/Core/DateAndTime.h"
27#include "MantidTypes/Core/DateAndTimeHelpers.h"
28
29#include <Poco/DOM/DOMParser.h>
30#include <Poco/DOM/DOMWriter.h>
31#include <Poco/DOM/Document.h>
32#include <Poco/DOM/Element.h>
33#include <Poco/DOM/NodeFilter.h>
34#include <Poco/DOM/NodeIterator.h>
35#include <Poco/DOM/NodeList.h>
36#include <Poco/Path.h>
37#include <Poco/SAX/AttributesImpl.h>
38#include <Poco/String.h>
39#include <Poco/XML/XMLWriter.h>
40
41#include <boost/regex.hpp>
42#include <memory>
43#include <unordered_set>
44#include <utility>
45
46using namespace Mantid;
47using namespace Mantid::Kernel;
48using namespace Mantid::Types::Core;
49using Poco::XML::Document;
50using Poco::XML::DOMParser;
51using Poco::XML::Element;
52using Poco::XML::Node;
53using Poco::XML::NodeFilter;
54using Poco::XML::NodeIterator;
55using Poco::XML::NodeList;
56
57namespace Mantid::Geometry {
58namespace {
59// initialize the static logger
60Kernel::Logger g_log("InstrumentDefinitionParser");
61} // namespace
62//----------------------------------------------------------------------------------------------
66 : m_xmlFile(std::make_shared<NullIDFObject>()), m_cacheFile(std::make_shared<NullIDFObject>()), m_pDoc(nullptr),
67 m_hasParameterElement_beenSet(false), m_haveDefaultFacing(false), m_deltaOffsets(false), m_angleConvertConst(1.0),
68 m_indirectPositions(false), m_cachingOption(NoneApplied) {
69 initialise("", "", "", "");
70}
71//----------------------------------------------------------------------------------------------
78InstrumentDefinitionParser::InstrumentDefinitionParser(const std::string &filename, const std::string &instName,
79 const std::string &xmlText)
80 : m_xmlFile(std::make_shared<NullIDFObject>()), m_cacheFile(std::make_shared<NullIDFObject>()), m_pDoc(nullptr),
81 m_hasParameterElement_beenSet(false), m_haveDefaultFacing(false), m_deltaOffsets(false), m_angleConvertConst(1.0),
82 m_indirectPositions(false), m_cachingOption(NoneApplied) {
83 initialise(filename, instName, xmlText, "");
84}
85
86//----------------------------------------------------------------------------------------------
95 const IDFObject_const_sptr &expectedCacheFile,
96 const std::string &instName, const std::string &xmlText)
97 : m_xmlFile(std::make_shared<NullIDFObject>()), m_cacheFile(std::make_shared<NullIDFObject>()), m_pDoc(nullptr),
98 m_hasParameterElement_beenSet(false), m_haveDefaultFacing(false), m_deltaOffsets(false), m_angleConvertConst(1.0),
99 m_indirectPositions(false), m_cachingOption(NoneApplied) {
100 initialise(xmlFile->getFileFullPathStr(), instName, xmlText, expectedCacheFile->getFileFullPathStr());
101
102 m_cacheFile = expectedCacheFile;
103}
104
105//----------------------------------------------------------------------------------------------
114void InstrumentDefinitionParser::initialise(const std::string &filename, const std::string &instName,
115 const std::string &xmlText, const std::string &vtpFilename) {
116
117 IDFObject_const_sptr xmlFile = std::make_shared<const IDFObject>(filename);
118
119 // Handle the parameters
120 m_instName = instName;
121 m_xmlFile = xmlFile;
122
123 // Create our new instrument
124 // We don't want the instrument name taken out of the XML file itself, it
125 // should come from the filename (or the property)
126 m_instrument = std::make_shared<Instrument>(m_instName);
127
128 // Save the XML file path and contents
129 m_instrument->setFilename(filename);
130 m_instrument->setXmlText(xmlText);
131
132 // Use the filename to construct the cachefile name so that there is a 1:1 map
133 // between a definition file & cache
134 if (vtpFilename.empty()) {
135 m_cacheFile = std::make_shared<const IDFObject>(createVTPFileName());
136 } else {
137 m_cacheFile = std::make_shared<const IDFObject>(vtpFilename);
138 }
139}
140
141//----------------------------------------------------------------------------------------------
153
154 std::string retVal;
155 // use the xml in preference if available
156 auto xml = Poco::trim(m_instrument->getXmlText());
157 if (!(xml.empty())) {
158 std::string checksum = Kernel::ChecksumHelper::sha1FromString(xml);
159 retVal = m_instName + checksum;
160 } else if (this->m_xmlFile->exists()) { // Use the file
161 retVal = m_xmlFile->getMangledName();
162 }
163
164 return retVal;
165}
166
167//----------------------------------------------------------------------------------------------
172Poco::AutoPtr<Poco::XML::Document> InstrumentDefinitionParser::getDocument() {
173 if (!m_pDoc) {
174 // instantiate if not created
175 if (m_instrument->getXmlText().empty()) {
176 throw std::invalid_argument("Instrument XML string is empty");
177 }
178 // Set up the DOM parser and parse xml file
179 DOMParser pParser;
180 try {
181 m_pDoc = pParser.parseString(m_instrument->getXmlText());
182 } catch (Poco::Exception &exc) {
183 throw std::invalid_argument(exc.displayText() + ". Unable to parse XML");
184 } catch (...) {
185 throw std::invalid_argument("Unable to parse XML");
186 }
187 }
188 return m_pDoc;
189}
190
198 const std::string &typeName) const {
199 if (getTypeElement.find(typeName) != getTypeElement.end()) {
200 g_log.error(std::string("XML file: ")
201 .append(filename)
202 .append("contains more than one type element named ")
203 .append(typeName));
205 std::string("XML instrument file contains more than one type element named ")
206 .append(typeName)
207 .append(filename));
208 }
209}
210
211//----------------------------------------------------------------------------------------------
219 auto pDoc = getDocument();
220
221 // Get pointer to root element
222 Poco::XML::Element *pRootElem = pDoc->documentElement();
223
224 if (!pRootElem->hasChildNodes()) {
225 g_log.error("Instrument XML contains no root element.");
226 throw Kernel::Exception::InstrumentDefinitionError("No root element in XML instrument");
227 }
228
229 setValidityRange(pRootElem);
230 readDefaults(pRootElem->getChildElement("defaults"));
231 Geometry::ShapeFactory shapeCreator;
232
233 const std::string filename = m_xmlFile->getFileFullPathStr();
234
235 std::vector<Element *> typeElems;
236 std::vector<Element *> compElems;
237 getTypeAndComponentPointers(pRootElem, typeElems, compElems);
238
239 if (typeElems.empty()) {
240 g_log.error("XML file: " + filename + "contains no type elements.");
241 throw Kernel::Exception::InstrumentDefinitionError("No type elements in XML instrument file", filename);
242 }
243
244 collateTypeInformation(filename, typeElems, shapeCreator);
245
246 // Populate m_hasParameterElement
248
249 // See if any parameters set at instrument level
250 setLogfile(m_instrument.get(), pRootElem, m_instrument->getLogfileCache());
251
252 parseLocationsForEachTopLevelComponent(progressReporter, filename, compElems);
253
254 // Don't need this anymore (if it was even used) so empty it out to save
255 // memory
256 m_tempPosHolder.clear();
257
258 // Read in or create the geometry cache file
260
261 // Add/overwrite any instrument params with values specified in
262 // <component-link> XML elements
264
267
268 // Instrument::markAsDetector is slow unless the detector IDs in the IDF are
269 // sorted. To circumvent this we use the 2-part interface,
270 // markAsDetectorIncomplete (which does not sort) and markAsDetectorFinalize
271 // (which does the final sorting).
272 m_instrument->markAsDetectorFinalize();
273
274 // And give back what we created
275 return m_instrument;
276}
277
292 const std::vector<Element *> &typeElems,
293 ShapeFactory &shapeCreator) {
294 const size_t numberOfTypes = typeElems.size();
295 for (size_t iType = 0; iType < numberOfTypes; ++iType) {
296 Element *pTypeElem = typeElems[iType];
297 std::string typeName = pTypeElem->getAttribute("name");
298
299 // If type contains <combine-components-into-one-shape> then make adjustment
300 // after this loop has completed
301 Poco::AutoPtr<NodeList> pNL_type_combine_into_one_shape =
302 pTypeElem->getElementsByTagName("combine-components-into-one-shape");
303 if (pNL_type_combine_into_one_shape->length() > 0) {
304 continue;
305 }
306
307 throwIfTypeNameNotUnique(filename, typeName);
308 getTypeElement[typeName] = pTypeElem;
309 createShapeIfTypeIsNotAnAssembly(shapeCreator, iType, pTypeElem, typeName);
310 }
311
312 adjustTypesContainingCombineComponentsElement(shapeCreator, filename, typeElems, numberOfTypes);
313}
314
323 const std::string &filename,
324 const std::vector<Element *> &compElems) {
325 if (progressReporter)
326 progressReporter->resetNumSteps(compElems.size(), 0.0, 1.0);
327
328 for (auto pElem : compElems) {
329 if (progressReporter)
330 progressReporter->report("Loading instrument Definition");
331
332 {
333 IdList idList; // structure to possibly be populated with detector IDs
334
336
337 // Loop through all children of this component and see if any
338 // are a <location> or <locations>. Done this way, the
339 // order they are processed is the order they are listed in the
340 // IDF. This is necessary to match the order of the detector IDs.
341 for (Node *pNode = pElem->firstChild(); pNode != nullptr; pNode = pNode->nextSibling()) {
342 auto pChildElem = dynamic_cast<Element *>(pNode);
343 if (!pChildElem)
344 continue;
345 if (pChildElem->tagName() == "location") {
346 // process differently depending on whether component is and
347 // assembly or leaf
348 if (isAssembly(pElem->getAttribute("type"))) {
349 appendAssembly(m_instrument.get(), pChildElem, pElem, idList);
350 } else {
351 appendLeaf(m_instrument.get(), pChildElem, pElem, idList);
352 }
353 } else if (pChildElem->tagName() == "locations") {
354 // append <locations> elements in <locations>
355 appendLocations(m_instrument.get(), pChildElem, pElem, idList);
356 }
357 } // finished looping over all children of this component
358
359 checkIdListExistsAndDefinesEnoughIDs(idList, pElem, filename);
360 idList.reset();
361 }
362 }
363}
364
373 const std::string &filename) const {
374 Poco::AutoPtr<NodeList> pNL_location = pElem->getElementsByTagName("location");
375 Poco::AutoPtr<NodeList> pNL_locations = pElem->getElementsByTagName("locations");
376
377 if (pNL_location->length() == 0 && pNL_locations->length() == 0) {
378 g_log.error(std::string("A component element must contain at least one "
379 "<location> or <locations> element") +
380 " even if it is just an empty location element of the form "
381 "<location />");
382 throw Kernel::Exception::InstrumentDefinitionError(std::string("A component element must contain at least one "
383 "<location> or <locations> element") +
384 " even if it is just an empty location element of the form "
385 "<location />",
386 filename);
387 }
388}
389
399 const std::string &filename) const {
400 if (idList.counted != static_cast<int>(idList.vec.size())) {
401 std::stringstream ss1, ss2;
402 ss1 << idList.vec.size();
403 ss2 << idList.counted;
404 if (!pElem->hasAttribute("idlist")) {
405 g_log.error("No detector ID list found for detectors of type " + pElem->getAttribute("type"));
406 } else if (idList.vec.empty()) {
407 g_log.error("No detector IDs found for detectors in list " + pElem->getAttribute("idlist") +
408 "for detectors of type" + pElem->getAttribute("type"));
409 } else {
410 g_log.error("The number of detector IDs listed in idlist named " + pElem->getAttribute("idlist") +
411 " is larger than the number of detectors listed in type = " + pElem->getAttribute("type"));
412 }
414 "Number of IDs listed in idlist (=" + ss1.str() + ") is larger than the number of detectors listed in type = " +
415 pElem->getAttribute("type") + " (=" + ss2.str() + ").",
416 filename);
417 }
418}
419
426 Poco::AutoPtr<NodeList> pNL_parameter = pRootElem->getElementsByTagName("parameter");
427 unsigned long numParameter = pNL_parameter->length();
428 m_hasParameterElement.reserve(numParameter);
429
430 // It turns out that looping over all nodes and checking if their nodeName is
431 // equal to "parameter" is much quicker than looping over the pNL_parameter
432 // NodeList.
433 NodeIterator it(pRootElem, NodeFilter::SHOW_ELEMENT);
434 Node *pNode = it.nextNode();
435 while (pNode) {
436 if (pNode->nodeName() == "parameter") {
437 auto pParameterElem = dynamic_cast<Element *>(pNode);
438 m_hasParameterElement.emplace_back(dynamic_cast<Element *>(pParameterElem->parentNode()));
439 }
440 pNode = it.nextNode();
441 }
442
444}
445
456 const std::string &filename,
457 const std::vector<Element *> &typeElems,
458 const size_t numberOfTypes) {
459 for (size_t iType = 0; iType < numberOfTypes; ++iType) {
460 Element *pTypeElem = typeElems[iType];
461 std::string typeName = pTypeElem->getAttribute("name");
462
463 // In this loop only interested in types containing
464 // <combine-components-into-one-shape>
465 Poco::AutoPtr<NodeList> pNL_type_combine_into_one_shape =
466 pTypeElem->getElementsByTagName("combine-components-into-one-shape");
467 if (pNL_type_combine_into_one_shape->length() == 0)
468 continue;
469
470 throwIfTypeNameNotUnique(filename, typeName);
471 getTypeElement[typeName] = pTypeElem;
472
474 helper.adjust(pTypeElem, isTypeAssembly, getTypeElement);
475
476 isTypeAssembly[typeName] = false;
477
478 mapTypeNameToShape[typeName] = shapeCreator.createShape(pTypeElem);
479 // Only CSGObjects can be combined into one shape.
480 if (auto csgObj = std::dynamic_pointer_cast<CSGObject>(mapTypeNameToShape[typeName])) {
481 csgObj->setName(static_cast<int>(iType));
482 }
483 }
484}
485
496 Element *pTypeElem, const std::string &typeName) {
497 Poco::AutoPtr<NodeList> pNL_local = pTypeElem->getElementsByTagName("component");
498 if (pNL_local->length() == 0) {
499 isTypeAssembly[typeName] = false;
500
501 // for now try to create a geometry shape associated with every type
502 // that does not contain any component elements
503 mapTypeNameToShape[typeName] = shapeCreator.createShape(pTypeElem);
504 // Name can be set only for a CSGObject.
505 if (auto csgObj = std::dynamic_pointer_cast<CSGObject>(mapTypeNameToShape[typeName])) {
506 csgObj->setName(static_cast<int>(iType));
507 }
508 } else {
509 isTypeAssembly[typeName] = true;
510 if (pTypeElem->hasAttribute("outline")) {
511 pTypeElem->setAttribute("object_created", "no");
512 }
513 }
514}
515
524 std::vector<Element *> &typeElems,
525 std::vector<Element *> &compElems) const {
526 for (auto pNode = pRootElem->firstChild(); pNode != nullptr; pNode = pNode->nextSibling()) {
527 auto pElem = dynamic_cast<Element *>(pNode);
528 if (pElem) {
529 if (pElem->tagName() == "type")
530 typeElems.emplace_back(pElem);
531 else if (pElem->tagName() == "component")
532 compElems.emplace_back(pElem);
533 }
534 }
535}
536
537//-----------------------------------------------------------------------------------------------------------------------
552void InstrumentDefinitionParser::appendLocations(Geometry::ICompAssembly *parent, const Poco::XML::Element *pLocElems,
553 const Poco::XML::Element *pCompElem, IdList &idList) {
554 // create detached <location> elements from <locations> element
555 Poco::AutoPtr<Document> pLocationsDoc = convertLocationsElement(pLocElems);
556
557 // Get pointer to root element
558 const Element *pRootLocationsElem = pLocationsDoc->documentElement();
559 const bool assembly = isAssembly(pCompElem->getAttribute("type"));
560
561 auto *pElem = dynamic_cast<Poco::XML::Element *>(pRootLocationsElem->firstChild());
562
563 while (pElem) {
564 if (pElem->tagName() != "location") {
565 pElem = dynamic_cast<Poco::XML::Element *>(pElem->nextSibling());
566 continue;
567 }
568
569 if (assembly) {
570 appendAssembly(parent, pElem, pCompElem, idList);
571 } else {
572 appendLeaf(parent, pElem, pCompElem, idList);
573 }
574
575 pElem = dynamic_cast<Poco::XML::Element *>(pElem->nextSibling());
576 }
577}
578
579//-----------------------------------------------------------------------------------------------------------------------
589void InstrumentDefinitionParser::saveDOM_Tree(std::string &outFilename) {
590 Poco::XML::DOMWriter writer;
591 writer.setNewLine("\n");
592 writer.setOptions(Poco::XML::XMLWriter::PRETTY_PRINT);
593
594 auto pDoc = getDocument();
595 std::ofstream outFile(outFilename.c_str());
596 writer.writeNode(outFile, pDoc);
597 outFile.close();
598}
599
600double InstrumentDefinitionParser::attrToDouble(const Poco::XML::Element *pElem, const std::string &name) {
601 if (pElem->hasAttribute(name)) {
602 const std::string &value = pElem->getAttribute(name);
603 if (!value.empty()) {
604 try {
605 return std::stod(value);
606 } catch (...) {
607 std::stringstream msg;
608 msg << "failed to convert \"" << value << "\" to double for xml attribute \"" << name
609 << "\" - using 0. instead";
610 g_log.warning(msg.str());
611 return 0.;
612 }
613 }
614 }
615 return 0.;
616}
617
618//-----------------------------------------------------------------------------------------------------------------------
631void InstrumentDefinitionParser::setLocation(Geometry::IComponent *comp, const Poco::XML::Element *pElem,
632 const double angleConvertConst, const bool deltaOffsets) {
633 comp->setPos(getRelativeTranslation(comp, pElem, angleConvertConst, deltaOffsets));
634
635 // Rotate coordinate system of this component
636 if (pElem->hasAttribute("rot")) {
637 double rotAngle = angleConvertConst * attrToDouble(pElem, "rot"); // assumed to be in degrees
638
639 double axis_x = 0.0;
640 double axis_y = 0.0;
641 double axis_z = 1.0;
642
643 if (pElem->hasAttribute("axis-x"))
644 axis_x = std::stod(pElem->getAttribute("axis-x"));
645 if (pElem->hasAttribute("axis-y"))
646 axis_y = std::stod(pElem->getAttribute("axis-y"));
647 if (pElem->hasAttribute("axis-z"))
648 axis_z = std::stod(pElem->getAttribute("axis-z"));
649
650 comp->rotate(Kernel::Quat(rotAngle, Kernel::V3D(axis_x, axis_y, axis_z)));
651 }
652
653 // Check if sub-elements <trans> or <rot> of present - for now ignore these if
654 // m_deltaOffset = true
655
656 Element *pRecursive = nullptr;
657 Element *tElem = pElem->getChildElement("trans");
658 Element *rElem = pElem->getChildElement("rot");
659 bool stillTransElement = true;
660 bool firstRound = true; // during first round below pRecursive has not been set up front
661 while (stillTransElement) {
662 // figure out if child element is <trans> or <rot> or none of these
663
664 if (firstRound) {
665 firstRound = false;
666 } else if (pRecursive != nullptr) {
667 tElem = pRecursive->getChildElement("trans");
668 rElem = pRecursive->getChildElement("rot");
669 }
670
671 if (tElem && rElem) {
672 // if both a <trans> and <rot> child element present. Ignore <rot> element
673 rElem = nullptr;
674 }
675
676 if (!tElem && !rElem) {
677 stillTransElement = false;
678 }
679
680 Kernel::V3D posTrans;
681
682 if (tElem) {
683 posTrans = getRelativeTranslation(comp, tElem, angleConvertConst, deltaOffsets);
684
685 // to get the change in translation relative to current rotation of comp
686 Geometry::CompAssembly compToGetRot;
688 compRot.setRot(comp->getRotation());
689 compToGetRot.setParent(&compRot);
690 compToGetRot.setPos(posTrans);
691
692 // Apply translation
693 comp->translate(compToGetRot.getPos());
694
695 // for recursive action
696 pRecursive = tElem;
697 } // end translation
698
699 if (rElem) {
700 double rotAngle = angleConvertConst * attrToDouble(rElem, "val"); // assumed to be in degrees
701
702 double axis_x = 0.0;
703 double axis_y = 0.0;
704 double axis_z = 1.0;
705
706 if (rElem->hasAttribute("axis-x"))
707 axis_x = std::stod(rElem->getAttribute("axis-x"));
708 if (rElem->hasAttribute("axis-y"))
709 axis_y = std::stod(rElem->getAttribute("axis-y"));
710 if (rElem->hasAttribute("axis-z"))
711 axis_z = std::stod(rElem->getAttribute("axis-z"));
712
713 comp->rotate(Kernel::Quat(rotAngle, Kernel::V3D(axis_x, axis_y, axis_z)));
714
715 // for recursive action
716 pRecursive = rElem;
717 }
718
719 } // end while
720}
721
722//-----------------------------------------------------------------------------------------------------------------------
737 const Poco::XML::Element *pElem,
738 const double angleConvertConst,
739 const bool deltaOffsets) {
740 Kernel::V3D retVal; // position relative to parent
741
742 // Polar coordinates can be labelled as (r,t,p) or (R,theta,phi)
743 if (pElem->hasAttribute("r") || pElem->hasAttribute("t") || pElem->hasAttribute("p") || pElem->hasAttribute("R") ||
744 pElem->hasAttribute("theta") || pElem->hasAttribute("phi")) {
745
746 double R = attrToDouble(pElem, "r");
747 double theta = angleConvertConst * attrToDouble(pElem, "t");
748 double phi = angleConvertConst * attrToDouble(pElem, "p");
749
750 if (pElem->hasAttribute("R"))
751 R = attrToDouble(pElem, "R");
752 if (pElem->hasAttribute("theta"))
753 theta = angleConvertConst * attrToDouble(pElem, "theta");
754 if (pElem->hasAttribute("phi"))
755 phi = angleConvertConst * attrToDouble(pElem, "phi");
756
757 if (deltaOffsets) {
758 // In this case, locations given are radial offsets to the (radial)
759 // position of the parent,
760 // so need to do some extra calculation before they're stored internally
761 // as x,y,z offsets.
762
763 // Temporary vector to hold the parent's absolute position (will be 0,0,0
764 // if no parent)
765 Kernel::V3D parentPos;
766 // Get the parent's absolute position (if the component has a parent)
767 if (comp->getParent()) {
768 std::map<const Geometry::IComponent *, SphVec>::iterator it;
769 it = m_tempPosHolder.find(comp);
770 SphVec parent;
771 if (it == m_tempPosHolder.end())
772 parent = m_tempPosHolder[comp->getParent().get()];
773 else
774 parent = it->second;
775
776 // Add to the current component to get its absolute position
777 R += parent.r;
778 theta += parent.theta;
779 phi += parent.phi;
780 // Set the temporary V3D with the parent's absolute position
781 parentPos.spherical(parent.r, parent.theta, parent.phi);
782 }
783
784 // Create a temporary vector that holds the absolute r,theta,phi position
785 // Needed to make things work in situation when a parent object has a phi
786 // value but a theta of zero
787 SphVec tmp(R, theta, phi);
788 // Add it to the map with the pointer to the Component object as key
789 m_tempPosHolder[comp] = tmp;
790
791 // Create a V3D and set its position to be the child's absolute position
792 Kernel::V3D absPos;
793 absPos.spherical(R, theta, phi);
794
795 // Subtract the two V3D's to get what we want (child's relative position
796 // in x,y,z)
797 retVal = absPos - parentPos;
798 } else {
799 // In this case, the value given represents a vector from the parent to
800 // the child
801 retVal.spherical(R, theta, phi);
802 }
803
804 } else {
805 double x = attrToDouble(pElem, "x");
806 double y = attrToDouble(pElem, "y");
807 double z = attrToDouble(pElem, "z");
808
809 retVal(x, y, z);
810 }
811
812 return retVal;
813}
814
815//-----------------------------------------------------------------------------------------------------------------------
824Poco::XML::Element *InstrumentDefinitionParser::getParentComponent(const Poco::XML::Element *pLocElem) {
825 if (((pLocElem->tagName()) != "location") && ((pLocElem->tagName()) != "locations")) {
826 const std::string &tagname = pLocElem->tagName();
827 g_log.error("Argument to function getParentComponent must be a pointer to "
828 "an XML element with tag name location or locations.");
829 throw std::logic_error(std::string("Argument to function getParentComponent must be a pointer "
830 "to an XML element") +
831 "with tag name location or locations." + " The tag name is " + tagname);
832 }
833
834 // The location element is required to be a child of a component element. Get
835 // this component element
836
837 Node *pCompNode = pLocElem->parentNode();
838
839 Element *pCompElem;
840 if (pCompNode->nodeType() == 1) {
841 pCompElem = static_cast<Element *>(pCompNode);
842 if ((pCompElem->tagName()) != "component") {
843 g_log.error("Argument to function getParentComponent must be a XML "
844 "element sitting inside a component element.");
845 throw std::logic_error("Argument to function getParentComponent must be "
846 "a XML element sitting inside a component "
847 "element.");
848 }
849 } else {
850 g_log.error("Argument to function getParentComponent must be a XML element "
851 "whos parent is an element.");
852 throw std::logic_error("Argument to function getParentComponent must be a "
853 "XML element whos parent is an element.");
854 }
855
856 return pCompElem;
857}
858
859//-----------------------------------------------------------------------------------------------------------------------
871std::string InstrumentDefinitionParser::getNameOfLocationElement(const Poco::XML::Element *pElem,
872 const Poco::XML::Element *pCompElem) {
873 std::string retVal;
874
875 if (pElem->hasAttribute("name"))
876 retVal = pElem->getAttribute("name");
877 else if (pCompElem->hasAttribute("name")) {
878 retVal = pCompElem->getAttribute("name");
879 } else {
880 retVal = pCompElem->getAttribute("type");
881 }
882
883 return retVal;
884}
885
886//------------------------------------------------------------------------------------------------------------------------------
890void InstrumentDefinitionParser::setValidityRange(const Poco::XML::Element *pRootElem) {
891 const std::string filename = m_xmlFile->getFileFullPathStr();
892 // check if IDF has valid-from and valid-to tags defined
893 if (!pRootElem->hasAttribute("valid-from")) {
894 throw Kernel::Exception::InstrumentDefinitionError("<instrument> element must contain a valid-from tag", filename);
895 } else {
896 try {
897 DateAndTime d(pRootElem->getAttribute("valid-from"));
898 m_instrument->setValidFromDate(d);
899 } catch (...) {
900 throw Kernel::Exception::InstrumentDefinitionError("The valid-from <instrument> tag must be a ISO8601 string",
901 filename);
902 }
903 }
904
905 if (!pRootElem->hasAttribute("valid-to")) {
906 DateAndTime d = DateAndTime::getCurrentTime();
907 m_instrument->setValidToDate(d);
908 // Ticket #2335: no required valid-to date.
909 // throw Kernel::Exception::InstrumentDefinitionError("<instrument> element
910 // must contain a valid-to tag", filename);
911 } else {
912 try {
913 DateAndTime d(pRootElem->getAttribute("valid-to"));
914 m_instrument->setValidToDate(d);
915 } catch (...) {
916 throw Kernel::Exception::InstrumentDefinitionError("The valid-to <instrument> tag must be a ISO8601 string",
917 filename);
918 }
919 }
920}
921
922PointingAlong axisNameToAxisType(const std::string &label, const std::string &input) {
923 PointingAlong direction;
924 if (input == "x") {
925 direction = X;
926 } else if (input == "y") {
927 direction = Y;
928 } else if (input == "z") {
929 direction = Z;
930 } else {
931 std::stringstream msg;
932 msg << "Cannot create \"" << label << "\" with axis direction other than \"x\", \"y\", or \"z\", found \"" << input
933 << "\"";
935 }
936 return direction;
937}
938
939//-----------------------------------------------------------------------------------------------------------------------
945void InstrumentDefinitionParser::readDefaults(Poco::XML::Element *defaults) {
946 // Return without complaint, if there are no defaults
947 if (!defaults)
948 return;
949
950 // Check whether spherical coordinates should be treated as offsets to parents
951 // position
952 std::string offsets;
953 Element *offsetElement = defaults->getChildElement("offsets");
954 if (offsetElement)
955 offsets = offsetElement->getAttribute("spherical");
956 if (offsets == "delta")
957 m_deltaOffsets = true;
958
959 // Check whether default facing is set
960 Element *defaultFacingElement = defaults->getChildElement("components-are-facing");
961 if (defaultFacingElement) {
962 m_haveDefaultFacing = true;
963 m_defaultFacing = parseFacingElementToV3D(defaultFacingElement);
964 }
965
966 // the default view is used by the instrument viewer to decide the angle to
967 // display the instrument from on start up
968 Element *defaultView = defaults->getChildElement("default-view");
969 if (defaultView) {
970 m_instrument->setDefaultViewAxis(defaultView->getAttribute("axis-view"));
971 if (defaultView->hasAttribute("view")) {
972 m_instrument->setDefaultView(defaultView->getAttribute("view"));
973 }
974 }
975
976 // check if angle=radian has been set
977 Element *angleUnit = defaults->getChildElement("angle");
978 if (angleUnit) {
979 if (angleUnit->getAttribute("unit") == "radian") {
980 m_angleConvertConst = 180.0 / M_PI;
981 std::map<std::string, std::string> &units = m_instrument->getLogfileUnit();
982 units["angle"] = "radian";
983 }
984 }
985
986 // Check if the IDF specifies that this is an indirect geometry instrument
987 // that includes
988 // both physical and 'neutronic' postions.
989 // Any neutronic position tags will be ignored if this tag is missing
990 if (defaults->getChildElement("indirect-neutronic-positions"))
991 m_indirectPositions = true;
992
993 /*
994 Try to extract the reference frame information.
995 */
996 // Get the target xml element.
997 Element *referenceFrameElement = defaults->getChildElement("reference-frame");
998 // Extract if available
999 if (referenceFrameElement) {
1000 using Poco::XML::XMLString;
1001 // Get raw xml values
1002 Element *upElement = referenceFrameElement->getChildElement("pointing-up");
1003 Element *alongElement = referenceFrameElement->getChildElement("along-beam");
1004 Element *handednessElement = referenceFrameElement->getChildElement("handedness");
1005 Element *originElement = referenceFrameElement->getChildElement("origin");
1006 Element *thetaSignElement = referenceFrameElement->getChildElement("theta-sign");
1007
1008 // Defaults
1009 XMLString s_alongBeam("z");
1010 XMLString s_pointingUp("y");
1011 XMLString s_handedness("right");
1012 XMLString s_origin;
1013
1014 // Make extractions from sub elements where possible.
1015 if (alongElement) {
1016 s_alongBeam = alongElement->getAttribute("axis");
1017 }
1018 if (upElement) {
1019 s_pointingUp = upElement->getAttribute("axis");
1020 }
1021 if (handednessElement) {
1022 s_handedness = handednessElement->getAttribute("val");
1023 }
1024 if (originElement) {
1025 s_origin = originElement->getAttribute("val");
1026 }
1027
1028 // Extract theta sign axis if specified.
1029 XMLString s_thetaSign(s_pointingUp);
1030 if (thetaSignElement) {
1031 s_thetaSign = thetaSignElement->getAttribute("axis");
1032 }
1033
1034 // Convert to input types
1035 PointingAlong alongBeam = axisNameToAxisType("along-beam", s_alongBeam);
1036 PointingAlong pointingUp = axisNameToAxisType("pointing-up", s_pointingUp);
1037 PointingAlong thetaSign = axisNameToAxisType("theta-sign", s_thetaSign);
1038 Handedness handedness = s_handedness == "right" ? Right : Left;
1039
1040 // Overwrite the default reference frame.
1041 m_instrument->setReferenceFrame(
1042 std::make_shared<ReferenceFrame>(pointingUp, alongBeam, thetaSign, handedness, s_origin));
1043 }
1044}
1045
1046std::vector<std::string> InstrumentDefinitionParser::buildExcludeList(const Poco::XML::Element *const location) {
1047 // check if <exclude> sub-elements for this location and create new exclude
1048 // list to pass on
1049 Poco::AutoPtr<NodeList> pNLexclude = location->getElementsByTagName("exclude");
1050 unsigned long numberExcludeEle = pNLexclude->length();
1051 std::vector<std::string> newExcludeList;
1052 for (unsigned long i = 0; i < numberExcludeEle; i++) {
1053 auto *pExElem = static_cast<Element *>(pNLexclude->item(i));
1054 if (pExElem->hasAttribute("sub-part"))
1055 newExcludeList.emplace_back(pExElem->getAttribute("sub-part"));
1056 }
1057
1058 return newExcludeList;
1059}
1060
1061//-----------------------------------------------------------------------------------------------------------------------
1076void InstrumentDefinitionParser::appendAssembly(Geometry::ICompAssembly *parent, const Poco::XML::Element *pLocElem,
1077 const Poco::XML::Element *pCompElem, IdList &idList) {
1078 const std::string filename = m_xmlFile->getFileFullPathStr();
1079 // The location element is required to be a child of a component element. Get
1080 // this component element
1081 // Element* pCompElem =
1082 // InstrumentDefinitionParser::getParentComponent(pLocElem);
1083
1084 // Read detector IDs into idlist if required
1085 // Note idlist may be defined for any component
1086 // Note any new idlist found will take precedence.
1087
1088 if (pCompElem->hasAttribute("idlist")) {
1089 std::string idlist = pCompElem->getAttribute("idlist");
1090
1091 if (idlist != idList.idname) {
1092 Element *pFound = pCompElem->ownerDocument()->getElementById(idlist, "idname");
1093
1094 if (pFound == nullptr) {
1096 "No <idlist> with name idname=\"" + idlist + "\" present in instrument definition file.", filename);
1097 }
1098 idList.reset();
1099 populateIdList(pFound, idList);
1100 }
1101 }
1102
1103 // Create the assembly that will be appended into the parent.
1105 // The newly added component is required to have a type. Find out what this
1106 // type is and find all the location elements of this type. Finally loop over
1107 // these
1108 // location elements
1109
1110 Element *pType = getTypeElement[pCompElem->getAttribute("type")];
1111 std::string category;
1112 if (pType->hasAttribute("is"))
1113 category = pType->getAttribute("is");
1114 if (category == "SamplePos" || category == "samplePos") {
1116 } else if (pType->hasAttribute("outline") && pType->getAttribute("outline") != "no") {
1118 parent);
1119 } else {
1121 }
1122
1123 // set location for this newly added comp and set facing if specified in
1124 // instrument def. file. Also
1125 // check if any logfiles are referred to through the <parameter> element.
1126
1128 setFacing(ass, pLocElem);
1129 setLogfile(ass, pCompElem,
1130 m_instrument->getLogfileCache()); // params specified within <component>
1131 setLogfile(ass, pLocElem,
1132 m_instrument->getLogfileCache()); // params specified within specific <location>
1133
1134 // check if special Component
1135 if (category == "SamplePos" || category == "samplePos") {
1136 m_instrument->markAsSamplePos(ass);
1137 }
1138 if (category == "Source" || category == "source") {
1139 m_instrument->markAsSource(ass);
1140 }
1141
1142 // If enabled, check for a 'neutronic position' tag and add to cache if found
1143 if (m_indirectPositions) {
1144 Element *neutronic = pLocElem->getChildElement("neutronic");
1145 if (neutronic)
1146 m_neutronicPos[ass] = neutronic;
1147 }
1148
1149 // Check for <exclude> tags for this location
1150 const std::vector<std::string> excludeList = buildExcludeList(pLocElem);
1151
1152 NodeIterator it(pType, NodeFilter::SHOW_ELEMENT);
1153
1154 Node *pNode = it.nextNode();
1155 while (pNode) {
1156 if (pNode->nodeName() == "location") {
1157 // pLocElem is the location of a type. This type is here an assembly and
1158 // pElem below is a <location> within this type
1159 const Element *pElem = static_cast<Element *>(pNode);
1160
1161 // get the parent of pElem, i.e. a pointer to the <component> element that
1162 // contains pElem
1163 const Element *pParentElem = InstrumentDefinitionParser::getParentComponent(pElem);
1164
1165 // check if this location is in the exclude list
1166 auto inExcluded = find(excludeList.cbegin(), excludeList.cend(),
1168 if (inExcluded == excludeList.end()) {
1169
1170 std::string typeName = (InstrumentDefinitionParser::getParentComponent(pElem))->getAttribute("type");
1171
1172 if (isAssembly(typeName)) {
1173 appendAssembly(ass, pElem, pParentElem, idList);
1174 } else {
1175 appendLeaf(ass, pElem, pParentElem, idList);
1176 }
1177 }
1178 }
1179 if (pNode->nodeName() == "locations") {
1180 const Element *pLocationsElems = static_cast<Element *>(pNode);
1181 const Element *pParentLocationsElem = InstrumentDefinitionParser::getParentComponent(pLocationsElems);
1182
1183 // append <locations> elements in <locations>
1184 appendLocations(ass, pLocationsElems, pParentLocationsElem, idList);
1185 }
1186 pNode = it.nextNode();
1187 }
1188
1189 // create outline object for the assembly
1190 if (pType->hasAttribute("outline") && pType->getAttribute("outline") != "no") {
1191 auto *objAss = dynamic_cast<Geometry::ObjCompAssembly *>(ass);
1192 if (!objAss) {
1193 throw std::logic_error("Failed to cast ICompAssembly object to ObjCompAssembly");
1194 }
1195 if (pType->getAttribute("object_created") == "no") {
1196 pType->setAttribute("object_created", "yes");
1197 std::shared_ptr<Geometry::IObject> obj = objAss->createOutline();
1198 if (obj) {
1199 mapTypeNameToShape[pType->getAttribute("name")] = obj;
1200 } else { // object failed to be created
1201 pType->setAttribute("outline", "no");
1202 g_log.warning() << "Failed to create outline object for assembly " << pType->getAttribute("name") << '\n';
1203 }
1204 } else {
1205 objAss->setOutline(mapTypeNameToShape[pType->getAttribute("name")]);
1206 }
1207 }
1208}
1209
1211 const Poco::XML::Element *pLocElem,
1212 const Poco::XML::Element *pCompElem,
1213 const std::string &filename, IdList &idList,
1214 const std::string &category) {
1215
1216 //-------------- Create a Detector
1217 //------------------------------------------------
1218 std::string name = InstrumentDefinitionParser::getNameOfLocationElement(pLocElem, pCompElem);
1219
1220 // before setting detector ID check that the IDF satisfies the following
1221
1222 if (idList.counted >= static_cast<int>(idList.vec.size())) {
1223 std::stringstream ss1, ss2;
1224 ss1 << idList.vec.size();
1225 ss2 << idList.counted;
1226 if (idList.idname.empty()) {
1227 g_log.error("No list of detector IDs found for location element " + name);
1228 throw Kernel::Exception::InstrumentDefinitionError("Detector location element " + name + " has no idlist.",
1229 filename);
1230 } else if (idList.vec.empty()) {
1231 g_log.error("No detector IDs found for detectors in list " + idList.idname);
1232 } else {
1233 g_log.error("The number of detector IDs listed in idlist named " + idList.idname +
1234 " is less then the number of detectors");
1235 }
1237 "Number of IDs listed in idlist (=" + ss1.str() + ") is less than the number of detectors.", filename);
1238 }
1239
1240 std::string typeName = pCompElem->getAttribute("type");
1241
1242 // Create detector and increment id. Finally add the detector to the parent
1243 Geometry::Detector *detector =
1244 new Geometry::Detector(name, idList.vec[idList.counted], mapTypeNameToShape[typeName], parent);
1245 idList.counted++;
1246 parent->add(detector);
1247
1248 // set location for this newly added comp and set facing if specified in
1249 // instrument def. file. Also
1250 // check if any logfiles are referred to through the <parameter> element.
1251 setLocation(detector, pLocElem, m_angleConvertConst, m_deltaOffsets);
1252 setFacing(detector, pLocElem);
1253 setLogfile(detector, pCompElem,
1254 m_instrument->getLogfileCache()); // params specified within <component>
1255 setLogfile(detector, pLocElem,
1256 m_instrument->getLogfileCache()); // params specified within specific <location>
1257
1258 // If enabled, check for a 'neutronic position' tag and add to cache
1259 // (null pointer added INTENTIONALLY if not found)
1260 if (m_indirectPositions) {
1261 m_neutronicPos[detector] = pLocElem->getChildElement("neutronic");
1262 }
1263
1264 // mark-as is a depricated attribute used before is="monitor" was introduced
1265 if (pCompElem->hasAttribute("mark-as") || pLocElem->hasAttribute("mark-as")) {
1266 g_log.warning() << "Attribute 'mark-as' is a depricated attribute in "
1267 "Instrument Definition File."
1268 << " Please see the deprecated section of "
1269 "www.mantidproject.org/IDF for how to remove this "
1270 "warning message\n";
1271 }
1272
1273 try {
1274 if (category == "Monitor" || category == "monitor")
1275 m_instrument->markAsMonitor(detector);
1276 else {
1277 // for backwards compatebility look for mark-as="monitor"
1278 if ((pCompElem->hasAttribute("mark-as") && pCompElem->getAttribute("mark-as") == "monitor") ||
1279 (pLocElem->hasAttribute("mark-as") && pLocElem->getAttribute("mark-as") == "monitor")) {
1280 m_instrument->markAsMonitor(detector);
1281 } else
1282 m_instrument->markAsDetectorIncomplete(detector);
1283 }
1284
1285 } catch (Kernel::Exception::ExistsError &) {
1286 std::stringstream convert;
1287 convert << detector->getID();
1289 "Detector with ID = " + convert.str() + " present more then once in XML instrument file", filename);
1290 }
1291
1292 // Add all monitors and detectors to 'facing component' container. This is
1293 // only used if the
1294 // "facing" elements are defined in the instrument definition file
1295 m_facingComponent.emplace_back(detector);
1296}
1297
1298void InstrumentDefinitionParser::createGridDetector(Geometry::ICompAssembly *parent, const Poco::XML::Element *pLocElem,
1299 const Poco::XML::Element *pCompElem, const std::string &filename,
1300 const Poco::XML::Element *pType) {
1301
1302 //-------------- Create a RectangularDetector
1303 //------------------------------------------------
1304 std::string name = InstrumentDefinitionParser::getNameOfLocationElement(pLocElem, pCompElem);
1305
1306 // Create the bank with the given parent.
1307 auto bank = new Geometry::GridDetector(name, parent);
1308
1309 // set location for this newly added comp and set facing if specified in
1310 // instrument def. file. Also
1311 // check if any logfiles are referred to through the <parameter> element.
1313 setFacing(bank, pLocElem);
1314 setLogfile(bank, pCompElem,
1315 m_instrument->getLogfileCache()); // params specified within <component>
1316 setLogfile(bank, pLocElem,
1317 m_instrument->getLogfileCache()); // params specified within specific <location>
1318
1319 // Extract all the parameters from the XML attributes
1320 int xpixels = 0;
1321 int ypixels = 0;
1322 int zpixels = 0;
1323 int idstart = 0;
1324 std::string idfillorder;
1325 int idstepbyrow = 0;
1326 int idstep = 1;
1327
1328 // The shape!
1329 // Given that this leaf component is actually an assembly, its constituent
1330 // component detector shapes comes from its type attribute.
1331 const std::string shapeType = pType->getAttribute("type");
1332 std::shared_ptr<Geometry::IObject> shape = mapTypeNameToShape[shapeType];
1333 // These parameters are in the TYPE defining RectangularDetector
1334 if (pType->hasAttribute("xpixels"))
1335 xpixels = std::stoi(pType->getAttribute("xpixels"));
1336 double xstart = attrToDouble(pType, "xstart");
1337 double xstep = attrToDouble(pType, "xstep");
1338
1339 if (pType->hasAttribute("ypixels"))
1340 ypixels = std::stoi(pType->getAttribute("ypixels"));
1341 double ystart = attrToDouble(pType, "ystart");
1342 double ystep = attrToDouble(pType, "ystep");
1343
1344 if (pType->hasAttribute("zpixels"))
1345 zpixels = std::stoi(pType->getAttribute("zpixels"));
1346 double zstart = attrToDouble(pType, "zstart");
1347 double zstep = attrToDouble(pType, "zstep");
1348
1349 // THESE parameters are in the INSTANCE of this type - since they will
1350 // change.
1351 if (pCompElem->hasAttribute("idstart"))
1352 idstart = std::stoi(pCompElem->getAttribute("idstart"));
1353 if (pCompElem->hasAttribute("idfillorder"))
1354 idfillorder = pCompElem->getAttribute("idfillorder");
1355 // Default ID row step size
1356 if (!idfillorder.empty() && idfillorder[0] == 'x')
1357 idstepbyrow = xpixels;
1358 else if (!idfillorder.empty() && idfillorder[0] == 'y')
1359 idstepbyrow = ypixels;
1360 else
1361 idstepbyrow = zpixels;
1362
1363 if (pCompElem->hasAttribute("idstepbyrow")) {
1364 idstepbyrow = std::stoi(pCompElem->getAttribute("idstepbyrow"));
1365 }
1366 // Default ID row step size
1367 if (pCompElem->hasAttribute("idstep"))
1368 idstep = std::stoi(pCompElem->getAttribute("idstep"));
1369
1370 // Now, initialize all the pixels in the bank
1371 bank->initialize(shape, xpixels, xstart, xstep, ypixels, ystart, ystep, zpixels, zstart, zstep, idstart, idfillorder,
1372 idstepbyrow, idstep);
1373
1374 // Loop through all detectors in the newly created bank and mark those in
1375 // the instrument.
1376 try {
1377 for (int z = 0; z < bank->nelements(); ++z) {
1378 auto zLayer = std::dynamic_pointer_cast<Geometry::ICompAssembly>((*bank)[z]);
1379 for (int x = 0; x < zLayer->nelements(); ++x) {
1380 auto xColumn = std::dynamic_pointer_cast<Geometry::ICompAssembly>((*zLayer)[x]);
1381 for (int y = 0; y < xColumn->nelements(); ++y) {
1382 std::shared_ptr<Geometry::Detector> detector = std::dynamic_pointer_cast<Geometry::Detector>((*xColumn)[y]);
1383 if (detector) {
1384 // Make default facing for the pixel
1385 auto *comp = static_cast<IComponent *>(detector.get());
1388 // Mark it as a detector (add to the instrument cache)
1389 m_instrument->markAsDetectorIncomplete(detector.get());
1390 }
1391 }
1392 }
1393 }
1394 } catch (Kernel::Exception::ExistsError &) {
1395 throw Kernel::Exception::InstrumentDefinitionError("Duplicate detector ID found when adding GridDetector " + name +
1396 " in XML instrument file" + filename);
1397 }
1398}
1399
1401 const Poco::XML::Element *pLocElem,
1402 const Poco::XML::Element *pCompElem,
1403 const std::string &filename,
1404 const Poco::XML::Element *pType) {
1405 //-------------- Create a RectangularDetector
1406 //------------------------------------------------
1407 std::string name = InstrumentDefinitionParser::getNameOfLocationElement(pLocElem, pCompElem);
1408
1409 // Create the bank with the given parent.
1410 auto bank = new Geometry::RectangularDetector(name, parent);
1411
1412 // set location for this newly added comp and set facing if specified in
1413 // instrument def. file. Also
1414 // check if any logfiles are referred to through the <parameter> element.
1416 setFacing(bank, pLocElem);
1417 setLogfile(bank, pCompElem,
1418 m_instrument->getLogfileCache()); // params specified within <component>
1419 setLogfile(bank, pLocElem,
1420 m_instrument->getLogfileCache()); // params specified within specific <location>
1421
1422 // Extract all the parameters from the XML attributes
1423 int xpixels = 0;
1424 int ypixels = 0;
1425 int idstart = 0;
1426 bool idfillbyfirst_y = true;
1427 int idstepbyrow = 0;
1428 int idstep = 1;
1429
1430 // The shape!
1431 // Given that this leaf component is actually an assembly, its constituent
1432 // component detector shapes comes from its type attribute.
1433 const std::string shapeType = pType->getAttribute("type");
1434 std::shared_ptr<Geometry::IObject> shape = mapTypeNameToShape[shapeType];
1435
1436 // These parameters are in the TYPE defining RectangularDetector
1437 if (pType->hasAttribute("xpixels"))
1438 xpixels = std::stoi(pType->getAttribute("xpixels"));
1439 double xstart = attrToDouble(pType, "xstart");
1440 double xstep = attrToDouble(pType, "xstep");
1441
1442 if (pType->hasAttribute("ypixels"))
1443 ypixels = std::stoi(pType->getAttribute("ypixels"));
1444 double ystart = attrToDouble(pType, "ystart");
1445 double ystep = attrToDouble(pType, "ystep");
1446
1447 // THESE parameters are in the INSTANCE of this type - since they will
1448 // change.
1449 if (pCompElem->hasAttribute("idstart"))
1450 idstart = std::stoi(pCompElem->getAttribute("idstart"));
1451 if (pCompElem->hasAttribute("idfillbyfirst"))
1452 idfillbyfirst_y = (pCompElem->getAttribute("idfillbyfirst") == "y");
1453 // Default ID row step size
1454 if (idfillbyfirst_y)
1455 idstepbyrow = ypixels;
1456 else
1457 idstepbyrow = xpixels;
1458 if (pCompElem->hasAttribute("idstepbyrow")) {
1459 idstepbyrow = std::stoi(pCompElem->getAttribute("idstepbyrow"));
1460 }
1461 // Default ID row step size
1462 if (pCompElem->hasAttribute("idstep"))
1463 idstep = std::stoi(pCompElem->getAttribute("idstep"));
1464
1465 // Now, initialize all the pixels in the bank
1466 bank->initialize(shape, xpixels, xstart, xstep, ypixels, ystart, ystep, idstart, idfillbyfirst_y, idstepbyrow,
1467 idstep);
1468
1469 // Loop through all detectors in the newly created bank and mark those in
1470 // the instrument.
1471 try {
1472 for (int x = 0; x < bank->nelements(); x++) {
1473 std::shared_ptr<Geometry::ICompAssembly> xColumn = std::dynamic_pointer_cast<Geometry::ICompAssembly>((*bank)[x]);
1474 for (int y = 0; y < xColumn->nelements(); y++) {
1475 std::shared_ptr<Geometry::Detector> detector = std::dynamic_pointer_cast<Geometry::Detector>((*xColumn)[y]);
1476 if (detector) {
1477 // Make default facing for the pixel
1478 auto *comp = static_cast<IComponent *>(detector.get());
1481 // Mark it as a detector (add to the instrument cache)
1482 m_instrument->markAsDetectorIncomplete(detector.get());
1483 }
1484 }
1485 }
1486 } catch (Kernel::Exception::ExistsError &) {
1487 throw Kernel::Exception::InstrumentDefinitionError("Duplicate detector ID found when adding RectangularDetector " +
1488 name + " in XML instrument file" + filename);
1489 }
1490}
1491
1493 const Poco::XML::Element *pLocElem,
1494 const Poco::XML::Element *pCompElem,
1495 const std::string &filename,
1496 const Poco::XML::Element *pType) {
1497 //-------------- Create a StructuredDetector
1498 //------------------------------------------------
1499 std::string name = InstrumentDefinitionParser::getNameOfLocationElement(pLocElem, pCompElem);
1500
1501 // Create the bank with the given parent.
1502 auto bank = new Geometry::StructuredDetector(name, parent);
1503
1504 // set location for this newly added comp and set facing if specified in
1505 // instrument def. file. Also
1506 // check if any logfiles are referred to through the <parameter> element.
1508 setLogfile(bank, pCompElem,
1509 m_instrument->getLogfileCache()); // params specified within <component>
1510 setLogfile(bank, pLocElem,
1511 m_instrument->getLogfileCache()); // params specified within specific <location>
1512
1513 // Extract all the parameters from the XML attributes
1514 int xpixels = 0;
1515 int ypixels = 0;
1516 int idstart = 0;
1517 bool idfillbyfirst_y = true;
1518 int idstepbyrow = 0;
1519 int idstep = 1;
1520 std::vector<double> xValues;
1521 std::vector<double> yValues;
1522
1523 // The shape!
1524 // Given that this leaf component is actually an assembly, its constituent
1525 // component detector shapes comes from its type attribute.
1526 const std::string shapeType = pType->getAttribute("type");
1527 std::shared_ptr<Geometry::IObject> shape = mapTypeNameToShape[shapeType];
1528
1529 std::string typeName = pType->getAttribute("name");
1530 // These parameters are in the TYPE defining StructuredDetector
1531 if (pType->hasAttribute("xpixels"))
1532 xpixels = std::stoi(pType->getAttribute("xpixels"));
1533 if (pType->hasAttribute("ypixels"))
1534 ypixels = std::stoi(pType->getAttribute("ypixels"));
1535
1536 // THESE parameters are in the INSTANCE of this type - since they will
1537 // change.
1538 if (pCompElem->hasAttribute("idstart"))
1539 idstart = std::stoi(pCompElem->getAttribute("idstart"));
1540 if (pCompElem->hasAttribute("idfillbyfirst"))
1541 idfillbyfirst_y = (pCompElem->getAttribute("idfillbyfirst") == "y");
1542 // Default ID row step size
1543 if (idfillbyfirst_y)
1544 idstepbyrow = ypixels;
1545 else
1546 idstepbyrow = xpixels;
1547 if (pCompElem->hasAttribute("idstepbyrow")) {
1548 idstepbyrow = std::stoi(pCompElem->getAttribute("idstepbyrow"));
1549 }
1550 // Default ID row step size
1551 if (pCompElem->hasAttribute("idstep"))
1552 idstep = std::stoi(pCompElem->getAttribute("idstep"));
1553
1554 // Access type element which defines structured detecor vertices
1555 Element *pElem = nullptr;
1556 NodeIterator tags(pCompElem->ownerDocument(), NodeFilter::SHOW_ELEMENT);
1557 Node *pNode = tags.nextNode();
1558
1559 while (pNode) {
1560 auto *check = static_cast<Element *>(pNode);
1561 if (pNode->nodeName() == "type" && check->hasAttribute("is")) {
1562 std::string is = check->getAttribute("is");
1563 if (StructuredDetector::compareName(is) && typeName == check->getAttribute("name")) {
1564 pElem = check;
1565 break;
1566 }
1567 }
1568
1569 pNode = tags.nextNode();
1570 }
1571
1572 if (pElem == nullptr)
1573 throw Kernel::Exception::InstrumentDefinitionError("No <type> with attribute is=\"StructuredDetector\"", filename);
1574
1575 // Ensure vertices are present within the IDF
1576 Poco::AutoPtr<NodeList> pNL = pElem->getElementsByTagName("vertex");
1577 if (pNL->length() == 0)
1578 throw Kernel::Exception::InstrumentDefinitionError("StructuredDetector must contain vertices.", filename);
1579
1580 NodeIterator it(pElem, NodeFilter::SHOW_ELEMENT);
1581
1582 pNode = it.nextNode();
1583
1584 while (pNode) {
1585 if (pNode->nodeName() == "vertex") {
1586 auto *pVertElem = static_cast<Element *>(pNode);
1587
1588 if (pVertElem->hasAttribute("x"))
1589 xValues.emplace_back(attrToDouble(pVertElem, "x"));
1590 if (pVertElem->hasAttribute("y"))
1591 yValues.emplace_back(attrToDouble(pVertElem, "y"));
1592 }
1593
1594 pNode = it.nextNode();
1595 }
1596
1597 V3D zVector(0, 0, 1); // Z aligned beam
1598 bool isZBeam = m_instrument->getReferenceFrame()->isVectorPointingAlongBeam(zVector);
1599 // Now, initialize all the pixels in the bank
1600 bank->initialize(xpixels, ypixels, std::move(xValues), std::move(yValues), isZBeam, idstart, idfillbyfirst_y,
1601 idstepbyrow, idstep);
1602
1603 // Loop through all detectors in the newly created bank and mark those in
1604 // the instrument.
1605 try {
1606 for (int x = 0; x < bank->nelements(); x++) {
1607 std::shared_ptr<Geometry::ICompAssembly> xColumn = std::dynamic_pointer_cast<Geometry::ICompAssembly>((*bank)[x]);
1608 for (int y = 0; y < xColumn->nelements(); y++) {
1609 std::shared_ptr<Geometry::Detector> detector = std::dynamic_pointer_cast<Geometry::Detector>((*xColumn)[y]);
1610 if (detector) {
1611 // Make default facing for the pixel
1612 auto *comp = static_cast<IComponent *>(detector.get());
1615 // Mark it as a detector (add to the instrument cache)
1616 m_instrument->markAsDetectorIncomplete(detector.get());
1617 }
1618 }
1619 }
1620 } catch (Kernel::Exception::ExistsError &) {
1621 throw Kernel::Exception::InstrumentDefinitionError("Duplicate detector ID found when adding StructuredDetector " +
1622 name + " in XML instrument file" + filename);
1623 }
1624}
1625
1626//-----------------------------------------------------------------------------------------------------------------------
1645void InstrumentDefinitionParser::appendLeaf(Geometry::ICompAssembly *parent, const Poco::XML::Element *pLocElem,
1646 const Poco::XML::Element *pCompElem, IdList &idList) {
1647 const std::string filename = m_xmlFile->getFileFullPathStr();
1648
1649 //--- Get the detector's X/Y pixel sizes (optional) ---
1650 // Read detector IDs into idlist if required
1651 // Note idlist may be defined for any component
1652 // Note any new idlist found will take precedence.
1653
1654 if (pCompElem->hasAttribute("idlist")) {
1655 std::string idlist = pCompElem->getAttribute("idlist");
1656
1657 if (idlist != idList.idname) {
1658 Element *pFound = pCompElem->ownerDocument()->getElementById(idlist, "idname");
1659
1660 if (pFound == nullptr) {
1662 "No <idlist> with name idname=\"" + idlist + "\" present in instrument definition file.", filename);
1663 }
1664
1665 idList.reset();
1666 populateIdList(pFound, idList);
1667 }
1668 }
1669
1670 // get the type element of the component element in order to determine if
1671 // the
1672 // type
1673 // belong to the category: "detector", "SamplePos or "Source".
1674
1675 std::string typeName = pCompElem->getAttribute("type");
1676 Element *pType = getTypeElement[typeName];
1677
1678 std::string category;
1679 if (pType->hasAttribute("is"))
1680 category = pType->getAttribute("is");
1681
1682 static const boost::regex exp("Detector|detector|Monitor|monitor");
1683
1684 // do stuff a bit differently depending on which category the type belong to
1685 if (GridDetector::compareName(category)) {
1686 createGridDetector(parent, pLocElem, pCompElem, filename, pType);
1687 } else if (RectangularDetector::compareName(category)) {
1688 createRectangularDetector(parent, pLocElem, pCompElem, filename, pType);
1689 } else if (StructuredDetector::compareName(category)) {
1690 createStructuredDetector(parent, pLocElem, pCompElem, filename, pType);
1691 } else if (boost::regex_match(category, exp)) {
1692 createDetectorOrMonitor(parent, pLocElem, pCompElem, filename, idList, category);
1693 } else {
1694 //-------------- Not a Detector, RectangularDetector or Structured Detector
1695 //------------------------------
1696 IComponent *comp;
1697 if (category == "SamplePos" || category == "samplePos") {
1698 // check if special SamplePos Component
1699 std::string name = InstrumentDefinitionParser::getNameOfLocationElement(pLocElem, pCompElem);
1700 comp = new Geometry::Component(name, parent);
1701 m_instrument->markAsSamplePos(comp);
1702 } else {
1703 std::string name = InstrumentDefinitionParser::getNameOfLocationElement(pLocElem, pCompElem);
1704
1705 comp = new Geometry::ObjComponent(name, mapTypeNameToShape[typeName], parent);
1706 }
1707 parent->add(comp);
1708
1709 // check if special Source Component
1710 if (category == "Source" || category == "source") {
1711 m_instrument->markAsSource(comp);
1712 }
1713
1714 // set location for this newly added comp and set facing if specified in
1715 // instrument def. file. Also
1716 // check if any logfiles are referred to through the <parameter> element.
1717
1719 setFacing(comp, pLocElem);
1720 setLogfile(comp, pCompElem,
1721 m_instrument->getLogfileCache()); // params specified within <component>
1722 setLogfile(comp, pLocElem,
1723 m_instrument->getLogfileCache()); // params specified within
1724 // specific <location>
1725 }
1726}
1727
1728//-----------------------------------------------------------------------------------------------------------------------
1738void InstrumentDefinitionParser::populateIdList(Poco::XML::Element *pE, IdList &idList) {
1739 const std::string filename = m_xmlFile->getFileFullPathStr();
1740
1741 if ((pE->tagName()) != "idlist") {
1742 g_log.error("Argument to function createIdList must be a pointer to an XML "
1743 "element with tag name idlist.");
1744 throw std::logic_error("Argument to function createIdList must be a "
1745 "pointer to an XML element with tag name idlist.");
1746 }
1747
1748 // set name of idlist
1749
1750 idList.idname = pE->getAttribute("idname");
1751
1752 // If idname element has start and end attributes then just use those to
1753 // populate idlist.
1754 // Otherwise id sub-elements
1755
1756 if (pE->hasAttribute("start")) {
1757 int startID = std::stoi(pE->getAttribute("start"));
1758
1759 int endID;
1760 if (pE->hasAttribute("end"))
1761 endID = std::stoi(pE->getAttribute("end"));
1762 else
1763 endID = startID;
1764
1765 int increment = 1;
1766 if (pE->hasAttribute("step"))
1767 increment = std::stoi(pE->getAttribute("step"));
1768
1769 if (0 == increment) {
1770 std::stringstream ss;
1771 ss << "The step element cannot be zero, got start: " << startID << ", end: " << endID << ", step: " << increment;
1772 throw Kernel::Exception::InstrumentDefinitionError(ss.str(), filename);
1773 }
1774
1775 // check the start end and increment values are sensible
1776 int steps = (endID - startID) / increment;
1777 if (steps < 0) {
1778 std::stringstream ss;
1779 ss << "The start, end, and step elements do not allow a single id in "
1780 "the "
1781 "idlist entry - ";
1782 ss << "start: " << startID << ", end: " << endID << ", step: " << increment;
1783
1784 throw Kernel::Exception::InstrumentDefinitionError(ss.str(), filename);
1785 }
1786
1787 idList.vec.reserve(steps);
1788 for (int i = startID; i != endID + increment; i += increment) {
1789 idList.vec.emplace_back(i);
1790 }
1791 } else {
1792 // test first if any <id> elements
1793
1794 Poco::AutoPtr<NodeList> pNL = pE->getElementsByTagName("id");
1795
1796 if (pNL->length() == 0) {
1797 throw Kernel::Exception::InstrumentDefinitionError("No id subelement of idlist element in XML instrument file",
1798 filename);
1799 }
1800
1801 // get id numbers
1802
1803 NodeIterator it(pE, NodeFilter::SHOW_ELEMENT);
1804
1805 Node *pNode = it.nextNode();
1806 while (pNode) {
1807 if (pNode->nodeName() == "id") {
1808 auto *pIDElem = static_cast<Element *>(pNode);
1809
1810 if (pIDElem->hasAttribute("val")) {
1811 int valID = std::stoi(pIDElem->getAttribute("val"));
1812 idList.vec.emplace_back(valID);
1813 } else if (pIDElem->hasAttribute("start")) {
1814 int startID = std::stoi(pIDElem->getAttribute("start"));
1815
1816 int endID;
1817 if (pIDElem->hasAttribute("end"))
1818 endID = std::stoi(pIDElem->getAttribute("end"));
1819 else
1820 endID = startID;
1821
1822 int increment = 1;
1823 if (pIDElem->hasAttribute("step"))
1824 increment = std::stoi(pIDElem->getAttribute("step"));
1825
1826 // check the start end and increment values are sensible
1827 if (0 == increment) {
1828 std::stringstream ss;
1829 ss << "The step element cannot be zero, found step: " << increment;
1830
1831 throw Kernel::Exception::InstrumentDefinitionError(ss.str(), filename);
1832 }
1833 int numSteps = (endID - startID) / increment;
1834 if (numSteps < 0) {
1835 std::stringstream ss;
1836 ss << "The start, end, and step elements do not allow a single "
1837 "id "
1838 "in the idlist entry - ";
1839 ss << "start: " << startID << ", end: " << endID << ", step: " << increment;
1840
1841 throw Kernel::Exception::InstrumentDefinitionError(ss.str(), filename);
1842 }
1843
1844 idList.vec.reserve(numSteps);
1845 for (int i = startID; i != endID + increment; i += increment) {
1846 idList.vec.emplace_back(i);
1847 }
1848 } else {
1850 "id subelement of idlist " + std::string("element wrongly specified in XML instrument file"), filename);
1851 }
1852 }
1853
1854 pNode = it.nextNode();
1855 } // end while loop
1856 }
1857}
1858
1859//-----------------------------------------------------------------------------------------------------------------------
1868bool InstrumentDefinitionParser::isAssembly(const std::string &type) const {
1869 const std::string filename = m_xmlFile->getFileFullPathStr();
1870 auto it = isTypeAssembly.find(type);
1871
1872 if (it == isTypeAssembly.end()) {
1873 throw Kernel::Exception::InstrumentDefinitionError("type with name = " + type + " not defined.", filename);
1874 }
1875
1876 return it->second;
1877}
1878
1879//-----------------------------------------------------------------------------------------------------------------------
1891 const Geometry::ObjComponent *facing) {
1892 makeXYplaneFaceComponent(in, facing->getPos());
1893}
1894
1895//-----------------------------------------------------------------------------------------------------------------------
1905 Kernel::V3D pos = in->getPos();
1906
1907 // vector from facing object to component we want to rotate
1908 Kernel::V3D facingDirection = pos - facingPoint;
1909 const auto facingDirLength = facingDirection.norm();
1910 if (facingDirLength == 0.0)
1911 return;
1912 facingDirection /= facingDirLength;
1913
1914 // now aim to rotate shape such that the z-axis of of the object we want to
1915 // rotate points in the direction of facingDirection. That way the XY plane
1916 // faces the 'facing object'.
1917 constexpr Kernel::V3D z(0, 0, 1);
1918 Kernel::Quat R = in->getRotation();
1919 R.inverse();
1920 R.rotate(facingDirection);
1921
1922 Kernel::V3D normal = facingDirection.cross_prod(z);
1923 const auto normalLength = normal.norm();
1924 if (normalLength == 0.) {
1925 normal = normalize(-facingDirection);
1926 } else {
1927 normal /= normalLength;
1928 }
1929 double theta = (180.0 / M_PI) * facingDirection.angle(z);
1930
1931 if (normal.norm() > 0.0)
1932 in->rotate(Kernel::Quat(-theta, normal));
1933 else {
1934 // To take into account the case where the facing direction is in the
1935 // (0,0,1) or (0,0,-1) direction.
1936 in->rotate(Kernel::Quat(-theta, Kernel::V3D(0, 1, 0)));
1937 }
1938}
1939
1940//-----------------------------------------------------------------------------------------------------------------------
1947 Kernel::V3D retV3D;
1948
1949 // Polar coordinates can be labelled as (r,t,p) or (R,theta,phi)
1950 if (pElem->hasAttribute("r") || pElem->hasAttribute("t") || pElem->hasAttribute("p") || pElem->hasAttribute("R") ||
1951 pElem->hasAttribute("theta") || pElem->hasAttribute("phi")) {
1952 double R = attrToDouble(pElem, "r");
1953 double theta = m_angleConvertConst * attrToDouble(pElem, "t");
1954 double phi = m_angleConvertConst * attrToDouble(pElem, "p");
1955
1956 if (pElem->hasAttribute("R"))
1957 R = attrToDouble(pElem, "R");
1958 if (pElem->hasAttribute("theta"))
1959 theta = m_angleConvertConst * attrToDouble(pElem, "theta");
1960 if (pElem->hasAttribute("phi"))
1961 phi = m_angleConvertConst * attrToDouble(pElem, "phi");
1962
1963 retV3D.spherical(R, theta, phi);
1964 } else {
1965 double x = attrToDouble(pElem, "x");
1966 double y = attrToDouble(pElem, "y");
1967 double z = attrToDouble(pElem, "z");
1968
1969 retV3D(x, y, z);
1970 }
1971
1972 return retV3D;
1973}
1974
1975//-----------------------------------------------------------------------------------------------------------------------
1989void InstrumentDefinitionParser::setFacing(Geometry::IComponent *comp, const Poco::XML::Element *pElem) {
1990 // Require that pElem points to an element with tag name 'location'
1991
1992 if ((pElem->tagName()) != "location") {
1993 g_log.error("Second argument to function setLocation must be a pointer to "
1994 "an XML element with tag name location.");
1995 throw std::logic_error("Second argument to function setLocation must be a "
1996 "pointer to an XML element with tag name location.");
1997 }
1998
1999 Element *facingElem = pElem->getChildElement("facing");
2000 if (facingElem) {
2001 // check if user want to rotate about z-axis before potentially applying
2002 // facing
2003
2004 if (facingElem->hasAttribute("rot")) {
2005 double rotAngle = m_angleConvertConst * attrToDouble(facingElem, "rot"); // assumed to be in degrees
2006 comp->rotate(Kernel::Quat(rotAngle, Kernel::V3D(0, 0, 1)));
2007 }
2008
2009 // For now assume that if has val attribute it means facing = none. This
2010 // option only has an
2011 // effect when a default facing setting is set. In which case this then
2012 // means "ignore the
2013 // default facing setting" for this component
2014
2015 if (facingElem->hasAttribute("val"))
2016 return;
2017
2018 // Face the component, i.e. rotate the z-axis of the component such that
2019 // it
2020 // points in the direction from
2021 // the point x,y,z (or r,t,p) specified by the <facing> xml element
2022 // towards
2023 // the component
2024
2026
2027 } else // so if no facing element associated with location element apply
2028 // default facing if set
2031}
2032
2033//-----------------------------------------------------------------------------------------------------------------------
2044void InstrumentDefinitionParser::setLogfile(const Geometry::IComponent *comp, const Poco::XML::Element *pElem,
2045 InstrumentParameterCache &logfileCache, const std::string &requestedDate) {
2046 const std::string filename = m_xmlFile->getFileFullPathStr();
2047
2048 // The purpose below is to have a quicker way to judge if pElem contains a
2049 // parameter, see
2050 // defintion of m_hasParameterElement for more info
2052 if (m_hasParameterElement.end() == std::find(m_hasParameterElement.begin(), m_hasParameterElement.end(), pElem))
2053 return;
2054
2055 Poco::AutoPtr<NodeList> pNL_comp = pElem->childNodes(); // here get all child nodes
2056 unsigned long pNL_comp_length = pNL_comp->length();
2057
2058 for (unsigned long i = 0; i < pNL_comp_length; i++) {
2059 // we are only interest in the top level parameter elements hence
2060 // the reason for the if statement below
2061 if (!((pNL_comp->item(i))->nodeType() == Node::ELEMENT_NODE && ((pNL_comp->item(i))->nodeName()) == "parameter"))
2062 continue;
2063
2064 auto *pParamElem = static_cast<Element *>(pNL_comp->item(i));
2065
2066 if (!pParamElem->hasAttribute("name"))
2068 "XML element with name or type = " + comp->getName() +
2069 " contain <parameter> element with no name attribute in XML "
2070 "instrument file",
2071 filename);
2072
2073 std::string paramName = pParamElem->getAttribute("name");
2074
2075 if (paramName == "rot" || paramName == "pos") {
2076 g_log.error() << "XML element with name or type = " << comp->getName()
2077 << " contains <parameter> element with name=\"" << paramName << "\"."
2078 << " This is a reserved Mantid keyword. Please use other name, "
2079 << "and see www.mantidproject.org/IDF for list of reserved "
2080 "keywords."
2081 << " This parameter is ignored";
2082 continue;
2083 }
2084
2085 std::string visible = "true";
2086 if (pParamElem->hasAttribute("visible")) {
2087 visible = pParamElem->getAttribute("visible");
2088 }
2089
2090 DateAndTime validityDate;
2091
2092 if (requestedDate.empty()) {
2093 validityDate = DateAndTime::getCurrentTime();
2094 } else {
2095 validityDate.setFromISO8601(requestedDate);
2096 }
2097
2098 std::string logfileID;
2099 std::string value;
2100
2101 DateAndTime validFrom;
2102 DateAndTime validTo;
2103
2104 std::string type = "double"; // default
2105 std::string extractSingleValueAs = "mean"; // default
2106 std::string eq;
2107
2108 Poco::AutoPtr<NodeList> pNLvalue = pParamElem->getElementsByTagName("value");
2109 size_t numberValueEle = pNLvalue->length();
2110 Element *pValueElem;
2111
2112 Poco::AutoPtr<NodeList> pNLlogfile = pParamElem->getElementsByTagName("logfile");
2113 size_t numberLogfileEle = pNLlogfile->length();
2114 Element *pLogfileElem;
2115
2116 Poco::AutoPtr<NodeList> pNLLookUp = pParamElem->getElementsByTagName("lookuptable");
2117 size_t numberLookUp = pNLLookUp->length();
2118
2119 Poco::AutoPtr<NodeList> pNLFormula = pParamElem->getElementsByTagName("formula");
2120 size_t numberFormula = pNLFormula->length();
2121
2122 if ((numberValueEle > 0 && numberLogfileEle + numberLookUp + numberFormula > 0) ||
2123 (numberValueEle == 0 && numberLogfileEle + numberLookUp + numberFormula > 1)) {
2124 g_log.warning() << "XML element with name or type = " << comp->getName()
2125 << " contains <parameter> element where the value of the "
2126 << "parameter has been specified more than once. See "
2127 << "www.mantidproject.org/IDF for how the value of the "
2128 << "parameter is set in this case.";
2129 }
2130
2131 if (numberValueEle + numberLogfileEle + numberLookUp + numberFormula == 0) {
2132 g_log.error() << "XML element with name or type = " << comp->getName()
2133 << " contains <parameter> for which no value is specified."
2134 << " See www.mantidproject.org/IDF for how to set the value"
2135 << " of a parameter. This parameter is ignored.";
2136 continue;
2137 }
2138
2139 DateAndTime currentValidFrom;
2140 DateAndTime currentValidTo;
2141 currentValidFrom.setToMinimum();
2142 currentValidTo.setToMaximum();
2143
2144 // if more than one <value> specified for a parameter, check the validity
2145 // range
2146 if (numberValueEle >= 1) {
2147 bool hasValue = false;
2148
2149 for (unsigned long j = 0; j < numberValueEle; ++j) {
2150 pValueElem = static_cast<Element *>(pNLvalue->item(j));
2151
2152 if (!pValueElem->hasAttribute(("val")))
2153 continue;
2154
2155 validFrom.setToMinimum();
2156 if (pValueElem->hasAttribute("valid-from"))
2157 validFrom.setFromISO8601(pValueElem->getAttribute("valid-from"));
2158
2159 validTo.setToMaximum();
2160 if (pValueElem->hasAttribute("valid-to"))
2161 validTo.setFromISO8601(pValueElem->getAttribute("valid-to"));
2162
2163 if (validFrom <= validityDate && validityDate <= validTo &&
2164 (validFrom > currentValidFrom || (validFrom == currentValidFrom && validTo <= currentValidTo))) {
2165
2166 currentValidFrom = validFrom;
2167 currentValidTo = validTo;
2168 } else
2169 continue;
2170 hasValue = true;
2171 value = pValueElem->getAttribute("val");
2172 }
2173
2174 if (!hasValue) {
2176 "XML element with name or type = " + comp->getName() +
2177 " contains <parameter> element with invalid syntax for its "
2178 "subelement <value>. Correct syntax is <value val=\"\"/>",
2179 filename);
2180 }
2181
2182 } else if (numberLogfileEle >= 1) {
2183 // <logfile > tag was used at least once.
2184 pLogfileElem = static_cast<Element *>(pNLlogfile->item(0));
2185 if (!pLogfileElem->hasAttribute("id"))
2187 "XML element with name or type = " + comp->getName() +
2188 " contains <parameter> element with invalid syntax for its "
2189 "subelement logfile>." +
2190 " Correct syntax is <logfile id=\"\"/>",
2191 filename);
2192 logfileID = pLogfileElem->getAttribute("id");
2193
2194 if (pLogfileElem->hasAttribute("eq"))
2195 eq = pLogfileElem->getAttribute("eq");
2196 if (pLogfileElem->hasAttribute("extract-single-value-as"))
2197 extractSingleValueAs = pLogfileElem->getAttribute("extract-single-value-as");
2198 }
2199
2200 if (pParamElem->hasAttribute("type"))
2201 type = pParamElem->getAttribute("type");
2202
2203 // check if <fixed /> element present
2204
2205 bool fixed = false;
2206 Poco::AutoPtr<NodeList> pNLFixed = pParamElem->getElementsByTagName("fixed");
2207 size_t numberFixed = pNLFixed->length();
2208 if (numberFixed >= 1) {
2209 fixed = true;
2210 }
2211
2212 // some processing
2213
2214 std::string fittingFunction;
2215 std::string tie;
2216
2217 if (type == "fitting") {
2218 size_t found = paramName.find(':');
2219 if (found != std::string::npos) {
2220 // check that only one : in name
2221 size_t index = paramName.find(':', found + 1);
2222 if (index != std::string::npos) {
2223 g_log.error() << "Fitting <parameter> in instrument definition file defined "
2224 "with"
2225 << " more than one column character :. One must used.\n";
2226 } else {
2227 fittingFunction = paramName.substr(0, found);
2228 paramName = paramName.substr(found + 1, paramName.size());
2229 }
2230 }
2231 }
2232
2233 if (fixed) {
2234 std::ostringstream str;
2235 str << paramName << "=" << value;
2236 tie = str.str();
2237 }
2238
2239 // check if <min> or <max> elements present
2240
2241 std::vector<std::string> constraint(2, "");
2242
2243 Poco::AutoPtr<NodeList> pNLMin = pParamElem->getElementsByTagName("min");
2244 size_t numberMin = pNLMin->length();
2245 Poco::AutoPtr<NodeList> pNLMax = pParamElem->getElementsByTagName("max");
2246 size_t numberMax = pNLMax->length();
2247
2248 if (numberMin >= 1) {
2249 auto *pMin = static_cast<Element *>(pNLMin->item(0));
2250 constraint[0] = pMin->getAttribute("val");
2251 }
2252 if (numberMax >= 1) {
2253 auto *pMax = static_cast<Element *>(pNLMax->item(0));
2254 constraint[1] = pMax->getAttribute("val");
2255 }
2256
2257 // check if penalty-factor> elements present
2258
2259 std::string penaltyFactor;
2260
2261 Poco::AutoPtr<NodeList> pNL_penaltyFactor = pParamElem->getElementsByTagName("penalty-factor");
2262 size_t numberPenaltyFactor = pNL_penaltyFactor->length();
2263
2264 if (numberPenaltyFactor >= 1) {
2265 auto *pPenaltyFactor = static_cast<Element *>(pNL_penaltyFactor->item(0));
2266 penaltyFactor = pPenaltyFactor->getAttribute("val");
2267 }
2268
2269 // Check if look up table is specified
2270
2271 std::vector<std::string> allowedUnits = UnitFactory::Instance().getKeys();
2272
2273 std::shared_ptr<Interpolation> interpolation = std::make_shared<Interpolation>();
2274
2275 if (numberLookUp >= 1) {
2276 auto *pLookUp = static_cast<Element *>(pNLLookUp->item(0));
2277
2278 if (pLookUp->hasAttribute("interpolation"))
2279 interpolation->setMethod(pLookUp->getAttribute("interpolation"));
2280 if (pLookUp->hasAttribute("x-unit")) {
2281 std::vector<std::string>::iterator it;
2282 it = find(allowedUnits.begin(), allowedUnits.end(), pLookUp->getAttribute("x-unit"));
2283 if (it == allowedUnits.end()) {
2284 g_log.warning() << "x-unit used with interpolation table must be "
2285 "one of the recognised units "
2286 << " see http://www.mantidproject.org/Unit_Factory";
2287 } else
2288 interpolation->setXUnit(pLookUp->getAttribute("x-unit"));
2289 }
2290 if (pLookUp->hasAttribute("y-unit")) {
2291 std::vector<std::string>::iterator it;
2292 it = find(allowedUnits.begin(), allowedUnits.end(), pLookUp->getAttribute("y-unit"));
2293 if (it == allowedUnits.end()) {
2294 g_log.warning() << "y-unit used with interpolation table must be "
2295 "one of the recognised units "
2296 << " see http://www.mantidproject.org/Unit_Factory";
2297 } else
2298 interpolation->setYUnit(pLookUp->getAttribute("y-unit"));
2299 }
2300
2301 Poco::AutoPtr<NodeList> pNLpoint = pLookUp->getElementsByTagName("point");
2302 unsigned long numberPoint = pNLpoint->length();
2303
2304 for (unsigned long j = 0; j < numberPoint; j++) {
2305 auto *pPoint = static_cast<Element *>(pNLpoint->item(j));
2306 double x = attrToDouble(pPoint, "x");
2307 double y = attrToDouble(pPoint, "y");
2308 interpolation->addPoint(x, y);
2309 }
2310 }
2311
2312 // Check if formula is specified
2313
2314 std::string formula;
2315 std::string formulaUnit;
2316 std::string resultUnit;
2317
2318 if (numberFormula >= 1) {
2319 auto *pFormula = static_cast<Element *>(pNLFormula->item(0));
2320 formula = pFormula->getAttribute("eq");
2321 if (pFormula->hasAttribute("unit")) {
2322 std::vector<std::string>::iterator it;
2323 it = find(allowedUnits.begin(), allowedUnits.end(), pFormula->getAttribute("unit"));
2324 if (it == allowedUnits.end()) {
2325 g_log.warning() << "unit attribute used with formula must be one "
2326 "of the recognized units "
2327 << " see http://www.mantidproject.org/Unit_Factory";
2328 } else
2329 formulaUnit = pFormula->getAttribute("unit");
2330 }
2331 if (pFormula->hasAttribute("result-unit"))
2332 resultUnit = pFormula->getAttribute("result-unit");
2333 }
2334 // Check if parameter description is
2335 std::string description;
2336
2337 Poco::AutoPtr<NodeList> pNLDescription = pParamElem->getElementsByTagName("description");
2338 size_t numberDescription = pNLDescription->length();
2339
2340 if (numberDescription >= 1) {
2341 // use only first description from a list
2342 auto *pDescription = static_cast<Element *>(pNLDescription->item(0));
2343 description = pDescription->getAttribute("is");
2344 }
2345
2346 auto cacheKey = std::make_pair(paramName, comp);
2347 auto cacheValue = std::make_shared<XMLInstrumentParameter>(
2348 logfileID, value, interpolation, formula, formulaUnit, resultUnit, paramName, type, tie, constraint,
2349 penaltyFactor, fittingFunction, extractSingleValueAs, eq, comp, m_angleConvertConst, description, visible);
2350 auto inserted = logfileCache.emplace(cacheKey, cacheValue);
2351 if (!inserted.second) {
2352 logfileCache[cacheKey] = cacheValue;
2353 }
2354 } // end element loop
2355}
2356
2357//-----------------------------------------------------------------------------------------------------------------------
2371void InstrumentDefinitionParser::setComponentLinks(std::shared_ptr<Geometry::Instrument> &instrument,
2372 Poco::XML::Element *pRootElem, Kernel::ProgressBase *progress,
2373 const std::string &requestedDate) {
2374 // check if any logfile cache units set. As of this writing the only unit to
2375 // check is if "angle=radian"
2376 std::map<std::string, std::string> &units = instrument->getLogfileUnit();
2377 std::map<std::string, std::string>::iterator unit_it;
2378 unit_it = units.find("angle");
2379 if (unit_it != units.end())
2380 if (unit_it->second == "radian")
2381 m_angleConvertConst = 180.0 / M_PI;
2382
2383 const std::string elemName = "component-link";
2384 Poco::AutoPtr<NodeList> pNL_link = pRootElem->getElementsByTagName(elemName);
2385 unsigned long numberLinks = pNL_link->length();
2386
2387 if (progress)
2388 progress->resetNumSteps(static_cast<int64_t>(numberLinks), 0.0, 0.95);
2389
2390 Node *curNode = pRootElem->firstChild();
2391 while (curNode) {
2392 if (curNode->nodeType() == Node::ELEMENT_NODE && curNode->nodeName() == elemName) {
2393 auto *curElem = static_cast<Element *>(curNode);
2394
2395 if (progress) {
2396 if (progress->hasCancellationBeenRequested())
2397 return;
2398 progress->report("Loading parameters");
2399 }
2400
2401 std::string id = curElem->getAttribute("id");
2402 std::string name = curElem->getAttribute("name");
2403 std::vector<std::shared_ptr<const Geometry::IComponent>> sharedIComp;
2404
2405 // If available, use the detector id as it's the most specific.
2406 if (id.length() > 0) {
2407 int detid;
2408 std::stringstream(id) >> detid;
2409 std::shared_ptr<const Geometry::IComponent> detector = instrument->getDetector(static_cast<detid_t>(detid));
2410
2411 // If we didn't find anything with the detector id, explain why to the
2412 // user, and throw an exception.
2413 if (!detector) {
2414 g_log.error() << "Error whilst loading parameters. No detector "
2415 "found with id '"
2416 << detid << "'\n";
2417 g_log.error() << "Please check that your detectors' ids are correct.\n";
2418 throw Kernel::Exception::InstrumentDefinitionError("Invalid detector id in component-link tag.");
2419 }
2420
2421 sharedIComp.emplace_back(detector);
2422
2423 // If the user also supplied a name, make sure it's consistent with
2424 // the
2425 // detector id.
2426 if (name.length() > 0) {
2427 auto comp = std::dynamic_pointer_cast<const IComponent>(detector);
2428 if (comp) {
2429 bool consistent = (comp->getFullName() == name || comp->getName() == name);
2430 if (!consistent) {
2431 g_log.warning() << "Error whilst loading parameters. Name '" << name << "' does not match id '" << detid
2432 << "'.\n";
2433 g_log.warning() << "Parameters have been applied to detector with id '" << detid
2434 << "'. Please check the name is correct.\n";
2435 }
2436 }
2437 }
2438 } else {
2439 // No detector id given, fall back to using the name
2440
2441 if (name.find('/', 0) == std::string::npos) { // Simple name, look for
2442 // all components of that
2443 // name.
2444 sharedIComp = instrument->getAllComponentsWithName(name);
2445 } else { // Pathname given. Assume it is unique.
2446 std::shared_ptr<const Geometry::IComponent> shared = instrument->getComponentByName(name);
2447 sharedIComp.emplace_back(shared);
2448 }
2449 }
2450
2451 for (auto &ptr : sharedIComp) {
2452 std::shared_ptr<const Geometry::Component> sharedComp =
2453 std::dynamic_pointer_cast<const Geometry::Component>(ptr);
2454 if (sharedComp) {
2455 // Not empty Component
2456 if (sharedComp->isParametrized()) {
2457 setLogfile(sharedComp->base(), curElem, instrument->getLogfileCache(), requestedDate);
2458 } else {
2459 setLogfile(ptr.get(), curElem, instrument->getLogfileCache(), requestedDate);
2460 }
2461 }
2462 }
2463 }
2464 curNode = curNode->nextSibling();
2465 }
2466}
2467
2473 const std::string cacheFullPath = cacheToApply->getFileFullPathStr();
2474 g_log.information("Loading geometry cache from " + cacheFullPath);
2475 // create a vtk reader
2476 std::map<std::string, std::shared_ptr<Geometry::IObject>>::iterator objItr;
2477 std::shared_ptr<Mantid::Geometry::vtkGeometryCacheReader> reader(
2478 new Mantid::Geometry::vtkGeometryCacheReader(cacheFullPath));
2479 for (objItr = mapTypeNameToShape.begin(); objItr != mapTypeNameToShape.end(); ++objItr) {
2480 // caching only applies to CSGObject
2481 if (auto csgObj = std::dynamic_pointer_cast<CSGObject>(((*objItr).second))) {
2482 csgObj->setVtkGeometryCacheReader(reader);
2483 }
2484 }
2485}
2486
2494 IDFObject_const_sptr fallBackCache) {
2495 IDFObject_const_sptr usedCache = std::move(firstChoiceCache);
2496 auto cachingOption = WroteGeomCache;
2497
2498 g_log.notice("Geometry cache is not available");
2499 try {
2500 Poco::File dir = usedCache->getParentDirectory();
2501 if (dir.path().empty() || !dir.exists() || !dir.canWrite()) {
2502 usedCache = std::move(fallBackCache);
2503 cachingOption = WroteCacheTemp;
2504 g_log.information() << "Geometrycache directory is read only, writing cache "
2505 "to system temp.\n";
2506 }
2507 } catch (Poco::FileNotFoundException &) {
2508 g_log.error() << "Unable to find instrument definition while attempting to "
2509 "write cache.\n";
2510 throw std::runtime_error("Unable to find instrument definition while "
2511 "attempting to write cache.\n");
2512 }
2513 const std::string cacheFullPath = usedCache->getFileFullPathStr();
2514 g_log.notice() << "Creating cache in " << cacheFullPath << "\n";
2515 // create a vtk writer
2516 std::map<std::string, std::shared_ptr<Geometry::IObject>>::iterator objItr;
2517 std::shared_ptr<Mantid::Geometry::vtkGeometryCacheWriter> writer(
2518 new Mantid::Geometry::vtkGeometryCacheWriter(cacheFullPath));
2519 for (objItr = mapTypeNameToShape.begin(); objItr != mapTypeNameToShape.end(); ++objItr) {
2520 // caching only applies to CSGObject
2521 if (auto csgObj = std::dynamic_pointer_cast<CSGObject>(((*objItr).second))) {
2522 csgObj->setVtkGeometryCacheWriter(writer);
2523 }
2524 }
2525 writer->write();
2526 return cachingOption;
2527}
2528
2533 // Get cached file name
2534 // If the instrument directory is writable, put them there else use
2535 // temporary
2536 // directory.
2537 IDFObject_const_sptr fallBackCache = std::make_shared<const IDFObject>(
2538 Poco::Path(ConfigService::Instance().getTempDir()).append(this->getMangledName() + ".vtp").toString());
2539 CachingOption cachingOption = NoneApplied;
2540 if (m_cacheFile->exists()) {
2542 cachingOption = ReadGeomCache;
2543 } else if (fallBackCache->exists()) {
2544 applyCache(fallBackCache);
2545 cachingOption = ReadFallBack;
2546 } else {
2547 cachingOption = writeAndApplyCache(m_cacheFile, fallBackCache);
2548 }
2549 return cachingOption;
2550}
2551
2557 return m_cachingOption;
2558}
2559
2561 // Create a copy of the instrument
2562 auto physical = std::make_unique<Instrument>(*m_instrument);
2563 // Store the physical instrument 'inside' the neutronic instrument
2564 m_instrument->setPhysicalInstrument(std::move(physical));
2565
2566 // Now we manipulate the original instrument (m_instrument) to hold
2567 // neutronic positions
2568 for (const auto &component : m_neutronicPos) {
2569 if (component.second) {
2570 setLocation(component.first, component.second, m_angleConvertConst, m_deltaOffsets);
2571 // TODO: Do we need to deal with 'facing'???
2572
2573 // Check for a 'type' attribute, indicating that we want to set the
2574 // neutronic shape
2575 if (component.second->hasAttribute("type") && dynamic_cast<ObjComponent *>(component.first)) {
2576 const Poco::XML::XMLString shapeName = component.second->getAttribute("type");
2577 auto shapeIt = mapTypeNameToShape.find(shapeName);
2578 if (shapeIt != mapTypeNameToShape.end()) {
2579 // Change the shape on the current component to the one requested
2580 auto objCmpt = dynamic_cast<ObjComponent *>(component.first);
2581 if (objCmpt)
2582 objCmpt->setShape(shapeIt->second);
2583 } else {
2584 throw Exception::InstrumentDefinitionError("Requested type " + shapeName + " not defined in IDF");
2585 }
2586 }
2587 } else // We have a null Element*, which signals a detector with no
2588 // neutronic position
2589 {
2590 // This should only happen for detectors
2591 auto *det = dynamic_cast<Detector *>(component.first);
2592 if (det)
2593 m_instrument->removeDetector(det);
2594 }
2595 }
2596}
2597
2615void InstrumentDefinitionParser::adjust(Poco::XML::Element *pElem, std::map<std::string, bool> &isTypeAssembly,
2616 std::map<std::string, Poco::XML::Element *> &getTypeElement) {
2618 // check if pElem is an element with tag name 'type'
2619 if (pElem->tagName() != "type")
2620 throw Exception::InstrumentDefinitionError("Argument to function adjust() "
2621 "must be a pointer to an XML "
2622 "element with tag name type.");
2623
2624 // check that there is a <combine-components-into-one-shape> element in type
2625 Poco::AutoPtr<NodeList> pNLccioh = pElem->getElementsByTagName("combine-components-into-one-shape");
2626 if (pNLccioh->length() == 0) {
2627 throw Exception::InstrumentDefinitionError(std::string("Argument to function adjust() must be a pointer to an XML "
2628 "element with tag name type,") +
2629 " which contain a <combine-components-into-one-shape> element.");
2630 }
2631
2632 // check that there is a <algebra> element in type
2633 Poco::AutoPtr<NodeList> pNLalg = pElem->getElementsByTagName("algebra");
2634 if (pNLalg->length() == 0) {
2635 throw Exception::InstrumentDefinitionError(std::string("An <algebra> element must be part of a <type>, which") +
2636 " includes a <combine-components-into-one-shape> element. See "
2637 "www.mantidproject.org/IDF.");
2638 }
2639
2640 // check that there is a <location> element in type
2641 Poco::AutoPtr<NodeList> pNL = pElem->getElementsByTagName("location");
2642 unsigned long numLocation = pNL->length();
2643 if (numLocation == 0) {
2644 throw Exception::InstrumentDefinitionError(std::string("At least one <location> element must be part of a "
2645 "<type>, which") +
2646 " includes a <combine-components-into-one-shape> element. See "
2647 "www.mantidproject.org/IDF.");
2648 }
2649
2650 // check if a <translate-rotate-combined-shape-to> is defined
2651 Poco::AutoPtr<NodeList> pNL_TransRot = pElem->getElementsByTagName("translate-rotate-combined-shape-to");
2652 Element *pTransRot = nullptr;
2653 if (pNL_TransRot->length() == 1) {
2654 pTransRot = static_cast<Element *>(pNL_TransRot->item(0));
2655 }
2656
2657 // to convert all <component>'s in type into <cuboid> elements, which are
2658 // added
2659 // to pElem, and these <component>'s are deleted after loop
2660
2661 std::unordered_set<Element *> allComponentInType; // used to hold <component>'s found
2662 std::vector<std::string> allLocationName; // used to check if loc names unique
2663 for (unsigned long i = 0; i < numLocation; i++) {
2664 auto *pLoc = static_cast<Element *>(pNL->item(i));
2665
2666 // The location element is required to be a child of a component element.
2667 // Get this component element
2668 Element *pCompElem = InstrumentDefinitionParser::getParentComponent(pLoc);
2669
2670 // get the name given to the <location> element in focus
2671 // note these names are required to be unique for the purpose of
2672 // constructing the <algebra>
2673 std::string locationElementName = pLoc->getAttribute("name");
2674 if (std::find(allLocationName.begin(), allLocationName.end(), locationElementName) == allLocationName.end())
2675 allLocationName.emplace_back(locationElementName);
2676 else
2677 throw Exception::InstrumentDefinitionError(std::string("Names in a <type> element containing ") +
2678 "a <combine-components-into-one-shape> element must be unique. " +
2679 "Here error is that " + locationElementName +
2680 " appears at least twice. See www.mantidproject.org/IDF.");
2681
2682 // create dummy component to hold coord. sys. of cuboid
2683 auto baseCoor = std::make_unique<CompAssembly>("base"); // dummy assembly used to get to end assembly if nested
2684 ICompAssembly *endComponent = nullptr; // end assembly, its purpose is to
2685 // hold the shape coordinate system
2686 // get shape coordinate system, returned as endComponent, as defined by
2687 // pLoc
2688 // and nested <location> elements
2689 // of pLoc
2690 std::string shapeTypeName = getShapeCoorSysComp(baseCoor.get(), pLoc, getTypeElement, endComponent);
2691
2692 // translate and rotate cuboid according to shape coordinate system in
2693 // endComponent
2694 std::string cuboidStr = translateRotateXMLcuboid(endComponent, getTypeElement[shapeTypeName], locationElementName);
2695
2696 // if <translate-rotate-combined-shape-to> is specified
2697 if (pTransRot) {
2698 baseCoor = std::make_unique<CompAssembly>("base");
2699
2700 setLocation(baseCoor.get(), pTransRot, m_angleConvertConst);
2701
2702 // Translate and rotate shape xml string according to
2703 // <translate-rotate-combined-shape-to>
2704 cuboidStr = translateRotateXMLcuboid(baseCoor.get(), cuboidStr, locationElementName);
2705 }
2706
2707 DOMParser pParser;
2708 Poco::AutoPtr<Document> pDoc;
2709 try {
2710 pDoc = pParser.parseString(cuboidStr);
2711 } catch (...) {
2712 throw Exception::InstrumentDefinitionError(std::string("Unable to parse XML string ") + cuboidStr);
2713 }
2714 // Get pointer to root element and add this element to pElem
2715 Element *pCuboid = pDoc->documentElement();
2716 Poco::AutoPtr<Node> fisse = (pElem->ownerDocument())->importNode(pCuboid, true);
2717 pElem->appendChild(fisse);
2718
2719 allComponentInType.insert(pCompElem);
2720 }
2721
2722 // delete all <component> found in pElem
2723 for (const auto &component : allComponentInType)
2724 pElem->removeChild(component);
2725}
2726
2736 const Poco::XML::Element *cuboidEle,
2737 const std::string &cuboidName) {
2738 Element *pElem_lfb = getShapeElement(cuboidEle, "left-front-bottom-point");
2739 Element *pElem_lft = getShapeElement(cuboidEle, "left-front-top-point");
2740 Element *pElem_lbb = getShapeElement(cuboidEle, "left-back-bottom-point");
2741 Element *pElem_rfb = getShapeElement(cuboidEle, "right-front-bottom-point");
2742
2743 V3D lfb = parsePosition(pElem_lfb); // left front bottom
2744 V3D lft = parsePosition(pElem_lft); // left front top
2745 V3D lbb = parsePosition(pElem_lbb); // left back bottom
2746 V3D rfb = parsePosition(pElem_rfb); // right front bottom
2747
2748 // translate and rotate cuboid according to coord. sys. of comp
2749 V3D p_lfb = getAbsolutPositionInCompCoorSys(comp, lfb);
2750 V3D p_lft = getAbsolutPositionInCompCoorSys(comp, lft);
2751 V3D p_lbb = getAbsolutPositionInCompCoorSys(comp, lbb);
2752 V3D p_rfb = getAbsolutPositionInCompCoorSys(comp, rfb);
2753
2754 // create output cuboid XML string
2755 std::ostringstream obj_str;
2756
2757 obj_str << "<cuboid id=\"" << cuboidName << "\">";
2758 obj_str << "<left-front-bottom-point ";
2759 obj_str << "x=\"" << p_lfb.X();
2760 obj_str << "\" y=\"" << p_lfb.Y();
2761 obj_str << "\" z=\"" << p_lfb.Z();
2762 obj_str << "\" />";
2763 obj_str << "<left-front-top-point ";
2764 obj_str << "x=\"" << p_lft.X();
2765 obj_str << "\" y=\"" << p_lft.Y();
2766 obj_str << "\" z=\"" << p_lft.Z();
2767 obj_str << "\" />";
2768 obj_str << "<left-back-bottom-point ";
2769 obj_str << "x=\"" << p_lbb.X();
2770 obj_str << "\" y=\"" << p_lbb.Y();
2771 obj_str << "\" z=\"" << p_lbb.Z();
2772 obj_str << "\" />";
2773 obj_str << "<right-front-bottom-point ";
2774 obj_str << "x=\"" << p_rfb.X();
2775 obj_str << "\" y=\"" << p_rfb.Y();
2776 obj_str << "\" z=\"" << p_rfb.Z();
2777 obj_str << "\" />";
2778 obj_str << "</cuboid>";
2779
2780 return obj_str.str();
2781}
2782
2789 Component *dummyComp = new Component("dummy", comp);
2790 comp->add(dummyComp);
2791
2792 dummyComp->setPos(pos); // set pos relative to comp coord. sys.
2793
2794 V3D retVal = dummyComp->getPos(); // get absolute position
2795
2796 return retVal;
2797}
2798
2807std::string InstrumentDefinitionParser::translateRotateXMLcuboid(ICompAssembly *comp, const std::string &cuboidXML,
2808 const std::string &cuboidName) {
2809 DOMParser pParser;
2810 Poco::AutoPtr<Document> pDoc;
2811 try {
2812 pDoc = pParser.parseString(cuboidXML);
2813 } catch (...) {
2814 throw Exception::InstrumentDefinitionError(std::string("Unable to parse XML string ") + cuboidXML);
2815 }
2816
2817 Element *pCuboid = pDoc->documentElement();
2818
2819 std::string retVal = translateRotateXMLcuboid(comp, pCuboid, cuboidName);
2820
2821 return retVal;
2822}
2823
2831Poco::AutoPtr<Poco::XML::Document>
2833 // Number of <location> this <locations> element is shorthand for
2834 size_t nElements(0);
2835 if (pElem->hasAttribute("n-elements")) {
2836 auto n = boost::lexical_cast<int>(Strings::strip(pElem->getAttribute("n-elements")));
2837
2838 if (n <= 0) {
2839 throw Exception::InstrumentDefinitionError("n-elements must be positive");
2840 } else {
2841 nElements = static_cast<size_t>(n);
2842 }
2843 } else {
2844 throw Exception::InstrumentDefinitionError("When using <locations> n-elements attribute is required. See "
2845 "www.mantidproject.org/IDF.");
2846 }
2847
2848 std::string name;
2849 if (pElem->hasAttribute("name")) {
2850 name = pElem->getAttribute("name");
2851 }
2852
2853 int nameCountStart(0);
2854 if (pElem->hasAttribute("name-count-start")) {
2855 nameCountStart = boost::lexical_cast<int>(Strings::strip(pElem->getAttribute("name-count-start")));
2856 }
2857
2858 int nameCountIncrement(1);
2859 if (pElem->hasAttribute("name-count-increment")) {
2860 nameCountIncrement = boost::lexical_cast<int>(Strings::strip(pElem->getAttribute("name-count-increment")));
2861
2862 if (nameCountIncrement <= 0)
2863 throw Exception::InstrumentDefinitionError("name-count-increment must be greater than zero.");
2864 }
2865
2866 // A list of numeric attributes which are allowed to have corresponding -end
2867 std::set<std::string> rangeAttrs = {"x", "y", "z", "r", "t", "p", "rot"};
2868
2869 // Numeric attributes related to rotation. Doesn't make sense to have -end
2870 // for
2871 // those
2872 std::set<std::string> rotAttrs = {"axis-x", "axis-y", "axis-z"};
2873
2874 // A set of all numeric attributes for convenience
2875 std::set<std::string> allAttrs;
2876 allAttrs.insert(rangeAttrs.begin(), rangeAttrs.end());
2877 allAttrs.insert(rotAttrs.begin(), rotAttrs.end());
2878
2879 // Attribute values as read from <locations>. If the attribute doesn't have
2880 // a
2881 // value here, it
2882 // means that it wasn't set
2883 std::map<std::string, double> attrValues;
2884
2885 // Read all the set attribute values
2886 for (const auto &attr : allAttrs) {
2887 if (pElem->hasAttribute(attr)) {
2888 attrValues[attr] = boost::lexical_cast<double>(Strings::strip(pElem->getAttribute(attr)));
2889 }
2890 }
2891
2892 // Range attribute steps
2893 std::map<std::string, double> rangeAttrSteps;
2894
2895 // Find *-end for range attributes and calculate steps
2896 for (const auto &rangeAttr : rangeAttrs) {
2897 std::string endAttr = rangeAttr + "-end";
2898 if (pElem->hasAttribute(endAttr)) {
2899 if (attrValues.find(rangeAttr) == attrValues.end()) {
2900 throw Exception::InstrumentDefinitionError("*-end attribute without corresponding * attribute.");
2901 }
2902
2903 double from = attrValues[rangeAttr];
2904 auto to = boost::lexical_cast<double>(Strings::strip(pElem->getAttribute(endAttr)));
2905
2906 rangeAttrSteps[rangeAttr] = (to - from) / (static_cast<double>(nElements) - 1);
2907 }
2908 }
2909
2910 Poco::AutoPtr<Document> pDoc = new Document;
2911 Poco::AutoPtr<Element> pRoot = pDoc->createElement("expansion-of-locations-element");
2912 pDoc->appendChild(pRoot);
2913
2914 for (size_t i = 0; i < nElements; ++i) {
2915 Poco::AutoPtr<Element> pLoc = pDoc->createElement("location");
2916
2917 if (!name.empty()) {
2918 // Add name with appropriate numeric postfix
2919 pLoc->setAttribute("name", name + std::to_string(nameCountStart + (i * nameCountIncrement)));
2920 }
2921
2922 // Copy values of all the attributes set
2923 for (auto &attrValue : attrValues) {
2924 pLoc->setAttribute(attrValue.first, boost::lexical_cast<std::string>(attrValue.second));
2925
2926 // If attribute has a step, increase the value by the step
2927 if (rangeAttrSteps.find(attrValue.first) != rangeAttrSteps.end()) {
2928 attrValue.second += rangeAttrSteps[attrValue.first];
2929 }
2930 }
2931
2932 pRoot->appendChild(pLoc);
2933 }
2934
2935 return pDoc;
2936}
2937
2944 std::string retVal;
2945 std::string filename = getMangledName();
2946 if (!filename.empty()) {
2947 Poco::Path path(ConfigService::Instance().getVTPFileDirectory());
2948 path.makeDirectory();
2949 path.append(filename + ".vtp");
2950 retVal = path.toString();
2951 }
2952 return retVal;
2953}
2954
2965Poco::XML::Element *InstrumentDefinitionParser::getShapeElement(const Poco::XML::Element *pElem,
2966 const std::string &name) {
2967 // check if this shape element contain an element with name specified by the
2968 // 2nd function argument
2969 Poco::AutoPtr<NodeList> pNL = pElem->getElementsByTagName(name);
2970 if (pNL->length() != 1) {
2971 throw std::invalid_argument("XML element: <" + pElem->tagName() +
2972 "> must contain exactly one sub-element with name: <" + name + ">.");
2973 }
2974 auto *retVal = static_cast<Element *>(pNL->item(0));
2975 return retVal;
2976}
2977
2984 V3D retVal;
2985
2986 if (pElem->hasAttribute("R") || pElem->hasAttribute("theta") || pElem->hasAttribute("phi")) {
2987 double R = attrToDouble(pElem, "R");
2988 double theta = attrToDouble(pElem, "theta");
2989 double phi = attrToDouble(pElem, "phi");
2990
2991 retVal.spherical(R, theta, phi);
2992 } else if (pElem->hasAttribute("r") || pElem->hasAttribute("t") || pElem->hasAttribute("p"))
2993 // This is alternative way a user may specify spherical coordinates
2994 // which may be preferred in the long run to the more verbose of
2995 // using R, theta and phi.
2996 {
2997 double R = attrToDouble(pElem, "r");
2998 double theta = attrToDouble(pElem, "t");
2999 double phi = attrToDouble(pElem, "p");
3000
3001 retVal.spherical(R, theta, phi);
3002 } else {
3003
3004 double x = attrToDouble(pElem, "x");
3005 double y = attrToDouble(pElem, "y");
3006 double z = attrToDouble(pElem, "z");
3007
3008 retVal(x, y, z);
3009 }
3010
3011 return retVal;
3012}
3013
3014//-----------------------------------------------------------------------------------------------------------------------
3033 Poco::XML::Element *pLocElem,
3034 std::map<std::string, Poco::XML::Element *> &getTypeElement,
3035 Geometry::ICompAssembly *&endAssembly) {
3036 // The location element is required to be a child of a component element.
3037 // Get
3038 // this component element
3039 Element *pCompElem = InstrumentDefinitionParser::getParentComponent(pLocElem);
3040
3041 // Create the assembly that will be appended into the parent.
3043
3044 // The newly added component is required to have a type. Find out what this
3045 // type is and find all the location elements of this type. Finally loop
3046 // over
3047 // these
3048 // location elements
3049
3050 Element *pType = getTypeElement[pCompElem->getAttribute("type")];
3051
3053 endAssembly = ass;
3054
3055 // set location for this newly added comp
3056 setLocation(ass, pLocElem, m_angleConvertConst);
3057
3058 Poco::AutoPtr<NodeList> pNL = pType->getElementsByTagName("location");
3059 if (pNL->length() == 0) {
3060 return pType->getAttribute("name");
3061 } else if (pNL->length() == 1) {
3062 auto *pElem = static_cast<Element *>(pNL->item(0));
3063 return getShapeCoorSysComp(ass, pElem, getTypeElement, endAssembly);
3064 } else {
3065 throw Exception::InstrumentDefinitionError(std::string("When using <combine-components-into-one-shape> ") +
3066 " the containing component elements are not allowed to contain "
3067 "multiple nested components. See www.mantidproject.org/IDF.");
3068 }
3069}
3070
3071} // namespace Mantid::Geometry
gsl_vector * tmp
double value
The value of the point.
Definition: FitMW.cpp:51
std::map< DeltaEMode::Type, std::string > index
Definition: DeltaEMode.cpp:19
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
Definition: System.h:64
double obj
the value of the quadratic function
Class for Assembly of geometric components.
Definition: CompAssembly.h:31
Kernel::V3D getPos() const override
Gets the absolute position of the Parametrized CompAssembly This attempts to read the cached position...
Component is a wrapper for a Component which can modify some of its parameters, e....
Definition: Component.h:41
void setRot(const Kernel::Quat &) override
Set the orientation Kernel::Quaternion relative to parent (if present)
Definition: Component.cpp:226
void setParent(IComponent *) override
Assign a parent IComponent. Previous parent link is lost.
Definition: Component.cpp:107
Kernel::V3D getPos() const override
Get the position of the IComponent. Tree structure is traverse through the.
Definition: Component.cpp:325
void setPos(double, double, double) override
Set the IComponent position, x, y, z respective to parent (if present)
Definition: Component.cpp:204
This class represents a detector - i.e.
Definition: Detector.h:30
detid_t getID() const override
Gets the detector id.
Definition: Detector.cpp:51
GridDetector is a type of CompAssembly, an assembly of components.
Definition: GridDetector.h:34
static bool compareName(const std::string &proposedMatch)
Matches name to Structured Detector.
Class for Assembly of geometric components.
Definition: ICompAssembly.h:30
virtual int add(IComponent *)=0
Add a component to the assembly.
base class for Geometric IComponent
Definition: IComponent.h:51
virtual Kernel::V3D getPos() const =0
Get the position of the IComponent. Tree structure is traverse through the.
virtual void setPos(double, double, double)=0
Set the IComponent position, x, y, z respective to parent (if present)
virtual std::shared_ptr< const IComponent > getParent() const =0
Return a pointer to the current parent.
virtual Kernel::Quat getRotation() const =0
Get the absolute orientation of the IComponent.
virtual void translate(const Kernel::V3D &)=0
Copy the Rotation from another IComponent.
virtual void rotate(const Kernel::Quat &)=0
Rotate the IComponent. This is relative to parent.
virtual std::string getName() const =0
Get the IComponent name.
Creates an instrument data from a XML instrument description file.
bool m_deltaOffsets
Flag to indicate whether offsets given in spherical coordinates are to be added to the current positi...
void appendLocations(Geometry::ICompAssembly *parent, const Poco::XML::Element *pLocElems, const Poco::XML::Element *pCompElem, IdList &idList)
Append <locations> in a locations element.
void createNeutronicInstrument()
If appropriate, creates a second instrument containing neutronic detector positions.
std::shared_ptr< Instrument > parseXML(Kernel::ProgressBase *progressReporter)
Parse XML contents.
void createStructuredDetector(Geometry::ICompAssembly *parent, const Poco::XML::Element *pLocElem, const Poco::XML::Element *pCompElem, const std::string &filename, const Poco::XML::Element *pType)
void adjustTypesContainingCombineComponentsElement(ShapeFactory &shapeCreator, const std::string &filename, const std::vector< Poco::XML::Element * > &typeElems, size_t numberOfTypes)
Adjust each type which contains a <combine-components-into-one-shape> element.
void getTypeAndComponentPointers(const Poco::XML::Element *pRootElem, std::vector< Poco::XML::Element * > &typeElems, std::vector< Poco::XML::Element * > &compElems) const
Populate vectors of pointers to type and component xml elements.
void throwIfTypeNameNotUnique(const std::string &filename, const std::string &typeName) const
Throw exception if type name is not unique in the IDF.
std::map< const Geometry::IComponent *, SphVec > m_tempPosHolder
Map to store positions of parent components in spherical coordinates.
void createDetectorOrMonitor(Geometry::ICompAssembly *parent, const Poco::XML::Element *pLocElem, const Poco::XML::Element *pCompElem, const std::string &filename, IdList &idList, const std::string &category)
std::string translateRotateXMLcuboid(Geometry::ICompAssembly *comp, const Poco::XML::Element *cuboidEle, const std::string &cuboidName)
Returns a translated and rotated <cuboid> element.
void createRectangularDetector(Geometry::ICompAssembly *parent, const Poco::XML::Element *pLocElem, const Poco::XML::Element *pCompElem, const std::string &filename, const Poco::XML::Element *pType)
double m_angleConvertConst
when this const equals 1 it means that angle=degree (default) is set in IDF otherwise if this const e...
void appendLeaf(Geometry::ICompAssembly *parent, const Poco::XML::Element *pLocElem, const Poco::XML::Element *pCompElem, IdList &idList)
Add XML element to parent assuming the element contains no other component elements.
std::string getMangledName()
Handle used in the singleton constructor for instrument file should append the value file sha-1 check...
void setComponentLinks(std::shared_ptr< Geometry::Instrument > &instrument, Poco::XML::Element *pRootElem, Kernel::ProgressBase *progress=nullptr, const std::string &requestedDate=std::string())
Add/overwrite any parameters specified in instrument with param values specified in <component-link> ...
bool m_haveDefaultFacing
True if defaults->components-are-facing is set in instrument def. file.
void setLocation(Geometry::IComponent *comp, const Poco::XML::Element *pElem, const double angleConvertConst, const bool deltaOffsets=false)
Set location (position) of comp as specified in XML location element.
std::string getShapeCoorSysComp(Geometry::ICompAssembly *parent, Poco::XML::Element *pLocElem, std::map< std::string, Poco::XML::Element * > &getTypeElement, Geometry::ICompAssembly *&endAssembly)
This method returns the parent appended which its child components and also name of type of the last ...
Kernel::V3D m_defaultFacing
Hold default facing position.
CachingOption getAppliedCachingOption() const
Getter the the applied caching option.
std::map< Geometry::IComponent *, Poco::XML::Element * > m_neutronicPos
A map containing the neutronic position for each detector.
void checkComponentContainsLocationElement(Poco::XML::Element *pElem, const std::string &filename) const
Check component has a <location> or <locations> element.
Kernel::V3D parseFacingElementToV3D(Poco::XML::Element *pElem)
Parse position of facing element to V3D.
void collateTypeInformation(const std::string &filename, const std::vector< Poco::XML::Element * > &typeElems, ShapeFactory &shapeCreator)
Collect some information about types for later use.
std::shared_ptr< Geometry::Instrument > m_instrument
For convenience added pointer to instrument here.
InstrumentDefinitionParser()
Default Constructor - not very functional in this state.
CachingOption writeAndApplyCache(IDFObject_const_sptr firstChoiceCache, IDFObject_const_sptr fallBackCache)
Write out a cache file.
Kernel::V3D parsePosition(Poco::XML::Element *pElem)
Get position coordinates from XML element.
void makeXYplaneFaceComponent(Geometry::IComponent *&in, const Geometry::ObjComponent *facing)
Make the shape defined in 1st argument face the component in the second argument.
Kernel::V3D getRelativeTranslation(const Geometry::IComponent *comp, const Poco::XML::Element *pElem, const double angleConvertConst, const bool deltaOffsets=false)
Calculate the position of comp relative to its parent from info provided by <location> element.
void adjust(Poco::XML::Element *pElem, std::map< std::string, bool > &isTypeAssembly, std::map< std::string, Poco::XML::Element * > &getTypeElement)
Takes as input a <type> element containing a <combine-components-into-one-shape>, and adjust the <typ...
std::vector< Poco::XML::Element * > m_hasParameterElement
Holds all the xml elements that have a <parameter> child element.
void setFacing(Geometry::IComponent *comp, const Poco::XML::Element *pElem)
Set facing of comp as specified in XML facing element.
void readDefaults(Poco::XML::Element *defaults)
Reads the contents of the <defaults> element to set member variables,.
Poco::AutoPtr< Poco::XML::Document > m_pDoc
XML document is lazy loaded.
void populateIdList(Poco::XML::Element *pE, IdList &idList)
Method for populating IdList.
std::map< std::string, std::shared_ptr< Geometry::IObject > > mapTypeNameToShape
map which maps the type name to a shared pointer to a geometric shape
void createShapeIfTypeIsNotAnAssembly(Mantid::Geometry::ShapeFactory &shapeCreator, size_t iType, Poco::XML::Element *pTypeElem, const std::string &typeName)
Record type as an assembly if it contains a component, otherwise create a shape for it.
std::map< std::string, bool > isTypeAssembly
map which holds names of types and whether or not they are categorized as being assemblies,...
void setLogfile(const Geometry::IComponent *comp, const Poco::XML::Element *pElem, InstrumentParameterCache &logfileCache, const std::string &requestedDate=std::string())
Set parameter/logfile info (if any) associated with component.
void createGridDetector(Geometry::ICompAssembly *parent, const Poco::XML::Element *pLocElem, const Poco::XML::Element *pCompElem, const std::string &filename, const Poco::XML::Element *pType)
const std::string createVTPFileName()
creates a vtp filename from a given xml filename
void parseLocationsForEachTopLevelComponent(Kernel::ProgressBase *progressReporter, const std::string &filename, const std::vector< Poco::XML::Element * > &compElems)
Aggregate locations and IDs for components.
static Poco::XML::Element * getParentComponent(const Poco::XML::Element *pLocElem)
Get parent component element of location element.
std::map< std::string, Poco::XML::Element * > getTypeElement
map which holds names of types and pointers to these type for fast retrieval in code
Poco::XML::Element * getShapeElement(const Poco::XML::Element *pElem, const std::string &name)
Return a subelement of an XML element.
void appendAssembly(Geometry::ICompAssembly *parent, const Poco::XML::Element *pLocElem, const Poco::XML::Element *pCompElem, IdList &idList)
Add XML element to parent assuming the element contains other component elements.
std::vector< std::string > buildExcludeList(const Poco::XML::Element *const location)
void createVectorOfElementsContainingAParameterElement(Poco::XML::Element *pRootElem)
Create a vector of elements which contain a <parameter>
CachingOption setupGeometryCache()
Reads in or creates the geometry cache ('vtp') file.
void setValidityRange(const Poco::XML::Element *pRootElem)
Check the validity range and add it to the instrument object.
bool m_hasParameterElement_beenSet
has m_hasParameterElement been set - used when public method setComponentLinks is used
double attrToDouble(const Poco::XML::Element *pElem, const std::string &name)
return 0 if the attribute doesn't exist.
void initialise(const std::string &filename, const std::string &instName, const std::string &xmlText, const std::string &vtpFilename)
shared Constructor logic
Poco::AutoPtr< Poco::XML::Document > convertLocationsElement(const Poco::XML::Element *pElem)
Take as input a <locations> element.
std::vector< Geometry::ObjComponent * > m_facingComponent
Container to hold all detectors and monitors added to the instrument.
Kernel::V3D getAbsolutPositionInCompCoorSys(Geometry::ICompAssembly *comp, Kernel::V3D)
return absolute position of point which is set relative to the coordinate system of the input compone...
static std::string getNameOfLocationElement(const Poco::XML::Element *pElem, const Poco::XML::Element *pCompElem)
get name of location element
Poco::AutoPtr< Poco::XML::Document > getDocument()
lazy loads the document and returns a pointer
bool isAssembly(const std::string &) const
Return true if assembly, false if not assembly and throws exception if string not in assembly.
bool m_indirectPositions
Flag to indicate whether IDF contains physical & neutronic positions.
void checkIdListExistsAndDefinesEnoughIDs(const IdList &idList, Poco::XML::Element *pElem, const std::string &filename) const
Check IdList.
void saveDOM_Tree(std::string &outFilename)
Save DOM tree to xml file.
void applyCache(const IDFObject_const_sptr &cacheToApply)
Reads from a cache file.
Class for Assembly of geometric components.
Object Component class, this class brings together the physical attributes of the component to the po...
Definition: ObjComponent.h:33
void setShape(std::shared_ptr< const IObject > newShape)
Set a new shape on the component void setShape(std::shared_ptr<const IObject> newShape);.
RectangularDetector is a type of CompAssembly, an assembly of components.
static bool compareName(const std::string &proposedMatch)
Matches name to Structured Detector.
Class originally intended to be used with the DataHandling 'LoadInstrument' algorithm.
Definition: ShapeFactory.h:89
std::shared_ptr< CSGObject > createShape(Poco::XML::Element *pElem)
Creates a geometric object from a DOM-element-node pointing to an element whose child nodes contain t...
StructuredDetector is a type of CompAssembly, an assembly of components.
static bool compareName(const std::string &proposedMatch)
Matches name to Structured Detector.
Reads the Geometry Cache from the file to the Object.
Writes the Geometry from Object to Cache.
Exception for when an item is already in a collection.
Definition: Exception.h:164
Exception for errors associated with the instrument definition.
Definition: Exception.h:220
The Logger class is in charge of the publishing messages from the framework through various channels.
Definition: Logger.h:52
void notice(const std::string &msg)
Logs at notice level.
Definition: Logger.cpp:95
void error(const std::string &msg)
Logs at error level.
Definition: Logger.cpp:77
void warning(const std::string &msg)
Logs at warning level.
Definition: Logger.cpp:86
void information(const std::string &msg)
Logs at information level.
Definition: Logger.cpp:105
void resetNumSteps(int64_t nsteps, double start, double end)
Change the number of steps between start/end.
virtual bool hasCancellationBeenRequested() const
Override so that the reporter can inform whether a cancellation request has been used.
Definition: ProgressBase.h:42
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
Definition: ProgressBase.h:51
Class for quaternions.
Definition: Quat.h:39
void inverse()
Inverse a quaternion (in the sense of rotation inversion)
Definition: Quat.cpp:376
void rotate(V3D &) const
Rotate a vector.
Definition: Quat.cpp:397
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
Class for 3D vectors.
Definition: V3D.h:34
constexpr double X() const noexcept
Get x.
Definition: V3D.h:232
constexpr V3D cross_prod(const V3D &v) const noexcept
Cross product (this * argument)
Definition: V3D.h:278
constexpr double Y() const noexcept
Get y.
Definition: V3D.h:233
void spherical(const double R, const double theta, const double phi) noexcept
Sets the vector position based on spherical coordinates.
Definition: V3D.cpp:57
double angle(const V3D &) const
Angle between this and another vector.
Definition: V3D.cpp:165
double norm() const noexcept
Definition: V3D.h:263
constexpr double Z() const noexcept
Get z.
Definition: V3D.h:234
Handedness
Type to distingusih between l and r handedness.
std::map< std::pair< std::string, const IComponent * >, std::shared_ptr< XMLInstrumentParameter > > InstrumentParameterCache
Convenience typedef.
Definition: Instrument.h:37
Mantid::Kernel::Logger g_log("Goniometer")
std::shared_ptr< const AbstractIDFObject > IDFObject_const_sptr
Definition: IDFObject.h:92
PointingAlong axisNameToAxisType(const std::string &label, const std::string &input)
std::shared_ptr< Instrument > Instrument_sptr
Shared pointer to an instrument object.
PointingAlong
Type to describe pointing along options.
MANTID_KERNEL_DLL std::string sha1FromString(const std::string &input)
create a SHA-1 checksum from a string
MANTID_KERNEL_DLL std::string strip(const std::string &A)
strip pre/post spaces
Definition: Strings.cpp:397
MANTID_KERNEL_DLL V3D normalize(V3D v)
Normalizes a V3D.
Definition: V3D.h:341
Helper class which provides the Collimation Length for SANS instruments.
int32_t detid_t
Typedef for a detector ID.
Definition: SpectrumInfo.h:21
STL namespace.
std::string to_string(const wide_integer< Bits, Signed > &n)
int counted
Used to count the number of detector encounted so far.
Stripped down vector that holds position in terms of spherical coordinates, Needed when processing in...