80 auto const &allEntries = descriptor->getAllEntries();
82 auto const iterSDS = allEntries.find(
"SDS");
83 if (iterSDS == allEntries.cend()) {
84 throw std::runtime_error(
"Could not find any entries.");
86 auto const &entries = iterSDS->second;
88 const char *attributeName =
"long_name";
89 std::vector<std::string> eventEntries;
90 std::map<std::string, std::vector<std::string>> histogramEntries;
91 for (
auto &entry : entries) {
92 if (entry.find(
"/entry1/data") == std::string::npos) {
97 const auto groupAddress =
"/" +
Strings::join(parts.cbegin(), parts.cend() - 1,
"/");
98 const auto groupName = *(parts.cend() - 2);
99 const auto datasetName = parts.back();
101 if (groupName ==
"content_nxs")
104 const H5::Group
group = file.openGroup(groupAddress);
105 const H5::DataSet dataset =
group.openDataSet(datasetName);
111 std::string nameAttrValue;
113 if (nameAttrValue.find(
"Neutron_ID") != std::string::npos) {
114 eventEntries.emplace_back(groupAddress);
115 }
else if (histogramEntries.find(groupAddress) == histogramEntries.cend()) {
116 histogramEntries[groupAddress] = {datasetName};
118 histogramEntries[groupAddress].emplace_back(datasetName);
122 std::vector<std::string> scatteringWSNames;
123 if (!eventEntries.empty()) {
130 scatteringWSNames.insert(scatteringWSNames.end(), histoWSNames.cbegin(), histoWSNames.cend());
158 const H5::H5File &file) {
161 std::vector<std::string> scatteringWSNames;
164 const bool errorBarsSetTo1 =
getProperty(
"ErrorBarsSetTo1");
170 const double progressFractionInitial = 0.1;
171 Progress progInitial(
this, 0.0, progressFractionInitial, reports);
173 std::string instrumentXML;
174 progInitial.
report(
"Loading instrument");
176 const H5::Group
group = file.openGroup(
"/entry1/instrument/instrument_xml");
177 const H5::DataSet dataset =
group.openDataSet(
"data");
180 g_log.
warning() <<
"\nCould not find the instrument description in the Nexus file:" << filename
181 <<
" Ignore eventdata from the Nexus file\n";
182 return scatteringWSNames;
187 std::string instrumentName =
"McStas";
192 if (InstrumentDataService::Instance().doesExist(instrumentNameMangled)) {
194 instrument = InstrumentDataService::Instance().retrieve(instrumentNameMangled);
197 instrument = parser.
parseXML(
nullptr);
199 InstrumentDataService::Instance().add(instrumentNameMangled, instrument);
202 g_log.
warning() <<
"When trying to read the instrument description in the Nexus file: " << filename
203 <<
" the following error is reported: " << e.
what() <<
" Ignore eventdata from the Nexus file\n";
204 return scatteringWSNames;
207 g_log.
warning() <<
"Could not parse instrument description in the Nexus file: " << filename
208 <<
" Ignore eventdata from the Nexus file\n";
209 return scatteringWSNames;
214 progInitial.
report(
"Set up EventWorkspace");
218 eventWS->initialize(instrument->getNumberDetectors(), 1, 1);
220 eventWS->getAxis(0)->unit() = UnitFactory::Instance().create(
"TOF");
221 eventWS->setYUnit(
"Counts");
223 eventWS->setInstrument(instrument);
226 std::vector<detid_t> detIDs = instrument->getDetectorIDs();
228 for (
size_t i = 0; i < instrument->getNumberDetectors(); i++) {
229 eventWS->getSpectrum(i).addDetectorID(detIDs[i]);
231 eventWS->getSpectrum(i).setSpectrumNo(detIDs[i]);
234 eventWS->rebuildSpectraMapping(
true);
235 const auto detIDtoWSIndex = eventWS->getDetectorIDToWorkspaceIndexMap(
true);
237 bool isAnyNeutrons =
false;
239 double shortestTOF(0.0);
240 double longestTOF(0.0);
243 const size_t numEventEntries = eventEntries.size();
244 std::string nameOfGroupWS =
getProperty(
"OutputWorkspace");
245 const auto eventDataTotalName =
"EventData_" + nameOfGroupWS;
246 std::vector<std::pair<EventWorkspace_sptr, std::string>> allEventWS = {{eventWS, eventDataTotalName}};
248 const bool onlySummedEventWorkspace =
getProperty(
"OutputOnlySummedEventWorkspace");
249 if (!onlySummedEventWorkspace && numEventEntries > 1) {
250 for (
const auto &eventEntry : eventEntries) {
252 const auto groupName = parts.back();
255 const auto ws_name = groupName +
"_" + nameOfGroupWS;
256 allEventWS.emplace_back(eventWS->clone(), ws_name);
260 Progress progEntries(
this, progressFractionInitial, 1.0, numEventEntries * 2);
263 auto eventWSIndex = 1u;
265 for (
const auto &groupAddress : eventEntries) {
266 const H5::Group
group = file.openGroup(groupAddress);
267 const H5::DataSet dataset =
group.openDataSet(
"events");
270 std::vector<double> data;
271 progEntries.
report(
"read event data from nexus");
287 const H5::DataSpace dataspace = dataset.getSpace();
288 const auto rank = dataspace.getSimpleExtentNdims();
290 std::vector<hsize_t> dims(rank);
291 dataspace.getSimpleExtentDims(dims.data());
292 if (dims.size() != 2) {
293 g_log.
error() <<
"Event data in McStas nexus file not loaded. Expected "
294 "event data block to be two dimensional\n";
295 return scatteringWSNames;
298 hsize_t numberOfDataColumn = dims[1];
299 if (nNeutrons && numberOfDataColumn != 6) {
300 g_log.
error() <<
"Event data in McStas nexus file expecting 6 columns\n";
301 return scatteringWSNames;
304 if (!isAnyNeutrons && nNeutrons > 0)
305 isAnyNeutrons =
true;
312 hsize_t nNeutronsInBlock = 1000000;
313 hsize_t nOfFullBlocks = nNeutrons / nNeutronsInBlock;
314 hsize_t nRemainingNeutrons = nNeutrons - nOfFullBlocks * nNeutronsInBlock;
316 for (
hsize_t iBlock = 0; iBlock < nOfFullBlocks + 1; iBlock++) {
317 if (iBlock == nOfFullBlocks) {
319 start[0] = nOfFullBlocks * nNeutronsInBlock;
321 step[0] = nRemainingNeutrons;
322 step[1] = numberOfDataColumn;
325 start[0] = iBlock * nNeutronsInBlock;
327 step[0] = nNeutronsInBlock;
328 step[1] = numberOfDataColumn;
330 const hsize_t nNeutronsForthisBlock = step[0];
331 data.resize(nNeutronsForthisBlock * numberOfDataColumn);
334 const H5::DataType datatype = dataset.getDataType();
335 if (datatype.getClass() != H5T_FLOAT) {
336 g_log.
warning() <<
"Entry event field is not H5T_FLOAT! It will be skipped.\n";
340 H5::DataSpace memspace(rank, step);
341 dataspace.selectHyperslab(H5S_SELECT_SET, step, start);
343 dataset.read(data.data(), H5::PredType::NATIVE_DOUBLE, memspace, dataspace);
346 progEntries.
report(
"read event data into workspace");
347 for (
hsize_t in = 0; in < nNeutronsForthisBlock; in++) {
348 const auto detectorID =
static_cast<int>(data[4 + numberOfDataColumn * in]);
349 const double detector_time = data[5 + numberOfDataColumn * in] * 1.0e6;
350 if (in == 0 && iBlock == 0) {
351 shortestTOF = detector_time;
352 longestTOF = detector_time;
354 if (detector_time < shortestTOF)
355 shortestTOF = detector_time;
356 if (detector_time > longestTOF)
357 longestTOF = detector_time;
360 const size_t workspaceIndex = detIDtoWSIndex.find(detectorID)->second;
362 int64_t pulse_time = 0;
364 if (errorBarsSetTo1) {
365 weightedEvent =
WeightedEvent(detector_time, pulse_time, data[numberOfDataColumn * in], 1.0);
367 weightedEvent =
WeightedEvent(detector_time, pulse_time, data[numberOfDataColumn * in],
368 data[numberOfDataColumn * in] * data[numberOfDataColumn * in]);
370 allEventWS[0].first->getSpectrum(workspaceIndex) += weightedEvent;
371 if (!onlySummedEventWorkspace && numEventEntries > 1) {
372 allEventWS[eventWSIndex].first->getSpectrum(workspaceIndex) += weightedEvent;
384 auto axis = HistogramData::BinEdges{shortestTOF - 1, longestTOF + 1};
388 for (
const auto &wsAndName : allEventWS) {
389 const auto ws = wsAndName.first;
391 AnalysisDataService::Instance().addOrReplace(wsAndName.second, ws);
392 scatteringWSNames.emplace_back(wsAndName.second);
394 return scatteringWSNames;
405 const H5::H5File &file) {
407 std::string nameAttrValueYLABEL;
408 std::vector<std::string> histoWSNames;
410 for (
const auto &entry : histogramEntries) {
411 const auto groupAddress = entry.first;
412 const H5::Group
group = file.openGroup(groupAddress);
414 std::string nameAttrValueTITLE;
422 std::string axis1Name, axis2Name;
423 for (
const auto &datasetName : entry.second) {
424 if (datasetName ==
"ncount")
426 H5::DataSet dataset =
group.openDataSet(datasetName);
429 const auto axisNo = H5Util::readNumAttributeCoerce<int>(dataset,
"axis");
431 axis1Name = datasetName;
432 else if (axisNo == 2)
433 axis2Name = datasetName;
435 throw std::invalid_argument(
"Unknown axis number");
439 std::vector<double> axis1Values;
441 std::vector<double> axis2Values;
443 if (axis2Name.length() == 0) {
444 axis2Name = nameAttrValueYLABEL;
445 axis2Values.emplace_back(0.0);
450 const size_t axis1Length = axis1Values.size();
451 const size_t axis2Length = axis2Values.size();
452 g_log.
debug() <<
"Axis lengths=" << axis1Length <<
" " << axis2Length <<
'\n';
455 std::vector<double> data;
459 std::vector<double> errors;
460 if (
group.exists(
"errors")) {
465 Axis *axis1 = ws->getAxis(0);
466 axis1->
title() = axis1Name;
468 auto lblUnit = std::make_shared<Units::Label>();
469 lblUnit->setLabel(axis1Name,
"");
470 axis1->
unit() = lblUnit;
472 auto axis2 = std::make_unique<NumericAxis>(axis2Length);
473 auto axis2Raw = axis2.get();
474 axis2->title() = axis2Name;
476 lblUnit = std::make_shared<Units::Label>();
477 lblUnit->setLabel(axis2Name,
"");
478 axis2->unit() = lblUnit;
480 ws->setYUnit(axis2Name);
481 ws->replaceAxis(1, std::move(axis2));
483 for (
size_t wsIndex = 0; wsIndex < axis2Length; ++wsIndex) {
484 auto &dataX = ws->mutableX(wsIndex);
485 auto &dataY = ws->mutableY(wsIndex);
486 auto &dataE = ws->mutableE(wsIndex);
488 for (
size_t j = 0; j < axis1Length; ++j) {
491 const size_t fileDataIndex = j * axis2Length + wsIndex;
493 dataX[j] = axis1Values[j];
494 dataY[j] = data[fileDataIndex];
496 dataE[j] = errors[fileDataIndex];
498 axis2Raw->setValue(wsIndex, axis2Values[wsIndex]);
502 ws->setTitle(nameAttrValueTITLE);
505 std::replace(nameAttrValueTITLE.begin(), nameAttrValueTITLE.end(),
' ',
'_');
509 const std::string outputWS =
getProperty(
"OutputWorkspace");
510 const std::string nameUserSee = nameAttrValueTITLE +
"_" + outputWS;
511 AnalysisDataService::Instance().addOrReplace(nameUserSee, ws);
513 histoWSNames.emplace_back(ws->getName());