Mantid
Loading...
Searching...
No Matches
CreateCalFileByNames.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 <boost/algorithm/string/detail/classification.hpp>
18#include <boost/algorithm/string/split.hpp>
19
20#include <fstream>
21#include <queue>
22
23using namespace Mantid::API;
24using namespace Mantid::Kernel;
25
26namespace Mantid::Algorithms {
27
28// Register the class into the algorithm factory
29DECLARE_ALGORITHM(CreateCalFileByNames)
30
31using namespace Kernel;
33using API::Progress;
35
40 declareProperty(std::make_unique<WorkspaceProperty<>>("InstrumentWorkspace", "", Direction::Input,
41 std::make_shared<InstrumentValidator>()),
42 "A workspace that contains a reference to the instrument of interest. "
43 "You can use LoadEmptyInstrument to create such a workspace.");
44 declareProperty(std::make_unique<FileProperty>("GroupingFileName", "", FileProperty::Save, ".cal"),
45 "The name of the output CalFile");
46 declareProperty("GroupNames", "",
47 "A string of the instrument component names to use as separate groups. "
48 "/ or , can be used to separate multiple groups.");
49}
50
60 MatrixWorkspace_const_sptr ws = getProperty("InstrumentWorkspace");
61
62 // Get the instrument.
63 Instrument_const_sptr inst = ws->getInstrument();
64
65 // Get the names of groups
66 std::string groupsname = getProperty("GroupNames");
67 groups = groupsname;
68
69 // Split the names of the group and insert in a vector, throw if group empty
70 std::vector<std::string> vgroups;
71 boost::split(vgroups, groupsname, boost::algorithm::detail::is_any_ofF<char>(",/*"));
72 if (vgroups.empty()) {
73 g_log.error("Could not determine group names. Group names should be "
74 "separated by / or ,");
75 throw std::runtime_error("Could not determine group names. Group names "
76 "should be separated by / or ,");
77 }
78
79 // Assign incremental number to each group
80 std::map<std::string, int> group_map;
81 int index = 0;
82 for (auto &vgroup : vgroups) {
83 boost::trim(vgroup);
84 group_map[vgroup] = ++index;
85 }
86
87 // Not needed anymore
88 vgroups.clear();
89
90 // Find Detectors that belong to groups
91 using sptr_ICompAss = std::shared_ptr<const Geometry::ICompAssembly>;
92 using sptr_IComp = std::shared_ptr<const Geometry::IComponent>;
93 using sptr_IDet = std::shared_ptr<const Geometry::IDetector>;
94 std::queue<std::pair<sptr_ICompAss, int>> assemblies;
95 sptr_ICompAss current = std::dynamic_pointer_cast<const Geometry::ICompAssembly>(inst);
96 sptr_IDet currentDet;
97 sptr_IComp currentIComp;
98 sptr_ICompAss currentchild;
99
100 int top_group, child_group;
101
102 if (current.get()) {
103 top_group = group_map[current->getName()]; // Return 0 if not in map
104 assemblies.emplace(current, top_group);
105 }
106
107 std::string filename = getProperty("GroupingFilename");
108
109 // Check if a template cal file is given
110 bool overwrite = groupingFileDoesExist(filename);
111
112 int number = 0;
113 Progress prog(this, 0.0, 0.8, assemblies.size());
114 while (!assemblies.empty()) // Travel the tree from the instrument point
115 {
116 current = assemblies.front().first;
117 top_group = assemblies.front().second;
118 assemblies.pop();
119 int nchilds = current->nelements();
120 if (nchilds != 0) {
121 for (int i = 0; i < nchilds; ++i) {
122 currentIComp = (*(current.get()))[i]; // Get child
123 currentDet = std::dynamic_pointer_cast<const Geometry::IDetector>(currentIComp);
124 if (currentDet.get()) // Is detector
125 {
126 if (overwrite) // Map will contains udet as the key
127 instrcalib[currentDet->getID()] = std::make_pair(number++, top_group);
128 else // Map will contains the entry number as the key
129 instrcalib[number++] = std::make_pair(currentDet->getID(), top_group);
130 } else // Is an assembly, push in the queue
131 {
132 currentchild = std::dynamic_pointer_cast<const Geometry::ICompAssembly>(currentIComp);
133 if (currentchild.get()) {
134 child_group = group_map[currentchild->getName()];
135 if (child_group == 0)
136 child_group = top_group;
137 assemblies.emplace(currentchild, child_group);
138 }
139 }
140 }
141 }
142 prog.report();
143 }
144 // Write the results in a file
145 saveGroupingFile(filename, overwrite);
146 progress(0.2);
147}
148
149bool CreateCalFileByNames::groupingFileDoesExist(const std::string &filename) const {
150 std::ifstream file(filename.c_str());
151 // Check if the file already exists
152 if (!file)
153 return false;
154 file.close();
155 std::ostringstream mess;
156 mess << "Calibration file " << filename << " already exist. Only grouping will be modified";
157 g_log.information(mess.str());
158 return true;
159}
160
162void CreateCalFileByNames::saveGroupingFile(const std::string &filename, bool overwrite) const {
163 std::ostringstream message;
164 std::fstream outfile;
165 std::fstream infile;
166 if (!overwrite) // Open the file directly
167 {
168 outfile.open(filename.c_str(), std::ios::out);
169 if (!outfile.is_open()) {
170 message << "Can't open Calibration File: " << filename;
171 g_log.error(message.str());
172 throw std::runtime_error(message.str());
173 }
174 } else {
175 infile.open(filename.c_str(), std::ios::in);
176 std::string newfilename = filename + "2";
177 outfile.open(newfilename.c_str(), std::ios::out);
178 if (!infile.is_open()) {
179 message << "Can't open input Calibration File: " << filename;
180 g_log.error(message.str());
181 throw std::runtime_error(message.str());
182 }
183 if (!outfile.is_open()) {
184 message << "Can't open new Calibration File: " << newfilename;
185 g_log.error(message.str());
186 throw std::runtime_error(message.str());
187 }
188 }
189
190 // Write the headers
191 writeHeaders(outfile, filename, overwrite);
192
193 if (overwrite) {
194 int number, udet, select, group;
195 double offset;
196
197 std::string str;
198 while (getline(infile, str)) {
199 if (str.empty() || str[0] == '#') // Skip the headers
200 continue;
201 std::istringstream istr(str);
202 istr >> number >> udet >> offset >> select >> group;
203 auto it = instrcalib.find(udet);
204 if (it == instrcalib.end()) // Not found, don't assign a group
205 group = 0;
206 else
207 group = ((*it).second).second; // If found then assign new group
208 // write out
209 writeCalEntry(outfile, number, udet, offset, select, group);
210 }
211 } else //
212 {
213 for (const auto &value : instrcalib)
214 writeCalEntry(outfile, value.first, (value.second).first, 0.0, 1, (value.second).second);
215 }
216
217 // Closing
218 outfile.close();
219 if (overwrite)
220 infile.close();
221}
222
224void CreateCalFileByNames::writeCalEntry(std::ostream &os, int number, int udet, double offset, int select, int group) {
225 os << std::fixed << std::setw(9) << number << std::fixed << std::setw(15) << udet << std::fixed
226 << std::setprecision(7) << std::setw(15) << offset << std::fixed << std::setw(8) << select << std::fixed
227 << std::setw(8) << group << "\n";
228}
229
231void CreateCalFileByNames::writeHeaders(std::ostream &os, const std::string &filename, bool overwrite) const {
232 os << "# Diffraction focusing calibration file created by Mantid"
233 << "\n";
234 os << "# Detectors have been grouped using assembly names:" << groups << "\n";
235 if (overwrite) {
236 os << "# Template file " << filename << " has been used"
237 << "\n";
238 os << "# Only grouping has been changed, offset from template file have "
239 "been copied"
240 << "\n";
241 } else
242 os << "# No template file, all offsets set to 0.0 and select to 1"
243 << "\n";
244
245 os << "# Number UDET offset select group"
246 << "\n";
247}
248
249} // 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
A specialized class for dealing with file properties.
Definition: FileProperty.h:42
@ 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 saveGroupingFile(const std::string &, bool overwrite) const
Creates and saves the output file.
void writeHeaders(std::ostream &os, const std::string &filename, bool overwrite) const
Writes out the header to the output file.
std::string groups
The names of the groups.
bool groupingFileDoesExist(const std::string &filename) const
Determine whether the grouping file already exists.
instrcalmap instrcalib
Calibration map used if the *.cal file exist.
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.
void init() override
Initialisation code.
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