Mantid
Loading...
Searching...
No Matches
GroupingLoader.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 +
15#include <Poco/DOM/DOMParser.h>
16#include <Poco/DOM/Document.h>
17#include <Poco/DOM/NodeList.h>
18#include <memory>
19#include <utility>
20
21using namespace Poco::XML;
22
23namespace Mantid::API {
24
25//----------------------------------------------------------------------------------------------
29GroupingLoader::GroupingLoader(Geometry::Instrument_const_sptr instrument) : m_instrument(std::move(instrument)) {}
30
35GroupingLoader::GroupingLoader(Geometry::Instrument_const_sptr instrument, std::string mainFieldDirection)
36 : m_instrument(std::move(instrument)), m_mainFieldDirection(std::move(mainFieldDirection)) {}
37
38//----------------------------------------------------------------------------------------------
42
47std::shared_ptr<Grouping> GroupingLoader::getGroupingFromIDF() const {
48 std::string parameterName = "Default grouping file";
49 auto loadedGrouping = std::make_shared<Grouping>();
50
51 // Special case for MUSR or CHRONUS, because it has two possible groupings
52 if (m_instrument->getName() == "MUSR" || m_instrument->getName() == "CHRONUS") {
53 parameterName.append(" - " + m_mainFieldDirection);
54 }
55
56 std::vector<std::string> groupingFiles = m_instrument->getStringParameter(parameterName);
57
58 if (groupingFiles.size() == 1) {
59 const std::string groupingFile = groupingFiles[0];
60
61 // Get search directory for XML instrument definition files (IDFs)
62 std::string directoryName = Kernel::ConfigService::Instance().getInstrumentDirectory();
63
64 loadGroupingFromXML(directoryName + groupingFile, *loadedGrouping);
65 } else {
66 throw std::runtime_error("Multiple groupings specified for the instrument");
67 }
68 return loadedGrouping;
69}
70
77void GroupingLoader::loadGroupingFromXML(const std::string &filename, Grouping &grouping) {
78 // Set up the DOM parser and parse xml file
79 DOMParser pParser;
80 Poco::AutoPtr<Document> pDoc;
81 try {
82 pDoc = pParser.parse(filename);
83 } catch (...) {
84 throw Mantid::Kernel::Exception::FileError("Unable to parse File", filename);
85 }
86
87 // Get pointer to root element
88 Element *pRootElem = pDoc->documentElement();
89 if (!pRootElem->hasChildNodes())
90 throw Mantid::Kernel::Exception::FileError("No root element in XML grouping file", filename);
91
92 // Parse information for groups
93 Poco::AutoPtr<NodeList> groups = pRootElem->getElementsByTagName("group");
94 if (groups->length() == 0)
95 throw Mantid::Kernel::Exception::FileError("No groups specified in XML grouping file", filename);
96
97 // Resize vectors
98 grouping.groupNames.resize(groups->length());
99 grouping.groups.resize(groups->length());
100
101 for (size_t ig = 0; ig < groups->length(); ig++) {
102 auto *pGroupElem = static_cast<Element *>(groups->item(static_cast<long>(ig)));
103
104 if (!pGroupElem->hasAttribute("name"))
105 throw Mantid::Kernel::Exception::FileError("Group element without name", filename);
106
107 grouping.groupNames[ig] = pGroupElem->getAttribute("name");
108
109 Element *idlistElement = pGroupElem->getChildElement("ids");
110 if (!idlistElement)
111 throw Mantid::Kernel::Exception::FileError("Group element without <ids>", filename);
112
113 grouping.groups[ig] = idlistElement->getAttribute("val");
114 }
115
116 // Parse information for pairs
117 Poco::AutoPtr<NodeList> pairs = pRootElem->getElementsByTagName("pair");
118
119 // Resize vectors
120 grouping.pairNames.resize(pairs->length());
121 grouping.pairs.resize(pairs->length());
122 grouping.pairAlphas.resize(pairs->length());
123
124 for (size_t ip = 0; ip < pairs->length(); ip++) {
125 auto *pPairElem = static_cast<Element *>(pairs->item(static_cast<long>(ip)));
126
127 if (!pPairElem->hasAttribute("name"))
128 throw Mantid::Kernel::Exception::FileError("Pair element without name", filename);
129
130 grouping.pairNames[ip] = pPairElem->getAttribute("name");
131
132 size_t fwdGroupId, bwdGroupId; // Ids of forward/backward groups
133
134 // Try to get id of the first group
135 if (Element *fwdElement = pPairElem->getChildElement("forward-group")) {
136 if (!fwdElement->hasAttribute("val"))
137 throw Mantid::Kernel::Exception::FileError("Pair forward-group without <val>", filename);
138
139 // Find the group with the given name
140 auto it = std::find(grouping.groupNames.begin(), grouping.groupNames.end(), fwdElement->getAttribute("val"));
141
142 if (it == grouping.groupNames.end())
143 throw Mantid::Kernel::Exception::FileError("Pair forward-group name not recognized", filename);
144
145 // Get index of the iterator
146 fwdGroupId = it - grouping.groupNames.begin();
147 } else {
148 throw Mantid::Kernel::Exception::FileError("Pair element without <forward-group>", filename);
149 }
150
151 // Try to get id of the second group
152 if (Element *bwdElement = pPairElem->getChildElement("backward-group")) {
153 if (!bwdElement->hasAttribute("val"))
154 throw Mantid::Kernel::Exception::FileError("Pair backward-group without <val>", filename);
155
156 // Find the group with the given name
157 auto it = std::find(grouping.groupNames.begin(), grouping.groupNames.end(), bwdElement->getAttribute("val"));
158
159 if (it == grouping.groupNames.end())
160 throw Mantid::Kernel::Exception::FileError("Pair backward-group name not recognized", filename);
161
162 // Get index of the iterator
163 bwdGroupId = it - grouping.groupNames.begin();
164 } else {
165 throw Mantid::Kernel::Exception::FileError("Pair element without <backward-group>", filename);
166 }
167
168 grouping.pairs[ip] = std::make_pair(fwdGroupId, bwdGroupId);
169
170 // Try to get alpha element
171 if (Element *aElement = pPairElem->getChildElement("alpha")) {
172 if (!aElement->hasAttribute("val"))
173 throw Mantid::Kernel::Exception::FileError("Pair alpha element with no <val>", filename);
174
175 try // ... to convert value to double
176 {
177 grouping.pairAlphas[ip] = boost::lexical_cast<double>(aElement->getAttribute("val"));
178 }
179 catch (boost::bad_lexical_cast &) {
180 throw Mantid::Kernel::Exception::FileError("Pair alpha value is not a number", filename);
181 }
182 }
183 // If alpha element not there, default it to 1.0
184 else {
185 grouping.pairAlphas[ip] = 1.0;
186 }
187 }
188
189 // Try to get description
190 if (pRootElem->hasAttribute("description")) {
191 grouping.description = pRootElem->getAttribute("description");
192 }
193
194 // Try to get default group/pair name
195 if (Element *defaultElement = pRootElem->getChildElement("default")) {
196 if (!defaultElement->hasAttribute("name"))
197 throw Mantid::Kernel::Exception::FileError("Default element with no <name>", filename);
198
199 grouping.defaultName = defaultElement->getAttribute("name");
200 }
201}
202
207std::shared_ptr<Grouping> GroupingLoader::getDummyGrouping() {
208 // Group with all the detectors
209 std::ostringstream all;
210 all << "1-" << m_instrument->getNumberDetectors();
211
212 auto dummyGrouping = std::make_shared<Mantid::API::Grouping>();
213 dummyGrouping->description = "Dummy grouping";
214 dummyGrouping->groupNames.emplace_back("all");
215 dummyGrouping->groups.emplace_back(all.str());
216 return dummyGrouping;
217}
218
219//----------------------------------------------------------------------------------------------
225 for (size_t row = 0; row < table->rowCount(); ++row) {
226 std::vector<int> detectors = table->cell<std::vector<int>>(row, 0);
227
228 // toString() expects the sequence to be sorted
229 std::sort(detectors.begin(), detectors.end());
230
231 // Convert to a range string, i.e. 1-5,6-8,9
232 std::string detectorRange = Kernel::Strings::toString(detectors);
233
234 this->groupNames.emplace_back(std::to_string(row + 1));
235 this->groups.emplace_back(detectorRange);
236 }
237
238 // If we have 2 groups only - create a longitudinal pair
239 if (this->groups.size() == 2) {
240 this->pairNames.emplace_back("long");
241 this->pairAlphas.emplace_back(1.0);
242 this->pairs.emplace_back(0, 1);
243 }
244}
245
253 auto newTable =
254 std::dynamic_pointer_cast<ITableWorkspace>(WorkspaceFactory::Instance().createTable("TableWorkspace"));
255
256 newTable->addColumn("vector_int", "Detectors");
257
258 for (const auto &group : this->groups) {
259 TableRow newRow = newTable->appendRow();
260 newRow << Kernel::Strings::parseRange(group);
261 }
262
263 return newTable;
264}
265
269Grouping::~Grouping() = default;
270
271} // namespace Mantid::API
static void loadGroupingFromXML(const std::string &filename, Grouping &grouping)
Loads grouping from the XML file specified.
std::shared_ptr< Grouping > getDummyGrouping()
Returns a "dummy" grouping of a single group with all the detectors in it.
std::shared_ptr< Grouping > getGroupingFromIDF() const
Load the grouping from the instrument's IDF.
const std::string m_mainFieldDirection
Orientation of instrument (e.g. for MUSR)
const Geometry::Instrument_const_sptr m_instrument
Instrument to load grouping from.
virtual ~GroupingLoader()
Destructor.
GroupingLoader(Geometry::Instrument_const_sptr instrument)
Constructor without field direction.
Structure to represent grouping information.
Grouping()=default
Default constructor.
std::vector< std::pair< size_t, size_t > > pairs
std::vector< std::string > groupNames
~Grouping()
Destructor.
std::vector< double > pairAlphas
std::vector< std::string > pairNames
std::vector< std::string > groups
ITableWorkspace_sptr toTable() const
Convert to grouping table.
TableRow represents a row in a TableWorkspace.
Definition: TableRow.h:39
Records the filename and the description of failure.
Definition: Exception.h:98
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
std::shared_ptr< ITableWorkspace > ITableWorkspace_sptr
shared pointer to Mantid::API::ITableWorkspace
std::shared_ptr< const Instrument > Instrument_const_sptr
Shared pointer to an const instrument object.
MANTID_KERNEL_DLL std::vector< int > parseRange(const std::string &str, const std::string &elemSep=",", const std::string &rangeSep="-")
Parses a number range, e.g.
Definition: Strings.cpp:1071
std::string toString(const T &value)
Convert a number to a string.
Definition: Strings.cpp:703
STL namespace.
std::string to_string(const wide_integer< Bits, Signed > &n)