Skip to content

ADD: Support for loading version 2 of the HDF hit info#100

Merged
fhagemann merged 10 commits intocositools:develop/emfrom
fhagemann:hdf5v2
Mar 24, 2026
Merged

ADD: Support for loading version 2 of the HDF hit info#100
fhagemann merged 10 commits intocositools:develop/emfrom
fhagemann:hdf5v2

Conversation

@fhagemann
Copy link
Copy Markdown

This is my attempt to implement a HDF loader for the newest version 2 of the HDF hit into.
I'm not claiming that this is perfect, but it seems to give something reasonable at least..
It also fixes #57.

I developed this based on a file that was taken with HDF v2.3 and GSE v7.2.2 on the FM assembly at SSL.

The changes between versions 1 and 2 addressed in this PR are:

  • where the HDFVersion is saved in the file

    Version 1 Version 2
    HDFVersion is its own dataset within the file. HDFVersion is an attribute of the Events dataset.
    🗂️ HDF5.File (version 1)
    ├─ 🏷️ CLASS
    ├─ 🏷️ FILTERS
    ├─ 🏷️ PYTABLES_FORMAT_VERSION
    ├─ 🏷️ TITLE
    ├─ 🏷️ VERSION
    ├─ 🔢 Buffers
    ├─ 🔢 Config
    ├─ 🔢 GSEVersion
    ├─ 🔢 HDFVersion
    │ ├─ 🏷️ CLASS
    │ ├─ 🏷️ FIELD_0_FILL
    │ ├─ 🏷️ FIELD_0_NAME
    │ ├─ 🏷️ NROWS
    │ ├─ 🏷️ TITLE
    │ └─ 🏷️ VERSION
    ├─ 🔢 Headers
    └─ 🔢 Hits
      🗂️ HDF5.File (version 2)
    ├─ 🔢 ACSHits
    ├─ 🔢 Buffers
    ├─ 🔢 DIBCoincidence
    ├─ 🔢 DetectorHits
    ├─ 🔢 DetectorLiveTime
    ├─ 🔢 EventIndices
    ├─ 🔢 Events
    │ ├─ 🏷️ BackendVersion
    │ ├─ 🏷️ Config
    │ ├─ 🏷️ Firmware
    │ ├─ 🏷️ GSEVersion
    │ └─ 🏷️ HDFVersion
    ├─ 🔢 FEEHits
    ├─ 🔢 H&S
    ├─ 🔢 Headers
    ├─ 🔢 RTBHousekeeping
    ├─ 🔢 SCBHousekeeping
    └─ 🔢 SinglesCounts

    --> If no dataset HDFVersion exists, check for the existence of Events and attribute HDFVersion therein.

  • Hit and event information are now stored in different datasets

    Version 1 Version 2
    Both, hit and event information was stored in the dataset Hits. The hit information is saved in the dataset FEEHits and the event information is saved in the dataset Events. Hit entries in FEEHits have a field event_index which denotes which "row" in the Events dataset correspond to the given hit.

    For clarification:

    • Hit information = strip ID, energy data, timing data, hit type, timing type
    • Event information = event ID, timecode, GSE timecode, SPW timecode, number of hits, ...

    --> use the same buffer logic for hit information, but read in the event information as a whole.

Right now, the handling of SPWTimeCode (spacewire time code) is commented out to avoid undeclared variable warnings.

I would be very grateful for feedback! :)

@fhagemann fhagemann linked an issue Feb 26, 2026 that may be closed by this pull request
@zoglauer
Copy link
Copy Markdown
Collaborator

Thanks for starting this and taking it off my todo list, but there are a few more things to do:
(1) Based on info in the JSON ASIC setup file, we have to switch between strip maps - that is what Clio was supposed to implement in python and we just replicate it - but she thinks there is still a bug in her code - that is what we talked about on Tuesday.
(2) We need all the other info too: Live time, ACS hit info, etc.

@fhagemann
Copy link
Copy Markdown
Author

fhagemann commented Feb 26, 2026

Thanks for the feedback, I will try to look into this.
Should this all become one big PR (this PR) and review all the code at the end?
Or do you want to tackle this in multiple PRs, each doing once change at a time, to keep reviews manageable?

@zoglauer
Copy link
Copy Markdown
Collaborator

I don't have v2.3 but in previous 2.x versions, there was an EventIndices table "Maps each packet in Events to a [start_index, end_index) range in each hit table that contains the hits from that event. An event at index i in the
Events table corresponds to the indices listed at index i in this table."
If it is still there in version 2.3, I don't see it in your code, to do the right linking

@zoglauer
Copy link
Copy Markdown
Collaborator

I think we have to do (1) and the EventIndices if they are still in version 2.3 - because otherwise the output is not correct. And then we can do the rest of the content in a later PR

@fhagemann
Copy link
Copy Markdown
Author

With the latest commit, I seem to be able to read the polarities from all 3 primary/secondary asics for all 16 detectors in the Config attribute of Events:

Geometry materials loaded!
Detector ID 0:
  primary: HV HV HV 
  secondary: LV LV LV 
Detector ID 1:
  primary: LV LV LV 
  secondary: LV LV LV 
Detector ID 2:
  primary: LV LV LV 
  secondary: LV LV LV 
Detector ID 3:
  primary: LV LV LV 
  secondary: LV LV LV 
Detector ID 4:
  primary: LV LV LV 
  secondary: LV LV LV 
Detector ID 5:
  primary: LV LV LV 
  secondary: LV LV LV 
Detector ID 6:
  primary: LV LV LV 
  secondary: LV LV LV 
Detector ID 7:
  primary: LV LV LV 
  secondary: LV LV LV 
Detector ID 8:
  primary: LV LV LV 
  secondary: LV LV LV 
Detector ID 9:
  primary: LV LV LV 
  secondary: LV LV LV 
Detector ID 10:
  primary: LV LV LV 
  secondary: LV LV LV 
Detector ID 11:
  primary: LV LV LV 
  secondary: LV LV LV 
Detector ID 12:
  primary: LV LV LV 
  secondary: LV LV LV 
Detector ID 13:
  primary: LV LV LV 
  secondary: LV LV LV 
Detector ID 14:
  primary: LV LV LV 
  secondary: LV LV LV 
Detector ID 15:
  primary: LV LV LV 
  secondary: LV LV LV 

I still need to implement using this information for strip mapping.

@fhagemann
Copy link
Copy Markdown
Author

From my understanding: instead of "switching" between strip maps, the ASIC polarities are used to update if an ASIC is on HV or LV side, by ignoring that entry in the strip map and calculating it from

  • detector ID,
  • if it's the primary/secondary ASIC, and
  • the ASIC number
    This is what StripMap::UpdateASICPolarities would now be doing.

@fhagemann fhagemann changed the title Add support for loading version 2.2 of the HDF hit info Add support for loading version 2 of the HDF hit info Mar 9, 2026
@fhagemann
Copy link
Copy Markdown
Author

Ok, the code in this PR still "only" allows reading FEEHits,
but it should be written in a way that is easy to extend to all other fields (ACSHits, H&S, DetectorLiveTime, ...)

There is a slight difference between v2.0-v2.1 and v2.2+, (v2.2+ added spacewire timing via spw_timecode), so I also split the v2 support into v2.0 and v2.2 support.

Comment thread include/MModuleLoaderMeasurementsHDF.h
Comment thread src/MModuleLoaderMeasurementsHDF.cxx
Comment thread src/MModuleLoaderMeasurementsHDF.cxx Outdated
Comment thread src/MModuleLoaderMeasurementsHDF.cxx
Comment on lines +628 to +643
// Catch a bug in the HDF5 data (v1)
if (EventID == 0 && StripID == 0 && ADCs == 0) {
IsZeroDataBug = true;
if (g_Verbosity >= c_Error) cout<<m_XmlTag<<": ZERO-DATA-BUG: Found empty data set. Ignoring event."<<endl;
continue;
} else {
if (IsZeroDataBug == true) { // We are now out of the bug and need to recover
// Clear the strip hits - everything else gets overwritten later
while (Event->GetNStripHits() > 0) {
MStripHit* H = Event->GetStripHit(0);
delete H;
Event->RemoveStripHit(0);
}
}
IsZeroDataBug = false;
}
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this something we would also expect in HDF v2?
The file structure has changed completely..

Comment thread src/MModuleLoaderMeasurementsHDF.cxx
Comment on lines +762 to +765
} else if (m_HDFStripHitVersion >= MHDFStripHitVersion::V2_0) {
Event->SetTI(TimeCode);
}

if (m_StripMap.HasReadOutID(StripID) == true) {
MStripHit* H = new MStripHit();
H->SetDetectorID(m_StripMap.GetDetectorID(StripID));
H->SetStripID(m_StripMap.GetStripNumber(StripID));
H->IsLowVoltageStrip(m_StripMap.IsLowVoltage(StripID));
H->SetADCUnits(ADCs);
H->SetTAC(TACs);


// Set boolean flags based on HitType and TimingType
H->IsGuardRing(HitType == 2);
if (H->IsGuardRing() == true) {
Event->SetGuardRingVeto(true);
}

H->IsNearestNeighbor(HitType == 1);
H->HasFastTiming(TimingType == 1);

// If the user does not want to include Nearest Neighbors in the data, then this is where we remove them
// NOTE: at some point we will want to remove this code and always include nearest neighbor data
if (m_IncludeNearestNeighbor == false && HitType == 1) {
delete H; // Clean up the memory we just allocated
// Increase counters
NStripHits = static_cast<unsigned int>(NumberOfHits);
StripHitIndex++;
continue;
if (m_HDFStripHitVersion >= MHDFStripHitVersion::V2_2) {
Event->SetCL(SPWTimeCode);
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm right now setting the TimeCode (which is GSETimeCode if existent) to TI and the SPWTimeCode to CL.
Is this how it should be?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know what it actually means.

Those are the times we currently have (Carolyn want to scrub it eventually):
//! TODO Scrub all clock/time variables for COSI SMEX
//! Set the Frame Counter of this event
void SetFC(unsigned int FC) { m_FC = FC; }
//! Return the Frame Counter of this event
unsigned int GetFC() const { return m_FC; }

//! set and get Unix clock time
void SetTI(unsigned long long TI) { m_TI = TI;}
unsigned long long GetTI() const { return m_TI;}

//! set and get clock tick
void SetCL(uint64_t CL) { m_CL = CL;}
uint64_t GetCL() const { return m_CL;}

//! Set and get the Modified Julian Date of this event
void SetMJD(double MJD) { m_MJD = MJD; }
double GetMJD() const { return m_MJD; }

//! Set and get the UTC time of this event
void SetTimeUTC(const MTime& TimeUTC) { m_EventTimeUTC = TimeUTC; }
MTime GetTimeUTC() const { return m_EventTimeUTC; }

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't touch that part of the code with my latest commit, but this goes along with #69.
We should eventually decide how/where we want to store that information (also for DEE output).

@fhagemann
Copy link
Copy Markdown
Author

I tried parsing files in v1.1, v2.1 and v2.3, and I'm not getting any errors at least.
I asked @robin4730 (huge thanks!!) to look into if after the updates, the ROA files still look reasonable/identical.

@fhagemann fhagemann changed the title Add support for loading version 2 of the HDF hit info ADD: Support for loading version 2 of the HDF hit info Mar 10, 2026
@ckierans ckierans requested a review from zoglauer March 11, 2026 01:55
Comment thread src/MStripMap.cxx Outdated
Comment thread include/MModuleLoaderMeasurementsHDF.h Outdated
Comment thread include/MModuleLoaderMeasurementsHDF.h Outdated
Comment thread src/MModuleLoaderMeasurementsHDF.cxx Outdated
Comment thread src/MModuleLoaderMeasurementsHDF.cxx Outdated
Comment thread src/MModuleLoaderMeasurementsHDF.cxx Outdated
@zoglauer
Copy link
Copy Markdown
Collaborator

Generally looks good, just a bunch of small things.

@fhagemann fhagemann added the enhancement New feature or request label Mar 23, 2026
@zoglauer
Copy link
Copy Markdown
Collaborator

Put you name into the copyright notices!

@fhagemann
Copy link
Copy Markdown
Author

Done (I also added my name to the copyright notices of MStripMap -- even though the changes in this PR might be minor, there were some bigger changes I made in #103)

@zoglauer
Copy link
Copy Markdown
Collaborator

Can you check if you initialize or clear everything in the Initialize function?
I don't see m_ASICPolarities there

@fhagemann
Copy link
Copy Markdown
Author

fhagemann commented Mar 23, 2026

That should also be done now. The only thing I don't initialize is m_HDFStripHitVersion (this is set at the beginning of OpenHDF5File, but I could also move it to Initialize to have everything initialized there)

And m_StripMap is also handled by m_StripMap::Open, but I could also explicitly clear it in Initialize if you want.

@zoglauer
Copy link
Copy Markdown
Collaborator

OK. Feel free to merge.

@fhagemann fhagemann merged commit 3621805 into cositools:develop/em Mar 24, 2026
@fhagemann fhagemann deleted the hdf5v2 branch March 24, 2026 20:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MModuleLoaderMeasurementsHDF Number of Events is 0

2 participants