Mantid
Loading...
Searching...
No Matches
SaveDetectorsGrouping.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 +
8
10#include "MantidAPI/ISpectrum.h"
11#include "MantidAPI/Run.h"
13
14#include <Poco/DOM/AutoPtr.h>
15#include <Poco/DOM/DOMWriter.h>
16#include <Poco/DOM/Document.h>
17#include <Poco/DOM/Element.h>
18#include <Poco/DOM/Text.h>
19#include <Poco/XML/XMLWriter.h>
20
21#include <algorithm>
22#include <fstream>
23#include <sstream>
24
25using namespace Mantid::Kernel;
26using namespace Mantid::API;
27using namespace Poco::XML;
28
29namespace Mantid::DataHandling {
30
32
33
35 declareProperty(
36 std::make_unique<API::WorkspaceProperty<DataObjects::GroupingWorkspace>>("InputWorkspace", "", Direction::Input),
37 "GroupingWorkspace to output to XML file (GroupingWorkspace)");
38 declareProperty(std::make_unique<FileProperty>("OutputFile", "", FileProperty::Save, ".xml"),
39 "File to save the detectors mask in XML format");
40 declareProperty("SaveUngroupedDetectors", true, "Whether to write out group number 0, the ungrouped group.");
41}
42
45
46 // 1. Get Input
47 const std::string xmlfilename = this->getProperty("OutputFile");
48 mGroupWS = this->getProperty("InputWorkspace");
49
50 // 2. Create Map(group ID, workspace-index vector)
51 std::map<int, std::vector<detid_t>> groupIDwkspIDMap;
52 this->createGroupDetectorIDMap(groupIDwkspIDMap);
53 g_log.debug() << "Size of map = " << groupIDwkspIDMap.size() << '\n';
54
55 // 3. Convert to detectors ranges
56 std::map<int, std::vector<detid_t>> groupIDdetectorRangeMap;
57 this->convertToDetectorsRanges(groupIDwkspIDMap, groupIDdetectorRangeMap);
58
59 // 4. Print out
60 this->printToXML(groupIDdetectorRangeMap, xmlfilename);
61}
62
63/*
64 * From GroupingWorkspace to generate a map.
65 * Each entry, key = GroupID, value = vector of workspace index
66 */
67void SaveDetectorsGrouping::createGroupDetectorIDMap(std::map<int, std::vector<detid_t>> &groupwkspmap) {
68
69 const bool excludeZero = !getProperty("SaveUngroupedDetectors");
70
71 // 1. Create map
72 for (size_t iws = 0; iws < mGroupWS->getNumberHistograms(); iws++) {
73 // a) Group ID
74 auto groupid = static_cast<int>(mGroupWS->y(iws)[0]);
75
76 if (excludeZero && groupid == 0)
77 continue;
78
79 // b) Exist? Yes --> get handler on vector. No --> create vector and
80 auto it = groupwkspmap.find(groupid);
81 if (it == groupwkspmap.end()) {
82 std::vector<detid_t> tempvector;
83 groupwkspmap[groupid] = tempvector;
84 }
85 it = groupwkspmap.find(groupid);
86 if (it == groupwkspmap.end()) {
87 throw std::invalid_argument("Could not find group ID the after creating it in the map.");
88 }
89
90 // c) Convert workspace ID to detector ID
91 const auto &mspec = mGroupWS->getSpectrum(iws);
92 auto &detids = mspec.getDetectorIDs();
93 if (detids.size() != 1) {
94 throw std::invalid_argument("Each spectrum should only have one detector. Spectrum " +
95 std::to_string(mspec.getSpectrumNo()) + " has " + std::to_string(detids.size()) +
96 " detectors.");
97 }
98 it->second.insert(it->second.end(), detids.begin(), detids.end());
99 }
100}
101
102/*
103 * Convert
104 */
105void SaveDetectorsGrouping::convertToDetectorsRanges(std::map<int, std::vector<detid_t>> groupdetidsmap,
106 std::map<int, std::vector<detid_t>> &groupdetidrangemap) {
107
108 for (auto &groupdetids : groupdetidsmap) {
109
110 // a) Get handler of group ID and detector Id vector
111 const int groupid = groupdetids.first;
112 sort(groupdetids.second.begin(), groupdetids.second.end());
113
114 g_log.debug() << "Group " << groupid << " has " << groupdetids.second.size() << " detectors. \n";
115
116 // b) Group to ranges
117 std::vector<detid_t> detranges;
118 detid_t st = groupdetids.second[0];
119 detid_t ed = st;
120 for (size_t i = 1; i < groupdetids.second.size(); i++) {
121 detid_t detid = groupdetids.second[i];
122 if (detid == ed + 1) {
123 // consecutive
124 ed = detid;
125 } else {
126 // broken: (1) store (2) start new
127 detranges.emplace_back(st);
128 detranges.emplace_back(ed);
129
130 st = detid;
131 ed = detid;
132 }
133 } // ENDFOR detectors
134 // Complete the uncompleted
135 detranges.emplace_back(st);
136 detranges.emplace_back(ed);
137
138 // c) Save entry in output
139 groupdetidrangemap[groupid] = detranges;
140
141 } // ENDFOR GroupID
142}
143
144void SaveDetectorsGrouping::printToXML(const std::map<int, std::vector<detid_t>> &groupdetidrangemap,
145 const std::string &xmlfilename) {
146
147 // 1. Get Instrument information
148 const auto &instrument = mGroupWS->getInstrument();
149 const std::string instrumentName = instrument->getName();
150 g_log.debug() << "Instrument " << instrumentName << '\n';
151
152 // 2. Start document (XML)
153 AutoPtr<Document> pDoc = new Document;
154 AutoPtr<Element> pRoot = pDoc->createElement("detector-grouping");
155 pDoc->appendChild(pRoot);
156 pRoot->setAttribute("instrument", instrumentName);
157 pRoot->setAttribute("idf-date", mGroupWS->instrumentMetadata().validFromDate().toISO8601String());
158
159 // Set description if was specified by user
160 if (mGroupWS->run().hasProperty("Description")) {
161 const std::string description = mGroupWS->run().getProperty("Description")->value();
162 pRoot->setAttribute("description", description);
163 }
164
165 // 3. Append Groups
166 for (const auto &groupdetidrange : groupdetidrangemap) {
167
168 // a) Group Node
169 const int groupid = groupdetidrange.first;
170 std::stringstream sid;
171 sid << groupid;
172
173 AutoPtr<Element> pChildGroup = pDoc->createElement("group");
174 pChildGroup->setAttribute("ID", sid.str());
175 // Set name if was specified by user
176 std::string groupNameProp = "GroupName_" + sid.str();
177 if (mGroupWS->run().hasProperty(groupNameProp)) {
178 const std::string groupName = mGroupWS->run().getProperty(groupNameProp)->value();
179 pChildGroup->setAttribute("name", groupName);
180 }
181
182 pRoot->appendChild(pChildGroup);
183
184 g_log.debug() << "Group ID = " << groupid << '\n';
185
186 // b) Detector ID Child Nodes
187 std::stringstream ss;
188
189 for (size_t i = 0; i < groupdetidrange.second.size() / 2; i++) {
190 // i. Generate text value
191
192 detid_t ist = groupdetidrange.second[i * 2];
193 detid_t ied = groupdetidrange.second[i * 2 + 1];
194 // "a-b" or "a"
195 if (ist < ied) {
196 ss << ist << "-" << ied;
197 } else if (ist == ied) {
198 ss << ist;
199 } else {
200 throw std::invalid_argument("Impossible to have this sitaution!");
201 }
202 // add ","
203 if (i < groupdetidrange.second.size() / 2 - 1) {
204 ss << ",";
205 }
206
207 g_log.debug() << "Detectors: " << groupdetidrange.second[i * 2] << ", " << groupdetidrange.second[i * 2 + 1]
208 << '\n';
209 } // FOREACH Detectors Range Set
210
211 const std::string textvalue = ss.str();
212
213 g_log.debug() << "Detector IDs Node: " << textvalue << '\n';
214
215 // c) Create element
216 AutoPtr<Element> pDetid = pDoc->createElement("detids");
217 AutoPtr<Text> pText1 = pDoc->createTextNode(textvalue);
218 pDetid->appendChild(pText1);
219 pChildGroup->appendChild(pDetid);
220
221 } // FOREACH GroupID
222
223 // 4. Write file
224 DOMWriter writer;
225 writer.setNewLine("\n");
226 writer.setOptions(XMLWriter::PRETTY_PRINT);
227
228 std::ofstream ofs;
229 ofs.open(xmlfilename.c_str(), std::fstream::out);
230
231 ofs << "<?xml version=\"1.0\"?>\n";
232
233 writer.writeNode(ofs, pDoc);
234 ofs.close();
235}
236
237} // namespace Mantid::DataHandling
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:542
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Kernel::Logger & g_log
Definition Algorithm.h:423
@ Save
to specify a file to write to, the file may or may not exist
A property class for workspaces.
SaveDetectorsGrouping : TODO: DESCRIPTION.
void convertToDetectorsRanges(std::map< int, std::vector< detid_t > > groupdetidsmap, std::map< int, std::vector< detid_t > > &groupdetidrangemap)
Convert vector of detector ID to range of Detector ID.
void createGroupDetectorIDMap(std::map< int, std::vector< detid_t > > &groupwkspmap)
Create map for GroupID – vector<detector ID>
DataObjects::GroupingWorkspace_const_sptr mGroupWS
void exec() override
Main body to execute algorithm.
void printToXML(const std::map< int, std::vector< detid_t > > &groupdetidrangemap, const std::string &xmlfilename)
Print Grouping to XML file.
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
int32_t detid_t
Typedef for a detector ID.
std::string to_string(const wide_integer< Bits, Signed > &n)
@ Input
An input workspace.
Definition Property.h:53