Mantid
Loading...
Searching...
No Matches
CreateDummyCalFile.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//----------------------------------------------------------------------
8// Includes
9//----------------------------------------------------------------------
16
17#include <Poco/DOM/DOMParser.h>
18#include <Poco/DOM/Document.h>
19#include <Poco/DOM/Element.h>
20#include <boost/algorithm/string/detail/classification.hpp>
21#include <boost/algorithm/string/split.hpp>
22#include <fstream>
23#include <queue>
24
25namespace Mantid::Algorithms {
26
27// Register the class into the algorithm factory
28DECLARE_ALGORITHM(CreateDummyCalFile)
29
30using namespace Kernel;
31using namespace API;
32using namespace Geometry;
33using namespace DataObjects;
34
39 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("InputWorkspace", "", Direction::Input),
40 "The workspace containing the geometry to be calibrated.");
41 declareProperty(std::make_unique<FileProperty>("CalFilename", "", FileProperty::Save, ".cal"),
42 "The name of the output [[CalFile]]");
43}
44
53 // Get the input workspace
54 MatrixWorkspace_const_sptr inputW = getProperty("InputWorkspace");
55 if (!inputW)
56 throw std::invalid_argument("No InputWorkspace");
57
58 // Get some stuff from the input workspace
59 Instrument_const_sptr inst = inputW->getInstrument();
60 if (!inst)
61 throw std::invalid_argument("The InputWorkspace does not have an instrument definition");
62
63 std::string instname = inst->getName();
64
65 // Get the names of groups
66 groups = instname;
67
68 // Split the names of the group and insert in a vector, throw if group empty
69 std::vector<std::string> vgroups;
70 boost::split(vgroups, instname, boost::algorithm::detail::is_any_ofF<char>(",/*"));
71 if (vgroups.empty()) {
72 g_log.error("Could not determine group names. Group names should be "
73 "separated by / or ,");
74 throw std::runtime_error("Could not determine group names. Group names "
75 "should be separated by / or ,");
76 }
77
78 // Assign incremental number to each group
79 std::map<std::string, int> group_map;
80 int index = 0;
81 for (std::vector<std::string>::const_iterator it = vgroups.begin(); it != vgroups.end(); ++it)
82 group_map[(*it)] = ++index;
83
84 // Not needed anymore
85 vgroups.clear();
86
87 // Find Detectors that belong to groups
88 using sptr_ICompAss = std::shared_ptr<const Geometry::ICompAssembly>;
89 using sptr_IComp = std::shared_ptr<const Geometry::IComponent>;
90 using sptr_IDet = std::shared_ptr<const Geometry::IDetector>;
91 std::queue<std::pair<sptr_ICompAss, int>> assemblies;
92 sptr_ICompAss current = std::dynamic_pointer_cast<const Geometry::ICompAssembly>(inst);
93 sptr_IDet currentDet;
94 sptr_IComp currentIComp;
95 sptr_ICompAss currentchild;
96
97 int top_group, child_group;
98
99 if (current.get()) {
100 top_group = group_map[current->getName()]; // Return 0 if not in map
101 assemblies.emplace(current, top_group);
102 }
103
104 std::string filename = getProperty("CalFilename");
105
106 int number = 0;
107 Progress prog(this, 0.0, 0.8, assemblies.size());
108 while (!assemblies.empty()) // Travel the tree from the instrument point
109 {
110 current = assemblies.front().first;
111 top_group = assemblies.front().second;
112 assemblies.pop();
113 int nchilds = current->nelements();
114 if (nchilds != 0) {
115 for (int i = 0; i < nchilds; ++i) {
116 currentIComp = (*(current.get()))[i]; // Get child
117 currentDet = std::dynamic_pointer_cast<const Geometry::IDetector>(currentIComp);
118 if (currentDet.get()) // Is detector
119 {
120 instrcalib[number++] = std::make_pair(currentDet->getID(), top_group);
121 } else // Is an assembly, push in the queue
122 {
123 currentchild = std::dynamic_pointer_cast<const Geometry::ICompAssembly>(currentIComp);
124 if (currentchild.get()) {
125 child_group = group_map[currentchild->getName()];
126 if (child_group == 0)
127 child_group = top_group;
128 assemblies.emplace(currentchild, child_group);
129 }
130 }
131 }
132 }
133 prog.report();
134 }
135 // Write the results in a file
136 // Plan to overwrite file, so do not check if it exists
137 const bool overwrite = false;
138 saveGroupingFile(filename, overwrite);
139 progress(0.2);
140}
141
142bool CreateDummyCalFile::groupingFileDoesExist(const std::string &filename) const {
143 std::ifstream file(filename.c_str());
144 // Check if the file already exists
145 if (!file)
146 return false;
147 file.close();
148 std::ostringstream mess;
149 mess << "Calibration file " << filename << " already exist. Only grouping will be modified";
150 g_log.information(mess.str());
151 return true;
152}
153
155void CreateDummyCalFile::saveGroupingFile(const std::string &filename, bool overwrite) const {
156 std::ostringstream message;
157 std::fstream outfile;
158 std::fstream infile;
159 if (!overwrite) // Open the file directly
160 {
161 outfile.open(filename.c_str(), std::ios::out);
162 if (!outfile.is_open()) {
163 message << "Can't open Calibration File: " << filename;
164 g_log.error(message.str());
165 throw std::runtime_error(message.str());
166 }
167 } else {
168 infile.open(filename.c_str(), std::ios::in);
169 std::string newfilename = filename + "2";
170 outfile.open(newfilename.c_str(), std::ios::out);
171 if (!infile.is_open()) {
172 message << "Can't open input Calibration File: " << filename;
173 g_log.error(message.str());
174 throw std::runtime_error(message.str());
175 }
176 if (!outfile.is_open()) {
177 message << "Can't open new Calibration File: " << newfilename;
178 g_log.error(message.str());
179 throw std::runtime_error(message.str());
180 }
181 }
182
183 // Write the headers
184 writeHeaders(outfile, filename, overwrite);
185
186 if (overwrite) {
187 int number, udet, select, group;
188 double offset;
189
190 std::string str;
191 while (getline(infile, str)) {
192 if (str.empty() || str[0] == '#') // Skip the headers
193 continue;
194 std::istringstream istr(str);
195 istr >> number >> udet >> offset >> select >> group;
196 auto it = instrcalib.find(udet);
197 if (it == instrcalib.end()) // Not found, don't assign a group
198 group = 0;
199 else
200 group = ((*it).second).second; // If found then assign new group
201 // write to file
202 writeCalEntry(outfile, number, udet, offset, select, group);
203 }
204 } else //
205 {
206 for (const auto &value : instrcalib)
207 writeCalEntry(outfile, value.first, (value.second).first, 0.0, 1, (value.second).second);
208 }
209
210 // Closing
211 outfile.close();
212 if (overwrite)
213 infile.close();
214}
215
217void CreateDummyCalFile::writeCalEntry(std::ostream &os, int number, int udet, double offset, int select, int group) {
218 os << std::fixed << std::setw(9) << number << std::fixed << std::setw(15) << udet << std::fixed
219 << std::setprecision(7) << std::setw(15) << offset << std::fixed << std::setw(8) << select << std::fixed
220 << std::setw(8) << group << "\n";
221}
222
224void CreateDummyCalFile::writeHeaders(std::ostream &os, const std::string &filename, bool overwrite) const {
225 os << "# Diffraction focusing calibration file created by Mantid"
226 << "\n";
227 os << "# Detectors have been grouped using assembly names:" << groups << "\n";
228 if (overwrite) {
229 os << "# Template file " << filename << " has been used"
230 << "\n";
231 os << "# Only grouping has been changed, offset from template file have "
232 "been copied"
233 << "\n";
234 } else
235 os << "# No template file, all offsets set to 0.0 and select to 1"
236 << "\n";
237
238 os << "# Number UDET offset select group"
239 << "\n";
240}
241
242} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
double value
The value of the point.
Definition: FitMW.cpp:51
std::map< DeltaEMode::Type, std::string > index
Definition: DeltaEMode.cpp:19
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
Definition: Algorithm.cpp:1913
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
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
Definition: Algorithm.cpp:231
@ Save
to specify a file to write to, the file may or may not exist
Definition: FileProperty.h:49
Helper class for reporting progress from algorithms.
Definition: Progress.h:25
A property class for workspaces.
void init() override
Initialisation code.
void exec() override
Execution code.
static void writeCalEntry(std::ostream &os, int number, int udet, double offset, int select, int group)
Writes a single calibration line to the output file.
instrcalmap instrcalib
Calibration map used if the *.cal file exist.
void saveGroupingFile(const std::string &, bool overwrite) const
Creates and saves the output file.
std::string groups
The names of the groups.
void writeHeaders(std::ostream &os, const std::string &filename, bool overwrite) const
Writes out the header to the output file.
bool groupingFileDoesExist(const std::string &filename) const
Determine whether the grouping file already exists.
void error(const std::string &msg)
Logs at error level.
Definition: Logger.cpp:77
void information(const std::string &msg)
Logs at information level.
Definition: Logger.cpp:105
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
Definition: ProgressBase.h:51
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
std::shared_ptr< const Instrument > Instrument_const_sptr
Shared pointer to an const instrument object.
@ Input
An input workspace.
Definition: Property.h:53