Mantid
Loading...
Searching...
No Matches
LoadBBY.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#include <algorithm>
8#include <cmath>
9#include <cstdio>
10
12#include "MantidAPI/Axis.h"
16#include "MantidAPI/Run.h"
26
27#include <boost/algorithm/string.hpp>
28#include <boost/algorithm/string/trim.hpp>
29#include <boost/math/special_functions/round.hpp>
30
31#include <Poco/AutoPtr.h>
32#include <Poco/DOM/AutoPtr.h>
33#include <Poco/DOM/DOMParser.h>
34#include <Poco/DOM/Document.h>
35#include <Poco/DOM/Element.h>
36#include <Poco/DOM/NodeFilter.h>
37#include <Poco/DOM/NodeIterator.h>
38#include <Poco/DOM/NodeList.h>
39#include <Poco/TemporaryFile.h>
40#include <Poco/Util/PropertyFileConfiguration.h>
41
42namespace Mantid::DataHandling {
43
44// register the algorithm into the AlgorithmFactory
46
47// consts
48static const size_t HISTO_BINS_X = 240;
49static const size_t HISTO_BINS_Y = 256;
50// 100 = 40 + 20 + 40
51static const size_t Progress_LoadBinFile = 48;
52static const size_t Progress_ReserveMemory = 4;
54
55static char const *const FilenameStr = "Filename";
56static char const *const MaskStr = "Mask";
57
58static char const *const FilterByTofMinStr = "FilterByTofMin";
59static char const *const FilterByTofMaxStr = "FilterByTofMax";
60
61static char const *const FilterByTimeStartStr = "FilterByTimeStart";
62static char const *const FilterByTimeStopStr = "FilterByTimeStop";
63
64using ANSTO::EventVector_pt;
65
66template <typename TYPE>
67void AddSinglePointTimeSeriesProperty(API::LogManager &logManager, const std::string &time, const std::string &name,
68 const TYPE value) {
69 // create time series property and add single value
71 p->addValue(time, value);
72
73 // add to log manager
74 logManager.addProperty(p);
75}
76
84 if (descriptor.extension() != ".tar")
85 return 0;
86
87 ANSTO::Tar::File file(descriptor.filename());
88 if (!file.good())
89 return 0;
90
91 size_t hdfFiles = 0;
92 size_t binFiles = 0;
93 const std::vector<std::string> &subFiles = file.files();
94 for (const auto &subFile : subFiles) {
95 auto len = subFile.length();
96 if ((len > 4) && (subFile.find_first_of("\\/", 0, 2) == std::string::npos)) {
97 if ((subFile.rfind(".hdf") == len - 4) && (subFile.compare(0, 3, "BBY") == 0))
98 hdfFiles++;
99 else if (subFile.rfind(".bin") == len - 4)
100 binFiles++;
101 }
102 }
103
104 return (hdfFiles == 1) && (binFiles == 1) ? 50 : 0;
105}
112 // Specify file extensions which can be associated with a specific file.
113 std::vector<std::string> exts;
114
115 // Declare the Filename algorithm property. Mandatory. Sets the path to the
116 // file to load.
117 exts.clear();
118 exts.emplace_back(".tar");
119 declareProperty(std::make_unique<API::FileProperty>(FilenameStr, "", API::FileProperty::Load, exts),
120 "The input filename of the stored data");
121
122 // mask
123 exts.clear();
124 exts.emplace_back(".xml");
125 declareProperty(std::make_unique<API::FileProperty>(MaskStr, "", API::FileProperty::OptionalLoad, exts),
126 "The input filename of the mask data");
127
128 // OutputWorkspace
130 std::make_unique<API::WorkspaceProperty<API::IEventWorkspace>>("OutputWorkspace", "", Kernel::Direction::Output));
131
132 // FilterByTofMin
134 "Optional: To exclude events that do not fall within a range "
135 "of times-of-flight. "
136 "This is the minimum accepted value in microseconds. Keep "
137 "blank to load all events.");
138
139 // FilterByTofMax
142 "Optional: To exclude events that do not fall within a range "
143 "of times-of-flight. "
144 "This is the maximum accepted value in microseconds. Keep "
145 "blank to load all events.");
146
147 // FilterByTimeStart
150 "Optional: To only include events after the provided start time, in "
151 "seconds (relative to the start of the run).");
152
153 // FilterByTimeStop
156 "Optional: To only include events before the provided stop time, in "
157 "seconds (relative to the start of the run).");
158
159 std::string grpOptional = "Filters";
164}
169 // Delete the output workspace name if it existed
170 std::string outName = getPropertyValue("OutputWorkspace");
171 if (API::AnalysisDataService::Instance().doesExist(outName))
172 API::AnalysisDataService::Instance().remove(outName);
173
174 // Get the name of the data file.
175 std::string filename = getPropertyValue(FilenameStr);
176 ANSTO::Tar::File tarFile(filename);
177 if (!tarFile.good())
178 throw std::invalid_argument("invalid BBY file");
179
180 // region of intreset
181 std::vector<bool> roi = createRoiVector(getPropertyValue(MaskStr));
182
183 double tofMinBoundary = getProperty(FilterByTofMinStr);
184 double tofMaxBoundary = getProperty(FilterByTofMaxStr);
185
186 double timeMinBoundary = getProperty(FilterByTimeStartStr);
187 double timeMaxBoundary = getProperty(FilterByTimeStopStr);
188
189 if (isEmpty(tofMaxBoundary))
190 tofMaxBoundary = std::numeric_limits<double>::infinity();
191 if (isEmpty(timeMaxBoundary))
192 timeMaxBoundary = std::numeric_limits<double>::infinity();
193
194 API::Progress prog(this, 0.0, 1.0, Progress_Total);
195 prog.doReport("creating instrument");
196
197 // create workspace
198 DataObjects::EventWorkspace_sptr eventWS = std::make_shared<DataObjects::EventWorkspace>();
199
200 eventWS->initialize(HISTO_BINS_Y * HISTO_BINS_X,
201 2, // number of TOF bin boundaries
202 1);
203
204 // create instrument
205 InstrumentInfo instrumentInfo;
206 std::map<std::string, double> logParams;
207 std::map<std::string, std::string> logStrings;
208 std::map<std::string, std::string> allParams;
209 createInstrument(tarFile, instrumentInfo, logParams, logStrings, allParams);
210
211 // set the units
212 if (instrumentInfo.is_tof)
213 eventWS->getAxis(0)->unit() = Kernel::UnitFactory::Instance().create("TOF");
214 else
215 eventWS->getAxis(0)->unit() = Kernel::UnitFactory::Instance().create("Wavelength");
216
217 eventWS->setYUnit("Counts");
218
219 // set title
220 const std::vector<std::string> &subFiles = tarFile.files();
221 const auto it = std::find_if(subFiles.cbegin(), subFiles.cend(),
222 [](const auto &subFile) { return subFile.compare(0, 3, "BBY") == 0; });
223 if (it != subFiles.cend()) {
224 std::string title = *it;
225
226 if (title.rfind(".hdf") == title.length() - 4)
227 title.resize(title.length() - 4);
228
229 if (title.rfind(".nx") == title.length() - 3)
230 title.resize(title.length() - 3);
231
232 eventWS->setTitle(title);
233 }
234
235 // load events
236 size_t numberHistograms = eventWS->getNumberHistograms();
237
238 std::vector<EventVector_pt> eventVectors(numberHistograms, nullptr);
239 std::vector<size_t> eventCounts(numberHistograms, 0);
240
241 // phase correction
242
243 double periodMaster = instrumentInfo.period_master;
244 double periodSlave = instrumentInfo.period_slave;
245 double phaseSlave = instrumentInfo.phase_slave;
246
247 double period = periodSlave;
248 double shift = -1.0 / 6.0 * periodMaster - periodSlave * phaseSlave / 360.0;
249
250 // get the start time from the file
251 Types::Core::DateAndTime startTime(instrumentInfo.start_time);
252 auto startInNanosec = startTime.totalNanoseconds();
253
254 // count total events per pixel to reserve necessary memory
255 ANSTO::EventCounter eventCounter(roi, HISTO_BINS_Y, period, shift, startInNanosec, tofMinBoundary, tofMaxBoundary,
256 timeMinBoundary, timeMaxBoundary, eventCounts);
257
258 loadEvents(prog, "loading neutron counts", tarFile, eventCounter);
259
260 // prepare event storage
261 ANSTO::ProgressTracker progTracker(prog, "creating neutron event lists", numberHistograms, Progress_ReserveMemory);
262
263 for (size_t i = 0; i != numberHistograms; ++i) {
264 DataObjects::EventList &eventList = eventWS->getSpectrum(i);
265
267 eventList.reserve(eventCounts[i]);
268
269 eventList.setDetectorID(static_cast<detid_t>(i));
270 eventList.setSpectrumNo(static_cast<detid_t>(i));
271
272 DataObjects::getEventsFrom(eventList, eventVectors[i]);
273
274 progTracker.update(i);
275 }
276 progTracker.complete();
277
278 if (instrumentInfo.is_tof) {
279 ANSTO::EventAssigner eventAssigner(roi, HISTO_BINS_Y, period, shift, startInNanosec, tofMinBoundary, tofMaxBoundary,
280 timeMinBoundary, timeMaxBoundary, eventVectors);
281
282 loadEvents(prog, "loading neutron events (TOF)", tarFile, eventAssigner);
283 } else {
284 ANSTO::EventAssignerFixedWavelength eventAssigner(roi, HISTO_BINS_Y, instrumentInfo.wavelength, period, shift,
285 startInNanosec, tofMinBoundary, tofMaxBoundary, timeMinBoundary,
286 timeMaxBoundary, eventVectors);
287
288 loadEvents(prog, "loading neutron events (Wavelength)", tarFile, eventAssigner);
289 }
290
291 auto getParam = [&allParams](const std::string &tag, double defValue) {
292 try {
293 return std::stod(allParams[tag]);
294 } catch (const std::invalid_argument &) {
295 return defValue;
296 }
297 };
298 if (instrumentInfo.is_tof) {
299 // just to make sure the bins hold it all
300 eventWS->setAllX(HistogramData::BinEdges{std::max(0.0, floor(eventCounter.tofMin())), eventCounter.tofMax() + 1});
301 } else {
302 double lof = getParam("wavelength_extn_lo", 0.95);
303 double hif = getParam("wavelength_extn_hi", 1.05);
304 eventWS->setAllX(HistogramData::BinEdges{instrumentInfo.wavelength * lof, instrumentInfo.wavelength * hif});
305 }
306
307 // count total number of masked bins
308 size_t maskedBins = std::count_if(roi.cbegin(), roi.cend(), [](bool v) { return !v; });
309
310 if (maskedBins > 0) {
311 // create list of masked bins
312 std::vector<size_t> maskIndexList(maskedBins);
313 size_t maskIndex = 0;
314
315 for (size_t i = 0; i != roi.size(); i++)
316 if (!roi[i])
317 maskIndexList[maskIndex++] = i;
318
319 auto maskingAlg = createChildAlgorithm("MaskDetectors");
320 maskingAlg->setProperty("Workspace", eventWS);
321 maskingAlg->setProperty("WorkspaceIndexList", maskIndexList);
322 maskingAlg->executeAsChildAlg();
323 }
324
325 // set log values
326 API::LogManager &logManager = eventWS->mutableRun();
327
328 auto frame_count = static_cast<int>(eventCounter.numFrames());
329
330 logManager.addProperty("filename", filename);
331 logManager.addProperty("att_pos", static_cast<int>(instrumentInfo.att_pos));
332 logManager.addProperty("frame_count", frame_count);
333 logManager.addProperty("period", period);
334
335 // currently beam monitor counts are not available, instead number of frames
336 // times period is used
337 logManager.addProperty("bm_counts", static_cast<double>(frame_count) * period /
338 1.0e6); // static_cast<double>(instrumentInfo.bm_counts)
339
340 Types::Core::time_duration duration =
341 boost::posix_time::microseconds(static_cast<boost::int64_t>(static_cast<double>(frame_count) * period));
342
343 Types::Core::DateAndTime start_time(instrumentInfo.start_time);
344 Types::Core::DateAndTime end_time(start_time + duration);
345
346 logManager.addProperty("start_time", start_time.toISO8601String());
347 logManager.addProperty("run_start", start_time.toISO8601String());
348 logManager.addProperty("end_time", end_time.toISO8601String());
349 logManager.addProperty("is_tof", instrumentInfo.is_tof);
350
351 std::string time_str = start_time.toISO8601String();
352
353 logManager.addProperty("sample_name", instrumentInfo.sample_name);
354 logManager.addProperty("sample_description", instrumentInfo.sample_description);
355 AddSinglePointTimeSeriesProperty(logManager, time_str, "wavelength", instrumentInfo.wavelength);
356 AddSinglePointTimeSeriesProperty(logManager, time_str, "master1_chopper_id", instrumentInfo.master1_chopper_id);
357 AddSinglePointTimeSeriesProperty(logManager, time_str, "master2_chopper_id", instrumentInfo.master2_chopper_id);
358
359 for (auto &x : logStrings) {
360 logManager.addProperty(x.first, x.second);
361 }
362 for (auto &x : logParams) {
363 AddSinglePointTimeSeriesProperty(logManager, time_str, x.first, x.second);
364 }
365
366 auto loadInstrumentAlg = createChildAlgorithm("LoadInstrument");
367 loadInstrumentAlg->setProperty("Workspace", eventWS);
368 loadInstrumentAlg->setPropertyValue("InstrumentName", "BILBY");
369 loadInstrumentAlg->setProperty("RewriteSpectraMap", Mantid::Kernel::OptionalBool(false));
370 loadInstrumentAlg->executeAsChildAlg();
371
372 setProperty("OutputWorkspace", eventWS);
373}
374
375// region of intreset
376std::vector<bool> LoadBBY::createRoiVector(const std::string &maskfile) {
377 std::vector<bool> result(HISTO_BINS_Y * HISTO_BINS_X, true);
378
379 if (maskfile.length() == 0)
380 return result;
381
382 std::ifstream input(maskfile.c_str());
383 if (!input.good())
384 throw std::invalid_argument("invalid mask file");
385
386 std::string line;
387 while (std::getline(input, line)) {
388 auto i0 = line.find("<detids>");
389 auto iN = line.find("</detids>");
390
391 if ((i0 != std::string::npos) && (iN != std::string::npos) && (i0 < iN)) {
392 line = line.substr(i0 + 8, iN - i0 - 8); // 8 = len("<detids>")
393 std::stringstream ss(line);
394
395 std::string item;
396 while (std::getline(ss, item, ',')) {
397 auto k = item.find('-');
398
399 size_t p0, p1;
400 if (k != std::string::npos) {
401 p0 = boost::lexical_cast<size_t>(item.substr(0, k));
402 p1 = boost::lexical_cast<size_t>(item.substr(k + 1, item.size() - k - 1));
403
404 if (p0 > p1)
405 std::swap(p0, p1);
406 } else {
407 p0 = boost::lexical_cast<size_t>(item);
408 p1 = p0;
409 }
410
411 if (p0 < result.size()) {
412 if (p1 >= result.size())
413 p1 = result.size() - 1;
414
415 while (p0 <= p1)
416 result[p0++] = false;
417 }
418 }
419 }
420 }
421
422 return result;
423}
424
425// loading instrument parameters
426void LoadBBY::loadInstrumentParameters(const Nexus::NXEntry &entry, std::map<std::string, double> &logParams,
427 std::map<std::string, std::string> &logStrings,
428 std::map<std::string, std::string> &allParams) {
429 using namespace Poco::XML;
430 std::string idfDirectory = Mantid::Kernel::ConfigService::Instance().getString("instrumentDefinition.directory");
431
432 try {
433 std::string parameterFilename = idfDirectory + "BILBY_Parameters.xml";
434 // Set up the DOM parser and parse xml file
435 DOMParser pParser;
436 Poco::AutoPtr<Poco::XML::Document> pDoc;
437 try {
438 pDoc = pParser.parse(parameterFilename);
439 } catch (...) {
440 throw Kernel::Exception::FileError("Unable to parse File:", std::move(parameterFilename));
441 }
442 NodeIterator it(pDoc, Poco::XML::NodeFilter::SHOW_ELEMENT);
443 Node *pNode = it.nextNode();
444 while (pNode) {
445 if (pNode->nodeName() == "parameter") {
446 auto pElem = dynamic_cast<Element *>(pNode);
447 std::string paramName = pElem->getAttribute("name");
448 Poco::AutoPtr<NodeList> nodeList = pElem->childNodes();
449 for (unsigned long i = 0; i < nodeList->length(); i++) {
450 auto cNode = nodeList->item(i);
451 if (cNode->nodeName() == "value") {
452 auto cElem = dynamic_cast<Poco::XML::Element *>(cNode);
453 std::string value = cElem->getAttribute("val");
454 allParams[paramName] = std::move(value);
455 }
456 }
457 }
458 pNode = it.nextNode();
459 }
460
461 auto isNumeric = [](const std::string &tag) {
462 try {
463 auto stag = boost::algorithm::trim_copy(tag);
464 size_t sz = 0;
465 auto value = std::stod(stag, &sz);
466 return sz > 0 && stag.size() == sz && std::isfinite(value);
467 } catch (const std::invalid_argument &) {
468 return false;
469 }
470 };
471
472 std::string tmpString;
473 float tmpFloat = 0.0f;
474 for (auto &x : allParams) {
475 if (x.first.find("log_") == 0) {
476 auto logTag = boost::algorithm::trim_copy(x.first.substr(4));
477 auto line = x.second;
478
479 // comma separated details
480 std::vector<std::string> details;
481 boost::split(details, line, boost::is_any_of(","));
482 if (details.size() < 3) {
483 g_log.warning() << "Invalid format for BILBY parameter " << x.first << std::endl;
484 continue;
485 }
486 auto hdfTag = boost::algorithm::trim_copy(details[0]);
487 try {
488 // extract the parameter and add it to the parameter dictionary,
489 // get the scale factor for numeric values
490 auto updateOk = false;
491 if (!hdfTag.empty()) {
492 if (isNumeric(details[1])) {
493 if (loadNXDataSet(entry, hdfTag, tmpFloat)) {
494 auto factor = std::stod(details[1]);
495 logParams[logTag] = factor * tmpFloat;
496 updateOk = true;
497 }
498 } else if (loadNXString(entry, hdfTag, tmpString)) {
499 logStrings[logTag] = tmpString;
500 updateOk = true;
501 }
502 }
503 if (!updateOk) {
504 // if the hdf is missing the tag then add the default if
505 // it is provided
506 auto defValue = boost::algorithm::trim_copy(details[2]);
507 if (!defValue.empty()) {
508 if (isNumeric(defValue))
509 logParams[logTag] = std::stod(defValue);
510 else
511 logStrings[logTag] = std::move(defValue);
512 if (!hdfTag.empty())
513 g_log.warning() << "Cannot find hdf parameter " << hdfTag << ", using default.\n";
514 }
515 }
516 } catch (const std::invalid_argument &) {
517 g_log.warning() << "Invalid format for BILBY parameter " << x.first << std::endl;
518 }
519 }
520 }
521 } catch (std::exception &ex) {
522 g_log.warning() << "Failed to load instrument with error: " << ex.what()
523 << ". The current facility may not be fully "
524 "supported.\n";
525 }
526}
527
528// instrument creation
530 std::map<std::string, double> &logParams, std::map<std::string, std::string> &logStrings,
531 std::map<std::string, std::string> &allParams) {
532
533 const double toMeters = 1.0 / 1000;
534
535 instrumentInfo.sample_name = "UNKNOWN";
536 instrumentInfo.sample_description = "UNKNOWN";
537 instrumentInfo.start_time = "2000-01-01T00:00:00";
538
539 instrumentInfo.bm_counts = 0;
540 instrumentInfo.att_pos = 0;
541 instrumentInfo.master1_chopper_id = -1;
542 instrumentInfo.master2_chopper_id = -1;
543
544 instrumentInfo.is_tof = true;
545 instrumentInfo.wavelength = 0.0;
546
547 instrumentInfo.period_master = 0.0;
548 instrumentInfo.period_slave = (1.0 / 50.0) * 1.0e6;
549 instrumentInfo.phase_slave = 0.0;
550
551 // extract log and hdf file
552 const std::vector<std::string> &files = tarFile.files();
553 auto file_it = std::find_if(files.cbegin(), files.cend(),
554 [](const std::string &file) { return file.rfind(".hdf") == file.length() - 4; });
555 if (file_it != files.end()) {
556 tarFile.select(file_it->c_str());
557 // extract hdf file into tmp file
558 Poco::TemporaryFile hdfFile;
559 std::shared_ptr<FILE> handle(fopen(hdfFile.path().c_str(), "wb"), fclose);
560 if (handle) {
561 // copy content
562 char buffer[4096];
563 size_t bytesRead;
564 while (0 != (bytesRead = tarFile.read(buffer, sizeof(buffer))))
565 fwrite(buffer, bytesRead, 1, handle.get());
566 handle.reset();
567
568 Nexus::NXRoot root(hdfFile.path());
569 Nexus::NXEntry entry = root.openFirstEntry();
570
571 float tmp_float = 0.0f;
572 int32_t tmp_int32 = 0;
573 std::string tmp_str;
574
575 if (loadNXDataSet(entry, "monitor/bm1_counts", tmp_int32))
576 instrumentInfo.bm_counts = tmp_int32;
577 if (loadNXDataSet(entry, "instrument/att_pos", tmp_float))
578 instrumentInfo.att_pos = boost::math::iround(tmp_float); // [1.0, 2.0, ..., 5.0]
579
580 if (loadNXString(entry, "sample/name", tmp_str))
581 instrumentInfo.sample_name = tmp_str;
582 if (loadNXString(entry, "sample/description", tmp_str))
583 instrumentInfo.sample_description = tmp_str;
584 if (loadNXString(entry, "start_time", tmp_str))
585 instrumentInfo.start_time = tmp_str;
586
587 if (loadNXDataSet(entry, "instrument/master1_chopper_id", tmp_int32))
588 instrumentInfo.master1_chopper_id = tmp_int32;
589 if (loadNXDataSet(entry, "instrument/master2_chopper_id", tmp_int32))
590 instrumentInfo.master2_chopper_id = tmp_int32;
591
592 if (loadNXString(entry, "instrument/detector/frame_source", tmp_str))
593 instrumentInfo.is_tof = tmp_str == "EXTERNAL";
594 if (loadNXDataSet(entry, "instrument/nvs067/lambda", tmp_float))
595 instrumentInfo.wavelength = tmp_float;
596
597 if (loadNXDataSet(entry, "instrument/master_chopper_freq", tmp_float) && (tmp_float > 0.0f))
598 instrumentInfo.period_master = 1.0 / tmp_float * 1.0e6;
599 if (loadNXDataSet(entry, "instrument/t0_chopper_freq", tmp_float) && (tmp_float > 0.0f))
600 instrumentInfo.period_slave = 1.0 / tmp_float * 1.0e6;
601 if (loadNXDataSet(entry, "instrument/t0_chopper_phase", tmp_float))
602 instrumentInfo.phase_slave = tmp_float < 999.0 ? tmp_float : 0.0;
603
604 loadInstrumentParameters(entry, logParams, logStrings, allParams);
605
606 // Ltof_det_value is not present for monochromatic data so check
607 // and replace with default
608 auto findLtof = logParams.find("Ltof_det_value");
609 if (findLtof != logParams.end()) {
610 logParams["L1_chopper_value"] = logParams["Ltof_det_value"] - logParams["L2_det_value"];
611 } else {
612 logParams["L1_chopper_value"] = 18.4726;
613 g_log.warning() << "Cannot recover parameter 'L1_chopper_value'"
614 << ", using default.\n";
615 }
616 }
617 }
618
619 // patching
620 file_it = std::find(files.cbegin(), files.cend(), "History.log");
621 if (file_it != files.cend()) {
622 tarFile.select(file_it->c_str());
623 std::string logContent;
624 logContent.resize(tarFile.selected_size());
625 tarFile.read(&logContent[0], logContent.size());
626 std::istringstream data(logContent);
627 Poco::AutoPtr<Poco::Util::PropertyFileConfiguration> conf(new Poco::Util::PropertyFileConfiguration(data));
628
629 if (conf->hasProperty("Bm1Counts"))
630 instrumentInfo.bm_counts = conf->getInt("Bm1Counts");
631 if (conf->hasProperty("AttPos"))
632 instrumentInfo.att_pos = boost::math::iround(conf->getDouble("AttPos"));
633
634 if (conf->hasProperty("SampleName"))
635 instrumentInfo.sample_name = conf->getString("SampleName");
636
637 if (conf->hasProperty("MasterChopperFreq")) {
638 auto tmp = conf->getDouble("MasterChopperFreq");
639 if (tmp > 0.0f)
640 instrumentInfo.period_master = 1.0 / tmp * 1.0e6;
641 }
642 if (conf->hasProperty("T0ChopperFreq")) {
643 auto tmp = conf->getDouble("T0ChopperFreq");
644 if (tmp > 0.0f)
645 instrumentInfo.period_slave = 1.0 / tmp * 1.0e6;
646 }
647 if (conf->hasProperty("T0ChopperPhase")) {
648 auto tmp = conf->getDouble("T0ChopperPhase");
649 instrumentInfo.phase_slave = tmp < 999.0 ? tmp : 0.0;
650 }
651
652 if (conf->hasProperty("FrameSource"))
653 instrumentInfo.is_tof = conf->getString("FrameSource") == "EXTERNAL";
654 if (conf->hasProperty("Wavelength"))
655 instrumentInfo.wavelength = conf->getDouble("Wavelength");
656
657 if (conf->hasProperty("SampleAperture"))
658 logParams["sample_aperture"] = conf->getDouble("SampleAperture");
659 if (conf->hasProperty("SourceAperture"))
660 logParams["source_aperture"] = conf->getDouble("SourceAperture");
661 if (conf->hasProperty("L1"))
662 logParams["L1_source_value"] = conf->getDouble("L1") * toMeters;
663 if (conf->hasProperty("LTofDet"))
664 logParams["L1_chopper_value"] = conf->getDouble("LTofDet") * toMeters - logParams["L2_det_value"];
665 if (conf->hasProperty("L2Det"))
666 logParams["L2_det_value"] = conf->getDouble("L2Det") * toMeters;
667
668 if (conf->hasProperty("L2CurtainL"))
669 logParams["L2_curtainl_value"] = conf->getDouble("L2CurtainL") * toMeters;
670 if (conf->hasProperty("L2CurtainR"))
671 logParams["L2_curtainr_value"] = conf->getDouble("L2CurtainR") * toMeters;
672 if (conf->hasProperty("L2CurtainU"))
673 logParams["L2_curtainu_value"] = conf->getDouble("L2CurtainU") * toMeters;
674 if (conf->hasProperty("L2CurtainD"))
675 logParams["L2_curtaind_value"] = conf->getDouble("L2CurtainD") * toMeters;
676
677 if (conf->hasProperty("CurtainL"))
678 logParams["D_curtainl_value"] = conf->getDouble("CurtainL") * toMeters;
679 if (conf->hasProperty("CurtainR"))
680 logParams["D_curtainr_value"] = conf->getDouble("CurtainR") * toMeters;
681 if (conf->hasProperty("CurtainU"))
682 logParams["D_curtainu_value"] = conf->getDouble("CurtainU") * toMeters;
683 if (conf->hasProperty("CurtainD"))
684 logParams["D_curtaind_value"] = conf->getDouble("CurtainD") * toMeters;
685 }
686}
687
688// load nx dataset
689template <class T> bool LoadBBY::loadNXDataSet(const Nexus::NXEntry &entry, const std::string &address, T &value) {
690 try {
691 Nexus::NXDataSetTyped<T> dataSet = entry.openNXDataSet<T>(address);
692 dataSet.load();
693
694 value = *dataSet();
695 return true;
696 } catch (std::runtime_error &) {
697 return false;
698 }
699}
700bool LoadBBY::loadNXString(const Nexus::NXEntry &entry, const std::string &address, std::string &value) {
701 try {
702 value = entry.getString(address);
703 return true;
704 } catch (const std::runtime_error &) {
705 return false;
706 }
707}
708
709// read counts/events from binary file
710template <class EventProcessor>
711void LoadBBY::loadEvents(API::Progress &prog, const char *progMsg, ANSTO::Tar::File &tarFile,
712 EventProcessor &eventProcessor) {
713 prog.doReport(progMsg);
714
715 // select bin file
716 int64_t fileSize = 0;
717 const std::vector<std::string> &files = tarFile.files();
718 const auto found = std::find_if(files.cbegin(), files.cend(),
719 [](const auto &file) { return file.rfind(".bin") == file.length() - 4; });
720 if (found != files.cend()) {
721 tarFile.select(found->c_str());
722 fileSize = tarFile.selected_size();
723 }
724
725 // for progress notifications
726 ANSTO::ProgressTracker progTracker(prog, progMsg, fileSize, Progress_LoadBinFile);
727
728 uint32_t x = 0; // 9 bits [0-239] tube number
729 uint32_t y = 0; // 8 bits [0-255] position along tube
730
731 // uint v = 0; // 0 bits [ ]
732 // uint w = 0; // 0 bits [ ] energy
733 uint32_t dt = 0;
734 double tof = 0.0;
735
736 if ((fileSize == 0) || !tarFile.skip(128))
737 return;
738
739 int state = 0;
740 int invalidEvents = 0;
741 uint32_t c;
742 while ((c = static_cast<uint32_t>(tarFile.read_byte())) != static_cast<uint32_t>(-1)) {
743
744 bool event_ended = false;
745 switch (state) {
746 case 0:
747 x = (c & 0xFF) >> 0; // set bit 1-8
748 break;
749
750 case 1:
751 x |= (c & 0x01) << 8; // set bit 9
752 y = (c & 0xFE) >> 1; // set bit 1-7
753 break;
754
755 case 2:
756 event_ended = (c & 0xC0) != 0xC0;
757 if (!event_ended)
758 c &= 0x3F;
759
760 y |= (c & 0x01) << 7; // set bit 8
761 dt = (c & 0xFE) >> 1; // set bit 1-5(7)
762 break;
763
764 case 3:
765 case 4:
766 case 5:
767 case 6:
768 case 7:
769 event_ended = (c & 0xC0) != 0xC0;
770 if (!event_ended)
771 c &= 0x3F;
772
773 // state is either 3, 4, 5, 6 or 7
774 dt |= (c & 0xFF) << (5 + 6 * (state - 3)); // set bit 6...
775 break;
776 }
777 state++;
778
779 if (event_ended || (state == 8)) {
780 state = 0;
781
782 if ((x == 0) && (y == 0) && (dt == 0xFFFFFFFF)) {
783 tof = 0.0;
784 eventProcessor.newFrame();
785 } else if ((x >= HISTO_BINS_X) || (y >= HISTO_BINS_Y)) {
786 // cannot ignore the dt contrbition even if the event
787 // is out of bounds as it is used in the encoding process
788 tof += static_cast<int>(dt) * 0.1;
789 invalidEvents++;
790 } else {
791 // conversion from 100 nanoseconds to 1 microsecond
792 tof += static_cast<int>(dt) * 0.1;
793
794 eventProcessor.addEvent(x, y, tof);
795 }
796
797 progTracker.update(tarFile.selected_position());
798 }
799 }
800 if (invalidEvents > 0) {
801 g_log.warning() << "BILBY loader dropped " << invalidEvents << " invalid event(s)" << std::endl;
802 }
803}
804
805} // namespace Mantid::DataHandling
std::string name
Definition Run.cpp:60
gsl_vector * tmp
double value
The value of the point.
Definition FitMW.cpp:51
#define DECLARE_FILELOADER_ALGORITHM(classname)
DECLARE_FILELOADER_ALGORITHM should be used in place of the standard DECLARE_ALGORITHM macro when wri...
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.
virtual std::shared_ptr< Algorithm > createChildAlgorithm(const std::string &name, const double startProgress=-1., const double endProgress=-1., const bool enableLogging=true, const int &version=-1)
Create a Child Algorithm.
Kernel::Logger & g_log
Definition Algorithm.h:422
static bool isEmpty(const NumT toCheck)
checks that the value was not set by users, uses the value in empty double/int.
@ OptionalLoad
to specify a file to read but the file doesn't have to exist
@ Load
allowed here which will be passed to the algorithm
void setDetectorID(const detid_t detID)
Clear the list of detector IDs, then add one.
Definition ISpectrum.cpp:84
void setSpectrumNo(specnum_t num)
Sets the spectrum number of this spectrum.
This class contains the information about the log entries.
Definition LogManager.h:44
void addProperty(Kernel::Property *prop, bool overwrite=false)
Add data to the object in the form of a property.
Definition LogManager.h:91
Helper class for reporting progress from algorithms.
Definition Progress.h:25
void doReport(const std::string &msg="") override
Actually do the reporting, without changing the loop counter.
Definition Progress.cpp:70
A property class for workspaces.
void addEvent(size_t x, size_t y, double tof)
helper class to keep track of progress
size_t read(void *dst, size_t size)
const std::vector< std::string > & files() const
void loadInstrumentParameters(const Nexus::NXEntry &entry, std::map< std::string, double > &logParams, std::map< std::string, std::string > &logStrings, std::map< std::string, std::string > &allParams)
Definition LoadBBY.cpp:426
bool loadNXString(const Nexus::NXEntry &entry, const std::string &address, std::string &value)
Definition LoadBBY.cpp:700
static std::vector< bool > createRoiVector(const std::string &maskfile)
Definition LoadBBY.cpp:376
void init() override
Initialise the algorithm.
Definition LoadBBY.cpp:111
void createInstrument(ANSTO::Tar::File &tarFile, InstrumentInfo &instrumentInfo, std::map< std::string, double > &logParams, std::map< std::string, std::string > &logStrings, std::map< std::string, std::string > &allParams)
Definition LoadBBY.cpp:529
static bool loadNXDataSet(const Nexus::NXEntry &entry, const std::string &address, T &value)
Definition LoadBBY.cpp:689
void loadEvents(API::Progress &prog, const char *progMsg, ANSTO::Tar::File &tarFile, EventProcessor &eventProcessor)
Definition LoadBBY.cpp:711
int confidence(Kernel::FileDescriptor &descriptor) const override
Return the confidence value that this algorithm can load the file.
Definition LoadBBY.cpp:83
void exec() override
Execute the algorithm.
Definition LoadBBY.cpp:168
A class for holding :
Definition EventList.h:57
void setSortOrder(const EventSortType order) const
Manually set the event list sort order value.
void reserve(size_t num) override
Reserve a certain number of entries in event list of the specified eventType.
Records the filename and the description of failure.
Definition Exception.h:98
Defines a wrapper around an open file.
const std::string & filename() const
Access the filename.
const std::string & extension() const
Access the file extension.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void setPropertyGroup(const std::string &name, const std::string &group)
Set the group for a given property.
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
OptionalBool : Tri-state bool.
The concrete, templated class for properties.
A specialised Property class for holding a series of time-value pairs.
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.
std::vector< Types::Event::TofEvent > * EventVector_pt
pointer to the vector of events
static char const *const FilenameStr
Definition LoadBBY.cpp:55
static char const *const FilterByTofMaxStr
Definition LoadBBY.cpp:59
static const size_t HISTO_BINS_X
Definition LoadBBY.cpp:48
static const size_t HISTO_BINS_Y
Definition LoadBBY.cpp:49
static const size_t Progress_LoadBinFile
Definition LoadBBY.cpp:51
static char const *const FilterByTofMinStr
Definition LoadBBY.cpp:58
void AddSinglePointTimeSeriesProperty(API::LogManager &logManager, const std::string &time, const std::string &name, const TYPE value)
Definition LoadBBY.cpp:67
static char const *const MaskStr
Definition LoadBBY.cpp:56
static char const *const FilterByTimeStartStr
Definition LoadBBY.cpp:61
static const size_t Progress_Total
Definition LoadBBY.cpp:53
static char const *const FilterByTimeStopStr
Definition LoadBBY.cpp:62
static const size_t Progress_ReserveMemory
Definition LoadBBY.cpp:52
DLLExport void getEventsFrom(EventList &el, std::vector< Types::Event::TofEvent > *&events)
std::shared_ptr< EventWorkspace > EventWorkspace_sptr
shared pointer to the EventWorkspace class
int32_t detid_t
Typedef for a detector ID.
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition EmptyValues.h:42
STL namespace.
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54