81 if (entries.empty()) {
82 throw std::runtime_error(
"Could not find any entries.");
85 const char *attributeName =
"long_name";
86 std::vector<std::string> eventEntries;
87 std::map<std::string, std::vector<std::string>> histogramEntries;
88 for (std::string
const &entry : entries) {
89 if (entry.find(
"/entry1/data") == std::string::npos) {
95 std::string
const datasetName = address.
stem();
97 if (groupAddress.
stem() ==
"content_nxs")
100 H5::DataSet
const dataset = file.openDataSet(address);
106 std::string nameAttrValue;
108 if (nameAttrValue.find(
"Neutron_ID") != std::string::npos) {
109 eventEntries.emplace_back(groupAddress);
110 }
else if (histogramEntries.find(groupAddress) == histogramEntries.cend()) {
111 histogramEntries[groupAddress] = {datasetName};
113 histogramEntries[groupAddress].emplace_back(datasetName);
117 std::vector<std::string> scatteringWSNames;
118 if (!eventEntries.empty()) {
125 scatteringWSNames.insert(scatteringWSNames.end(), histoWSNames.cbegin(), histoWSNames.cend());
153 const H5::H5File &file) {
156 std::vector<std::string> scatteringWSNames;
159 const bool errorBarsSetTo1 =
getProperty(
"ErrorBarsSetTo1");
165 const double progressFractionInitial = 0.1;
166 Progress progInitial(
this, 0.0, progressFractionInitial, reports);
168 std::string instrumentXML;
169 progInitial.
report(
"Loading instrument");
171 const H5::Group
group = file.openGroup(
"/entry1/instrument/instrument_xml");
172 const H5::DataSet dataset =
group.openDataSet(
"data");
175 g_log.
warning() <<
"\nCould not find the instrument description in the Nexus file:" << filename
176 <<
" Ignore eventdata from the Nexus file\n";
177 return scatteringWSNames;
182 std::string instrumentName =
"McStas";
187 if (InstrumentDataService::Instance().doesExist(instrumentNameMangled)) {
189 instrument = InstrumentDataService::Instance().retrieve(instrumentNameMangled);
192 instrument = parser.
parseXML(
nullptr);
194 InstrumentDataService::Instance().add(instrumentNameMangled, instrument);
197 g_log.
warning() <<
"When trying to read the instrument description in the Nexus file: " << filename
198 <<
" the following error is reported: " << e.
what() <<
" Ignore eventdata from the Nexus file\n";
199 return scatteringWSNames;
202 g_log.
warning() <<
"Could not parse instrument description in the Nexus file: " << filename
203 <<
" Ignore eventdata from the Nexus file\n";
204 return scatteringWSNames;
209 progInitial.
report(
"Set up EventWorkspace");
213 eventWS->initialize(instrument->getNumberDetectors(), 1, 1);
215 eventWS->getAxis(0)->unit() = UnitFactory::Instance().create(
"TOF");
216 eventWS->setYUnit(
"Counts");
218 eventWS->setInstrument(instrument);
221 std::vector<detid_t> detIDs = instrument->getDetectorIDs();
223 for (
size_t i = 0; i < instrument->getNumberDetectors(); i++) {
224 eventWS->getSpectrum(i).addDetectorID(detIDs[i]);
226 eventWS->getSpectrum(i).setSpectrumNo(detIDs[i]);
229 eventWS->rebuildSpectraMapping(
true);
230 const auto detIDtoWSIndex = eventWS->getDetectorIDToWorkspaceIndexMap(
true);
232 bool isAnyNeutrons =
false;
234 double shortestTOF(0.0);
235 double longestTOF(0.0);
238 const size_t numEventEntries = eventEntries.size();
239 std::string nameOfGroupWS =
getProperty(
"OutputWorkspace");
240 const auto eventDataTotalName =
"EventData_" + nameOfGroupWS;
241 std::vector<std::pair<EventWorkspace_sptr, std::string>> allEventWS = {{eventWS, eventDataTotalName}};
243 const bool onlySummedEventWorkspace =
getProperty(
"OutputOnlySummedEventWorkspace");
244 if (!onlySummedEventWorkspace && numEventEntries > 1) {
245 for (
const auto &eventEntry : eventEntries) {
247 std::string
const groupName = address.
stem();
250 const auto ws_name = groupName +
"_" + nameOfGroupWS;
251 allEventWS.emplace_back(eventWS->clone(), ws_name);
255 Progress progEntries(
this, progressFractionInitial, 1.0, numEventEntries * 2);
258 auto eventWSIndex = 1u;
260 for (
const auto &groupAddress : eventEntries) {
261 const H5::Group
group = file.openGroup(groupAddress);
262 const H5::DataSet dataset =
group.openDataSet(
"events");
265 std::vector<double> data;
266 progEntries.
report(
"read event data from nexus");
282 const H5::DataSpace dataspace = dataset.getSpace();
283 const auto rank = dataspace.getSimpleExtentNdims();
285 std::vector<hsize_t> dims(rank);
286 dataspace.getSimpleExtentDims(dims.data());
287 if (dims.size() != 2) {
288 g_log.
error() <<
"Event data in McStas nexus file not loaded. Expected "
289 "event data block to be two dimensional\n";
290 return scatteringWSNames;
293 hsize_t numberOfDataColumn = dims[1];
294 if (nNeutrons && numberOfDataColumn != 6) {
295 g_log.
error() <<
"Event data in McStas nexus file expecting 6 columns\n";
296 return scatteringWSNames;
299 if (!isAnyNeutrons && nNeutrons > 0)
300 isAnyNeutrons =
true;
307 hsize_t nNeutronsInBlock = 1000000;
308 hsize_t nOfFullBlocks = nNeutrons / nNeutronsInBlock;
309 hsize_t nRemainingNeutrons = nNeutrons - nOfFullBlocks * nNeutronsInBlock;
311 for (
hsize_t iBlock = 0; iBlock < nOfFullBlocks + 1; iBlock++) {
312 if (iBlock == nOfFullBlocks) {
314 start[0] = nOfFullBlocks * nNeutronsInBlock;
316 step[0] = nRemainingNeutrons;
317 step[1] = numberOfDataColumn;
320 start[0] = iBlock * nNeutronsInBlock;
322 step[0] = nNeutronsInBlock;
323 step[1] = numberOfDataColumn;
325 const hsize_t nNeutronsForthisBlock = step[0];
326 data.resize(nNeutronsForthisBlock * numberOfDataColumn);
329 const H5::DataType datatype = dataset.getDataType();
330 if (datatype.getClass() != H5T_FLOAT) {
331 g_log.
warning() <<
"Entry event field is not H5T_FLOAT! It will be skipped.\n";
335 H5::DataSpace memspace(rank, step);
336 dataspace.selectHyperslab(H5S_SELECT_SET, step, start);
338 dataset.read(data.data(), H5::PredType::NATIVE_DOUBLE, memspace, dataspace);
341 progEntries.
report(
"read event data into workspace");
342 for (
hsize_t in = 0; in < nNeutronsForthisBlock; in++) {
343 const auto detectorID =
static_cast<int>(data[4 + numberOfDataColumn * in]);
344 const double detector_time = data[5 + numberOfDataColumn * in] * 1.0e6;
345 if (in == 0 && iBlock == 0) {
346 shortestTOF = detector_time;
347 longestTOF = detector_time;
349 if (detector_time < shortestTOF)
350 shortestTOF = detector_time;
351 if (detector_time > longestTOF)
352 longestTOF = detector_time;
355 const size_t workspaceIndex = detIDtoWSIndex.find(detectorID)->second;
357 int64_t pulse_time = 0;
359 if (errorBarsSetTo1) {
360 weightedEvent =
WeightedEvent(detector_time, pulse_time, data[numberOfDataColumn * in], 1.0);
362 weightedEvent =
WeightedEvent(detector_time, pulse_time, data[numberOfDataColumn * in],
363 data[numberOfDataColumn * in] * data[numberOfDataColumn * in]);
365 allEventWS[0].first->getSpectrum(workspaceIndex) += weightedEvent;
366 if (!onlySummedEventWorkspace && numEventEntries > 1) {
367 allEventWS[eventWSIndex].first->getSpectrum(workspaceIndex) += weightedEvent;
379 auto axis = HistogramData::BinEdges{shortestTOF - 1, longestTOF + 1};
383 for (
const auto &wsAndName : allEventWS) {
384 const auto ws = wsAndName.first;
386 AnalysisDataService::Instance().addOrReplace(wsAndName.second, ws);
387 scatteringWSNames.emplace_back(wsAndName.second);
389 return scatteringWSNames;
400 const H5::H5File &file) {
402 std::string nameAttrValueYLABEL;
403 std::vector<std::string> histoWSNames;
405 for (
const auto &entry : histogramEntries) {
406 const auto groupAddress = entry.first;
407 const H5::Group
group = file.openGroup(groupAddress);
409 std::string nameAttrValueTITLE;
417 std::string axis1Name, axis2Name;
418 for (
const auto &datasetName : entry.second) {
419 if (datasetName ==
"ncount")
421 H5::DataSet dataset =
group.openDataSet(datasetName);
424 const auto axisNo = H5Util::readNumAttributeCoerce<int>(dataset,
"axis");
426 axis1Name = datasetName;
427 else if (axisNo == 2)
428 axis2Name = datasetName;
430 throw std::invalid_argument(
"Unknown axis number");
434 std::vector<double> axis1Values;
436 std::vector<double> axis2Values;
438 if (axis2Name.length() == 0) {
439 axis2Name = nameAttrValueYLABEL;
440 axis2Values.emplace_back(0.0);
445 const size_t axis1Length = axis1Values.size();
446 const size_t axis2Length = axis2Values.size();
447 g_log.
debug() <<
"Axis lengths=" << axis1Length <<
" " << axis2Length <<
'\n';
450 std::vector<double> data;
454 std::vector<double> errors;
455 if (
group.exists(
"errors")) {
460 Axis *axis1 = ws->getAxis(0);
461 axis1->
title() = axis1Name;
463 auto lblUnit = std::make_shared<Units::Label>();
464 lblUnit->setLabel(axis1Name,
"");
465 axis1->
unit() = lblUnit;
467 auto axis2 = std::make_unique<NumericAxis>(axis2Length);
468 auto axis2Raw = axis2.get();
469 axis2->title() = axis2Name;
471 lblUnit = std::make_shared<Units::Label>();
472 lblUnit->setLabel(axis2Name,
"");
473 axis2->unit() = lblUnit;
475 ws->setYUnit(axis2Name);
476 ws->replaceAxis(1, std::move(axis2));
478 for (
size_t wsIndex = 0; wsIndex < axis2Length; ++wsIndex) {
479 auto &dataX = ws->mutableX(wsIndex);
480 auto &dataY = ws->mutableY(wsIndex);
481 auto &dataE = ws->mutableE(wsIndex);
483 for (
size_t j = 0; j < axis1Length; ++j) {
486 const size_t fileDataIndex = j * axis2Length + wsIndex;
488 dataX[j] = axis1Values[j];
489 dataY[j] = data[fileDataIndex];
491 dataE[j] = errors[fileDataIndex];
493 axis2Raw->setValue(wsIndex, axis2Values[wsIndex]);
497 ws->setTitle(nameAttrValueTITLE);
500 std::replace(nameAttrValueTITLE.begin(), nameAttrValueTITLE.end(),
' ',
'_');
504 const std::string outputWS =
getProperty(
"OutputWorkspace");
505 const std::string nameUserSee = nameAttrValueTITLE +
"_" + outputWS;
506 AnalysisDataService::Instance().addOrReplace(nameUserSee, ws);
508 histoWSNames.emplace_back(ws->getName());