Mantid
Loading...
Searching...
No Matches
PatchBBY.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 +
12
13#include <Poco/String.h>
14#include <Poco/TemporaryFile.h>
15
16namespace Mantid::DataHandling {
17
18// register the algorithm into the AlgorithmFactory
19DECLARE_ALGORITHM(PatchBBY)
20
26
28 const char *const Group;
29 const char *const Name;
30 TYPE const Type;
31};
32
33// consts
34static char const *const HistoryStr = "History.log";
35static char const *const FilenameStr = "Filename";
36static char const *const EXTERNAL = "EXTERNAL";
37static char const *const INTERNAL = "INTERNAL";
39 {"Calibration", "Bm1Counts", TYPE_INT},
40 {"Calibration", "AttPos", TYPE_DBL},
41
42 {"Velocity Selector and Choppers", "MasterChopperFreq", TYPE_DBL},
43 {"Velocity Selector and Choppers", "T0ChopperFreq", TYPE_DBL},
44 {"Velocity Selector and Choppers", "T0ChopperPhase", TYPE_DBL},
45 {"Velocity Selector and Choppers", "FrameSource", TYPE_STR},
46 {"Velocity Selector and Choppers", "Wavelength", TYPE_DBL},
47
48 {"Geometry Setup", "L1", TYPE_DBL},
49 {"Geometry Setup", "LTofDet", TYPE_DBL},
50 {"Geometry Setup", "L2Det", TYPE_DBL},
51
52 {"Geometry Setup", "L2CurtainL", TYPE_DBL},
53 {"Geometry Setup", "L2CurtainR", TYPE_DBL},
54 {"Geometry Setup", "L2CurtainU", TYPE_DBL},
55 {"Geometry Setup", "L2CurtainD", TYPE_DBL},
56
57 {"Geometry Setup", "CurtainL", TYPE_DBL},
58 {"Geometry Setup", "CurtainR", TYPE_DBL},
59 {"Geometry Setup", "CurtainU", TYPE_DBL},
60 {"Geometry Setup", "CurtainD", TYPE_DBL},
61};
62
63// load nx dataset
64template <class T> bool loadNXDataSet(Nexus::NXEntry &entry, const std::string &address, T &value) {
65 try {
66 Nexus::NXDataSetTyped<T> dataSet = entry.openNXDataSet<T>(address);
67 dataSet.load();
68
69 value = *dataSet();
70 return true;
71 } catch (std::runtime_error &) {
72 return false;
73 }
74}
75bool loadNXString(const Nexus::NXEntry &entry, const std::string &address, std::string &value) {
76 try {
77 value = entry.getString(address);
78 return true;
79 } catch (std::runtime_error &) {
80 return false;
81 }
82}
83
90 // Specify file extensions which can be associated with a specific file.
91 std::vector<std::string> exts;
92
93 // Declare the Filename algorithm property. Mandatory. Sets the path to the
94 // file to load.
95 exts.clear();
96 exts.emplace_back(".tar");
97 declareProperty(std::make_unique<API::FileProperty>(FilenameStr, "", API::FileProperty::Load, exts),
98 "The filename of the stored data to be patched");
99
100 // patchable properties
101 for (auto itr = std::begin(PatchableProperties); itr != std::end(PatchableProperties); ++itr) {
102 switch (itr->Type) {
103 case TYPE_INT:
106 "Optional");
107 break;
108
109 case TYPE_DBL:
112 "Optional");
113 break;
114
115 case TYPE_STR:
116 if (std::strcmp(itr->Name, "FrameSource") == 0) {
117 std::array<std::string, 3> keys = {{"", EXTERNAL, INTERNAL}};
120 itr->Name, "", std::make_shared<Kernel::ListValidator<std::string>>(keys), Kernel::Direction::Input),
121 "Optional");
122 }
123 break;
124 }
125
126 setPropertyGroup(itr->Name, itr->Group);
127 }
128
130 "Optional");
131}
136 // get the name of the data file
137 std::string filename = getPropertyValue(FilenameStr);
138 ANSTO::Tar::File tarFile(filename);
139 if (!tarFile.good())
140 throw std::invalid_argument("invalid BBY file");
141
142 size_t hdfFiles = 0;
143 size_t binFiles = 0;
144 size_t logFiles = 0;
145 size_t logSize = 0;
146
147 // open file (and select hisotry file if it exists)
148 const std::vector<std::string> &files = tarFile.files();
149 for (auto itr = files.begin(); itr != files.end(); ++itr) {
150 auto len = itr->length();
151
152 if ((len > 4) && (itr->find_first_of("\\/", 0, 2) == std::string::npos)) {
153 if ((itr->compare(0, 3, "BBY") == 0) && (itr->rfind(".hdf") == len - 4))
154 hdfFiles++;
155 else if (itr->rfind(".bin") == len - 4)
156 binFiles++;
157 else if (*itr == HistoryStr) {
158 if (std::distance(itr, files.end()) != 1)
159 throw std::invalid_argument("invalid BBY file (history has to be at the end)");
160
161 logFiles++;
162 tarFile.select(itr->c_str());
163 logSize = tarFile.selected_size();
164 }
165 }
166 }
167
168 // check if it's valid
169 if ((hdfFiles != 1) || (binFiles != 1) || (logFiles > 1))
170 throw std::invalid_argument("invalid BBY file");
171
172 // read existing history
173 std::string logContent;
174 if (logFiles != 0) {
175 logContent.resize(logSize);
176 tarFile.read(&logContent[0], logSize);
177 }
178
179 // create new content
180 std::ostringstream logContentNewBuffer;
181 int tmp_int;
182 double tmp_dbl;
183 std::string tmp_str;
184 for (auto itr = std::begin(PatchableProperties); itr != std::end(PatchableProperties); ++itr) {
185 auto property_value = getProperty(itr->Name);
186
187 // if (!isEmpty(property_value))
188 switch (itr->Type) {
189 case TYPE_INT:
190 tmp_int = property_value;
191 if (tmp_int != EMPTY_INT())
192 logContentNewBuffer << itr->Name << " = " << tmp_int << '\n';
193 break;
194
195 case TYPE_DBL:
196 tmp_dbl = property_value;
197 if (tmp_dbl != EMPTY_DBL())
198 logContentNewBuffer << itr->Name << " = " << tmp_dbl << '\n';
199 break;
200
201 case TYPE_STR:
202 if (std::strcmp(itr->Name, "FrameSource") != 0)
203 throw std::invalid_argument(std::string("not implemented: ") + itr->Name);
204
205 tmp_str = static_cast<std::string>(property_value);
206 if (!tmp_str.empty()) {
207 if (Poco::icompare(tmp_str, EXTERNAL) == 0)
208 logContentNewBuffer << itr->Name << " = " << EXTERNAL << '\n';
209 else if (Poco::icompare(tmp_str, INTERNAL) == 0)
210 logContentNewBuffer << itr->Name << " = " << INTERNAL << '\n';
211 else
212 throw std::invalid_argument("invalid: FrameSource");
213 }
214 break;
215 }
216 }
217
218 // load original values from hdf
219 bool reset = getProperty("Reset");
220 if (reset) {
221 const auto file_it = std::find_if(files.cbegin(), files.cend(),
222 [](const std::string &file) { return file.rfind(".hdf") == file.length() - 4; });
223 if (file_it != files.end()) {
224 tarFile.select(file_it->c_str());
225 // extract hdf file into tmp file
226 Poco::TemporaryFile hdfFile;
227 std::shared_ptr<FILE> handle(fopen(hdfFile.path().c_str(), "wb"), fclose);
228 if (handle) {
229 // copy content
230 char buffer[4096];
231 size_t bytesRead;
232 while (0 != (bytesRead = tarFile.read(buffer, sizeof(buffer))))
233 fwrite(buffer, bytesRead, 1, handle.get());
234 handle.reset();
235
236 Nexus::NXRoot root(hdfFile.path());
237 Nexus::NXEntry entry = root.openFirstEntry();
238
239 float tmp_float;
240 int32_t tmp_int32 = 0;
241
242 if (loadNXDataSet(entry, "monitor/bm1_counts", tmp_int32))
243 logContentNewBuffer << "Bm1Counts = " << tmp_int32 << '\n';
244 if (loadNXDataSet(entry, "instrument/att_pos", tmp_float))
245 logContentNewBuffer << "AttPos = " << tmp_float << '\n';
246
247 if (loadNXString(entry, "instrument/detector/frame_source", tmp_str))
248 logContentNewBuffer << "FrameSource = " << tmp_str << '\n';
249 if (loadNXDataSet(entry, "instrument/nvs067/lambda", tmp_float))
250 logContentNewBuffer << "Wavelength = " << tmp_float << '\n';
251
252 if (loadNXDataSet(entry, "instrument/master_chopper_freq", tmp_float))
253 logContentNewBuffer << "MasterChopperFreq = " << tmp_float << '\n';
254 if (loadNXDataSet(entry, "instrument/t0_chopper_freq", tmp_float))
255 logContentNewBuffer << "T0ChopperFreq = " << tmp_float << '\n';
256 if (loadNXDataSet(entry, "instrument/t0_chopper_phase", tmp_float))
257 logContentNewBuffer << "T0ChopperPhase = " << (tmp_float < 999.0 ? tmp_float : 0.0) << '\n';
258
259 if (loadNXDataSet(entry, "instrument/L1", tmp_float))
260 logContentNewBuffer << "L1 = " << tmp_float << '\n';
261 if (loadNXDataSet(entry, "instrument/Ltof_det", tmp_float))
262 logContentNewBuffer << "LTofDet = " << tmp_float << '\n';
263 if (loadNXDataSet(entry, "instrument/L2_det", tmp_float))
264 logContentNewBuffer << "L2Det = " << tmp_float << '\n';
265
266 if (loadNXDataSet(entry, "instrument/L2_curtainl", tmp_float))
267 logContentNewBuffer << "L2CurtainL = " << tmp_float << '\n';
268 if (loadNXDataSet(entry, "instrument/L2_curtainr", tmp_float))
269 logContentNewBuffer << "L2CurtainR = " << tmp_float << '\n';
270 if (loadNXDataSet(entry, "instrument/L2_curtainu", tmp_float))
271 logContentNewBuffer << "L2CurtainU = " << tmp_float << '\n';
272 if (loadNXDataSet(entry, "instrument/L2_curtaind", tmp_float))
273 logContentNewBuffer << "L2CurtainD = " << tmp_float << '\n';
274
275 if (loadNXDataSet(entry, "instrument/detector/curtainl", tmp_float))
276 logContentNewBuffer << "CurtainL = " << tmp_float << '\n';
277 if (loadNXDataSet(entry, "instrument/detector/curtainr", tmp_float))
278 logContentNewBuffer << "CurtainR = " << tmp_float << '\n';
279 if (loadNXDataSet(entry, "instrument/detector/curtainu", tmp_float))
280 logContentNewBuffer << "CurtainU = " << tmp_float << '\n';
281 if (loadNXDataSet(entry, "instrument/detector/curtaind", tmp_float))
282 logContentNewBuffer << "CurtainD = " << tmp_float << '\n';
283 }
284 }
285 }
286
287 std::string logContentNew = logContentNewBuffer.str();
288 if (logContentNew.empty())
289 throw std::invalid_argument("nothing to patch");
290
291 // merge log content
292 logContent.append(logContentNew);
293
294 // append patches to file
295 tarFile.close();
296 if (!ANSTO::Tar::File::append(filename, HistoryStr, logContent.c_str(), logContent.size()))
297 throw std::runtime_error("unable to patch");
298}
299
300} // namespace Mantid::DataHandling
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
double value
The value of the point.
Definition FitMW.cpp:51
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
@ Load
allowed here which will be passed to the algorithm
size_t read(void *dst, size_t size)
const std::vector< std::string > & files() const
static bool append(const std::string &path, const std::string &name, const void *buffer, size_t size)
void init() override
Initialise the algorithm.
Definition PatchBBY.cpp:89
void exec() override
Execute the algorithm.
Definition PatchBBY.cpp:135
void setPropertyGroup(const std::string &name, const std::string &group)
Set the group for a given property.
ListValidator is a validator that requires the value of a property to be one of a defined list of pos...
The concrete, templated class for properties.
std::string getString(const std::string &name) const
Returns a string.
NXDataSetTyped< T > openNXDataSet(const std::string &name) const
Templated method for creating datasets.
Templated class implementation of NXDataSet.
void load()
Read all of the datablock in.
Implements NXentry Nexus class.
Implements NXroot Nexus class.
NXEntry openFirstEntry()
Open the first NXentry in the file.
static char const *const FilenameStr
Definition LoadBBY.cpp:55
static char const *const HistoryStr
Definition PatchBBY.cpp:34
bool loadNXDataSet(Nexus::NXEntry &entry, const std::string &address, T &value)
Definition PatchBBY.cpp:64
bool loadNXString(const Nexus::NXEntry &entry, const std::string &address, std::string &value)
Definition PatchBBY.cpp:75
static char const *const EXTERNAL
Definition PatchBBY.cpp:36
static char const *const INTERNAL
Definition PatchBBY.cpp:37
static PropertyInfo PatchableProperties[]
Definition PatchBBY.cpp:38
constexpr int EMPTY_INT() noexcept
Returns what we consider an "empty" integer within a property.
Definition EmptyValues.h:24
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition EmptyValues.h:42
@ Input
An input workspace.
Definition Property.h:53