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