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