Add initial calo digi to fragment module and a validation module#1774
Add initial calo digi to fragment module and a validation module#1774michaelmackenzie wants to merge 4 commits intoMu2e:mainfrom
Conversation
|
Hi @michaelmackenzie,
which require these tests: build. @Mu2e/write, @Mu2e/fnalbuild-users have access to CI actions on main. ⌛ The following tests have been triggered for de3ca7d: build (Build queue - API unavailable) |
There was a problem hiding this comment.
Pull request overview
This PR introduces DAQ-side support for turning reconstructed calorimeter digis back into DTCEVT fragments, plus a small validation analyzer to compare two CaloDigiCollections (useful for round-trip checks through fragmentization/decoding).
Changes:
- Add
CaloDigisToFragmentsEDProducer to buildartdaq::Fragments(DTCEVT) fromCaloDigiCollection. - Add
CaloDigiCollectionsComparatorEDAnalyzer to compare a “reference” and “candidate”CaloDigiCollection. - Register both modules in
DAQ/CMakeLists.txt.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
DAQ/src/CaloDigisToFragments_module.cc |
New producer that encodes calo digis into DTCLib event/subevent/datablock buffers and emits a DTCEVT fragment. |
DAQ/src/CaloDigiCollectionsComparator_module.cc |
New analyzer to normalize/sort and diff two CaloDigiCollections, optionally throwing on mismatch. |
DAQ/CMakeLists.txt |
Adds plugin build rules for the two new modules. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Each hit occupies 12-byte chunks: 12-byte header + packed 12-bit samples + chunk padding. | ||
| size_t hitBytes = static_cast<size_t>(12 * std::ceil((12.0 + 1.5 * waveform.size()) / 12.0)); | ||
| size_t waveformBytes = hitBytes - 12; | ||
| std::vector<uint8_t> rawBytes(waveformBytes, 0xFF); | ||
| std::memcpy(rawBytes.data(), rawWords.data(), std::min(rawBytes.size(), rawWords.size() * sizeof(uint16_t))); | ||
| return rawBytes; |
There was a problem hiding this comment.
std::ceil is used (e.g., to compute hitBytes / transferByteCount) but <cmath> is not included in this file, which will fail to compile on standard toolchains. Add the appropriate header (and consider keeping math helpers near these calculations).
|
Let me review this pull request in detail.Now let me look at the existing decoder module to understand the expected data format conventions:Here is my review of PR #1774. I've cross-referenced the new encoder ( Issues Found1. 🔴 Wrong namespace — module is declared in
|
| Severity | Count | Key concerns |
|---|---|---|
| 🔴 High | 3 | uint16_t overflow on byte count, potential buffer overwrite, namespace choice |
| 🟡 Medium | 6 | Dead code, truncation of t0, hardcoded zeros, detectorID gap, unnecessary empty blocks, CMake style |
| 🟢 Low | 1 | PR description typo |
The most critical issue is the uint16_t transferByteCount overflow — this can silently corrupt the output fragment for events with many calorimeter hits on a single ROC link. The pos bounds check is also important to prevent memory corruption.
|
☀️ The build tests passed at de3ca7d.
N.B. These results were obtained from a build of this Pull Request at de3ca7d after being merged into the base branch at 5b02c13. For more information, please check the job page here. |
|
Responding to the Opus review:
Let me know if there are changes I should make given these comments or expert opinions! |
|
Hi @michaelmackenzie , before I start reviewing the code, isn't this module: https://github.com/Mu2e/Offline/blob/main/DAQ/src/ArtBinaryPacketsFromDigis_module.cc already built for this purpose? |
|
@giro94 I can have AI try to test and update that module instead of separating out subsystem digi -> fragment production into a separate model if you think this is best. Do you know if it's functional? |
| mu2e::CaloRawSiPMId rawId; | ||
| uint16_t detectorID = 0; | ||
|
|
||
| if (useOfflineID_) { |
There was a problem hiding this comment.
The useOfflineID_ flag in CaloDigiMaker is used for non-disk topologies (like HEERC tests for example).
I think this module can assume disk-only data.
There was a problem hiding this comment.
Sounds good, I'll remove this use-case
| rawId = calodaqconds.rawId(offId); | ||
| detectorID = offId.detType(); | ||
| } else { | ||
| rawId = mu2e::CaloRawSiPMId(static_cast<uint16_t>(digi.SiPMID())); |
There was a problem hiding this comment.
If we want to keep useOfflineID_ == false cases, we should also add the useDTCROCID_ logic in https://github.com/Mu2e/Offline/blob/main/DAQ/src/CaloDigisFromDTCEvents_module.cc#L198C13-L199
| } | ||
|
|
||
| if (!rawId.isValid()) { | ||
| continue; |
There was a problem hiding this comment.
throw exception rather than skip?
| } | ||
|
|
||
| auto const diracID = rawId.dirac(); | ||
| auto const dtcID = static_cast<uint8_t>(diracID / kCaloRocsPerDtc); |
There was a problem hiding this comment.
DTCs are not aligned with board (dirac) IDs.
We can't determine them from boardID unless we implement a map
There was a problem hiding this comment.
Maybe, for the purpose of this module, we can ignore that the DTC numbers are not the real ones
There was a problem hiding this comment.
This was somewhat my though, have it come up with some sort of DTC ID/ROC ID etc. numbering to create some sort of reasonable fragment collection, but not necessarily be 100% correct in figuring out the actual topology. But if we make maps, we can always update this
|
|
||
| auto const diracID = rawId.dirac(); | ||
| auto const dtcID = static_cast<uint8_t>(diracID / kCaloRocsPerDtc); | ||
| auto const linkID = static_cast<uint8_t>(diracID % kCaloRocsPerDtc); |
I used AI to create a calo digi -> fragment module (with many iterations to get it to work). I also had it create a validation module. Here's an example fcl to test it:
Where on 1k events I had no errors:
mu2e -c test_digi_to_frag.fcl -S mu2e-trig-config/ci/data_files.txt -n 1000This should be checked by experts, but it's just to get the ball rolling on this conversion code