From e2a42eadd5c524ab400caf7ac73f9f4757359490 Mon Sep 17 00:00:00 2001 From: Andreas Suter Date: Wed, 15 Jul 2026 07:54:42 +0200 Subject: [PATCH] add Red/Green mode handling for NeXus HDF5 IDF V2. See also the musrfit docu. --- CMakeLists.txt | 2 +- ChangeLog | 6 + src/include/PRunDataHandler.h | 225 +++++++++++++++++++++------------- 3 files changed, 146 insertions(+), 87 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7963cfd2..480764ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ if (CMAKE_VERSION GREATER_EQUAL "3.3") cmake_policy(SET CMP0167 NEW) endif () -project(musrfit VERSION 1.11.2 LANGUAGES C CXX) +project(musrfit VERSION 1.11.3 LANGUAGES C CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) diff --git a/ChangeLog b/ChangeLog index d7da31dd..11a0af66 100644 --- a/ChangeLog +++ b/ChangeLog @@ -12,6 +12,12 @@ or https://bitbucket.org/muonspin/musrfit +Release of V1.11.3, 2026/07/15 +============================== + +Add Red/Green mode handling for NeXus, especially HDF5 IDF V2. Offset between the +routed histograms is 10000 (for LEM it is 20). + Release of V1.11.2, 2026/06/27 ============================== diff --git a/src/include/PRunDataHandler.h b/src/include/PRunDataHandler.h index b283a4d7..849807b3 100644 --- a/src/include/PRunDataHandler.h +++ b/src/include/PRunDataHandler.h @@ -871,95 +871,148 @@ Bool_t PRunDataHandler::ReadNexusFileIdf2(T& nxs_file) ival = nxs_file->template GetDataset("/raw_data_1/run_number").GetData()[0]; runData.SetRunNumber(ival); - // get/set temperature - dval = PMUSR_UNDEFINED; - sstr = "n/a"; - if (nxs_file->HasDataset("/raw_data_1/sample/temperature")) { - auto tmp_ds = nxs_file->template GetDataset("/raw_data_1/sample/temperature"); - dval = tmp_ds.GetData()[0]; - if (tmp_ds.HasAttribute("units")) - sstr = std::any_cast(tmp_ds.GetAttribute("units")); - if (sstr == "Celcius") - dval += 273.16; + // get/set temperature + dval = PMUSR_UNDEFINED; + sstr = "n/a"; + if (nxs_file->HasDataset("/raw_data_1/sample/temperature")) { + auto tmp_ds = nxs_file->template GetDataset("/raw_data_1/sample/temperature"); + dval = tmp_ds.GetData()[0]; + if (tmp_ds.HasAttribute("units")) + sstr = std::any_cast(tmp_ds.GetAttribute("units")); + if (sstr == "Celcius") + dval += 273.16; + } + runData.SetTemperature(0, dval, 0.0); + + // get/set field + dval = PMUSR_UNDEFINED; + sstr = "n/a"; + factor = 1.0; + if (nxs_file->HasDataset("/raw_data_1/sample/magnetic_field")) { + auto mag_ds = nxs_file->template GetDataset("/raw_data_1/sample/magnetic_field"); + dval = mag_ds.GetData()[0]; + if (mag_ds.HasAttribute("units")) + sstr = std::any_cast(mag_ds.GetAttribute("units")); + if (sstr == "Tesla") + factor = 1.0e4; + } + runData.SetField(dval*factor); + + // get/set implantation energy + runData.SetEnergy(PMUSR_UNDEFINED); + + // get/set implantation energy + runData.SetEnergy(PMUSR_UNDEFINED); + + // get/set moderator HV + runData.SetTransport(PMUSR_UNDEFINED); + + // get/set RA HV's (LEM specific) + for (UInt_t i=0; i<4; i++) + runData.SetRingAnode(i, PMUSR_UNDEFINED); + + // get/set setup + sstr = "n/a"; + runData.SetSetup(str); + + // get/set sample + sstr = "n/a"; + if (nxs_file->HasDataset("/raw_data_1/sample/name")) + sstr = nxs_file->template GetDataset("/raw_data_1/sample/name").GetData()[0]; + runData.SetSample(sstr); + + // get/set orientation + runData.SetOrientation("n/a"); + + // get/set time resolution (ns) + dval = PMUSR_UNDEFINED; + sstr = "n/a"; + factor = 1.0; + if (nxs_file->HasDataset("/raw_data_1/instrument/detector_1/resolution")) { + auto res_ds = nxs_file->template GetDataset("/raw_data_1/instrument/detector_1/resolution"); + dval = res_ds.GetData()[0]; + if (res_ds.HasAttribute("units")) + sstr = std::any_cast(res_ds.GetAttribute("units")); + if ((sstr == "picoseconds") || (sstr == "pico.seconds")) + factor = 1.0e-3; // ps -> ns + } + runData.SetTimeResolution(dval*factor); + + // get/set start/stop time + sstr = "n/a"; + TString date{"n/a"}, time{"n/a"}; + if (nxs_file->HasDataset("/raw_data_1/start_time")) + sstr = nxs_file->template GetDataset("/raw_data_1/start_time").GetData()[0]; + str = sstr; + SplitTimeDate(str, time, date, ok); + if (ok) { + runData.SetStartTime(time); + runData.SetStartDate(date); + } + + sstr = "n/a"; + date = "n/a"; + time = "n/a"; + if (nxs_file->HasDataset("/raw_data_1/end_time")) + sstr = nxs_file->template GetDataset("/raw_data_1/end_time").GetData()[0]; + str = sstr; + SplitTimeDate(str, time, date, ok); + if (ok) { + runData.SetStopTime(time); + runData.SetStopDate(date); + } + + // get/set deadtime relevant parameters + if (nxs_file->HasDataset("/raw_data_1/instrument/detector_1/dead_time")) { + std::vector dt; + dt = nxs_file->template GetDataset("/raw_data_1/instrument/detector_1/dead_time").GetData(); + runData.SetDeadTimeParam(dt); + } + if (nxs_file->HasDataset("/raw_data_1/good_frames")) { + ival = nxs_file->template GetDataset("/raw_data_1/good_frames").GetData()[0]; + runData.SetNumberOfGoodFrames(ival); + } + + // data with its metadata + if (nxs_file->HasDataset("/raw_data_1/instrument/detector_1/counts")) { + int t0_bin{-1}, fgb{-1}, lgb{-1}, noOfPeriods{-1}, noOfHistos{-1}, histoLength{-1}; + auto count_ds = nxs_file->template GetDataset("/raw_data_1/instrument/detector_1/counts"); + auto count = count_ds.GetData(); + auto dims = count_ds.GetDimensions(); + if (dims.size() < 3) { + std::cerr << std::endl << "**ERROR** PNeXus data dimension error! dims.size()=" << dims.size() << ", expecting == 3." << std::endl; + return false; } - runData.SetTemperature(0, dval, 0.0); - - // get/set field - dval = PMUSR_UNDEFINED; - sstr = "n/a"; - factor = 1.0; - if (nxs_file->HasDataset("/raw_data_1/sample/magnetic_field")) { - auto mag_ds = nxs_file->template GetDataset("/raw_data_1/sample/magnetic_field"); - dval = mag_ds.GetData()[0]; - if (mag_ds.HasAttribute("units")) - sstr = std::any_cast(mag_ds.GetAttribute("units")); - if (sstr == "Tesla") - factor = 1.0e4; - } - runData.SetField(dval*factor); - - // get/set implantation energy - runData.SetEnergy(PMUSR_UNDEFINED); - - // get/set implantation energy - runData.SetEnergy(PMUSR_UNDEFINED); - - // get/set moderator HV - runData.SetTransport(PMUSR_UNDEFINED); - - // get/set RA HV's (LEM specific) - for (UInt_t i=0; i<4; i++) - runData.SetRingAnode(i, PMUSR_UNDEFINED); - - // get/set setup - sstr = "n/a"; - runData.SetSetup(str); - - // get/set sample - sstr = "n/a"; - if (nxs_file->HasDataset("/raw_data_1/sample/name")) - sstr = nxs_file->template GetDataset("/raw_data_1/sample/name").GetData()[0]; - runData.SetSample(sstr); - - // get/set orientation - runData.SetOrientation("n/a"); - - // get/set time resolution (ns) - dval = PMUSR_UNDEFINED; - sstr = "n/a"; - factor = 1.0; - if (nxs_file->HasDataset("/raw_data_1/instrument/detector_1/resolution")) { - auto res_ds = nxs_file->template GetDataset("/raw_data_1/instrument/detector_1/resolution"); - dval = res_ds.GetData()[0]; - if (res_ds.HasAttribute("units")) - sstr = std::any_cast(res_ds.GetAttribute("units")); - if ((sstr == "picoseconds") || (sstr == "pico.seconds")) - factor = 1.0e-3; // ps -> ns - } - runData.SetTimeResolution(dval*factor); - - // get/set start/stop time - sstr = "n/a"; - TString date{"n/a"}, time{"n/a"}; - if (nxs_file->HasDataset("/raw_data_1/start_time")) - sstr = nxs_file->template GetDataset("/raw_data_1/start_time").GetData()[0]; - str = sstr; - SplitTimeDate(str, time, date, ok); - if (ok) { - runData.SetStartTime(time); - runData.SetStartDate(date); + noOfPeriods = dims[0]; + noOfHistos = dims[1]; + histoLength = dims[2]; + // get all necessary attributes + if (count_ds.HasAttribute("t0_bin")) + t0_bin = std::any_cast(count_ds.GetAttribute("t0_bin")); + if (count_ds.HasAttribute("first_good_bin")) + fgb = std::any_cast(count_ds.GetAttribute("first_good_bin")); + if (count_ds.HasAttribute("last_good_bin")) + lgb = std::any_cast(count_ds.GetAttribute("last_good_bin")); + if (static_cast(count.size()) != noOfPeriods*noOfHistos*histoLength) { + std::cerr << std::endl << "**ERROR** PNeXus data size error! count.size()=" << count.size() << ", #periods=" << noOfPeriods << ", #histos=" << noOfHistos << ", length=" << histoLength << "." << std::endl; + return false; } - sstr = "n/a"; - date = "n/a"; - time = "n/a"; - if (nxs_file->HasDataset("/raw_data_1/end_time")) - sstr = nxs_file->template GetDataset("/raw_data_1/end_time").GetData()[0]; - str = sstr; - SplitTimeDate(str, time, date, ok); - if (ok) { - runData.SetStopTime(time); - runData.SetStopDate(date); + // fill dataSet + PDoubleVector data; + for (int i=0; i