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#include "MantidKernel/System.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}
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 // 1. Create map
69 for (size_t iws = 0; iws < mGroupWS->getNumberHistograms(); iws++) {
70 // a) Group ID
71 auto groupid = static_cast<int>(mGroupWS->y(iws)[0]);
72
73 // b) Exist? Yes --> get handler on vector. No --> create vector and
74 auto it = groupwkspmap.find(groupid);
75 if (it == groupwkspmap.end()) {
76 std::vector<detid_t> tempvector;
77 groupwkspmap[groupid] = tempvector;
78 }
79 it = groupwkspmap.find(groupid);
80 if (it == groupwkspmap.end()) {
81 throw std::invalid_argument("Could not find group ID the after creating it in the map.");
82 }
83
84 // c) Convert workspace ID to detector ID
85 const auto &mspec = mGroupWS->getSpectrum(iws);
86 auto &detids = mspec.getDetectorIDs();
87 if (detids.size() != 1) {
88 throw std::invalid_argument("Each spectrum should only have one detector. Spectrum " +
89 std::to_string(mspec.getSpectrumNo()) + " has " + std::to_string(detids.size()) +
90 " detectors.");
91 }
92 it->second.insert(it->second.end(), detids.begin(), detids.end());
93 }
94}
95
96/*
97 * Convert
98 */
99void SaveDetectorsGrouping::convertToDetectorsRanges(std::map<int, std::vector<detid_t>> groupdetidsmap,
100 std::map<int, std::vector<detid_t>> &groupdetidrangemap) {
101
102 for (auto &groupdetids : groupdetidsmap) {
103
104 // a) Get handler of group ID and detector Id vector
105 const int groupid = groupdetids.first;
106 sort(groupdetids.second.begin(), groupdetids.second.end());
107
108 g_log.debug() << "Group " << groupid << " has " << groupdetids.second.size() << " detectors. \n";
109
110 // b) Group to ranges
111 std::vector<detid_t> detranges;
112 detid_t st = groupdetids.second[0];
113 detid_t ed = st;
114 for (size_t i = 1; i < groupdetids.second.size(); i++) {
115 detid_t detid = groupdetids.second[i];
116 if (detid == ed + 1) {
117 // consecutive
118 ed = detid;
119 } else {
120 // broken: (1) store (2) start new
121 detranges.emplace_back(st);
122 detranges.emplace_back(ed);
123
124 st = detid;
125 ed = detid;
126 }
127 } // ENDFOR detectors
128 // Complete the uncompleted
129 detranges.emplace_back(st);
130 detranges.emplace_back(ed);
131
132 // c) Save entry in output
133 groupdetidrangemap[groupid] = detranges;
134
135 } // ENDFOR GroupID
136}
137
138void SaveDetectorsGrouping::printToXML(const std::map<int, std::vector<detid_t>> &groupdetidrangemap,
139 const std::string &xmlfilename) {
140
141 // 1. Get Instrument information
142 const auto &instrument = mGroupWS->getInstrument();
143 const std::string name = instrument->getName();
144 g_log.debug() << "Instrument " << name << '\n';
145
146 // 2. Start document (XML)
147 AutoPtr<Document> pDoc = new Document;
148 AutoPtr<Element> pRoot = pDoc->createElement("detector-grouping");
149 pDoc->appendChild(pRoot);
150 pRoot->setAttribute("instrument", name);
151 pRoot->setAttribute("idf-date", instrument->getValidFromDate().toISO8601String());
152
153 // Set description if was specified by user
154 if (mGroupWS->run().hasProperty("Description")) {
155 const std::string description = mGroupWS->run().getProperty("Description")->value();
156 pRoot->setAttribute("description", description);
157 }
158
159 // 3. Append Groups
160 for (const auto &groupdetidrange : groupdetidrangemap) {
161
162 // a) Group Node
163 const int groupid = groupdetidrange.first;
164 std::stringstream sid;
165 sid << groupid;
166
167 AutoPtr<Element> pChildGroup = pDoc->createElement("group");
168 pChildGroup->setAttribute("ID", sid.str());
169 // Set name if was specified by user
170 std::string groupNameProp = "GroupName_" + sid.str();
171 if (mGroupWS->run().hasProperty(groupNameProp)) {
172 const std::string groupName = mGroupWS->run().getProperty(groupNameProp)->value();
173 pChildGroup->setAttribute("name", groupName);
174 }
175
176 pRoot->appendChild(pChildGroup);
177
178 g_log.debug() << "Group ID = " << groupid << '\n';
179
180 // b) Detector ID Child Nodes
181 std::stringstream ss;
182
183 for (size_t i = 0; i < groupdetidrange.second.size() / 2; i++) {
184 // i. Generate text value
185
186 detid_t ist = groupdetidrange.second[i * 2];
187 detid_t ied = groupdetidrange.second[i * 2 + 1];
188 // "a-b" or "a"
189 if (ist < ied) {
190 ss << ist << "-" << ied;
191 } else if (ist == ied) {
192 ss << ist;
193 } else {
194 throw std::invalid_argument("Impossible to have this sitaution!");
195 }
196 // add ","
197 if (i < groupdetidrange.second.size() / 2 - 1) {
198 ss << ",";
199 }
200
201 g_log.debug() << "Detectors: " << groupdetidrange.second[i * 2] << ", " << groupdetidrange.second[i * 2 + 1]
202 << '\n';
203 } // FOREACH Detectors Range Set
204
205 const std::string textvalue = ss.str();
206
207 g_log.debug() << "Detector IDs Node: " << textvalue << '\n';
208
209 // c) Create element
210 AutoPtr<Element> pDetid = pDoc->createElement("detids");
211 AutoPtr<Text> pText1 = pDoc->createTextNode(textvalue);
212 pDetid->appendChild(pText1);
213 pChildGroup->appendChild(pDetid);
214
215 } // FOREACH GroupID
216
217 // 4. Write file
218 DOMWriter writer;
219 writer.setNewLine("\n");
220 writer.setOptions(XMLWriter::PRETTY_PRINT);
221
222 std::ofstream ofs;
223 ofs.open(xmlfilename.c_str(), std::fstream::out);
224
225 ofs << "<?xml version=\"1.0\"?>\n";
226
227 writer.writeNode(std::cout, pDoc);
228 writer.writeNode(ofs, pDoc);
229 ofs.close();
230}
231
232} // namespace Mantid::DataHandling
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Definition: Algorithm.cpp:2076
Kernel::Logger & g_log
Definition: Algorithm.h:451
@ Save
to specify a file to write to, the file may or may not exist
Definition: FileProperty.h:49
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.
const std::string name() const override
Algorithm's name for identification.
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:114
int32_t detid_t
Typedef for a detector ID.
Definition: SpectrumInfo.h:21
std::string to_string(const wide_integer< Bits, Signed > &n)
@ Input
An input workspace.
Definition: Property.h:53