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 // do quick check for side-by-side-view-location string, if it doesn't exist we can skip checking every element,
124 // thereby speeding up processing
125 m_sideBySideViewLocation_exists = xmlText.find("side-by-side-view-location") != std::string::npos;
126
127 // Create our new instrument
128 // We don't want the instrument name taken out of the XML file itself, it
129 // should come from the filename (or the property)
130 m_instrument = std::make_shared<Instrument>(m_instName);
131
132 // Save the XML file path and contents
133 m_instrument->setFilename(filename);
134 m_instrument->setXmlText(xmlText);
135
136 // Use the filename to construct the cachefile name so that there is a 1:1 map
137 // between a definition file & cache
138 if (vtpFilename.empty()) {
139 m_cacheFile = std::make_shared<const IDFObject>(createVTPFileName());
140 } else {
141 m_cacheFile = std::make_shared<const IDFObject>(vtpFilename);
142 }
143}
144
145//----------------------------------------------------------------------------------------------
157
158 std::string retVal;
159 // use the xml in preference if available
160 auto xml = Poco::trim(m_instrument->getXmlText());
161 if (!(xml.empty())) {
162 std::string checksum = Kernel::ChecksumHelper::sha1FromString(xml);
163 retVal = m_instName + checksum;
164 } else if (this->m_xmlFile->exists()) { // Use the file
165 retVal = m_xmlFile->getMangledName();
166 }
167
168 return retVal;
169}
170
171//----------------------------------------------------------------------------------------------
176Poco::AutoPtr<Poco::XML::Document> InstrumentDefinitionParser::getDocument() {
177 if (!m_pDoc) {
178 // instantiate if not created
179 if (m_instrument->getXmlText().empty()) {
180 throw std::invalid_argument("Instrument XML string is empty");
181 }
182 // Set up the DOM parser and parse xml file
183 DOMParser pParser;
184 try {
185 m_pDoc = pParser.parseString(m_instrument->getXmlText());
186 } catch (Poco::Exception &exc) {
187 throw std::invalid_argument(exc.displayText() + ". Unable to parse XML");
188 } catch (...) {
189 throw std::invalid_argument("Unable to parse XML");
190 }
191 }
192 return m_pDoc;
193}
194
202 const std::string &typeName) const {
203 if (getTypeElement.find(typeName) != getTypeElement.end()) {
204 g_log.error(std::string("XML file: ")
205 .append(filename)
206 .append("contains more than one type element named ")
207 .append(typeName));
209 std::string("XML instrument file contains more than one type element named ")
210 .append(typeName)
211 .append(filename));
212 }
213}
214
215//----------------------------------------------------------------------------------------------
223 auto pDoc = getDocument();
224
225 // Get pointer to root element
226 Poco::XML::Element *pRootElem = pDoc->documentElement();
227
228 if (!pRootElem->hasChildNodes()) {
229 g_log.error("Instrument XML contains no root element.");
230 throw Kernel::Exception::InstrumentDefinitionError("No root element in XML instrument");
231 }
232
233 setValidityRange(pRootElem);
234 readDefaults(pRootElem->getChildElement("defaults"));
235 Geometry::ShapeFactory shapeCreator;
236
237 const std::string filename = m_xmlFile->getFileFullPathStr();
238
239 std::vector<Element *> typeElems;
240 std::vector<Element *> compElems;
241 getTypeAndComponentPointers(pRootElem, typeElems, compElems);
242
243 if (typeElems.empty()) {
244 g_log.error("XML file: " + filename + "contains no type elements.");
245 throw Kernel::Exception::InstrumentDefinitionError("No type elements in XML instrument file", filename);
246 }
247
248 collateTypeInformation(filename, typeElems, shapeCreator);
249
250 // Populate m_hasParameterElement
252
253 // See if any parameters set at instrument level
254 setLogfile(m_instrument.get(), pRootElem, m_instrument->getLogfileCache());
255
256 parseLocationsForEachTopLevelComponent(progressReporter, filename, compElems);
257
258 // Don't need this anymore (if it was even used) so empty it out to save
259 // memory
260 m_tempPosHolder.clear();
261
262 // Read in or create the geometry cache file
264
265 // Add/overwrite any instrument params with values specified in
266 // <component-link> XML elements
268
271
272 // Instrument::markAsDetector is slow unless the detector IDs in the IDF are
273 // sorted. To circumvent this we use the 2-part interface,
274 // markAsDetectorIncomplete (which does not sort) and markAsDetectorFinalize
275 // (which does the final sorting).
276 m_instrument->markAsDetectorFinalize();
277
278 // And give back what we created
279 return m_instrument;
280}
281
296 const std::vector<Element *> &typeElems,
297 ShapeFactory &shapeCreator) {
298 const size_t numberOfTypes = typeElems.size();
299 for (size_t iType = 0; iType < numberOfTypes; ++iType) {
300 Element *pTypeElem = typeElems[iType];
301 std::string typeName = pTypeElem->getAttribute("name");
302
303 // If type contains <combine-components-into-one-shape> then make adjustment
304 // after this loop has completed
305 Poco::AutoPtr<NodeList> pNL_type_combine_into_one_shape =
306 pTypeElem->getElementsByTagName("combine-components-into-one-shape");
307 if (pNL_type_combine_into_one_shape->length() > 0) {
308 continue;
309 }
310
311 throwIfTypeNameNotUnique(filename, typeName);
312 getTypeElement[typeName] = pTypeElem;
313 createShapeIfTypeIsNotAnAssembly(shapeCreator, iType, pTypeElem, typeName);
314 }
315
316 adjustTypesContainingCombineComponentsElement(shapeCreator, filename, typeElems, numberOfTypes);
317}
318
327 const std::string &filename,
328 const std::vector<Element *> &compElems) {
329 if (progressReporter)
330 progressReporter->resetNumSteps(compElems.size(), 0.0, 1.0);
331
332 for (auto pElem : compElems) {
333 if (progressReporter)
334 progressReporter->report("Loading instrument Definition");
335
336 {
337 IdList idList; // structure to possibly be populated with detector IDs
338
340
341 // Loop through all children of this component and see if any
342 // are a <location> or <locations>. Done this way, the
343 // order they are processed is the order they are listed in the
344 // IDF. This is necessary to match the order of the detector IDs.
345 for (Node *pNode = pElem->firstChild(); pNode != nullptr; pNode = pNode->nextSibling()) {
346 auto pChildElem = dynamic_cast<Element *>(pNode);
347 if (!pChildElem)
348 continue;
349 if (pChildElem->tagName() == "location") {
350 // process differently depending on whether component is and
351 // assembly or leaf
352 if (isAssembly(pElem->getAttribute("type"))) {
353 appendAssembly(m_instrument.get(), pChildElem, pElem, idList);
354 } else {
355 appendLeaf(m_instrument.get(), pChildElem, pElem, idList);
356 }
357 } else if (pChildElem->tagName() == "locations") {
358 // append <locations> elements in <locations>
359 appendLocations(m_instrument.get(), pChildElem, pElem, idList);
360 }
361 } // finished looping over all children of this component
362
363 checkIdListExistsAndDefinesEnoughIDs(idList, pElem, filename);
364 idList.reset();
365 }
366 }
367}
368
377 const std::string &filename) const {
378 Poco::AutoPtr<NodeList> pNL_location = pElem->getElementsByTagName("location");
379 Poco::AutoPtr<NodeList> pNL_locations = pElem->getElementsByTagName("locations");
380
381 if (pNL_location->length() == 0 && pNL_locations->length() == 0) {
382 g_log.error(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 throw Kernel::Exception::InstrumentDefinitionError(std::string("A component element must contain at least one "
387 "<location> or <locations> element") +
388 " even if it is just an empty location element of the form "
389 "<location />",
390 filename);
391 }
392}
393
403 const std::string &filename) const {
404 if (idList.counted != static_cast<int>(idList.vec.size())) {
405 std::stringstream ss1, ss2;
406 ss1 << idList.vec.size();
407 ss2 << idList.counted;
408 if (!pElem->hasAttribute("idlist")) {
409 g_log.error("No detector ID list found for detectors of type " + pElem->getAttribute("type"));
410 } else if (idList.vec.empty()) {
411 g_log.error("No detector IDs found for detectors in list " + pElem->getAttribute("idlist") +
412 "for detectors of type" + pElem->getAttribute("type"));
413 } else {
414 g_log.error("The number of detector IDs listed in idlist named " + pElem->getAttribute("idlist") +
415 " is larger than the number of detectors listed in type = " + pElem->getAttribute("type"));
416 }
418 "Number of IDs listed in idlist (=" + ss1.str() + ") is larger than the number of detectors listed in type = " +
419 pElem->getAttribute("type") + " (=" + ss2.str() + ").",
420 filename);
421 }
422}
423
430 Poco::AutoPtr<NodeList> pNL_parameter = pRootElem->getElementsByTagName("parameter");
431 unsigned long numParameter = pNL_parameter->length();
432 m_hasParameterElement.reserve(numParameter);
433
434 // It turns out that looping over all nodes and checking if their nodeName is
435 // equal to "parameter" is much quicker than looping over the pNL_parameter
436 // NodeList.
437 NodeIterator it(pRootElem, NodeFilter::SHOW_ELEMENT);
438 Node *pNode = it.nextNode();
439 while (pNode) {
440 if (pNode->nodeName() == "parameter") {
441 auto pParameterElem = dynamic_cast<Element *>(pNode);
442 m_hasParameterElement.emplace_back(dynamic_cast<Element *>(pParameterElem->parentNode()));
443 }
444 pNode = it.nextNode();
445 }
446
448}
449
460 const std::string &filename,
461 const std::vector<Element *> &typeElems,
462 const size_t numberOfTypes) {
463 for (size_t iType = 0; iType < numberOfTypes; ++iType) {
464 Element *pTypeElem = typeElems[iType];
465 std::string typeName = pTypeElem->getAttribute("name");
466
467 // In this loop only interested in types containing
468 // <combine-components-into-one-shape>
469 Poco::AutoPtr<NodeList> pNL_type_combine_into_one_shape =
470 pTypeElem->getElementsByTagName("combine-components-into-one-shape");
471 if (pNL_type_combine_into_one_shape->length() == 0)
472 continue;
473
474 throwIfTypeNameNotUnique(filename, typeName);
475 getTypeElement[typeName] = pTypeElem;
476
478 helper.adjust(pTypeElem, isTypeAssembly, getTypeElement);
479
480 isTypeAssembly[typeName] = false;
481
482 mapTypeNameToShape[typeName] = shapeCreator.createShape(pTypeElem);
483 // Only CSGObjects can be combined into one shape.
484 if (auto csgObj = std::dynamic_pointer_cast<CSGObject>(mapTypeNameToShape[typeName])) {
485 csgObj->setName(static_cast<int>(iType));
486 }
487 }
488}
489
500 Element *pTypeElem, const std::string &typeName) {
501 Poco::AutoPtr<NodeList> pNL_local = pTypeElem->getElementsByTagName("component");
502 if (pNL_local->length() == 0) {
503 isTypeAssembly[typeName] = false;
504
505 // for now try to create a geometry shape associated with every type
506 // that does not contain any component elements
507 mapTypeNameToShape[typeName] = shapeCreator.createShape(pTypeElem);
508 // Name can be set only for a CSGObject.
509 if (auto csgObj = std::dynamic_pointer_cast<CSGObject>(mapTypeNameToShape[typeName])) {
510 csgObj->setName(static_cast<int>(iType));
511 }
512 } else {
513 isTypeAssembly[typeName] = true;
514 if (pTypeElem->hasAttribute("outline")) {
515 pTypeElem->setAttribute("object_created", "no");
516 }
517 }
518}
519
528 std::vector<Element *> &typeElems,
529 std::vector<Element *> &compElems) const {
530 for (auto pNode = pRootElem->firstChild(); pNode != nullptr; pNode = pNode->nextSibling()) {
531 auto pElem = dynamic_cast<Element *>(pNode);
532 if (pElem) {
533 if (pElem->tagName() == "type")
534 typeElems.emplace_back(pElem);
535 else if (pElem->tagName() == "component")
536 compElems.emplace_back(pElem);
537 }
538 }
539}
540
541//-----------------------------------------------------------------------------------------------------------------------
556void InstrumentDefinitionParser::appendLocations(Geometry::ICompAssembly *parent, const Poco::XML::Element *pLocElems,
557 const Poco::XML::Element *pCompElem, IdList &idList) {
558 // create detached <location> elements from <locations> element
559 Poco::AutoPtr<Document> pLocationsDoc = convertLocationsElement(pLocElems);
560
561 // Get pointer to root element
562 const Element *pRootLocationsElem = pLocationsDoc->documentElement();
563 const bool assembly = isAssembly(pCompElem->getAttribute("type"));
564
565 auto *pElem = dynamic_cast<Poco::XML::Element *>(pRootLocationsElem->firstChild());
566
567 while (pElem) {
568 if (pElem->tagName() != "location") {
569 pElem = dynamic_cast<Poco::XML::Element *>(pElem->nextSibling());
570 continue;
571 }
572
573 if (assembly) {
574 appendAssembly(parent, pElem, pCompElem, idList);
575 } else {
576 appendLeaf(parent, pElem, pCompElem, idList);
577 }
578
579 pElem = dynamic_cast<Poco::XML::Element *>(pElem->nextSibling());
580 }
581}
582
583//-----------------------------------------------------------------------------------------------------------------------
593void InstrumentDefinitionParser::saveDOM_Tree(const std::string &outFilename) {
594 Poco::XML::DOMWriter writer;
595 writer.setNewLine("\n");
596 writer.setOptions(Poco::XML::XMLWriter::PRETTY_PRINT);
597
598 auto pDoc = getDocument();
599 std::ofstream outFile(outFilename.c_str());
600 writer.writeNode(outFile, pDoc);
601 outFile.close();
602}
603
604double InstrumentDefinitionParser::attrToDouble(const Poco::XML::Element *pElem, const std::string &name) {
605 if (pElem->hasAttribute(name)) {
606 const std::string &value = pElem->getAttribute(name);
607 if (!value.empty()) {
608 try {
609 return std::stod(value);
610 } catch (...) {
611 std::stringstream msg;
612 msg << "failed to convert \"" << value << "\" to double for xml attribute \"" << name
613 << "\" - using 0. instead";
614 g_log.warning(msg.str());
615 return 0.;
616 }
617 }
618 }
619 return 0.;
620}
621
622//-----------------------------------------------------------------------------------------------------------------------
635void InstrumentDefinitionParser::setLocation(Geometry::IComponent *comp, const Poco::XML::Element *pElem,
636 const double angleConvertConst, const bool deltaOffsets) {
637 comp->setPos(getRelativeTranslation(comp, pElem, angleConvertConst, deltaOffsets));
638
639 // Rotate coordinate system of this component
640 if (pElem->hasAttribute("rot")) {
641 double rotAngle = angleConvertConst * attrToDouble(pElem, "rot"); // assumed to be in degrees
642
643 double axis_x = 0.0;
644 double axis_y = 0.0;
645 double axis_z = 1.0;
646
647 if (pElem->hasAttribute("axis-x"))
648 axis_x = std::stod(pElem->getAttribute("axis-x"));
649 if (pElem->hasAttribute("axis-y"))
650 axis_y = std::stod(pElem->getAttribute("axis-y"));
651 if (pElem->hasAttribute("axis-z"))
652 axis_z = std::stod(pElem->getAttribute("axis-z"));
653
654 comp->rotate(Kernel::Quat(rotAngle, Kernel::V3D(axis_x, axis_y, axis_z)));
655 }
656
657 // Check if sub-elements <trans> or <rot> of present - for now ignore these if
658 // m_deltaOffset = true
659
660 Element *pRecursive = nullptr;
661 Element *tElem = pElem->getChildElement("trans");
662 Element *rElem = pElem->getChildElement("rot");
663 bool stillTransElement = true;
664 bool firstRound = true; // during first round below pRecursive has not been set up front
665 while (stillTransElement) {
666 // figure out if child element is <trans> or <rot> or none of these
667
668 if (firstRound) {
669 firstRound = false;
670 } else if (pRecursive != nullptr) {
671 tElem = pRecursive->getChildElement("trans");
672 rElem = pRecursive->getChildElement("rot");
673 }
674
675 if (tElem && rElem) {
676 // if both a <trans> and <rot> child element present. Ignore <rot> element
677 rElem = nullptr;
678 }
679
680 if (!tElem && !rElem) {
681 stillTransElement = false;
682 }
683
684 Kernel::V3D posTrans;
685
686 if (tElem) {
687 posTrans = getRelativeTranslation(comp, tElem, angleConvertConst, deltaOffsets);
688
689 // to get the change in translation relative to current rotation of comp
690 Geometry::CompAssembly compToGetRot;
692 compRot.setRot(comp->getRotation());
693 compToGetRot.setParent(&compRot);
694 compToGetRot.setPos(posTrans);
695
696 // Apply translation
697 comp->translate(compToGetRot.getPos());
698
699 // for recursive action
700 pRecursive = tElem;
701 } // end translation
702
703 if (rElem) {
704 double rotAngle = angleConvertConst * attrToDouble(rElem, "val"); // assumed to be in degrees
705
706 double axis_x = 0.0;
707 double axis_y = 0.0;
708 double axis_z = 1.0;
709
710 if (rElem->hasAttribute("axis-x"))
711 axis_x = std::stod(rElem->getAttribute("axis-x"));
712 if (rElem->hasAttribute("axis-y"))
713 axis_y = std::stod(rElem->getAttribute("axis-y"));
714 if (rElem->hasAttribute("axis-z"))
715 axis_z = std::stod(rElem->getAttribute("axis-z"));
716
717 comp->rotate(Kernel::Quat(rotAngle, Kernel::V3D(axis_x, axis_y, axis_z)));
718
719 // for recursive action
720 pRecursive = rElem;
721 }
722
723 } // end while
724}
725
727 const Poco::XML::Element *pCompElem) {
728 // return if no elements contain side-by-side-view-location parameter
730 return;
731
732 auto pViewLocElem = pCompElem->getChildElement("side-by-side-view-location");
733 if (pViewLocElem) {
734 double x = attrToDouble(pViewLocElem, "x");
735 double y = attrToDouble(pViewLocElem, "y");
736 comp->setSideBySideViewPos(V2D(x, y));
737 }
738}
739
740//-----------------------------------------------------------------------------------------------------------------------
755 const Poco::XML::Element *pElem,
756 const double angleConvertConst,
757 const bool deltaOffsets) {
758 Kernel::V3D retVal; // position relative to parent
759
760 // Polar coordinates can be labelled as (r,t,p) or (R,theta,phi)
761 if (pElem->hasAttribute("r") || pElem->hasAttribute("t") || pElem->hasAttribute("p") || pElem->hasAttribute("R") ||
762 pElem->hasAttribute("theta") || pElem->hasAttribute("phi")) {
763
764 double R = attrToDouble(pElem, "r");
765 double theta = angleConvertConst * attrToDouble(pElem, "t");
766 double phi = angleConvertConst * attrToDouble(pElem, "p");
767
768 if (pElem->hasAttribute("R"))
769 R = attrToDouble(pElem, "R");
770 if (pElem->hasAttribute("theta"))
771 theta = angleConvertConst * attrToDouble(pElem, "theta");
772 if (pElem->hasAttribute("phi"))
773 phi = angleConvertConst * attrToDouble(pElem, "phi");
774
775 if (deltaOffsets) {
776 // In this case, locations given are radial offsets to the (radial)
777 // position of the parent,
778 // so need to do some extra calculation before they're stored internally
779 // as x,y,z offsets.
780
781 // Temporary vector to hold the parent's absolute position (will be 0,0,0
782 // if no parent)
783 Kernel::V3D parentPos;
784 // Get the parent's absolute position (if the component has a parent)
785 if (comp->getParent()) {
786 std::map<const Geometry::IComponent *, SphVec>::iterator it;
787 it = m_tempPosHolder.find(comp);
788 SphVec parent;
789 if (it == m_tempPosHolder.end())
790 parent = m_tempPosHolder[comp->getParent().get()];
791 else
792 parent = it->second;
793
794 // Add to the current component to get its absolute position
795 R += parent.r;
796 theta += parent.theta;
797 phi += parent.phi;
798 // Set the temporary V3D with the parent's absolute position
799 parentPos.spherical(parent.r, parent.theta, parent.phi);
800 }
801
802 // Create a temporary vector that holds the absolute r,theta,phi position
803 // Needed to make things work in situation when a parent object has a phi
804 // value but a theta of zero
805 SphVec tmp(R, theta, phi);
806 // Add it to the map with the pointer to the Component object as key
807 m_tempPosHolder[comp] = tmp;
808
809 // Create a V3D and set its position to be the child's absolute position
810 Kernel::V3D absPos;
811 absPos.spherical(R, theta, phi);
812
813 // Subtract the two V3D's to get what we want (child's relative position
814 // in x,y,z)
815 retVal = absPos - parentPos;
816 } else {
817 // In this case, the value given represents a vector from the parent to
818 // the child
819 retVal.spherical(R, theta, phi);
820 }
821
822 } else {
823 double x = attrToDouble(pElem, "x");
824 double y = attrToDouble(pElem, "y");
825 double z = attrToDouble(pElem, "z");
826
827 retVal(x, y, z);
828 }
829
830 return retVal;
831}
832
833//-----------------------------------------------------------------------------------------------------------------------
842Poco::XML::Element *InstrumentDefinitionParser::getParentComponent(const Poco::XML::Element *pLocElem) {
843 if (((pLocElem->tagName()) != "location") && ((pLocElem->tagName()) != "locations")) {
844 const std::string &tagname = pLocElem->tagName();
845 g_log.error("Argument to function getParentComponent must be a pointer to "
846 "an XML element with tag name location or locations.");
847 throw std::logic_error(std::string("Argument to function getParentComponent must be a pointer "
848 "to an XML element") +
849 "with tag name location or locations." + " The tag name is " + tagname);
850 }
851
852 // The location element is required to be a child of a component element. Get
853 // this component element
854
855 Node *pCompNode = pLocElem->parentNode();
856
857 Element *pCompElem;
858 if (pCompNode->nodeType() == 1) {
859 pCompElem = static_cast<Element *>(pCompNode);
860 if ((pCompElem->tagName()) != "component") {
861 g_log.error("Argument to function getParentComponent must be a XML "
862 "element sitting inside a component element.");
863 throw std::logic_error("Argument to function getParentComponent must be "
864 "a XML element sitting inside a component "
865 "element.");
866 }
867 } else {
868 g_log.error("Argument to function getParentComponent must be a XML element "
869 "whos parent is an element.");
870 throw std::logic_error("Argument to function getParentComponent must be a "
871 "XML element whos parent is an element.");
872 }
873
874 return pCompElem;
875}
876
877//-----------------------------------------------------------------------------------------------------------------------
889std::string InstrumentDefinitionParser::getNameOfLocationElement(const Poco::XML::Element *pElem,
890 const Poco::XML::Element *pCompElem) {
891 std::string retVal;
892
893 if (pElem->hasAttribute("name"))
894 retVal = pElem->getAttribute("name");
895 else if (pCompElem->hasAttribute("name")) {
896 retVal = pCompElem->getAttribute("name");
897 } else {
898 retVal = pCompElem->getAttribute("type");
899 }
900
901 return retVal;
902}
903
904//------------------------------------------------------------------------------------------------------------------------------
908void InstrumentDefinitionParser::setValidityRange(const Poco::XML::Element *pRootElem) {
909 const std::string filename = m_xmlFile->getFileFullPathStr();
910 // check if IDF has valid-from and valid-to tags defined
911 if (!pRootElem->hasAttribute("valid-from")) {
912 throw Kernel::Exception::InstrumentDefinitionError("<instrument> element must contain a valid-from tag", filename);
913 } else {
914 try {
915 DateAndTime d(pRootElem->getAttribute("valid-from"));
916 m_instrument->setValidFromDate(d);
917 } catch (...) {
918 throw Kernel::Exception::InstrumentDefinitionError("The valid-from <instrument> tag must be a ISO8601 string",
919 filename);
920 }
921 }
922
923 if (!pRootElem->hasAttribute("valid-to")) {
924 DateAndTime d = DateAndTime::getCurrentTime();
925 m_instrument->setValidToDate(d);
926 // Ticket #2335: no required valid-to date.
927 // throw Kernel::Exception::InstrumentDefinitionError("<instrument> element
928 // must contain a valid-to tag", filename);
929 } else {
930 try {
931 DateAndTime d(pRootElem->getAttribute("valid-to"));
932 m_instrument->setValidToDate(d);
933 } catch (...) {
934 throw Kernel::Exception::InstrumentDefinitionError("The valid-to <instrument> tag must be a ISO8601 string",
935 filename);
936 }
937 }
938}
939
940PointingAlong axisNameToAxisType(const std::string &label, const std::string &input) {
941 PointingAlong direction;
942 if (input == "x") {
943 direction = X;
944 } else if (input == "y") {
945 direction = Y;
946 } else if (input == "z") {
947 direction = Z;
948 } else {
949 std::stringstream msg;
950 msg << "Cannot create \"" << label << "\" with axis direction other than \"x\", \"y\", or \"z\", found \"" << input
951 << "\"";
953 }
954 return direction;
955}
956
957//-----------------------------------------------------------------------------------------------------------------------
963void InstrumentDefinitionParser::readDefaults(Poco::XML::Element *defaults) {
964 // Return without complaint, if there are no defaults
965 if (!defaults)
966 return;
967
968 // Check whether spherical coordinates should be treated as offsets to parents
969 // position
970 std::string offsets;
971 Element *offsetElement = defaults->getChildElement("offsets");
972 if (offsetElement)
973 offsets = offsetElement->getAttribute("spherical");
974 if (offsets == "delta")
975 m_deltaOffsets = true;
976
977 // Check whether default facing is set
978 Element *defaultFacingElement = defaults->getChildElement("components-are-facing");
979 if (defaultFacingElement) {
980 m_haveDefaultFacing = true;
981 m_defaultFacing = parseFacingElementToV3D(defaultFacingElement);
982 }
983
984 // the default view is used by the instrument viewer to decide the angle to
985 // display the instrument from on start up
986 Element *defaultView = defaults->getChildElement("default-view");
987 if (defaultView) {
988 m_instrument->setDefaultViewAxis(defaultView->getAttribute("axis-view"));
989 if (defaultView->hasAttribute("view")) {
990 m_instrument->setDefaultView(defaultView->getAttribute("view"));
991 }
992 }
993
994 // check if angle=radian has been set
995 Element *angleUnit = defaults->getChildElement("angle");
996 if (angleUnit) {
997 if (angleUnit->getAttribute("unit") == "radian") {
998 m_angleConvertConst = 180.0 / M_PI;
999 std::map<std::string, std::string> &units = m_instrument->getLogfileUnit();
1000 units["angle"] = "radian";
1001 }
1002 }
1003
1004 // Check if the IDF specifies that this is an indirect geometry instrument
1005 // that includes
1006 // both physical and 'neutronic' postions.
1007 // Any neutronic position tags will be ignored if this tag is missing
1008 if (defaults->getChildElement("indirect-neutronic-positions"))
1009 m_indirectPositions = true;
1010
1011 /*
1012 Try to extract the reference frame information.
1013 */
1014 // Get the target xml element.
1015 Element *referenceFrameElement = defaults->getChildElement("reference-frame");
1016 // Extract if available
1017 if (referenceFrameElement) {
1018 using Poco::XML::XMLString;
1019 // Get raw xml values
1020 Element *upElement = referenceFrameElement->getChildElement("pointing-up");
1021 Element *alongElement = referenceFrameElement->getChildElement("along-beam");
1022 Element *handednessElement = referenceFrameElement->getChildElement("handedness");
1023 Element *originElement = referenceFrameElement->getChildElement("origin");
1024 Element *thetaSignElement = referenceFrameElement->getChildElement("theta-sign");
1025
1026 // Defaults
1027 XMLString s_alongBeam("z");
1028 XMLString s_pointingUp("y");
1029 XMLString s_handedness("right");
1030 XMLString s_origin;
1031
1032 // Make extractions from sub elements where possible.
1033 if (alongElement) {
1034 s_alongBeam = alongElement->getAttribute("axis");
1035 }
1036 if (upElement) {
1037 s_pointingUp = upElement->getAttribute("axis");
1038 }
1039 if (handednessElement) {
1040 s_handedness = handednessElement->getAttribute("val");
1041 }
1042 if (originElement) {
1043 s_origin = originElement->getAttribute("val");
1044 }
1045
1046 // Extract theta sign axis if specified.
1047 XMLString s_thetaSign(s_pointingUp);
1048 if (thetaSignElement) {
1049 s_thetaSign = thetaSignElement->getAttribute("axis");
1050 }
1051
1052 // Convert to input types
1053 PointingAlong alongBeam = axisNameToAxisType("along-beam", s_alongBeam);
1054 PointingAlong pointingUp = axisNameToAxisType("pointing-up", s_pointingUp);
1055 PointingAlong thetaSign = axisNameToAxisType("theta-sign", s_thetaSign);
1056 Handedness handedness = s_handedness == "right" ? Right : Left;
1057
1058 // Overwrite the default reference frame.
1059 m_instrument->setReferenceFrame(
1060 std::make_shared<ReferenceFrame>(pointingUp, alongBeam, thetaSign, handedness, s_origin));
1061 }
1062}
1063
1064std::vector<std::string> InstrumentDefinitionParser::buildExcludeList(const Poco::XML::Element *const location) {
1065 // check if <exclude> sub-elements for this location and create new exclude
1066 // list to pass on
1067 Poco::AutoPtr<NodeList> pNLexclude = location->getElementsByTagName("exclude");
1068 unsigned long numberExcludeEle = pNLexclude->length();
1069 std::vector<std::string> newExcludeList;
1070 for (unsigned long i = 0; i < numberExcludeEle; i++) {
1071 auto *pExElem = static_cast<Element *>(pNLexclude->item(i));
1072 if (pExElem->hasAttribute("sub-part"))
1073 newExcludeList.emplace_back(pExElem->getAttribute("sub-part"));
1074 }
1075
1076 return newExcludeList;
1077}
1078
1079//-----------------------------------------------------------------------------------------------------------------------
1094void InstrumentDefinitionParser::appendAssembly(Geometry::ICompAssembly *parent, const Poco::XML::Element *pLocElem,
1095 const Poco::XML::Element *pCompElem, IdList &idList) {
1096 const std::string filename = m_xmlFile->getFileFullPathStr();
1097 // The location element is required to be a child of a component element. Get
1098 // this component element
1099 // Element* pCompElem =
1100 // InstrumentDefinitionParser::getParentComponent(pLocElem);
1101
1102 // Read detector IDs into idlist if required
1103 // Note idlist may be defined for any component
1104 // Note any new idlist found will take precedence.
1105
1106 if (pCompElem->hasAttribute("idlist")) {
1107 std::string idlist = pCompElem->getAttribute("idlist");
1108
1109 if (idlist != idList.idname) {
1110 Element *pFound = pCompElem->ownerDocument()->getElementById(idlist, "idname");
1111
1112 if (pFound == nullptr) {
1114 "No <idlist> with name idname=\"" + idlist + "\" present in instrument definition file.", filename);
1115 }
1116 idList.reset();
1117 populateIdList(pFound, idList);
1118 }
1119 }
1120
1121 // Create the assembly that will be appended into the parent.
1123 // The newly added component is required to have a type. Find out what this
1124 // type is and find all the location elements of this type. Finally loop over
1125 // these
1126 // location elements
1127
1128 Element *pType = getTypeElement[pCompElem->getAttribute("type")];
1129 std::string category;
1130 if (pType->hasAttribute("is"))
1131 category = pType->getAttribute("is");
1132 if (category == "SamplePos" || category == "samplePos") {
1134 } else if (pType->hasAttribute("outline") && pType->getAttribute("outline") != "no") {
1136 parent);
1137 } else {
1139 }
1140
1141 // set location for this newly added comp and set facing if specified in
1142 // instrument def. file. Also
1143 // check if any logfiles are referred to through the <parameter> element.
1144
1146 setSideBySideViewLocation(ass, pCompElem);
1147 setFacing(ass, pLocElem);
1148 setLogfile(ass, pCompElem,
1149 m_instrument->getLogfileCache()); // params specified within <component>
1150 setLogfile(ass, pLocElem,
1151 m_instrument->getLogfileCache()); // params specified within specific <location>
1152
1153 // check if special Component
1154 if (category == "SamplePos" || category == "samplePos") {
1155 m_instrument->markAsSamplePos(ass);
1156 }
1157 if (category == "Source" || category == "source") {
1158 m_instrument->markAsSource(ass);
1159 }
1160
1161 // If enabled, check for a 'neutronic position' tag and add to cache if found
1162 if (m_indirectPositions) {
1163 Element *neutronic = pLocElem->getChildElement("neutronic");
1164 if (neutronic)
1165 m_neutronicPos[ass] = neutronic;
1166 }
1167
1168 // Check for <exclude> tags for this location
1169 const std::vector<std::string> excludeList = buildExcludeList(pLocElem);
1170
1171 NodeIterator it(pType, NodeFilter::SHOW_ELEMENT);
1172
1173 Node *pNode = it.nextNode();
1174 while (pNode) {
1175 if (pNode->nodeName() == "location") {
1176 // pLocElem is the location of a type. This type is here an assembly and
1177 // pElem below is a <location> within this type
1178 const Element *pElem = static_cast<Element *>(pNode);
1179
1180 // get the parent of pElem, i.e. a pointer to the <component> element that
1181 // contains pElem
1182 const Element *pParentElem = InstrumentDefinitionParser::getParentComponent(pElem);
1183
1184 // check if this location is in the exclude list
1185 auto inExcluded = find(excludeList.cbegin(), excludeList.cend(),
1187 if (inExcluded == excludeList.end()) {
1188
1189 std::string typeName = (InstrumentDefinitionParser::getParentComponent(pElem))->getAttribute("type");
1190
1191 if (isAssembly(typeName)) {
1192 appendAssembly(ass, pElem, pParentElem, idList);
1193 } else {
1194 appendLeaf(ass, pElem, pParentElem, idList);
1195 }
1196 }
1197 }
1198 if (pNode->nodeName() == "locations") {
1199 const Element *pLocationsElems = static_cast<Element *>(pNode);
1200 const Element *pParentLocationsElem = InstrumentDefinitionParser::getParentComponent(pLocationsElems);
1201
1202 // append <locations> elements in <locations>
1203 appendLocations(ass, pLocationsElems, pParentLocationsElem, idList);
1204 }
1205 pNode = it.nextNode();
1206 }
1207
1208 // create outline object for the assembly
1209 if (pType->hasAttribute("outline") && pType->getAttribute("outline") != "no") {
1210 auto *objAss = dynamic_cast<Geometry::ObjCompAssembly *>(ass);
1211 if (!objAss) {
1212 throw std::logic_error("Failed to cast ICompAssembly object to ObjCompAssembly");
1213 }
1214 if (pType->getAttribute("object_created") == "no") {
1215 pType->setAttribute("object_created", "yes");
1216 std::shared_ptr<Geometry::IObject> obj = objAss->createOutline();
1217 if (obj) {
1218 mapTypeNameToShape[pType->getAttribute("name")] = obj;
1219 } else { // object failed to be created
1220 pType->setAttribute("outline", "no");
1221 g_log.warning() << "Failed to create outline object for assembly " << pType->getAttribute("name") << '\n';
1222 }
1223 } else {
1224 objAss->setOutline(mapTypeNameToShape[pType->getAttribute("name")]);
1225 }
1226 }
1227}
1228
1230 const Poco::XML::Element *pLocElem,
1231 const Poco::XML::Element *pCompElem,
1232 const std::string &filename, IdList &idList,
1233 const std::string &category) {
1234
1235 //-------------- Create a Detector
1236 //------------------------------------------------
1237 std::string name = InstrumentDefinitionParser::getNameOfLocationElement(pLocElem, pCompElem);
1238
1239 // before setting detector ID check that the IDF satisfies the following
1240
1241 if (idList.counted >= static_cast<int>(idList.vec.size())) {
1242 std::stringstream ss1, ss2;
1243 ss1 << idList.vec.size();
1244 ss2 << idList.counted;
1245 if (idList.idname.empty()) {
1246 g_log.error("No list of detector IDs found for location element " + name);
1247 throw Kernel::Exception::InstrumentDefinitionError("Detector location element " + name + " has no idlist.",
1248 filename);
1249 } else if (idList.vec.empty()) {
1250 g_log.error("No detector IDs found for detectors in list " + idList.idname);
1251 } else {
1252 g_log.error("The number of detector IDs listed in idlist named " + idList.idname +
1253 " is less then the number of detectors");
1254 }
1256 "Number of IDs listed in idlist (=" + ss1.str() + ") is less than the number of detectors.", filename);
1257 }
1258
1259 std::string typeName = pCompElem->getAttribute("type");
1260
1261 // Create detector and increment id. Finally add the detector to the parent
1262 Geometry::Detector *detector =
1263 new Geometry::Detector(name, idList.vec[idList.counted], mapTypeNameToShape[typeName], parent);
1264 idList.counted++;
1265 parent->add(detector);
1266
1267 // set location for this newly added comp and set facing if specified in
1268 // instrument def. file. Also
1269 // check if any logfiles are referred to through the <parameter> element.
1270 setLocation(detector, pLocElem, m_angleConvertConst, m_deltaOffsets);
1271 setFacing(detector, pLocElem);
1272 setLogfile(detector, pCompElem,
1273 m_instrument->getLogfileCache()); // params specified within <component>
1274 setLogfile(detector, pLocElem,
1275 m_instrument->getLogfileCache()); // params specified within specific <location>
1276
1277 // If enabled, check for a 'neutronic position' tag and add to cache
1278 // (null pointer added INTENTIONALLY if not found)
1279 if (m_indirectPositions) {
1280 m_neutronicPos[detector] = pLocElem->getChildElement("neutronic");
1281 }
1282
1283 // mark-as is a deprecated attribute used before is="monitor" was introduced
1284 if (pCompElem->hasAttribute("mark-as") || pLocElem->hasAttribute("mark-as")) {
1285 g_log.warning() << "Attribute 'mark-as' is a deprecated attribute in "
1286 "Instrument Definition File."
1287 << " Please see the deprecated section of "
1288 "docs.mantidproject.org/concepts/InstrumentDefinitionFile for how to remove this "
1289 "warning message\n";
1290 }
1291
1292 try {
1293 if (category == "Monitor" || category == "monitor")
1294 m_instrument->markAsMonitor(detector);
1295 else {
1296 // for backwards compatibility look for mark-as="monitor"
1297 if ((pCompElem->hasAttribute("mark-as") && pCompElem->getAttribute("mark-as") == "monitor") ||
1298 (pLocElem->hasAttribute("mark-as") && pLocElem->getAttribute("mark-as") == "monitor")) {
1299 m_instrument->markAsMonitor(detector);
1300 } else
1301 m_instrument->markAsDetectorIncomplete(detector);
1302 }
1303
1304 } catch (Kernel::Exception::ExistsError &) {
1305 std::stringstream convert;
1306 convert << detector->getID();
1308 "Detector with ID = " + convert.str() + " present more then once in XML instrument file", filename);
1309 }
1310
1311 // Add all monitors and detectors to 'facing component' container. This is
1312 // only used if the
1313 // "facing" elements are defined in the instrument definition file
1314 m_facingComponent.emplace_back(detector);
1315
1316 setSideBySideViewLocation(detector, pCompElem);
1317}
1318
1319void InstrumentDefinitionParser::createGridDetector(Geometry::ICompAssembly *parent, const Poco::XML::Element *pLocElem,
1320 const Poco::XML::Element *pCompElem, const std::string &filename,
1321 const Poco::XML::Element *pType) {
1322
1323 //-------------- Create a GridDetector
1324 //------------------------------------------------
1325 std::string name = InstrumentDefinitionParser::getNameOfLocationElement(pLocElem, pCompElem);
1326
1327 // Create the bank with the given parent.
1328 auto bank = new Geometry::GridDetector(name, parent);
1329
1330 // set location for this newly added comp and set facing if specified in
1331 // instrument def. file. Also
1332 // check if any logfiles are referred to through the <parameter> element.
1334 setFacing(bank, pLocElem);
1335 setLogfile(bank, pCompElem,
1336 m_instrument->getLogfileCache()); // params specified within <component>
1337 setLogfile(bank, pLocElem,
1338 m_instrument->getLogfileCache()); // params specified within specific <location>
1339
1340 // Extract all the parameters from the XML attributes
1341 int xpixels = 0;
1342 int ypixels = 0;
1343 int zpixels = 0;
1344 int idstart = 0;
1345 std::string idfillorder;
1346 int idstepbyrow = 0;
1347 int idstep = 1;
1348
1349 // The shape!
1350 // Given that this leaf component is actually an assembly, its constituent
1351 // component detector shapes comes from its type attribute.
1352 const std::string shapeType = pType->getAttribute("type");
1353 std::shared_ptr<Geometry::IObject> shape = mapTypeNameToShape[shapeType];
1354 // These parameters are in the TYPE defining RectangularDetector
1355 if (pType->hasAttribute("xpixels"))
1356 xpixels = std::stoi(pType->getAttribute("xpixels"));
1357 double xstart = attrToDouble(pType, "xstart");
1358 double xstep = attrToDouble(pType, "xstep");
1359
1360 if (pType->hasAttribute("ypixels"))
1361 ypixels = std::stoi(pType->getAttribute("ypixels"));
1362 double ystart = attrToDouble(pType, "ystart");
1363 double ystep = attrToDouble(pType, "ystep");
1364
1365 if (pType->hasAttribute("zpixels"))
1366 zpixels = std::stoi(pType->getAttribute("zpixels"));
1367 double zstart = attrToDouble(pType, "zstart");
1368 double zstep = attrToDouble(pType, "zstep");
1369
1370 // THESE parameters are in the INSTANCE of this type - since they will
1371 // change.
1372 if (pCompElem->hasAttribute("idstart"))
1373 idstart = std::stoi(pCompElem->getAttribute("idstart"));
1374 if (pCompElem->hasAttribute("idfillorder"))
1375 idfillorder = pCompElem->getAttribute("idfillorder");
1376 // Default ID row step size
1377 if (!idfillorder.empty() && idfillorder[0] == 'x')
1378 idstepbyrow = xpixels;
1379 else if (!idfillorder.empty() && idfillorder[0] == 'y')
1380 idstepbyrow = ypixels;
1381 else
1382 idstepbyrow = zpixels;
1383
1384 if (pCompElem->hasAttribute("idstepbyrow")) {
1385 idstepbyrow = std::stoi(pCompElem->getAttribute("idstepbyrow"));
1386 }
1387 // Default ID row step size
1388 if (pCompElem->hasAttribute("idstep"))
1389 idstep = std::stoi(pCompElem->getAttribute("idstep"));
1390
1391 setSideBySideViewLocation(bank, pCompElem);
1392
1393 // Now, initialize all the pixels in the bank
1394 bank->initialize(shape, xpixels, xstart, xstep, ypixels, ystart, ystep, zpixels, zstart, zstep, idstart, idfillorder,
1395 idstepbyrow, idstep);
1396
1397 // Loop through all detectors in the newly created bank and mark those in
1398 // the instrument.
1399 try {
1400 for (int z = 0; z < bank->nelements(); ++z) {
1401 auto zLayer = std::dynamic_pointer_cast<Geometry::ICompAssembly>((*bank)[z]);
1402 for (int x = 0; x < zLayer->nelements(); ++x) {
1403 auto xColumn = std::dynamic_pointer_cast<Geometry::ICompAssembly>((*zLayer)[x]);
1404 for (int y = 0; y < xColumn->nelements(); ++y) {
1405 std::shared_ptr<Geometry::Detector> detector = std::dynamic_pointer_cast<Geometry::Detector>((*xColumn)[y]);
1406 if (detector) {
1407 // Make default facing for the pixel
1408 auto *comp = static_cast<IComponent *>(detector.get());
1411 // Mark it as a detector (add to the instrument cache)
1412 m_instrument->markAsDetectorIncomplete(detector.get());
1413 }
1414 }
1415 }
1416 }
1417 } catch (Kernel::Exception::ExistsError &) {
1418 throw Kernel::Exception::InstrumentDefinitionError("Duplicate detector ID found when adding GridDetector " + name +
1419 " in XML instrument file" + filename);
1420 }
1421}
1422
1424 const Poco::XML::Element *pLocElem,
1425 const Poco::XML::Element *pCompElem,
1426 const std::string &filename,
1427 const Poco::XML::Element *pType) {
1428 //-------------- Create a RectangularDetector
1429 //------------------------------------------------
1430 std::string name = InstrumentDefinitionParser::getNameOfLocationElement(pLocElem, pCompElem);
1431
1432 // Create the bank with the given parent.
1433 auto bank = new Geometry::RectangularDetector(name, parent);
1434
1435 // set location for this newly added comp and set facing if specified in
1436 // instrument def. file. Also
1437 // check if any logfiles are referred to through the <parameter> element.
1439 setFacing(bank, pLocElem);
1440 setLogfile(bank, pCompElem,
1441 m_instrument->getLogfileCache()); // params specified within <component>
1442 setLogfile(bank, pLocElem,
1443 m_instrument->getLogfileCache()); // params specified within specific <location>
1444
1445 // Extract all the parameters from the XML attributes
1446 int xpixels = 0;
1447 int ypixels = 0;
1448 int idstart = 0;
1449 bool idfillbyfirst_y = true;
1450 int idstepbyrow = 0;
1451 int idstep = 1;
1452
1453 // The shape!
1454 // Given that this leaf component is actually an assembly, its constituent
1455 // component detector shapes comes from its type attribute.
1456 const std::string shapeType = pType->getAttribute("type");
1457 std::shared_ptr<Geometry::IObject> shape = mapTypeNameToShape[shapeType];
1458
1459 // These parameters are in the TYPE defining RectangularDetector
1460 if (pType->hasAttribute("xpixels"))
1461 xpixels = std::stoi(pType->getAttribute("xpixels"));
1462 double xstart = attrToDouble(pType, "xstart");
1463 double xstep = attrToDouble(pType, "xstep");
1464
1465 if (pType->hasAttribute("ypixels"))
1466 ypixels = std::stoi(pType->getAttribute("ypixels"));
1467 double ystart = attrToDouble(pType, "ystart");
1468 double ystep = attrToDouble(pType, "ystep");
1469
1470 // THESE parameters are in the INSTANCE of this type - since they will
1471 // change.
1472 if (pCompElem->hasAttribute("idstart"))
1473 idstart = std::stoi(pCompElem->getAttribute("idstart"));
1474 if (pCompElem->hasAttribute("idfillbyfirst"))
1475 idfillbyfirst_y = (pCompElem->getAttribute("idfillbyfirst") == "y");
1476 // Default ID row step size
1477 if (idfillbyfirst_y)
1478 idstepbyrow = ypixels;
1479 else
1480 idstepbyrow = xpixels;
1481 if (pCompElem->hasAttribute("idstepbyrow")) {
1482 idstepbyrow = std::stoi(pCompElem->getAttribute("idstepbyrow"));
1483 }
1484 // Default ID row step size
1485 if (pCompElem->hasAttribute("idstep"))
1486 idstep = std::stoi(pCompElem->getAttribute("idstep"));
1487
1488 setSideBySideViewLocation(bank, pCompElem);
1489
1490 // Now, initialize all the pixels in the bank
1491 bank->initialize(shape, xpixels, xstart, xstep, ypixels, ystart, ystep, idstart, idfillbyfirst_y, idstepbyrow,
1492 idstep);
1493
1494 // Loop through all detectors in the newly created bank and mark those in
1495 // the instrument.
1496 try {
1497 for (int x = 0; x < bank->nelements(); x++) {
1498 std::shared_ptr<Geometry::ICompAssembly> xColumn = std::dynamic_pointer_cast<Geometry::ICompAssembly>((*bank)[x]);
1499 for (int y = 0; y < xColumn->nelements(); y++) {
1500 std::shared_ptr<Geometry::Detector> detector = std::dynamic_pointer_cast<Geometry::Detector>((*xColumn)[y]);
1501 if (detector) {
1502 // Make default facing for the pixel
1503 auto *comp = static_cast<IComponent *>(detector.get());
1506 // Mark it as a detector (add to the instrument cache)
1507 m_instrument->markAsDetectorIncomplete(detector.get());
1508 }
1509 }
1510 }
1511 } catch (Kernel::Exception::ExistsError &) {
1512 throw Kernel::Exception::InstrumentDefinitionError("Duplicate detector ID found when adding RectangularDetector " +
1513 name + " in XML instrument file" + filename);
1514 }
1515}
1516
1518 const Poco::XML::Element *pLocElem,
1519 const Poco::XML::Element *pCompElem,
1520 const std::string &filename,
1521 const Poco::XML::Element *pType) {
1522 //-------------- Create a StructuredDetector
1523 //------------------------------------------------
1524 std::string name = InstrumentDefinitionParser::getNameOfLocationElement(pLocElem, pCompElem);
1525
1526 // Create the bank with the given parent.
1527 auto bank = new Geometry::StructuredDetector(name, parent);
1528
1529 // set location for this newly added comp and set facing if specified in
1530 // instrument def. file. Also
1531 // check if any logfiles are referred to through the <parameter> element.
1533 setLogfile(bank, pCompElem,
1534 m_instrument->getLogfileCache()); // params specified within <component>
1535 setLogfile(bank, pLocElem,
1536 m_instrument->getLogfileCache()); // params specified within specific <location>
1537
1538 // Extract all the parameters from the XML attributes
1539 int xpixels = 0;
1540 int ypixels = 0;
1541 int idstart = 0;
1542 bool idfillbyfirst_y = true;
1543 int idstepbyrow = 0;
1544 int idstep = 1;
1545 std::vector<double> xValues;
1546 std::vector<double> yValues;
1547
1548 std::string typeName = pType->getAttribute("name");
1549 // These parameters are in the TYPE defining StructuredDetector
1550 if (pType->hasAttribute("xpixels"))
1551 xpixels = std::stoi(pType->getAttribute("xpixels"));
1552 if (pType->hasAttribute("ypixels"))
1553 ypixels = std::stoi(pType->getAttribute("ypixels"));
1554
1555 // THESE parameters are in the INSTANCE of this type - since they will
1556 // change.
1557 if (pCompElem->hasAttribute("idstart"))
1558 idstart = std::stoi(pCompElem->getAttribute("idstart"));
1559 if (pCompElem->hasAttribute("idfillbyfirst"))
1560 idfillbyfirst_y = (pCompElem->getAttribute("idfillbyfirst") == "y");
1561 // Default ID row step size
1562 if (idfillbyfirst_y)
1563 idstepbyrow = ypixels;
1564 else
1565 idstepbyrow = xpixels;
1566 if (pCompElem->hasAttribute("idstepbyrow")) {
1567 idstepbyrow = std::stoi(pCompElem->getAttribute("idstepbyrow"));
1568 }
1569 // Default ID row step size
1570 if (pCompElem->hasAttribute("idstep"))
1571 idstep = std::stoi(pCompElem->getAttribute("idstep"));
1572
1573 // Access type element which defines structured detecor vertices
1574 Element *pElem = nullptr;
1575 NodeIterator tags(pCompElem->ownerDocument(), NodeFilter::SHOW_ELEMENT);
1576 Node *pNode = tags.nextNode();
1577
1578 while (pNode) {
1579 auto *check = static_cast<Element *>(pNode);
1580 if (pNode->nodeName() == "type" && check->hasAttribute("is")) {
1581 std::string is = check->getAttribute("is");
1582 if (StructuredDetector::compareName(is) && typeName == check->getAttribute("name")) {
1583 pElem = check;
1584 break;
1585 }
1586 }
1587
1588 pNode = tags.nextNode();
1589 }
1590
1591 if (pElem == nullptr)
1592 throw Kernel::Exception::InstrumentDefinitionError("No <type> with attribute is=\"StructuredDetector\"", filename);
1593
1594 // Ensure vertices are present within the IDF
1595 Poco::AutoPtr<NodeList> pNL = pElem->getElementsByTagName("vertex");
1596 if (pNL->length() == 0)
1597 throw Kernel::Exception::InstrumentDefinitionError("StructuredDetector must contain vertices.", filename);
1598
1599 NodeIterator it(pElem, NodeFilter::SHOW_ELEMENT);
1600
1601 pNode = it.nextNode();
1602
1603 while (pNode) {
1604 if (pNode->nodeName() == "vertex") {
1605 auto *pVertElem = static_cast<Element *>(pNode);
1606
1607 if (pVertElem->hasAttribute("x"))
1608 xValues.emplace_back(attrToDouble(pVertElem, "x"));
1609 if (pVertElem->hasAttribute("y"))
1610 yValues.emplace_back(attrToDouble(pVertElem, "y"));
1611 }
1612
1613 pNode = it.nextNode();
1614 }
1615
1616 V3D zVector(0, 0, 1); // Z aligned beam
1617 bool isZBeam = m_instrument->getReferenceFrame()->isVectorPointingAlongBeam(zVector);
1618 // Now, initialize all the pixels in the bank
1619 bank->initialize(xpixels, ypixels, std::move(xValues), std::move(yValues), isZBeam, idstart, idfillbyfirst_y,
1620 idstepbyrow, idstep);
1621
1622 // Loop through all detectors in the newly created bank and mark those in
1623 // the instrument.
1624 try {
1625 for (int x = 0; x < bank->nelements(); x++) {
1626 std::shared_ptr<Geometry::ICompAssembly> xColumn = std::dynamic_pointer_cast<Geometry::ICompAssembly>((*bank)[x]);
1627 for (int y = 0; y < xColumn->nelements(); y++) {
1628 std::shared_ptr<Geometry::Detector> detector = std::dynamic_pointer_cast<Geometry::Detector>((*xColumn)[y]);
1629 if (detector) {
1630 // Make default facing for the pixel
1631 auto *comp = static_cast<IComponent *>(detector.get());
1634 // Mark it as a detector (add to the instrument cache)
1635 m_instrument->markAsDetectorIncomplete(detector.get());
1636 }
1637 }
1638 }
1639 } catch (Kernel::Exception::ExistsError &) {
1640 throw Kernel::Exception::InstrumentDefinitionError("Duplicate detector ID found when adding StructuredDetector " +
1641 name + " in XML instrument file" + filename);
1642 }
1643}
1644
1645//-----------------------------------------------------------------------------------------------------------------------
1664void InstrumentDefinitionParser::appendLeaf(Geometry::ICompAssembly *parent, const Poco::XML::Element *pLocElem,
1665 const Poco::XML::Element *pCompElem, IdList &idList) {
1666 const std::string filename = m_xmlFile->getFileFullPathStr();
1667
1668 //--- Get the detector's X/Y pixel sizes (optional) ---
1669 // Read detector IDs into idlist if required
1670 // Note idlist may be defined for any component
1671 // Note any new idlist found will take precedence.
1672
1673 if (pCompElem->hasAttribute("idlist")) {
1674 std::string idlist = pCompElem->getAttribute("idlist");
1675
1676 if (idlist != idList.idname) {
1677 Element *pFound = pCompElem->ownerDocument()->getElementById(idlist, "idname");
1678
1679 if (pFound == nullptr) {
1681 "No <idlist> with name idname=\"" + idlist + "\" present in instrument definition file.", filename);
1682 }
1683
1684 idList.reset();
1685 populateIdList(pFound, idList);
1686 }
1687 }
1688
1689 // get the type element of the component element in order to determine if
1690 // the
1691 // type
1692 // belong to the category: "detector", "SamplePos or "Source".
1693
1694 std::string typeName = pCompElem->getAttribute("type");
1695 Element *pType = getTypeElement[typeName];
1696
1697 std::string category;
1698 if (pType->hasAttribute("is"))
1699 category = pType->getAttribute("is");
1700
1701 static const boost::regex exp("Detector|detector|Monitor|monitor");
1702
1703 // do stuff a bit differently depending on which category the type belong to
1704 if (GridDetector::compareName(category)) {
1705 createGridDetector(parent, pLocElem, pCompElem, filename, pType);
1706 } else if (RectangularDetector::compareName(category)) {
1707 createRectangularDetector(parent, pLocElem, pCompElem, filename, pType);
1708 } else if (StructuredDetector::compareName(category)) {
1709 createStructuredDetector(parent, pLocElem, pCompElem, filename, pType);
1710 } else if (boost::regex_match(category, exp)) {
1711 createDetectorOrMonitor(parent, pLocElem, pCompElem, filename, idList, category);
1712 } else {
1713 //-------------- Not a Detector, RectangularDetector or Structured Detector
1714 //------------------------------
1715 IComponent *comp;
1716 if (category == "SamplePos" || category == "samplePos") {
1717 // check if special SamplePos Component
1718 std::string name = InstrumentDefinitionParser::getNameOfLocationElement(pLocElem, pCompElem);
1719 comp = new Geometry::Component(name, parent);
1720 m_instrument->markAsSamplePos(comp);
1721 } else {
1722 std::string name = InstrumentDefinitionParser::getNameOfLocationElement(pLocElem, pCompElem);
1723
1724 comp = new Geometry::ObjComponent(name, mapTypeNameToShape[typeName], parent);
1725 }
1726 parent->add(comp);
1727
1728 // check if special Source Component
1729 if (category == "Source" || category == "source") {
1730 m_instrument->markAsSource(comp);
1731 }
1732
1733 // set location for this newly added comp and set facing if specified in
1734 // instrument def. file. Also
1735 // check if any logfiles are referred to through the <parameter> element.
1736
1738 setFacing(comp, pLocElem);
1739 setLogfile(comp, pCompElem,
1740 m_instrument->getLogfileCache()); // params specified within <component>
1741 setLogfile(comp, pLocElem,
1742 m_instrument->getLogfileCache()); // params specified within
1743 // specific <location>
1744 }
1745}
1746
1747//-----------------------------------------------------------------------------------------------------------------------
1757void InstrumentDefinitionParser::populateIdList(Poco::XML::Element *pE, IdList &idList) {
1758 const std::string filename = m_xmlFile->getFileFullPathStr();
1759
1760 if ((pE->tagName()) != "idlist") {
1761 g_log.error("Argument to function createIdList must be a pointer to an XML "
1762 "element with tag name idlist.");
1763 throw std::logic_error("Argument to function createIdList must be a "
1764 "pointer to an XML element with tag name idlist.");
1765 }
1766
1767 // set name of idlist
1768
1769 idList.idname = pE->getAttribute("idname");
1770
1771 // If idname element has start and end attributes then just use those to
1772 // populate idlist.
1773 // Otherwise id sub-elements
1774
1775 if (pE->hasAttribute("start")) {
1776 int startID = std::stoi(pE->getAttribute("start"));
1777
1778 int endID;
1779 if (pE->hasAttribute("end"))
1780 endID = std::stoi(pE->getAttribute("end"));
1781 else
1782 endID = startID;
1783
1784 int increment = 1;
1785 if (pE->hasAttribute("step"))
1786 increment = std::stoi(pE->getAttribute("step"));
1787
1788 if (0 == increment) {
1789 std::stringstream ss;
1790 ss << "The step element cannot be zero, got start: " << startID << ", end: " << endID << ", step: " << increment;
1791 throw Kernel::Exception::InstrumentDefinitionError(ss.str(), filename);
1792 }
1793
1794 // check the start end and increment values are sensible
1795 int steps = (endID - startID) / increment;
1796 if (steps < 0) {
1797 std::stringstream ss;
1798 ss << "The start, end, and step elements do not allow a single id in "
1799 "the "
1800 "idlist entry - ";
1801 ss << "start: " << startID << ", end: " << endID << ", step: " << increment;
1802
1803 throw Kernel::Exception::InstrumentDefinitionError(ss.str(), filename);
1804 }
1805
1806 idList.vec.reserve(steps);
1807 for (int i = startID; i != endID + increment; i += increment) {
1808 idList.vec.emplace_back(i);
1809 }
1810 } else {
1811 // test first if any <id> elements
1812
1813 Poco::AutoPtr<NodeList> pNL = pE->getElementsByTagName("id");
1814
1815 if (pNL->length() == 0) {
1816 throw Kernel::Exception::InstrumentDefinitionError("No id subelement of idlist element in XML instrument file",
1817 filename);
1818 }
1819
1820 // get id numbers
1821
1822 NodeIterator it(pE, NodeFilter::SHOW_ELEMENT);
1823
1824 Node *pNode = it.nextNode();
1825 while (pNode) {
1826 if (pNode->nodeName() == "id") {
1827 auto *pIDElem = static_cast<Element *>(pNode);
1828
1829 if (pIDElem->hasAttribute("val")) {
1830 int valID = std::stoi(pIDElem->getAttribute("val"));
1831 idList.vec.emplace_back(valID);
1832 } else if (pIDElem->hasAttribute("start")) {
1833 int startID = std::stoi(pIDElem->getAttribute("start"));
1834
1835 int endID;
1836 if (pIDElem->hasAttribute("end"))
1837 endID = std::stoi(pIDElem->getAttribute("end"));
1838 else
1839 endID = startID;
1840
1841 int increment = 1;
1842 if (pIDElem->hasAttribute("step"))
1843 increment = std::stoi(pIDElem->getAttribute("step"));
1844
1845 // check the start end and increment values are sensible
1846 if (0 == increment) {
1847 std::stringstream ss;
1848 ss << "The step element cannot be zero, found step: " << increment;
1849
1850 throw Kernel::Exception::InstrumentDefinitionError(ss.str(), filename);
1851 }
1852 int numSteps = (endID - startID) / increment;
1853 if (numSteps < 0) {
1854 std::stringstream ss;
1855 ss << "The start, end, and step elements do not allow a single "
1856 "id "
1857 "in the idlist entry - ";
1858 ss << "start: " << startID << ", end: " << endID << ", step: " << increment;
1859
1860 throw Kernel::Exception::InstrumentDefinitionError(ss.str(), filename);
1861 }
1862
1863 idList.vec.reserve(numSteps);
1864 for (int i = startID; i != endID + increment; i += increment) {
1865 idList.vec.emplace_back(i);
1866 }
1867 } else {
1869 "id subelement of idlist " + std::string("element wrongly specified in XML instrument file"), filename);
1870 }
1871 }
1872
1873 pNode = it.nextNode();
1874 } // end while loop
1875 }
1876}
1877
1878//-----------------------------------------------------------------------------------------------------------------------
1887bool InstrumentDefinitionParser::isAssembly(const std::string &type) const {
1888 const std::string filename = m_xmlFile->getFileFullPathStr();
1889 auto it = isTypeAssembly.find(type);
1890
1891 if (it == isTypeAssembly.end()) {
1892 throw Kernel::Exception::InstrumentDefinitionError("type with name = " + type + " not defined.", filename);
1893 }
1894
1895 return it->second;
1896}
1897
1898//-----------------------------------------------------------------------------------------------------------------------
1913
1914//-----------------------------------------------------------------------------------------------------------------------
1924 Kernel::V3D pos = in->getPos();
1925
1926 // vector from facing object to component we want to rotate
1927 Kernel::V3D facingDirection = pos - facingPoint;
1928 const auto facingDirLength = facingDirection.norm();
1929 if (facingDirLength == 0.0)
1930 return;
1931 facingDirection /= facingDirLength;
1932
1933 // now aim to rotate shape such that the z-axis of of the object we want to
1934 // rotate points in the direction of facingDirection. That way the XY plane
1935 // faces the 'facing object'.
1936 constexpr Kernel::V3D z(0, 0, 1);
1937 Kernel::Quat R = in->getRotation();
1938 R.inverse();
1939 R.rotate(facingDirection);
1940
1941 Kernel::V3D normal = facingDirection.cross_prod(z);
1942 const auto normalLength = normal.norm();
1943 if (normalLength == 0.) {
1944 normal = normalize(-facingDirection);
1945 } else {
1946 normal /= normalLength;
1947 }
1948 double theta = (180.0 / M_PI) * facingDirection.angle(z);
1949
1950 if (normal.norm() > 0.0)
1951 in->rotate(Kernel::Quat(-theta, normal));
1952 else {
1953 // To take into account the case where the facing direction is in the
1954 // (0,0,1) or (0,0,-1) direction.
1955 in->rotate(Kernel::Quat(-theta, Kernel::V3D(0, 1, 0)));
1956 }
1957}
1958
1959//-----------------------------------------------------------------------------------------------------------------------
1966 Kernel::V3D retV3D;
1967
1968 // Polar coordinates can be labelled as (r,t,p) or (R,theta,phi)
1969 if (pElem->hasAttribute("r") || pElem->hasAttribute("t") || pElem->hasAttribute("p") || pElem->hasAttribute("R") ||
1970 pElem->hasAttribute("theta") || pElem->hasAttribute("phi")) {
1971 double R = attrToDouble(pElem, "r");
1972 double theta = m_angleConvertConst * attrToDouble(pElem, "t");
1973 double phi = m_angleConvertConst * attrToDouble(pElem, "p");
1974
1975 if (pElem->hasAttribute("R"))
1976 R = attrToDouble(pElem, "R");
1977 if (pElem->hasAttribute("theta"))
1978 theta = m_angleConvertConst * attrToDouble(pElem, "theta");
1979 if (pElem->hasAttribute("phi"))
1980 phi = m_angleConvertConst * attrToDouble(pElem, "phi");
1981
1982 retV3D.spherical(R, theta, phi);
1983 } else {
1984 double x = attrToDouble(pElem, "x");
1985 double y = attrToDouble(pElem, "y");
1986 double z = attrToDouble(pElem, "z");
1987
1988 retV3D(x, y, z);
1989 }
1990
1991 return retV3D;
1992}
1993
1994//-----------------------------------------------------------------------------------------------------------------------
2008void InstrumentDefinitionParser::setFacing(Geometry::IComponent *comp, const Poco::XML::Element *pElem) {
2009 // Require that pElem points to an element with tag name 'location'
2010
2011 if ((pElem->tagName()) != "location") {
2012 g_log.error("Second argument to function setLocation must be a pointer to "
2013 "an XML element with tag name location.");
2014 throw std::logic_error("Second argument to function setLocation must be a "
2015 "pointer to an XML element with tag name location.");
2016 }
2017
2018 Element *facingElem = pElem->getChildElement("facing");
2019 if (facingElem) {
2020 // check if user want to rotate about z-axis before potentially applying
2021 // facing
2022
2023 if (facingElem->hasAttribute("rot")) {
2024 double rotAngle = m_angleConvertConst * attrToDouble(facingElem, "rot"); // assumed to be in degrees
2025 comp->rotate(Kernel::Quat(rotAngle, Kernel::V3D(0, 0, 1)));
2026 }
2027
2028 // For now assume that if has val attribute it means facing = none. This
2029 // option only has an
2030 // effect when a default facing setting is set. In which case this then
2031 // means "ignore the
2032 // default facing setting" for this component
2033
2034 if (facingElem->hasAttribute("val"))
2035 return;
2036
2037 // Face the component, i.e. rotate the z-axis of the component such that
2038 // it
2039 // points in the direction from
2040 // the point x,y,z (or r,t,p) specified by the <facing> xml element
2041 // towards
2042 // the component
2043
2045
2046 } else // so if no facing element associated with location element apply
2047 // default facing if set
2050}
2051
2052//-----------------------------------------------------------------------------------------------------------------------
2063void InstrumentDefinitionParser::setLogfile(const Geometry::IComponent *comp, const Poco::XML::Element *pElem,
2064 InstrumentParameterCache &logfileCache, const std::string &requestedDate) {
2065 const std::string filename = m_xmlFile->getFileFullPathStr();
2066
2067 // The purpose below is to have a quicker way to judge if pElem contains a
2068 // parameter, see
2069 // defintion of m_hasParameterElement for more info
2071 if (m_hasParameterElement.end() == std::find(m_hasParameterElement.begin(), m_hasParameterElement.end(), pElem))
2072 return;
2073
2074 Poco::AutoPtr<NodeList> pNL_comp = pElem->childNodes(); // here get all child nodes
2075 unsigned long pNL_comp_length = pNL_comp->length();
2076
2077 for (unsigned long i = 0; i < pNL_comp_length; i++) {
2078 // we are only interest in the top level parameter elements hence
2079 // the reason for the if statement below
2080 if (!((pNL_comp->item(i))->nodeType() == Node::ELEMENT_NODE && ((pNL_comp->item(i))->nodeName()) == "parameter"))
2081 continue;
2082
2083 auto *pParamElem = static_cast<Element *>(pNL_comp->item(i));
2084
2085 if (!pParamElem->hasAttribute("name"))
2087 "XML element with name or type = " + comp->getName() +
2088 " contain <parameter> element with no name attribute in XML "
2089 "instrument file",
2090 filename);
2091
2092 std::string paramName = pParamElem->getAttribute("name");
2093
2094 if (paramName == "rot" || paramName == "pos") {
2095 g_log.error() << "XML element with name or type = " << comp->getName()
2096 << " contains <parameter> element with name=\"" << paramName << "\"."
2097 << " This is a reserved Mantid keyword. Please use other name, "
2098 << "and see docs.mantidproject.org/concepts/InstrumentDefinitionFile for list of reserved "
2099 "keywords."
2100 << " This parameter is ignored";
2101 continue;
2102 }
2103
2104 std::string visible = "true";
2105 if (pParamElem->hasAttribute("visible")) {
2106 visible = pParamElem->getAttribute("visible");
2107 }
2108
2109 DateAndTime validityDate;
2110
2111 if (requestedDate.empty()) {
2112 validityDate = DateAndTime::getCurrentTime();
2113 } else {
2114 validityDate.setFromISO8601(requestedDate);
2115 }
2116
2117 std::string logfileID;
2118 std::string value;
2119
2120 DateAndTime validFrom;
2121 DateAndTime validTo;
2122
2123 std::string type = "double"; // default
2124 std::string extractSingleValueAs = "mean"; // default
2125 std::string eq;
2126
2127 Poco::AutoPtr<NodeList> pNLvalue = pParamElem->getElementsByTagName("value");
2128 size_t numberValueEle = pNLvalue->length();
2129 Element *pValueElem;
2130
2131 Poco::AutoPtr<NodeList> pNLlogfile = pParamElem->getElementsByTagName("logfile");
2132 size_t numberLogfileEle = pNLlogfile->length();
2133 Element *pLogfileElem;
2134
2135 Poco::AutoPtr<NodeList> pNLLookUp = pParamElem->getElementsByTagName("lookuptable");
2136 size_t numberLookUp = pNLLookUp->length();
2137
2138 Poco::AutoPtr<NodeList> pNLFormula = pParamElem->getElementsByTagName("formula");
2139 size_t numberFormula = pNLFormula->length();
2140
2141 if ((numberValueEle > 0 && numberLogfileEle + numberLookUp + numberFormula > 0) ||
2142 (numberValueEle == 0 && numberLogfileEle + numberLookUp + numberFormula > 1)) {
2143 g_log.warning() << "XML element with name or type = " << comp->getName()
2144 << " contains <parameter> element where the value of the "
2145 << "parameter has been specified more than once. See "
2146 << "docs.mantidproject.org/concepts/InstrumentDefinitionFile for how the value of the "
2147 << "parameter is set in this case.";
2148 }
2149
2150 if (numberValueEle + numberLogfileEle + numberLookUp + numberFormula == 0) {
2151 g_log.error() << "XML element with name or type = " << comp->getName()
2152 << " contains <parameter> for which no value is specified."
2153 << " See docs.mantidproject.org/concepts/InstrumentDefinitionFile for how to set the value"
2154 << " of a parameter. This parameter is ignored.";
2155 continue;
2156 }
2157
2158 DateAndTime currentValidFrom;
2159 DateAndTime currentValidTo;
2160 currentValidFrom.setToMinimum();
2161 currentValidTo.setToMaximum();
2162
2163 // if more than one <value> specified for a parameter, check the validity
2164 // range
2165 if (numberValueEle >= 1) {
2166 bool hasValue = false;
2167
2168 for (unsigned long j = 0; j < numberValueEle; ++j) {
2169 pValueElem = static_cast<Element *>(pNLvalue->item(j));
2170
2171 if (!pValueElem->hasAttribute(("val")))
2172 continue;
2173
2174 validFrom.setToMinimum();
2175 if (pValueElem->hasAttribute("valid-from"))
2176 validFrom.setFromISO8601(pValueElem->getAttribute("valid-from"));
2177
2178 validTo.setToMaximum();
2179 if (pValueElem->hasAttribute("valid-to"))
2180 validTo.setFromISO8601(pValueElem->getAttribute("valid-to"));
2181
2182 if (validFrom <= validityDate && validityDate <= validTo &&
2183 (validFrom > currentValidFrom || (validFrom == currentValidFrom && validTo <= currentValidTo))) {
2184
2185 currentValidFrom = validFrom;
2186 currentValidTo = validTo;
2187 } else
2188 continue;
2189 hasValue = true;
2190 value = pValueElem->getAttribute("val");
2191 }
2192
2193 if (!hasValue) {
2195 "XML element with name or type = " + comp->getName() +
2196 " contains <parameter> element with invalid syntax for its "
2197 "subelement <value>. Correct syntax is <value val=\"\"/>",
2198 filename);
2199 }
2200
2201 } else if (numberLogfileEle >= 1) {
2202 // <logfile > tag was used at least once.
2203 pLogfileElem = static_cast<Element *>(pNLlogfile->item(0));
2204 if (!pLogfileElem->hasAttribute("id"))
2206 "XML element with name or type = " + comp->getName() +
2207 " contains <parameter> element with invalid syntax for its "
2208 "subelement logfile>." +
2209 " Correct syntax is <logfile id=\"\"/>",
2210 filename);
2211 logfileID = pLogfileElem->getAttribute("id");
2212
2213 if (pLogfileElem->hasAttribute("eq"))
2214 eq = pLogfileElem->getAttribute("eq");
2215 if (pLogfileElem->hasAttribute("extract-single-value-as"))
2216 extractSingleValueAs = pLogfileElem->getAttribute("extract-single-value-as");
2217 }
2218
2219 if (pParamElem->hasAttribute("type"))
2220 type = pParamElem->getAttribute("type");
2221
2222 // check if <fixed /> element present
2223
2224 bool fixed = false;
2225 Poco::AutoPtr<NodeList> pNLFixed = pParamElem->getElementsByTagName("fixed");
2226 size_t numberFixed = pNLFixed->length();
2227 if (numberFixed >= 1) {
2228 fixed = true;
2229 }
2230
2231 // some processing
2232
2233 std::string fittingFunction;
2234 std::string tie;
2235
2236 if (type == "fitting") {
2237 size_t found = paramName.find(':');
2238 if (found != std::string::npos) {
2239 // check that only one : in name
2240 size_t index = paramName.find(':', found + 1);
2241 if (index != std::string::npos) {
2242 g_log.error() << "Fitting <parameter> in instrument definition file defined "
2243 "with"
2244 << " more than one column character :. One must used.\n";
2245 } else {
2246 fittingFunction = paramName.substr(0, found);
2247 paramName = paramName.substr(found + 1, paramName.size());
2248 }
2249 }
2250 }
2251
2252 if (fixed) {
2253 std::ostringstream str;
2254 str << paramName << "=" << value;
2255 tie = str.str();
2256 }
2257
2258 // check if <min> or <max> elements present
2259
2260 std::vector<std::string> constraint(2, "");
2261
2262 Poco::AutoPtr<NodeList> pNLMin = pParamElem->getElementsByTagName("min");
2263 size_t numberMin = pNLMin->length();
2264 Poco::AutoPtr<NodeList> pNLMax = pParamElem->getElementsByTagName("max");
2265 size_t numberMax = pNLMax->length();
2266
2267 if (numberMin >= 1) {
2268 auto *pMin = static_cast<Element *>(pNLMin->item(0));
2269 constraint[0] = pMin->getAttribute("val");
2270 }
2271 if (numberMax >= 1) {
2272 auto *pMax = static_cast<Element *>(pNLMax->item(0));
2273 constraint[1] = pMax->getAttribute("val");
2274 }
2275
2276 // check if penalty-factor> elements present
2277
2278 std::string penaltyFactor;
2279
2280 Poco::AutoPtr<NodeList> pNL_penaltyFactor = pParamElem->getElementsByTagName("penalty-factor");
2281 size_t numberPenaltyFactor = pNL_penaltyFactor->length();
2282
2283 if (numberPenaltyFactor >= 1) {
2284 auto *pPenaltyFactor = static_cast<Element *>(pNL_penaltyFactor->item(0));
2285 penaltyFactor = pPenaltyFactor->getAttribute("val");
2286 }
2287
2288 // Check if look up table is specified
2289
2290 std::vector<std::string> allowedUnits = UnitFactory::Instance().getKeys();
2291
2292 std::shared_ptr<Interpolation> interpolation = std::make_shared<Interpolation>();
2293
2294 if (numberLookUp >= 1) {
2295 auto *pLookUp = static_cast<Element *>(pNLLookUp->item(0));
2296
2297 if (pLookUp->hasAttribute("interpolation"))
2298 interpolation->setMethod(pLookUp->getAttribute("interpolation"));
2299 if (pLookUp->hasAttribute("x-unit")) {
2300 std::vector<std::string>::iterator it;
2301 it = find(allowedUnits.begin(), allowedUnits.end(), pLookUp->getAttribute("x-unit"));
2302 if (it == allowedUnits.end()) {
2303 g_log.warning() << "x-unit used with interpolation table must be "
2304 "one of the recognised units "
2305 << " see http://docs.mantidproject.org/concepts/UnitFactory";
2306 } else
2307 interpolation->setXUnit(pLookUp->getAttribute("x-unit"));
2308 }
2309 if (pLookUp->hasAttribute("y-unit")) {
2310 std::vector<std::string>::iterator it;
2311 it = find(allowedUnits.begin(), allowedUnits.end(), pLookUp->getAttribute("y-unit"));
2312 if (it == allowedUnits.end()) {
2313 g_log.warning() << "y-unit used with interpolation table must be "
2314 "one of the recognised units "
2315 << " see http://docs.mantidproject.org/concepts/UnitFactory";
2316 } else
2317 interpolation->setYUnit(pLookUp->getAttribute("y-unit"));
2318 }
2319
2320 Poco::AutoPtr<NodeList> pNLpoint = pLookUp->getElementsByTagName("point");
2321 unsigned long numberPoint = pNLpoint->length();
2322
2323 for (unsigned long j = 0; j < numberPoint; j++) {
2324 const auto *pPoint = static_cast<Element *>(pNLpoint->item(j));
2325 double x = attrToDouble(pPoint, "x");
2326 double y = attrToDouble(pPoint, "y");
2327 interpolation->addPoint(x, y);
2328 }
2329 }
2330
2331 // Check if formula is specified
2332
2333 std::string formula;
2334 std::string formulaUnit;
2335 std::string resultUnit;
2336
2337 if (numberFormula >= 1) {
2338 auto *pFormula = static_cast<Element *>(pNLFormula->item(0));
2339 formula = pFormula->getAttribute("eq");
2340 if (pFormula->hasAttribute("unit")) {
2341 std::vector<std::string>::iterator it;
2342 it = find(allowedUnits.begin(), allowedUnits.end(), pFormula->getAttribute("unit"));
2343 if (it == allowedUnits.end()) {
2344 g_log.warning() << "unit attribute used with formula must be one "
2345 "of the recognized units "
2346 << " see http://docs.mantidproject.org/concepts/UnitFactory";
2347 } else
2348 formulaUnit = pFormula->getAttribute("unit");
2349 }
2350 if (pFormula->hasAttribute("result-unit"))
2351 resultUnit = pFormula->getAttribute("result-unit");
2352 }
2353 // Check if parameter description is
2354 std::string description;
2355
2356 Poco::AutoPtr<NodeList> pNLDescription = pParamElem->getElementsByTagName("description");
2357 size_t numberDescription = pNLDescription->length();
2358
2359 if (numberDescription >= 1) {
2360 // use only first description from a list
2361 auto *pDescription = static_cast<Element *>(pNLDescription->item(0));
2362 description = pDescription->getAttribute("is");
2363 }
2364
2365 auto cacheKey = std::make_pair(paramName, comp);
2366 auto cacheValue = std::make_shared<XMLInstrumentParameter>(
2367 logfileID, value, interpolation, formula, formulaUnit, resultUnit, paramName, type, tie, constraint,
2368 penaltyFactor, fittingFunction, extractSingleValueAs, eq, comp, m_angleConvertConst, description, visible);
2369 auto inserted = logfileCache.emplace(cacheKey, cacheValue);
2370 if (!inserted.second) {
2371 logfileCache[cacheKey] = cacheValue;
2372 }
2373 } // end element loop
2374}
2375
2376//-----------------------------------------------------------------------------------------------------------------------
2390void InstrumentDefinitionParser::setComponentLinks(std::shared_ptr<Geometry::Instrument> &instrument,
2391 Poco::XML::Element *pRootElem, Kernel::ProgressBase *progress,
2392 const std::string &requestedDate) {
2393 // check if any logfile cache units set. As of this writing the only unit to
2394 // check is if "angle=radian"
2395 std::map<std::string, std::string> &units = instrument->getLogfileUnit();
2396 std::map<std::string, std::string>::iterator unit_it;
2397 unit_it = units.find("angle");
2398 if (unit_it != units.end())
2399 if (unit_it->second == "radian")
2400 m_angleConvertConst = 180.0 / M_PI;
2401
2402 const std::string elemName = "component-link";
2403 Poco::AutoPtr<NodeList> pNL_link = pRootElem->getElementsByTagName(elemName);
2404 unsigned long numberLinks = pNL_link->length();
2405
2406 if (progress)
2407 progress->resetNumSteps(static_cast<int64_t>(numberLinks), 0.0, 0.95);
2408
2409 Node *curNode = pRootElem->firstChild();
2410 while (curNode) {
2411 if (curNode->nodeType() == Node::ELEMENT_NODE && curNode->nodeName() == elemName) {
2412 auto *curElem = static_cast<Element *>(curNode);
2413
2414 if (progress) {
2415 if (progress->hasCancellationBeenRequested())
2416 return;
2417 progress->report("Loading parameters");
2418 }
2419
2420 std::string id = curElem->getAttribute("id");
2421 std::string name = curElem->getAttribute("name");
2422 std::vector<std::shared_ptr<const Geometry::IComponent>> sharedIComp;
2423
2424 // If available, use the detector id as it's the most specific.
2425 if (id.length() > 0) {
2426 int detid;
2427 std::stringstream(id) >> detid;
2428 std::shared_ptr<const Geometry::IComponent> detector = instrument->getDetector(static_cast<detid_t>(detid));
2429
2430 // If we didn't find anything with the detector id, explain why to the
2431 // user, and throw an exception.
2432 if (!detector) {
2433 g_log.error() << "Error whilst loading parameters. No detector "
2434 "found with id '"
2435 << detid << "'\n";
2436 g_log.error() << "Please check that your detectors' ids are correct.\n";
2437 throw Kernel::Exception::InstrumentDefinitionError("Invalid detector id in component-link tag.");
2438 }
2439
2440 sharedIComp.emplace_back(detector);
2441
2442 // If the user also supplied a name, make sure it's consistent with
2443 // the
2444 // detector id.
2445 if (name.length() > 0) {
2446 auto comp = std::dynamic_pointer_cast<const IComponent>(detector);
2447 if (comp) {
2448 bool consistent = (comp->getFullName() == name || comp->getName() == name);
2449 if (!consistent) {
2450 g_log.warning() << "Error whilst loading parameters. Name '" << name << "' does not match id '" << detid
2451 << "'.\n";
2452 g_log.warning() << "Parameters have been applied to detector with id '" << detid
2453 << "'. Please check the name is correct.\n";
2454 }
2455 }
2456 }
2457 } else {
2458 // No detector id given, fall back to using the name
2459
2460 if (name.find('/', 0) == std::string::npos) { // Simple name, look for
2461 // all components of that
2462 // name.
2463 sharedIComp = instrument->getAllComponentsWithName(name);
2464 } else { // Pathname given. Assume it is unique.
2465 std::shared_ptr<const Geometry::IComponent> shared = instrument->getComponentByName(name);
2466 sharedIComp.emplace_back(shared);
2467 }
2468 }
2469
2470 for (auto &ptr : sharedIComp) {
2471 std::shared_ptr<const Geometry::Component> sharedComp =
2472 std::dynamic_pointer_cast<const Geometry::Component>(ptr);
2473 if (sharedComp) {
2474 // Not empty Component
2475 if (sharedComp->isParametrized()) {
2476 setLogfile(sharedComp->base(), curElem, instrument->getLogfileCache(), requestedDate);
2477 } else {
2478 setLogfile(ptr.get(), curElem, instrument->getLogfileCache(), requestedDate);
2479 }
2480 }
2481 }
2482 }
2483 curNode = curNode->nextSibling();
2484 }
2485}
2486
2492 const std::string cacheFullPath = cacheToApply->getFileFullPathStr();
2493 g_log.information("Loading geometry cache from " + cacheFullPath);
2494 // create a vtk reader
2495 std::map<std::string, std::shared_ptr<Geometry::IObject>>::iterator objItr;
2496 std::shared_ptr<Mantid::Geometry::vtkGeometryCacheReader> reader(
2497 new Mantid::Geometry::vtkGeometryCacheReader(cacheFullPath));
2498 for (objItr = mapTypeNameToShape.begin(); objItr != mapTypeNameToShape.end(); ++objItr) {
2499 // caching only applies to CSGObject
2500 if (auto csgObj = std::dynamic_pointer_cast<CSGObject>(((*objItr).second))) {
2501 csgObj->setVtkGeometryCacheReader(reader);
2502 }
2503 }
2504}
2505
2513 IDFObject_const_sptr fallBackCache) {
2514 IDFObject_const_sptr usedCache = std::move(firstChoiceCache);
2515 auto cachingOption = WroteGeomCache;
2516
2517 g_log.notice("Geometry cache is not available");
2518 try {
2519 Poco::File dir = usedCache->getParentDirectory();
2520 if (dir.path().empty() || !dir.exists() || !dir.canWrite()) {
2521 usedCache = std::move(fallBackCache);
2522 cachingOption = WroteCacheTemp;
2523 g_log.information() << "Geometrycache directory is read only, writing cache "
2524 "to system temp.\n";
2525 }
2526 } catch (Poco::FileNotFoundException &) {
2527 g_log.error() << "Unable to find instrument definition while attempting to "
2528 "write cache.\n";
2529 throw std::runtime_error("Unable to find instrument definition while "
2530 "attempting to write cache.\n");
2531 }
2532 const std::string cacheFullPath = usedCache->getFileFullPathStr();
2533 g_log.notice() << "Creating cache in " << cacheFullPath << "\n";
2534 // create a vtk writer
2535 std::map<std::string, std::shared_ptr<Geometry::IObject>>::iterator objItr;
2536 std::shared_ptr<Mantid::Geometry::vtkGeometryCacheWriter> writer(
2537 new Mantid::Geometry::vtkGeometryCacheWriter(cacheFullPath));
2538 for (objItr = mapTypeNameToShape.begin(); objItr != mapTypeNameToShape.end(); ++objItr) {
2539 // caching only applies to CSGObject
2540 if (auto csgObj = std::dynamic_pointer_cast<CSGObject>(((*objItr).second))) {
2541 csgObj->setVtkGeometryCacheWriter(writer);
2542 }
2543 }
2544 writer->write();
2545 return cachingOption;
2546}
2547
2552 // Get cached file name
2553 // If the instrument directory is writable, put them there else use
2554 // temporary
2555 // directory.
2556 IDFObject_const_sptr fallBackCache = std::make_shared<const IDFObject>(
2557 Poco::Path(ConfigService::Instance().getTempDir()).append(this->getMangledName() + ".vtp").toString());
2558 CachingOption cachingOption = NoneApplied;
2559 if (m_cacheFile->exists()) {
2561 cachingOption = ReadGeomCache;
2562 } else if (fallBackCache->exists()) {
2563 applyCache(fallBackCache);
2564 cachingOption = ReadFallBack;
2565 } else {
2566 cachingOption = writeAndApplyCache(m_cacheFile, fallBackCache);
2567 }
2568 return cachingOption;
2569}
2570
2578
2580 // Create a copy of the instrument
2581 auto physical = std::make_unique<Instrument>(*m_instrument);
2582 // Store the physical instrument 'inside' the neutronic instrument
2583 m_instrument->setPhysicalInstrument(std::move(physical));
2584
2585 // Now we manipulate the original instrument (m_instrument) to hold
2586 // neutronic positions
2587 for (const auto &component : m_neutronicPos) {
2588 if (component.second) {
2589 setLocation(component.first, component.second, m_angleConvertConst, m_deltaOffsets);
2590 // TODO: Do we need to deal with 'facing'???
2591
2592 // Check for a 'type' attribute, indicating that we want to set the
2593 // neutronic shape
2594 if (component.second->hasAttribute("type") && dynamic_cast<ObjComponent *>(component.first)) {
2595 const Poco::XML::XMLString shapeName = component.second->getAttribute("type");
2596 auto shapeIt = mapTypeNameToShape.find(shapeName);
2597 if (shapeIt != mapTypeNameToShape.end()) {
2598 // Change the shape on the current component to the one requested
2599 auto objCmpt = dynamic_cast<ObjComponent *>(component.first);
2600 if (objCmpt)
2601 objCmpt->setShape(shapeIt->second);
2602 } else {
2603 throw Exception::InstrumentDefinitionError("Requested type " + shapeName + " not defined in IDF");
2604 }
2605 }
2606 } else // We have a null Element*, which signals a detector with no
2607 // neutronic position
2608 {
2609 // This should only happen for detectors
2610 auto *det = dynamic_cast<Detector *>(component.first);
2611 if (det)
2612 m_instrument->removeDetector(det);
2613 }
2614 }
2615}
2616
2634void InstrumentDefinitionParser::adjust(Poco::XML::Element *pElem, const std::map<std::string, bool> &isTypeAssembly,
2635 std::map<std::string, Poco::XML::Element *> &getTypeElement) {
2637 // check if pElem is an element with tag name 'type'
2638 if (pElem->tagName() != "type")
2639 throw Exception::InstrumentDefinitionError("Argument to function adjust() "
2640 "must be a pointer to an XML "
2641 "element with tag name type.");
2642
2643 // check that there is a <combine-components-into-one-shape> element in type
2644 Poco::AutoPtr<NodeList> pNLccioh = pElem->getElementsByTagName("combine-components-into-one-shape");
2645 if (pNLccioh->length() == 0) {
2646 throw Exception::InstrumentDefinitionError(std::string("Argument to function adjust() must be a pointer to an XML "
2647 "element with tag name type,") +
2648 " which contain a <combine-components-into-one-shape> element.");
2649 }
2650
2651 // check that there is a <algebra> element in type
2652 Poco::AutoPtr<NodeList> pNLalg = pElem->getElementsByTagName("algebra");
2653 if (pNLalg->length() == 0) {
2654 throw Exception::InstrumentDefinitionError(std::string("An <algebra> element must be part of a <type>, which") +
2655 " includes a <combine-components-into-one-shape> element. See "
2656 "docs.mantidproject.org/concepts/InstrumentDefinitionFile.");
2657 }
2658
2659 // check that there is a <location> element in type
2660 Poco::AutoPtr<NodeList> pNL = pElem->getElementsByTagName("location");
2661 unsigned long numLocation = pNL->length();
2662 if (numLocation == 0) {
2663 throw Exception::InstrumentDefinitionError(std::string("At least one <location> element must be part of a "
2664 "<type>, which") +
2665 " includes a <combine-components-into-one-shape> element. See "
2666 "docs.mantidproject.org/concepts/InstrumentDefinitionFile.");
2667 }
2668
2669 // check if a <translate-rotate-combined-shape-to> is defined
2670 Poco::AutoPtr<NodeList> pNL_TransRot = pElem->getElementsByTagName("translate-rotate-combined-shape-to");
2671 const Element *pTransRot = nullptr;
2672 if (pNL_TransRot->length() == 1) {
2673 pTransRot = static_cast<Element *>(pNL_TransRot->item(0));
2674 }
2675
2676 // to convert all <component>'s in type into <cuboid> elements, which are
2677 // added
2678 // to pElem, and these <component>'s are deleted after loop
2679
2680 std::unordered_set<Element *> allComponentInType; // used to hold <component>'s found
2681 std::vector<std::string> allLocationName; // used to check if loc names unique
2682 for (unsigned long i = 0; i < numLocation; i++) {
2683 auto *pLoc = static_cast<Element *>(pNL->item(i));
2684
2685 // The location element is required to be a child of a component element.
2686 // Get this component element
2687 Element *pCompElem = InstrumentDefinitionParser::getParentComponent(pLoc);
2688
2689 // get the name given to the <location> element in focus
2690 // note these names are required to be unique for the purpose of
2691 // constructing the <algebra>
2692 std::string locationElementName = pLoc->getAttribute("name");
2693 if (std::find(allLocationName.begin(), allLocationName.end(), locationElementName) == allLocationName.end())
2694 allLocationName.emplace_back(locationElementName);
2695 else
2697 std::string("Names in a <type> element containing ") +
2698 "a <combine-components-into-one-shape> element must be unique. " + "Here error is that " +
2699 locationElementName +
2700 " appears at least twice. See docs.mantidproject.org/concepts/InstrumentDefinitionFile.");
2701
2702 // create dummy component to hold coord. sys. of cuboid
2703 auto baseCoor = std::make_unique<CompAssembly>("base"); // dummy assembly used to get to end assembly if nested
2704 ICompAssembly *endComponent = nullptr; // end assembly, its purpose is to
2705 // hold the shape coordinate system
2706 // get shape coordinate system, returned as endComponent, as defined by
2707 // pLoc
2708 // and nested <location> elements
2709 // of pLoc
2710 std::string shapeTypeName = getShapeCoorSysComp(baseCoor.get(), pLoc, getTypeElement, endComponent);
2711
2712 // translate and rotate cuboid according to shape coordinate system in
2713 // endComponent
2714 std::string cuboidStr = translateRotateXMLcuboid(endComponent, getTypeElement[shapeTypeName], locationElementName);
2715
2716 // if <translate-rotate-combined-shape-to> is specified
2717 if (pTransRot) {
2718 baseCoor = std::make_unique<CompAssembly>("base");
2719
2720 setLocation(baseCoor.get(), pTransRot, m_angleConvertConst);
2721
2722 // Translate and rotate shape xml string according to
2723 // <translate-rotate-combined-shape-to>
2724 cuboidStr = translateRotateXMLcuboid(baseCoor.get(), cuboidStr, locationElementName);
2725 }
2726
2727 DOMParser pParser;
2728 Poco::AutoPtr<Document> pDoc;
2729 try {
2730 pDoc = pParser.parseString(cuboidStr);
2731 } catch (...) {
2732 throw Exception::InstrumentDefinitionError(std::string("Unable to parse XML string ") + cuboidStr);
2733 }
2734 // Get pointer to root element and add this element to pElem
2735 Element *pCuboid = pDoc->documentElement();
2736 Poco::AutoPtr<Node> fisse = (pElem->ownerDocument())->importNode(pCuboid, true);
2737 pElem->appendChild(fisse);
2738
2739 allComponentInType.insert(pCompElem);
2740 }
2741
2742 // delete all <component> found in pElem
2743 for (const auto &component : allComponentInType)
2744 pElem->removeChild(component);
2745}
2746
2756 const Poco::XML::Element *cuboidEle,
2757 const std::string &cuboidName) {
2758 Element *pElem_lfb = getShapeElement(cuboidEle, "left-front-bottom-point");
2759 Element *pElem_lft = getShapeElement(cuboidEle, "left-front-top-point");
2760 Element *pElem_lbb = getShapeElement(cuboidEle, "left-back-bottom-point");
2761 Element *pElem_rfb = getShapeElement(cuboidEle, "right-front-bottom-point");
2762
2763 V3D lfb = parsePosition(pElem_lfb); // left front bottom
2764 V3D lft = parsePosition(pElem_lft); // left front top
2765 V3D lbb = parsePosition(pElem_lbb); // left back bottom
2766 V3D rfb = parsePosition(pElem_rfb); // right front bottom
2767
2768 // translate and rotate cuboid according to coord. sys. of comp
2769 V3D p_lfb = getAbsolutPositionInCompCoorSys(comp, lfb);
2770 V3D p_lft = getAbsolutPositionInCompCoorSys(comp, lft);
2771 V3D p_lbb = getAbsolutPositionInCompCoorSys(comp, lbb);
2772 V3D p_rfb = getAbsolutPositionInCompCoorSys(comp, rfb);
2773
2774 // create output cuboid XML string
2775 std::ostringstream obj_str;
2776
2777 obj_str << "<cuboid id=\"" << cuboidName << "\">";
2778 obj_str << "<left-front-bottom-point ";
2779 obj_str << "x=\"" << p_lfb.X();
2780 obj_str << "\" y=\"" << p_lfb.Y();
2781 obj_str << "\" z=\"" << p_lfb.Z();
2782 obj_str << "\" />";
2783 obj_str << "<left-front-top-point ";
2784 obj_str << "x=\"" << p_lft.X();
2785 obj_str << "\" y=\"" << p_lft.Y();
2786 obj_str << "\" z=\"" << p_lft.Z();
2787 obj_str << "\" />";
2788 obj_str << "<left-back-bottom-point ";
2789 obj_str << "x=\"" << p_lbb.X();
2790 obj_str << "\" y=\"" << p_lbb.Y();
2791 obj_str << "\" z=\"" << p_lbb.Z();
2792 obj_str << "\" />";
2793 obj_str << "<right-front-bottom-point ";
2794 obj_str << "x=\"" << p_rfb.X();
2795 obj_str << "\" y=\"" << p_rfb.Y();
2796 obj_str << "\" z=\"" << p_rfb.Z();
2797 obj_str << "\" />";
2798 obj_str << "</cuboid>";
2799
2800 return obj_str.str();
2801}
2802
2809 Component *dummyComp = new Component("dummy", comp);
2810 comp->add(dummyComp);
2811
2812 dummyComp->setPos(pos); // set pos relative to comp coord. sys.
2813
2814 V3D retVal = dummyComp->getPos(); // get absolute position
2815
2816 return retVal;
2817}
2818
2827std::string InstrumentDefinitionParser::translateRotateXMLcuboid(ICompAssembly *comp, const std::string &cuboidXML,
2828 const std::string &cuboidName) {
2829 DOMParser pParser;
2830 Poco::AutoPtr<Document> pDoc;
2831 try {
2832 pDoc = pParser.parseString(cuboidXML);
2833 } catch (...) {
2834 throw Exception::InstrumentDefinitionError(std::string("Unable to parse XML string ") + cuboidXML);
2835 }
2836
2837 Element *pCuboid = pDoc->documentElement();
2838
2839 std::string retVal = translateRotateXMLcuboid(comp, pCuboid, cuboidName);
2840
2841 return retVal;
2842}
2843
2851Poco::AutoPtr<Poco::XML::Document>
2853 // Number of <location> this <locations> element is shorthand for
2854 size_t nElements(0);
2855 if (pElem->hasAttribute("n-elements")) {
2856 auto n = boost::lexical_cast<int>(Strings::strip(pElem->getAttribute("n-elements")));
2857
2858 if (n <= 0) {
2859 throw Exception::InstrumentDefinitionError("n-elements must be positive");
2860 } else {
2861 nElements = static_cast<size_t>(n);
2862 }
2863 } else {
2864 throw Exception::InstrumentDefinitionError("When using <locations> n-elements attribute is required. See "
2865 "docs.mantidproject.org/concepts/InstrumentDefinitionFile.");
2866 }
2867
2868 std::string name;
2869 if (pElem->hasAttribute("name")) {
2870 name = pElem->getAttribute("name");
2871 }
2872
2873 int nameCountStart(0);
2874 if (pElem->hasAttribute("name-count-start")) {
2875 nameCountStart = boost::lexical_cast<int>(Strings::strip(pElem->getAttribute("name-count-start")));
2876 }
2877
2878 int nameCountIncrement(1);
2879 if (pElem->hasAttribute("name-count-increment")) {
2880 nameCountIncrement = boost::lexical_cast<int>(Strings::strip(pElem->getAttribute("name-count-increment")));
2881
2882 if (nameCountIncrement <= 0)
2883 throw Exception::InstrumentDefinitionError("name-count-increment must be greater than zero.");
2884 }
2885
2886 // A list of numeric attributes which are allowed to have corresponding -end
2887 std::set<std::string> rangeAttrs = {"x", "y", "z", "r", "t", "p", "rot"};
2888
2889 // Numeric attributes related to rotation. Doesn't make sense to have -end
2890 // for
2891 // those
2892 std::set<std::string> rotAttrs = {"axis-x", "axis-y", "axis-z"};
2893
2894 // A set of all numeric attributes for convenience
2895 std::set<std::string> allAttrs;
2896 allAttrs.insert(rangeAttrs.begin(), rangeAttrs.end());
2897 allAttrs.insert(rotAttrs.begin(), rotAttrs.end());
2898
2899 // Attribute values as read from <locations>. If the attribute doesn't have
2900 // a
2901 // value here, it
2902 // means that it wasn't set
2903 std::map<std::string, double> attrValues;
2904
2905 // Read all the set attribute values
2906 for (const auto &attr : allAttrs) {
2907 if (pElem->hasAttribute(attr)) {
2908 attrValues[attr] = boost::lexical_cast<double>(Strings::strip(pElem->getAttribute(attr)));
2909 }
2910 }
2911
2912 // Range attribute steps
2913 std::map<std::string, double> rangeAttrSteps;
2914
2915 // Find *-end for range attributes and calculate steps
2916 for (const auto &rangeAttr : rangeAttrs) {
2917 std::string endAttr = rangeAttr + "-end";
2918 if (pElem->hasAttribute(endAttr)) {
2919 if (attrValues.find(rangeAttr) == attrValues.end()) {
2920 throw Exception::InstrumentDefinitionError("*-end attribute without corresponding * attribute.");
2921 }
2922
2923 double from = attrValues[rangeAttr];
2924 auto to = boost::lexical_cast<double>(Strings::strip(pElem->getAttribute(endAttr)));
2925
2926 rangeAttrSteps[rangeAttr] = (to - from) / (static_cast<double>(nElements) - 1);
2927 }
2928 }
2929
2930 Poco::AutoPtr<Document> pDoc = new Document;
2931 Poco::AutoPtr<Element> pRoot = pDoc->createElement("expansion-of-locations-element");
2932 pDoc->appendChild(pRoot);
2933
2934 for (size_t i = 0; i < nElements; ++i) {
2935 Poco::AutoPtr<Element> pLoc = pDoc->createElement("location");
2936
2937 if (!name.empty()) {
2938 // Add name with appropriate numeric postfix
2939 pLoc->setAttribute("name", name + std::to_string(nameCountStart + (i * nameCountIncrement)));
2940 }
2941
2942 // Copy values of all the attributes set
2943 for (auto &attrValue : attrValues) {
2944 pLoc->setAttribute(attrValue.first, boost::lexical_cast<std::string>(attrValue.second));
2945
2946 // If attribute has a step, increase the value by the step
2947 if (rangeAttrSteps.find(attrValue.first) != rangeAttrSteps.end()) {
2948 attrValue.second += rangeAttrSteps[attrValue.first];
2949 }
2950 }
2951
2952 pRoot->appendChild(pLoc);
2953 }
2954
2955 return pDoc;
2956}
2957
2964 std::string retVal;
2965 std::string filename = getMangledName();
2966 if (!filename.empty()) {
2967 Poco::Path path(ConfigService::Instance().getVTPFileDirectory());
2968 path.makeDirectory();
2969 path.append(filename + ".vtp");
2970 retVal = path.toString();
2971 }
2972 return retVal;
2973}
2974
2985Poco::XML::Element *InstrumentDefinitionParser::getShapeElement(const Poco::XML::Element *pElem,
2986 const std::string &name) {
2987 // check if this shape element contain an element with name specified by the
2988 // 2nd function argument
2989 Poco::AutoPtr<NodeList> pNL = pElem->getElementsByTagName(name);
2990 if (pNL->length() != 1) {
2991 throw std::invalid_argument("XML element: <" + pElem->tagName() +
2992 "> must contain exactly one sub-element with name: <" + name + ">.");
2993 }
2994 auto *retVal = static_cast<Element *>(pNL->item(0));
2995 return retVal;
2996}
2997
3004 V3D retVal;
3005
3006 if (pElem->hasAttribute("R") || pElem->hasAttribute("theta") || pElem->hasAttribute("phi")) {
3007 double R = attrToDouble(pElem, "R");
3008 double theta = attrToDouble(pElem, "theta");
3009 double phi = attrToDouble(pElem, "phi");
3010
3011 retVal.spherical(R, theta, phi);
3012 } else if (pElem->hasAttribute("r") || pElem->hasAttribute("t") || pElem->hasAttribute("p"))
3013 // This is alternative way a user may specify spherical coordinates
3014 // which may be preferred in the long run to the more verbose of
3015 // using R, theta and phi.
3016 {
3017 double R = attrToDouble(pElem, "r");
3018 double theta = attrToDouble(pElem, "t");
3019 double phi = attrToDouble(pElem, "p");
3020
3021 retVal.spherical(R, theta, phi);
3022 } else {
3023
3024 double x = attrToDouble(pElem, "x");
3025 double y = attrToDouble(pElem, "y");
3026 double z = attrToDouble(pElem, "z");
3027
3028 retVal(x, y, z);
3029 }
3030
3031 return retVal;
3032}
3033
3034//-----------------------------------------------------------------------------------------------------------------------
3053 const Poco::XML::Element *pLocElem,
3054 std::map<std::string, Poco::XML::Element *> &getTypeElement,
3055 Geometry::ICompAssembly *&endAssembly) {
3056 // The location element is required to be a child of a component element.
3057 // Get
3058 // this component element
3059 Element *pCompElem = InstrumentDefinitionParser::getParentComponent(pLocElem);
3060
3061 // Create the assembly that will be appended into the parent.
3063
3064 // The newly added component is required to have a type. Find out what this
3065 // type is and find all the location elements of this type. Finally loop
3066 // over
3067 // these
3068 // location elements
3069
3070 Element *pType = getTypeElement[pCompElem->getAttribute("type")];
3071
3073 endAssembly = ass;
3074
3075 // set location for this newly added comp
3076 setLocation(ass, pLocElem, m_angleConvertConst);
3077
3078 Poco::AutoPtr<NodeList> pNL = pType->getElementsByTagName("location");
3079 if (pNL->length() == 0) {
3080 return pType->getAttribute("name");
3081 } else if (pNL->length() == 1) {
3082 const auto *pElem = static_cast<Element *>(pNL->item(0));
3083 return getShapeCoorSysComp(ass, pElem, getTypeElement, endAssembly);
3084 } else {
3086 std::string("When using <combine-components-into-one-shape> ") +
3087 " the containing component elements are not allowed to contain "
3088 "multiple nested components. See docs.mantidproject.org/concepts/InstrumentDefinitionFile.");
3089 }
3090}
3091
3092} // namespace Mantid::Geometry
std::string name
Definition Run.cpp:60
gsl_vector * tmp
double value
The value of the point.
Definition FitMW.cpp:51
std::map< DeltaEMode::Type, std::string > index
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
Definition System.h:48
double obj
the value of the quadratic function
Class for Assembly of geometric components.
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:42
void setRot(const Kernel::Quat &) override
Set the orientation Kernel::Quaternion relative to parent (if present)
void setParent(IComponent *) override
Assign a parent IComponent. Previous parent link is lost.
Kernel::V3D getPos() const override
Get the position of the IComponent. Tree structure is traverse through the.
void setPos(double, double, double) override
Set the IComponent position, x, y, z respective to parent (if present)
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.
static bool compareName(const std::string &proposedMatch)
Matches name to Structured Detector.
Class for Assembly of geometric components.
virtual int add(IComponent *)=0
Add a component to the assembly.
base class for Geometric IComponent
Definition IComponent.h:53
virtual Kernel::V3D getPos() const =0
Get the position of the IComponent. Tree structure is traverse through the.
virtual void setSideBySideViewPos(const Kernel::V2D &)=0
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> ...
void adjust(Poco::XML::Element *pElem, const 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...
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.
Kernel::V3D m_defaultFacing
Hold default facing position.
CachingOption getAppliedCachingOption() const
Get 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.
void setSideBySideViewLocation(Geometry::IComponent *comp, const Poco::XML::Element *pCompElem)
Set location (position) of comp as specified in XML side-by-side-view-location element.
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.
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>
std::string getShapeCoorSysComp(Geometry::ICompAssembly *parent, const 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 ...
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_sideBySideViewLocation_exists
Store if xml text contains side-by-side-view-location string.
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(const 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...
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.
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:51
void notice(const std::string &msg)
Logs at notice level.
Definition Logger.cpp:126
void error(const std::string &msg)
Logs at error level.
Definition Logger.cpp:108
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
void information(const std::string &msg)
Logs at information level.
Definition Logger.cpp:136
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.
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
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
Implements a 2-dimensional vector embedded in a 3D space, i.e.
Definition V2D.h:29
Class for 3D vectors.
Definition V3D.h:34
constexpr double X() const noexcept
Get x.
Definition V3D.h:238
constexpr V3D cross_prod(const V3D &v) const noexcept
Cross product (this * argument)
Definition V3D.h:284
constexpr double Y() const noexcept
Get y.
Definition V3D.h:239
void spherical(const double R, const double theta, const double phi) noexcept
Sets the vector position based on spherical coordinates.
Definition V3D.cpp:56
double angle(const V3D &) const
Angle between this and another vector.
Definition V3D.cpp:162
double norm() const noexcept
Definition V3D.h:269
constexpr double Z() const noexcept
Get z.
Definition V3D.h:240
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:419
std::string toString(const T &value)
Convert values to strings.
MANTID_KERNEL_DLL V3D normalize(V3D v)
Normalizes a V3D.
Definition V3D.h:352
Helper class which provides the Collimation Length for SANS instruments.
int32_t detid_t
Typedef for a detector ID.
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...