From e7470da8c75defaa7eb9bbc0c896861fbb7a3e23 Mon Sep 17 00:00:00 2001 From: edcallaghan Date: Fri, 25 Jul 2025 15:54:54 -0700 Subject: [PATCH 01/15] scope std::endl --- Mu2eKinKal/inc/KKFit.hh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Mu2eKinKal/inc/KKFit.hh b/Mu2eKinKal/inc/KKFit.hh index 8cfb4091fb..1de97ae885 100644 --- a/Mu2eKinKal/inc/KKFit.hh +++ b/Mu2eKinKal/inc/KKFit.hh @@ -42,6 +42,9 @@ #include #include #include + +using std::endl; + namespace mu2e { using KinKal::SensorLine; using KinKal::TimeRange; From 02a964d4f015a727ea786cbe40356cc4cc886ce2 Mon Sep 17 00:00:00 2001 From: edcallaghan Date: Tue, 30 Sep 2025 13:49:12 -0700 Subject: [PATCH 02/15] add calorimeter digis to standard mixing flow --- Blinding/src/MergeDigis_module.cc | 15 ++++++++++++++- EventMixing/inc/Mu2eProductMixer.hh | 6 ++++++ EventMixing/src/Mu2eProductMixer.cc | 13 +++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/Blinding/src/MergeDigis_module.cc b/Blinding/src/MergeDigis_module.cc index 2dd183d9e7..c8352e6d7a 100644 --- a/Blinding/src/MergeDigis_module.cc +++ b/Blinding/src/MergeDigis_module.cc @@ -22,6 +22,7 @@ #include "Offline/TrackerConditions/inc/StrawElectronics.hh" #include "Offline/TrackerMC/inc/StrawDigiBundle.hh" #include "Offline/TrackerMC/inc/StrawDigiBundleCollection.hh" +#include "Offline/RecoDataProducts/inc/CaloDigi.hh" namespace mu2e{ class MergeDigis: public art::EDProducer{ @@ -35,6 +36,10 @@ namespace mu2e{ fhicl::Name("MergeStrawDigiMCs"), fhicl::Comment("True/false to merge tracker MC truth") }; + fhicl::Sequence calo_digi_tags{ + fhicl::Name("CaloDigiCollections"), + fhicl::Comment("art::InputTags of source CaloDigis") + }; }; using Parameters = art::EDProducer::Table; @@ -46,6 +51,9 @@ namespace mu2e{ bool _tracker_mc; ProditionsHandle _tracker_conditions_handle; + // calorimeter + std::vector _calo_digi_tags; + private: void produce(art::Event&); }; @@ -54,7 +62,8 @@ namespace mu2e{ MergeDigis::MergeDigis(const Parameters& config): art::EDProducer(config), _tracker_digi_tags(config().tracker_digi_tags()), - _tracker_mc(config().tracker_mc()){ + _tracker_mc(config().tracker_mc()), + _calo_digi_tags(config().calo_digi_tags()){ // tracker for (const auto& tag: _tracker_digi_tags){ this->consumes(tag); @@ -64,6 +73,10 @@ namespace mu2e{ this->produces(); // calorimeter... + for (const auto& tag: _calo_digi_tags){ + this->consumes(tag); + } + this->produces(); // crv... diff --git a/EventMixing/inc/Mu2eProductMixer.hh b/EventMixing/inc/Mu2eProductMixer.hh index c43f533236..b594e50e4b 100644 --- a/EventMixing/inc/Mu2eProductMixer.hh +++ b/EventMixing/inc/Mu2eProductMixer.hh @@ -44,6 +44,7 @@ #include "Offline/MCDataProducts/inc/PhysicalVolumeInfoMultiCollection.hh" #include "Offline/RecoDataProducts/inc/StrawDigi.hh" #include "Offline/MCDataProducts/inc/StrawDigiMC.hh" +#include "Offline/RecoDataProducts/inc/CaloDigi.hh" #include "Offline/DataProducts/inc/EventWindowMarker.hh" @@ -109,6 +110,7 @@ namespace mu2e { fhicl::Table strawDigiMixer { fhicl::Name("strawDigiMixer") }; fhicl::Table strawDigiADCWaveformMixer { fhicl::Name("strawDigiADCWaveformMixer") }; fhicl::Table strawDigiMCMixer { fhicl::Name("strawDigiMCMixer") }; + fhicl::Table caloDigiMixer { fhicl::Name("caloDigiMixer") }; fhicl::Table eventWindowMarkerMixer { fhicl::Name("eventWindowMarkerMixer") }; fhicl::OptionalTable cosmicLivetimeMixer { fhicl::Name("cosmicLivetimeMixer") }; fhicl::OptionalTable volumeInfoMixer { fhicl::Name("volumeInfoMixer") }; @@ -172,6 +174,10 @@ namespace mu2e { StrawDigiMCCollection& out, art::PtrRemapper const& remap); + bool mixCaloDigis(std::vector const& in, + CaloDigiCollection& out, + art::PtrRemapper const& remap); + bool mixEventWindowMarkers(std::vector const& in, EventWindowMarker& out, art::PtrRemapper const& remap); diff --git a/EventMixing/src/Mu2eProductMixer.cc b/EventMixing/src/Mu2eProductMixer.cc index 29a69668c5..47d0ac5e82 100644 --- a/EventMixing/src/Mu2eProductMixer.cc +++ b/EventMixing/src/Mu2eProductMixer.cc @@ -117,6 +117,11 @@ namespace mu2e { (e.inTag, e.resolvedInstanceName(), &Mu2eProductMixer::mixStrawDigiMCs, *this); } + for(const auto& e: conf.caloDigiMixer().mixingMap()) { + helper.declareMixOp + (e.inTag, e.resolvedInstanceName(), &Mu2eProductMixer::mixCaloDigis, *this); + } + for(const auto& e: conf.eventWindowMarkerMixer().mixingMap()) { helper.declareMixOp (e.inTag, e.resolvedInstanceName(), &Mu2eProductMixer::mixEventWindowMarkers, *this); @@ -480,6 +485,14 @@ namespace mu2e { return true; } + bool Mu2eProductMixer::mixCaloDigis(std::vector const& in, + CaloDigiCollection& out, + art::PtrRemapper const& remap) + { + art::flattenCollections(in, out); + return true; + } + bool Mu2eProductMixer::mixEventWindowMarkers(std::vector const& in, EventWindowMarker& out, art::PtrRemapper const& remap){ From 3870e851ad093c569b5a016f49bcb04f75cf676b Mon Sep 17 00:00:00 2001 From: edcallaghan Date: Tue, 30 Sep 2025 14:13:04 -0700 Subject: [PATCH 03/15] generalize timing chains to allow for non-uniform digitization windows --- TrackerMC/inc/TimeBasedBucket.hh | 36 ++++++++++++++++---------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/TrackerMC/inc/TimeBasedBucket.hh b/TrackerMC/inc/TimeBasedBucket.hh index ff2f76cf78..0acad79e68 100644 --- a/TrackerMC/inc/TimeBasedBucket.hh +++ b/TrackerMC/inc/TimeBasedBucket.hh @@ -18,7 +18,7 @@ namespace mu2e{ template class TimeBasedBucket{ public: - TimeBasedBucket(double); + TimeBasedBucket(); // forwarded calls to underlying container size_t size() const; @@ -28,12 +28,12 @@ namespace mu2e{ TBB_const_iterator end() const; // whether a candidate item "fits" into this bucket's gross time window - bool Accepts(T); + bool Accepts(T, double); // insertion --- assumes that appends are pre-sorted - void Append(T); + void Append(T, double); protected: std::vector _container; - double _window; + std::vector _windows; private: /**/ }; @@ -49,7 +49,7 @@ namespace mu2e{ template class TimeBasedBuckets{ public: - TimeBasedBuckets(double); + TimeBasedBuckets(); // forwarded calls to underlying container size_t size() const; @@ -59,16 +59,15 @@ namespace mu2e{ TBBS_const_iterator end() const; // insertion - void Insert(T); + void Insert(T, double); protected: std::vector< TimeBasedBucket > _buckets; - double _window; private: /**/ }; template - TimeBasedBucket::TimeBasedBucket(double window): _window(window){ + TimeBasedBucket::TimeBasedBucket(){ /**/ } @@ -106,15 +105,15 @@ namespace mu2e{ // whether a candidate item "fits" into this bucket's gross time window template - bool TimeBasedBucket::Accepts(T candidate){ + bool TimeBasedBucket::Accepts(T candidate, double window){ // empty bucket rejects nothing if (this->size() < 1){ return true; } // otherwise, check between first/last times, accounting for windowing - double lower = _container.front().time() - _window; - double upper = _container.back().time() + _window; + double lower = _container.front().time() - window; + double upper = _container.back().time() + _windows.back(); double now = candidate.time(); bool rv = (lower <= now) && (now <= upper); return rv; @@ -122,12 +121,13 @@ namespace mu2e{ // insertion --- assumes that appends are pre-sorted template - void TimeBasedBucket::Append(T candidate){ + void TimeBasedBucket::Append(T candidate, double window){ _container.push_back(candidate); + _windows.push_back(window); } template - TimeBasedBuckets::TimeBasedBuckets(double window): _window(window){ + TimeBasedBuckets::TimeBasedBuckets(){ /**/ } @@ -165,12 +165,12 @@ namespace mu2e{ // insertion template - void TimeBasedBuckets::Insert(T item){ + void TimeBasedBuckets::Insert(T item, double window){ // if the item belongs in a preexisting bucket, put it there bool inserted = false; for (auto& bucket: (*this)){ - if (bucket.Accepts(item)){ - bucket.Append(item); + if (bucket.Accepts(item, window)){ + bucket.Append(item, window); inserted = true; return; } @@ -178,9 +178,9 @@ namespace mu2e{ // otherwise, this item defines a new bucket if (!inserted){ - TimeBasedBucket bucket(_window); + TimeBasedBucket bucket; _buckets.push_back(bucket); - this->Insert(item); + this->Insert(item, window); } } } From eff58b2c4cd8e92d9528b7d989bb31cc0a4e16f7 Mon Sep 17 00:00:00 2001 From: edcallaghan Date: Tue, 30 Sep 2025 17:57:45 -0700 Subject: [PATCH 04/15] implement calorimeter digi collision resolution and include in merge module --- Blinding/CMakeLists.txt | 1 + Blinding/src/MergeDigis_module.cc | 14 +- Blinding/src/SConscript | 2 + CaloMC/inc/CaloDigiWrapper.hh | 28 +++ CaloMC/inc/CaloDigiWrapperCollection.hh | 61 +++++++ CaloMC/src/CaloDigiWrapper.cc | 23 +++ CaloMC/src/CaloDigiWrapperCollection.cc | 198 +++++++++++++++++++++ TrackerMC/src/StrawDigiBundleCollection.cc | 4 +- 8 files changed, 328 insertions(+), 3 deletions(-) create mode 100644 CaloMC/inc/CaloDigiWrapper.hh create mode 100644 CaloMC/inc/CaloDigiWrapperCollection.hh create mode 100644 CaloMC/src/CaloDigiWrapper.cc create mode 100644 CaloMC/src/CaloDigiWrapperCollection.cc diff --git a/Blinding/CMakeLists.txt b/Blinding/CMakeLists.txt index 134c529921..251cb4b9d9 100755 --- a/Blinding/CMakeLists.txt +++ b/Blinding/CMakeLists.txt @@ -80,6 +80,7 @@ cet_build_plugin(MergeDigis art::module LIBRARIES REG Offline::Blinding Offline::TrackerMC + Offline::CaloMC ) cet_build_plugin(TrackDigiExtractor art::module diff --git a/Blinding/src/MergeDigis_module.cc b/Blinding/src/MergeDigis_module.cc index c8352e6d7a..23f6783382 100644 --- a/Blinding/src/MergeDigis_module.cc +++ b/Blinding/src/MergeDigis_module.cc @@ -23,6 +23,7 @@ #include "Offline/TrackerMC/inc/StrawDigiBundle.hh" #include "Offline/TrackerMC/inc/StrawDigiBundleCollection.hh" #include "Offline/RecoDataProducts/inc/CaloDigi.hh" +#include "Offline/CaloMC/inc/CaloDigiWrapperCollection.hh" namespace mu2e{ class MergeDigis: public art::EDProducer{ @@ -117,7 +118,18 @@ namespace mu2e{ event.put(std::move(dgmc)); } - // calorimeter... + // calorimeter: two easy steps: + // i) read all digis into a CaloDigiWrapperCollection + // ii) defer collision resolution to that collection + CaloDigiWrapperCollection wrappers; + for (const auto& tag: _calo_digi_tags){ + auto handle = event.getValidHandle(tag); + wrappers.Append(*handle); + } + CaloDigiWrapperCollection calo_resolved; + wrappers.ResolveCollisions(calo_resolved); + auto calo_digis = calo_resolved.GetDigis(); + event.put(std::move(calo_digis)); // crv... } diff --git a/Blinding/src/SConscript b/Blinding/src/SConscript index 18335f5df8..3b7009c547 100644 --- a/Blinding/src/SConscript +++ b/Blinding/src/SConscript @@ -38,6 +38,7 @@ helper.make_plugins([ 'mu2e_SeedService', 'mu2e_TrackerConditions', 'mu2e_TrackerMC', + 'mu2e_CaloMC', ]) helper.make_dict_and_map([ @@ -54,4 +55,5 @@ helper.make_dict_and_map([ 'mu2e_SeedService', 'mu2e_TrackerConditions', 'mu2e_TrackerMC', + 'mu2e_CaloMC', ]) diff --git a/CaloMC/inc/CaloDigiWrapper.hh b/CaloMC/inc/CaloDigiWrapper.hh new file mode 100644 index 0000000000..1f8f7a84ed --- /dev/null +++ b/CaloMC/inc/CaloDigiWrapper.hh @@ -0,0 +1,28 @@ +// Ed Callaghan +// Simple wrapper around calorimeter digis to interface into a partitioning scheme +// September 2025 + +#ifndef CaloMC_CaloDigiWrapper_hh +#define CaloMC_CaloDigiWrapper_hh + +// mu2e +#include "Offline/RecoDataProducts/inc/CaloDigi.hh" + +namespace mu2e{ + class CaloDigiWrapper{ + public: + CaloDigiWrapper(const CaloDigi&); + const CaloDigi& Digi() const; + + // interface for sorting into buckets of overlapping digitization windows + const double time() const; + + protected: + const CaloDigi _digi; + + private: + /**/ + }; +} // namespace mu2e + +#endif diff --git a/CaloMC/inc/CaloDigiWrapperCollection.hh b/CaloMC/inc/CaloDigiWrapperCollection.hh new file mode 100644 index 0000000000..1308f713cd --- /dev/null +++ b/CaloMC/inc/CaloDigiWrapperCollection.hh @@ -0,0 +1,61 @@ +// Ed Callaghan +// Container for CaloDigiWrappers, with functionality to resolve overlapping digitization windows +// September 2025 + +#ifndef CaloMC_CaloDigiWrapperCollection_hh +#define CaloMC_CaloDigiWrapperCollection_hh + +// stl +#include +#include +#include +#include + +// mu2e +#include "Offline/CaloMC/inc/CaloDigiWrapper.hh" +#include "Offline/TrackerMC/inc/TimeBasedBucket.hh" + +namespace mu2e{ + using CDWC_iterator = std::vector::iterator; + using CDWC_const_iterator = std::vector::const_iterator; + + class CaloDigiWrapperCollection{ + public: + using SiPMID_t = int; + using sample_t = int; + using pos_t = size_t; + // forwarded calls to underlying container + size_t size() const; + CDWC_iterator begin(); + CDWC_const_iterator begin() const; + CDWC_iterator end(); + CDWC_const_iterator end() const; + CaloDigiWrapper& operator[](size_t); + const CaloDigiWrapper& operator[](size_t) const; + CaloDigiWrapper& front(); + const CaloDigiWrapper& front() const; + CaloDigiWrapper& back(); + const CaloDigiWrapper& back() const; + + // insertion + void Append(const CaloDigiCollection&); + void Append(const CaloDigiWrapper); + + // accessor + std::unique_ptr GetDigis() const; + + // identify sets of digis with overlapping digitization windows, and + // reduce each such set to a single digi, representing their "sum" + void ResolveCollisions(CaloDigiWrapperCollection&); + + protected: + std::vector _wrappers; + void ResolveCollision(CaloDigiWrapperCollection&, + CaloDigiWrapperCollection&); + + private: + /**/ + }; +} // namespace mu2e + +#endif diff --git a/CaloMC/src/CaloDigiWrapper.cc b/CaloMC/src/CaloDigiWrapper.cc new file mode 100644 index 0000000000..66a8816b6d --- /dev/null +++ b/CaloMC/src/CaloDigiWrapper.cc @@ -0,0 +1,23 @@ +// Ed Callaghan +// Simple wrapper around calorimeter digis to interface into a partitioning scheme +// September 2025 + +#include "Offline/CaloMC/inc/CaloDigiWrapper.hh" + +namespace mu2e{ + CaloDigiWrapper::CaloDigiWrapper(const CaloDigi& digi): + _digi(digi.SiPMID(), digi.t0(), digi.waveform(), digi.peakpos()){ + /**/ + } + + const CaloDigi& CaloDigiWrapper::Digi() const{ + const auto& rv = _digi; + return rv; + } + + const double CaloDigiWrapper::time() const{ + auto t0 = _digi.t0(); + auto rv = static_cast(t0); + return rv; + } +} // namespace mu2e diff --git a/CaloMC/src/CaloDigiWrapperCollection.cc b/CaloMC/src/CaloDigiWrapperCollection.cc new file mode 100644 index 0000000000..0ae0ae803d --- /dev/null +++ b/CaloMC/src/CaloDigiWrapperCollection.cc @@ -0,0 +1,198 @@ +// Ed Callaghan +// Container for CaloDigiWrappers, with functionality to resolve overlapping digitization windows +// September 2025 + +#include "Offline/CaloMC/inc/CaloDigiWrapperCollection.hh" + +namespace mu2e{ + // forward size query to underlying container + size_t CaloDigiWrapperCollection::size() const{ + auto rv = _wrappers.size(); + return rv; + } + + // forward iterator access to underlying wrappers + CDWC_iterator CaloDigiWrapperCollection::begin(){ + auto rv = _wrappers.begin(); + return rv; + } + + CDWC_const_iterator CaloDigiWrapperCollection::begin() const{ + auto rv = _wrappers.begin(); + return rv; + } + + CDWC_iterator CaloDigiWrapperCollection::end(){ + auto rv = _wrappers.end(); + return rv; + } + + CDWC_const_iterator CaloDigiWrapperCollection::end() const{ + auto rv = _wrappers.end(); + return rv; + } + + // forward lookups to underlying container + CaloDigiWrapper& CaloDigiWrapperCollection::operator[](size_t i){ + auto& rv = _wrappers[i]; + return rv; + } + + const CaloDigiWrapper& CaloDigiWrapperCollection::operator[](size_t i) const{ + const auto& rv = _wrappers[i]; + return rv; + } + + CaloDigiWrapper& CaloDigiWrapperCollection::front(){ + auto& rv = _wrappers.front(); + return rv; + } + + const CaloDigiWrapper& CaloDigiWrapperCollection::front() const{ + const auto& rv = _wrappers.front(); + return rv; + } + + CaloDigiWrapper& CaloDigiWrapperCollection::back(){ + auto& rv = _wrappers.back(); + return rv; + } + + const CaloDigiWrapper& CaloDigiWrapperCollection::back() const{ + const auto& rv = _wrappers.back(); + return rv; + } + + // insertion + void CaloDigiWrapperCollection::Append(const CaloDigiCollection& digis){ + for (size_t i = 0 ; i < digis.size() ; i++){ + const auto& digi = digis.at(i); + CaloDigiWrapper wrapper(digi); + _wrappers.emplace_back(digi); + continue; + } + } + + void CaloDigiWrapperCollection::Append(const CaloDigiWrapper wrapper){ + _wrappers.push_back(wrapper); + } + + // accessor + std::unique_ptr CaloDigiWrapperCollection::GetDigis() const{ + auto rv = std::make_unique(); + rv->reserve(_wrappers.size()); + for (const auto& wrapper: _wrappers){ + const auto& digi = wrapper.Digi(); + rv->push_back(digi); + } + + return rv; + } + + // collision resolution + // auxiliary comparison to facilitate time-sorting + bool compare_t0s(const CaloDigiWrapper* lhs, const CaloDigiWrapper* rhs){ + bool rv = (lhs->Digi().t0() < rhs->Digi().t0()); + return rv; + } + + // ejc: this overlaps _greatly_ with CaloDigiWrapperCollection + // TODO this assumes a fixed overlap window, which does not apply for calo + // here we need variable-length chain links --- -.- + void CaloDigiWrapperCollection::ResolveCollisions(CaloDigiWrapperCollection& rv){ + // identify time-overlapped chains: this is a 3 step process + // first, partition wrappers according to SiPMID_t + std::map unsorted_map; + for (const auto& wrapper: (*this)){ + const auto& digi = wrapper.Digi(); + SiPMID_t id = digi.SiPMID(); + unsorted_map[id].Append(wrapper); + } + + // next, (approximately) sort all subsets via time, to avoid + // pathological situations where timing buckets are misconstructed + // we shamefully and begrudgingly do this indirectly via bare pointers + std::map wrappers_map; + for (const auto& pair: unsorted_map){ + const auto& id = pair.first; + auto& wrappers = pair.second; + std::vector sortable(wrappers.size()); + for (size_t i = 0 ; i < wrappers.size() ; i++){ + sortable[i] = const_cast(&wrappers[i]); + } + std::sort(sortable.begin(), sortable.end(), compare_t0s); + CaloDigiWrapperCollection sorted; + for (size_t i = 0 ; i < wrappers.size() ; i++){ + sorted.Append(*sortable[i]); + } + wrappers_map.emplace(id, sorted); + } + + // then, filter each subset into buckets based on overlapping time windows + std::map< SiPMID_t, TimeBasedBuckets > buckets_map; + for (const auto& pair: wrappers_map){ + const auto& id = pair.first; + const auto& wrappers = pair.second; + TimeBasedBuckets buckets; + for (const auto& wrapper: wrappers){ + double window = static_cast(wrapper.Digi().waveform().size()); + buckets.Insert(wrapper, window); + } + buckets_map.emplace(id, buckets); + } + + // finally, recast each bucket as a regular container + // and resolve the set of degenerate digis into one + for (const auto& pair: buckets_map){ + const auto& buckets = pair.second; + for (const auto& bucket: buckets){ + CaloDigiWrapperCollection wrappers; + for (const auto& wrapper: bucket){ + wrappers.Append(wrapper); + } + this->ResolveCollision(wrappers, rv); + } + } + } + + void CaloDigiWrapperCollection::ResolveCollision(CaloDigiWrapperCollection& collided, CaloDigiWrapperCollection& rv){ + // if only one digi present, then nothing to do + if (collided.size() < 2){ + rv.Append(collided.front()); + } + + // multiple digis must be summed into a single waveform + const auto& first = collided.front().Digi(); + const auto& last = collided.back().Digi(); + size_t length = (last.t0() - first.t0()) + last.waveform().size(); + std::vector samples(length, 0); + + // sum each individual waveform into the total + // TODO this does not account for saturation + for (const auto& wrapper: collided){ + const auto& digi = wrapper.Digi(); + const auto& waveform = digi.waveform(); + const size_t shift = digi.t0() - first.t0(); + for (size_t i = 0 ; i < waveform.size() ; i++){ + samples[i + shift] += waveform[i]; + } + } + + // now find the peak position + pos_t peakpos = 0; + sample_t peak = 0; + for (size_t i = 0 ; i < samples.size() ; i++){ + const auto sample = samples[i]; + if (peak < sample){ + peakpos = i; + peak = sample; + } + } + + const auto id = first.SiPMID(); + const auto t0 = first.t0(); + const auto digi = CaloDigi(id, t0, samples, peakpos); + const auto wrapper = CaloDigiWrapper(digi); + rv.Append(wrapper); + } +} diff --git a/TrackerMC/src/StrawDigiBundleCollection.cc b/TrackerMC/src/StrawDigiBundleCollection.cc index 3ebfbb29c8..8f3492c18e 100644 --- a/TrackerMC/src/StrawDigiBundleCollection.cc +++ b/TrackerMC/src/StrawDigiBundleCollection.cc @@ -191,9 +191,9 @@ namespace mu2e{ for (const auto& pair: bundles_map){ const auto& id = pair.first; const auto& bundles = pair.second; - TimeBasedBuckets buckets(window); + TimeBasedBuckets buckets; for (const auto& bundle: bundles){ - buckets.Insert(bundle); + buckets.Insert(bundle, window); } buckets_map.emplace(id, buckets); } From eb9782459963fb49be29c7b62300133d1b23737a Mon Sep 17 00:00:00 2001 From: edcallaghan Date: Sun, 26 Oct 2025 20:43:47 -0700 Subject: [PATCH 05/15] bug fixes in calo digi collision resolution --- CaloMC/inc/CaloDigiWrapperCollection.hh | 2 +- CaloMC/src/CaloDigiWrapperCollection.cc | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/CaloMC/inc/CaloDigiWrapperCollection.hh b/CaloMC/inc/CaloDigiWrapperCollection.hh index 1308f713cd..21d3f414b2 100644 --- a/CaloMC/inc/CaloDigiWrapperCollection.hh +++ b/CaloMC/inc/CaloDigiWrapperCollection.hh @@ -39,7 +39,7 @@ namespace mu2e{ // insertion void Append(const CaloDigiCollection&); - void Append(const CaloDigiWrapper); + void Append(const CaloDigiWrapper&); // accessor std::unique_ptr GetDigis() const; diff --git a/CaloMC/src/CaloDigiWrapperCollection.cc b/CaloMC/src/CaloDigiWrapperCollection.cc index 0ae0ae803d..23a2f4c4f4 100644 --- a/CaloMC/src/CaloDigiWrapperCollection.cc +++ b/CaloMC/src/CaloDigiWrapperCollection.cc @@ -73,7 +73,7 @@ namespace mu2e{ } } - void CaloDigiWrapperCollection::Append(const CaloDigiWrapper wrapper){ + void CaloDigiWrapperCollection::Append(const CaloDigiWrapper& wrapper){ _wrappers.push_back(wrapper); } @@ -159,12 +159,21 @@ namespace mu2e{ // if only one digi present, then nothing to do if (collided.size() < 2){ rv.Append(collided.front()); + return; } // multiple digis must be summed into a single waveform + // here we determine the length of that waveform, by finding + // how far past the end of the first it extends, if at all const auto& first = collided.front().Digi(); - const auto& last = collided.back().Digi(); - size_t length = (last.t0() - first.t0()) + last.waveform().size(); + size_t length = 0; + for (const auto& wrapper: collided){ + const auto& digi = wrapper.Digi(); + size_t proposed = (digi.t0() - first.t0()) + digi.waveform().size(); + if (length < proposed){ + length = proposed; + } + } std::vector samples(length, 0); // sum each individual waveform into the total From 909597ab92a7056b40b8b82c7a252a3298a07437 Mon Sep 17 00:00:00 2001 From: edcallaghan Date: Fri, 19 Dec 2025 11:53:34 -0800 Subject: [PATCH 06/15] account for calo waveform saturation in digi mixing --- Blinding/src/MergeDigis_module.cc | 10 ++++++++-- CaloMC/inc/CaloDigiWrapper.hh | 3 +++ CaloMC/inc/CaloDigiWrapperCollection.hh | 11 ++++++----- CaloMC/src/CaloDigiWrapperCollection.cc | 12 ++++++++---- 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/Blinding/src/MergeDigis_module.cc b/Blinding/src/MergeDigis_module.cc index 23f6783382..dab5909d83 100644 --- a/Blinding/src/MergeDigis_module.cc +++ b/Blinding/src/MergeDigis_module.cc @@ -41,6 +41,10 @@ namespace mu2e{ fhicl::Name("CaloDigiCollections"), fhicl::Comment("art::InputTags of source CaloDigis") }; + fhicl::Atom calo_adc_bits{ + fhicl::Name("CalorimeterADCBitDepth"), + fhicl::Comment("Bit depth of calorimeter adc readings (temporary)") + }; }; using Parameters = art::EDProducer::Table; @@ -54,6 +58,7 @@ namespace mu2e{ // calorimeter std::vector _calo_digi_tags; + CaloDigiWrapper::sample_t _calo_max_adc; private: void produce(art::Event&); @@ -64,7 +69,8 @@ namespace mu2e{ art::EDProducer(config), _tracker_digi_tags(config().tracker_digi_tags()), _tracker_mc(config().tracker_mc()), - _calo_digi_tags(config().calo_digi_tags()){ + _calo_digi_tags(config().calo_digi_tags()), + _calo_max_adc(1 << config().calo_adc_bits()){ // tracker for (const auto& tag: _tracker_digi_tags){ this->consumes(tag); @@ -127,7 +133,7 @@ namespace mu2e{ wrappers.Append(*handle); } CaloDigiWrapperCollection calo_resolved; - wrappers.ResolveCollisions(calo_resolved); + wrappers.ResolveCollisions(_calo_max_adc, calo_resolved); auto calo_digis = calo_resolved.GetDigis(); event.put(std::move(calo_digis)); diff --git a/CaloMC/inc/CaloDigiWrapper.hh b/CaloMC/inc/CaloDigiWrapper.hh index 1f8f7a84ed..c1677edb60 100644 --- a/CaloMC/inc/CaloDigiWrapper.hh +++ b/CaloMC/inc/CaloDigiWrapper.hh @@ -11,6 +11,9 @@ namespace mu2e{ class CaloDigiWrapper{ public: + using SiPMID_t = int; + using sample_t = int; + using pos_t = size_t; CaloDigiWrapper(const CaloDigi&); const CaloDigi& Digi() const; diff --git a/CaloMC/inc/CaloDigiWrapperCollection.hh b/CaloMC/inc/CaloDigiWrapperCollection.hh index 21d3f414b2..eca4f4dc9e 100644 --- a/CaloMC/inc/CaloDigiWrapperCollection.hh +++ b/CaloMC/inc/CaloDigiWrapperCollection.hh @@ -21,9 +21,9 @@ namespace mu2e{ class CaloDigiWrapperCollection{ public: - using SiPMID_t = int; - using sample_t = int; - using pos_t = size_t; + using SiPMID_t = CaloDigiWrapper::SiPMID_t; + using sample_t = CaloDigiWrapper::sample_t; + using pos_t = CaloDigiWrapper::pos_t; // forwarded calls to underlying container size_t size() const; CDWC_iterator begin(); @@ -46,11 +46,12 @@ namespace mu2e{ // identify sets of digis with overlapping digitization windows, and // reduce each such set to a single digi, representing their "sum" - void ResolveCollisions(CaloDigiWrapperCollection&); + void ResolveCollisions(sample_t, CaloDigiWrapperCollection&); protected: std::vector _wrappers; - void ResolveCollision(CaloDigiWrapperCollection&, + void ResolveCollision(sample_t, + CaloDigiWrapperCollection&, CaloDigiWrapperCollection&); private: diff --git a/CaloMC/src/CaloDigiWrapperCollection.cc b/CaloMC/src/CaloDigiWrapperCollection.cc index 23a2f4c4f4..74ab8120d5 100644 --- a/CaloMC/src/CaloDigiWrapperCollection.cc +++ b/CaloMC/src/CaloDigiWrapperCollection.cc @@ -99,7 +99,7 @@ namespace mu2e{ // ejc: this overlaps _greatly_ with CaloDigiWrapperCollection // TODO this assumes a fixed overlap window, which does not apply for calo // here we need variable-length chain links --- -.- - void CaloDigiWrapperCollection::ResolveCollisions(CaloDigiWrapperCollection& rv){ + void CaloDigiWrapperCollection::ResolveCollisions(sample_t max_adc, CaloDigiWrapperCollection& rv){ // identify time-overlapped chains: this is a 3 step process // first, partition wrappers according to SiPMID_t std::map unsorted_map; @@ -150,12 +150,12 @@ namespace mu2e{ for (const auto& wrapper: bucket){ wrappers.Append(wrapper); } - this->ResolveCollision(wrappers, rv); + this->ResolveCollision(max_adc, wrappers, rv); } } } - void CaloDigiWrapperCollection::ResolveCollision(CaloDigiWrapperCollection& collided, CaloDigiWrapperCollection& rv){ + void CaloDigiWrapperCollection::ResolveCollision(sample_t max_adc, CaloDigiWrapperCollection& collided, CaloDigiWrapperCollection& rv){ // if only one digi present, then nothing to do if (collided.size() < 2){ rv.Append(collided.front()); @@ -177,7 +177,6 @@ namespace mu2e{ std::vector samples(length, 0); // sum each individual waveform into the total - // TODO this does not account for saturation for (const auto& wrapper: collided){ const auto& digi = wrapper.Digi(); const auto& waveform = digi.waveform(); @@ -187,6 +186,11 @@ namespace mu2e{ } } + // enforce saturation of waveforms from adc word size + for (size_t i = 0 ; i < samples.size() ; i++){ + samples[i] = std::min(max_adc, samples[i]); + } + // now find the peak position pos_t peakpos = 0; sample_t peak = 0; From 9ec187c9d5168c09eec7690189b7dddb90b4a137 Mon Sep 17 00:00:00 2001 From: edcallaghan Date: Mon, 22 Dec 2025 13:08:56 -0800 Subject: [PATCH 07/15] CaloShowerSim mixing to support MC truth info in digi mixing --- EventMixing/inc/Mu2eProductMixer.hh | 9 ++++++++ EventMixing/src/Mu2eProductMixer.cc | 36 ++++++++++++++++++++++++++--- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/EventMixing/inc/Mu2eProductMixer.hh b/EventMixing/inc/Mu2eProductMixer.hh index b594e50e4b..51bf37aab8 100644 --- a/EventMixing/inc/Mu2eProductMixer.hh +++ b/EventMixing/inc/Mu2eProductMixer.hh @@ -45,6 +45,7 @@ #include "Offline/RecoDataProducts/inc/StrawDigi.hh" #include "Offline/MCDataProducts/inc/StrawDigiMC.hh" #include "Offline/RecoDataProducts/inc/CaloDigi.hh" +#include "Offline/MCDataProducts/inc/CaloShowerSim.hh" #include "Offline/DataProducts/inc/EventWindowMarker.hh" @@ -111,6 +112,7 @@ namespace mu2e { fhicl::Table strawDigiADCWaveformMixer { fhicl::Name("strawDigiADCWaveformMixer") }; fhicl::Table strawDigiMCMixer { fhicl::Name("strawDigiMCMixer") }; fhicl::Table caloDigiMixer { fhicl::Name("caloDigiMixer") }; + fhicl::Table caloShowerSimMixer { fhicl::Name("caloShowerSimMixer") }; fhicl::Table eventWindowMarkerMixer { fhicl::Name("eventWindowMarkerMixer") }; fhicl::OptionalTable cosmicLivetimeMixer { fhicl::Name("cosmicLivetimeMixer") }; fhicl::OptionalTable volumeInfoMixer { fhicl::Name("volumeInfoMixer") }; @@ -178,6 +180,10 @@ namespace mu2e { CaloDigiCollection& out, art::PtrRemapper const& remap); + bool mixCaloShowerSims(std::vector const& in, + CaloShowerSimCollection& out, + art::PtrRemapper const& remap); + bool mixEventWindowMarkers(std::vector const& in, EventWindowMarker& out, art::PtrRemapper const& remap); @@ -215,6 +221,9 @@ namespace mu2e { typedef StrawGasStepCollection::size_type SGSOffset; std::vector sgsOffsets_; + typedef CaloShowerStepCollection::size_type CSSOffset; + std::vector cssOffsets_; + void updateSimParticle(SimParticle& particle, SPOffset offset, art::PtrRemapper const& remap); typedef std::map VolumeMap; diff --git a/EventMixing/src/Mu2eProductMixer.cc b/EventMixing/src/Mu2eProductMixer.cc index 47d0ac5e82..636a77f3a5 100644 --- a/EventMixing/src/Mu2eProductMixer.cc +++ b/EventMixing/src/Mu2eProductMixer.cc @@ -122,6 +122,11 @@ namespace mu2e { (e.inTag, e.resolvedInstanceName(), &Mu2eProductMixer::mixCaloDigis, *this); } + for(const auto& e: conf.caloShowerSimMixer().mixingMap()) { + helper.declareMixOp + (e.inTag, e.resolvedInstanceName(), &Mu2eProductMixer::mixCaloShowerSims, *this); + } + for(const auto& e: conf.eventWindowMarkerMixer().mixingMap()) { helper.declareMixOp (e.inTag, e.resolvedInstanceName(), &Mu2eProductMixer::mixEventWindowMarkers, *this); @@ -356,11 +361,11 @@ namespace mu2e { CaloShowerStepCollection& out, art::PtrRemapper const& remap) { - std::vector stepOffsets; - art::flattenCollections(in, out, stepOffsets); + std::vector cssOffsets_; + art::flattenCollections(in, out, cssOffsets_); for(CaloShowerStepCollection::size_type i=0; i const& in, + CaloShowerSimCollection& out, + art::PtrRemapper const& remap) + { + std::vector cssimOffsets; + art::flattenCollections(in, out, cssimOffsets); + + // remap art::Ptrs + for (CaloShowerSimCollection::size_type i=0; i < out.size(); ++i) { + auto& sim = out[i]; + auto ie = getInputEventIndex(i, cssimOffsets); + auto cssOffset = cssOffsets_[ie]; + + // remap CaloShowerSteps + auto& steps = sim.caloShowerSteps(); + CaloShowerSim::StepPtrs remapped; + for (size_t is = 0 ; is < steps.size(); is++){ + remapped.push_back(remap(steps[is], cssOffset)); + } + sim.setCaloShowerSteps(std::move(remapped)); + } + + return true; + } + bool Mu2eProductMixer::mixEventWindowMarkers(std::vector const& in, EventWindowMarker& out, art::PtrRemapper const& remap){ From 445af368012db1b43eaf56541a41cd10806e167f Mon Sep 17 00:00:00 2001 From: edcallaghan Date: Mon, 22 Dec 2025 14:26:39 -0800 Subject: [PATCH 08/15] fix shadow declaration --- EventMixing/src/Mu2eProductMixer.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/EventMixing/src/Mu2eProductMixer.cc b/EventMixing/src/Mu2eProductMixer.cc index 636a77f3a5..2edd07169e 100644 --- a/EventMixing/src/Mu2eProductMixer.cc +++ b/EventMixing/src/Mu2eProductMixer.cc @@ -361,7 +361,6 @@ namespace mu2e { CaloShowerStepCollection& out, art::PtrRemapper const& remap) { - std::vector cssOffsets_; art::flattenCollections(in, out, cssOffsets_); for(CaloShowerStepCollection::size_type i=0; i Date: Mon, 22 Dec 2025 15:30:51 -0800 Subject: [PATCH 09/15] replace missing syntax braces --- Blinding/src/MergeDigis_module.cc | 1 + EventMixing/src/Mu2eProductMixer.cc | 1 + 2 files changed, 2 insertions(+) diff --git a/Blinding/src/MergeDigis_module.cc b/Blinding/src/MergeDigis_module.cc index 5a91fd89b0..d90427350e 100644 --- a/Blinding/src/MergeDigis_module.cc +++ b/Blinding/src/MergeDigis_module.cc @@ -49,6 +49,7 @@ namespace mu2e{ fhicl::Atom calo_adc_bits{ fhicl::Name("CalorimeterADCBitDepth"), fhicl::Comment("Bit depth of calorimeter adc readings (temporary)") + }; fhicl::Sequence crv_digi_tags{ fhicl::Name("CrvDigiCollections"), fhicl::Comment("art::InputTags of source CrvDigi") diff --git a/EventMixing/src/Mu2eProductMixer.cc b/EventMixing/src/Mu2eProductMixer.cc index cd2b429518..16b9b3f41c 100644 --- a/EventMixing/src/Mu2eProductMixer.cc +++ b/EventMixing/src/Mu2eProductMixer.cc @@ -125,6 +125,7 @@ namespace mu2e { for(const auto& e: conf.caloShowerSimMixer().mixingMap()) { helper.declareMixOp (e.inTag, e.resolvedInstanceName(), &Mu2eProductMixer::mixCaloShowerSims, *this); + } for(const auto& e: conf.crvDigiMixer().mixingMap()) { helper.declareMixOp From fb026e0fe679372110468938e5bd1bf23e596e58 Mon Sep 17 00:00:00 2001 From: edcallaghan Date: Mon, 22 Dec 2025 15:52:57 -0800 Subject: [PATCH 10/15] data member reordering + clean up from merge --- Blinding/src/MergeDigis_module.cc | 9 +++++---- EventMixing/inc/Mu2eProductMixer.hh | 2 ++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Blinding/src/MergeDigis_module.cc b/Blinding/src/MergeDigis_module.cc index d90427350e..30517cf93b 100644 --- a/Blinding/src/MergeDigis_module.cc +++ b/Blinding/src/MergeDigis_module.cc @@ -68,15 +68,16 @@ namespace mu2e{ std::vector _tracker_digi_tags; bool _tracker_mc; ProditionsHandle _tracker_conditions_handle; - // crv - std::vector _crv_digi_tags; - std::vector _crv_digimc_tags; - ProditionsHandle _crv_calib_handle; // calorimeter std::vector _calo_digi_tags; CaloDigiWrapper::sample_t _calo_max_adc; + // crv + std::vector _crv_digi_tags; + std::vector _crv_digimc_tags; + ProditionsHandle _crv_calib_handle; + private: void produce(art::Event&); void mergeCrvDigis(art::Event&); diff --git a/EventMixing/inc/Mu2eProductMixer.hh b/EventMixing/inc/Mu2eProductMixer.hh index bb055e0d91..b230a78c1a 100644 --- a/EventMixing/inc/Mu2eProductMixer.hh +++ b/EventMixing/inc/Mu2eProductMixer.hh @@ -186,6 +186,8 @@ namespace mu2e { bool mixCaloShowerSims(std::vector const& in, CaloShowerSimCollection& out, + art::PtrRemapper const& remap); + bool mixCrvDigis(std::vector const& in, CrvDigiCollection& out, art::PtrRemapper const& remap); From b95f834f410dd175a1e52bb3e030d1ef0d7c11a9 Mon Sep 17 00:00:00 2001 From: edcallaghan Date: Mon, 22 Dec 2025 16:02:48 -0800 Subject: [PATCH 11/15] more fallout from merge :') --- EventMixing/src/Mu2eProductMixer.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/EventMixing/src/Mu2eProductMixer.cc b/EventMixing/src/Mu2eProductMixer.cc index 16b9b3f41c..41268b758f 100644 --- a/EventMixing/src/Mu2eProductMixer.cc +++ b/EventMixing/src/Mu2eProductMixer.cc @@ -501,6 +501,10 @@ namespace mu2e { bool Mu2eProductMixer::mixCaloDigis(std::vector const& in, CaloDigiCollection& out, art::PtrRemapper const& remap) + { + art::flattenCollections(in, out); + return true; + } bool Mu2eProductMixer::mixCrvDigis(std::vector const& in, CrvDigiCollection& out, From 479180ce7a4ae1ff8d14f01e5a884d64e7a2153a Mon Sep 17 00:00:00 2001 From: edcallaghan Date: Mon, 22 Dec 2025 17:30:39 -0800 Subject: [PATCH 12/15] last post-merge fix --- EventMixing/src/Mu2eProductMixer.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/EventMixing/src/Mu2eProductMixer.cc b/EventMixing/src/Mu2eProductMixer.cc index 41268b758f..620f96f859 100644 --- a/EventMixing/src/Mu2eProductMixer.cc +++ b/EventMixing/src/Mu2eProductMixer.cc @@ -534,6 +534,10 @@ namespace mu2e { remapped.push_back(remap(steps[is], cssOffset)); } sim.setCaloShowerSteps(std::move(remapped)); + } + + return true; + } bool Mu2eProductMixer::mixCrvDigiMCs(std::vector const& in, CrvDigiMCCollection& out, From 624f33ffa8a745908c39e39b311fdb8a8572efc9 Mon Sep 17 00:00:00 2001 From: edcallaghan Date: Mon, 22 Dec 2025 17:45:38 -0800 Subject: [PATCH 13/15] rm defunct commentary --- CaloMC/src/CaloDigiWrapperCollection.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/CaloMC/src/CaloDigiWrapperCollection.cc b/CaloMC/src/CaloDigiWrapperCollection.cc index 74ab8120d5..9e4f86310f 100644 --- a/CaloMC/src/CaloDigiWrapperCollection.cc +++ b/CaloMC/src/CaloDigiWrapperCollection.cc @@ -96,9 +96,6 @@ namespace mu2e{ return rv; } - // ejc: this overlaps _greatly_ with CaloDigiWrapperCollection - // TODO this assumes a fixed overlap window, which does not apply for calo - // here we need variable-length chain links --- -.- void CaloDigiWrapperCollection::ResolveCollisions(sample_t max_adc, CaloDigiWrapperCollection& rv){ // identify time-overlapped chains: this is a 3 step process // first, partition wrappers according to SiPMID_t From f56bda5120aeaf1288d5983a20fdea3f9fafa6d7 Mon Sep 17 00:00:00 2001 From: edcallaghan Date: Mon, 22 Dec 2025 17:58:46 -0800 Subject: [PATCH 14/15] correct calorimeter adc range --- Blinding/src/MergeDigis_module.cc | 2 +- CaloMC/src/CaloDigiMaker_module.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Blinding/src/MergeDigis_module.cc b/Blinding/src/MergeDigis_module.cc index 30517cf93b..f9c4ff2afd 100644 --- a/Blinding/src/MergeDigis_module.cc +++ b/Blinding/src/MergeDigis_module.cc @@ -89,7 +89,7 @@ namespace mu2e{ _tracker_digi_tags(config().tracker_digi_tags()), _tracker_mc(config().tracker_mc()), _calo_digi_tags(config().calo_digi_tags()), - _calo_max_adc(1 << config().calo_adc_bits()), + _calo_max_adc((1 << config().calo_adc_bits()) - 1), _crv_digi_tags(config().crv_digi_tags()), _crv_digimc_tags(config().crv_digimc_tags()){ // tracker diff --git a/CaloMC/src/CaloDigiMaker_module.cc b/CaloMC/src/CaloDigiMaker_module.cc index 2f654a269e..5e9705b687 100644 --- a/CaloMC/src/CaloDigiMaker_module.cc +++ b/CaloMC/src/CaloDigiMaker_module.cc @@ -82,7 +82,7 @@ namespace mu2e { digiSampling_ (config().digiSampling()), bufferDigi_ (config().bufferDigi()), startTimeBuffer_ (config().digiSampling()*config().bufferDigi()), - maxADCCounts_ (1 << config().nBits()), + maxADCCounts_ ((1 << config().nBits()) - 1), pulseShape_ (CaloPulseShape(config().digiSampling())), wfExtractor_ (config().bufferDigi(),config().nBinsPeak(),config().minPeakADC(),config().bufferDigi()), engine_ (createEngine(art::ServiceHandle()->getSeed())), From 71a8ca4242c787a4b080fd69e1fe305234d23cf7 Mon Sep 17 00:00:00 2001 From: edcallaghan Date: Mon, 22 Dec 2025 22:10:24 -0600 Subject: [PATCH 15/15] add calo support classes to CMakeLists --- CaloMC/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CaloMC/CMakeLists.txt b/CaloMC/CMakeLists.txt index a631ff4e95..915621ac7b 100644 --- a/CaloMC/CMakeLists.txt +++ b/CaloMC/CMakeLists.txt @@ -4,6 +4,8 @@ cet_make_library( src/CaloPhotonPropagation.cc src/CaloWFExtractor.cc src/ShowerStepUtil.cc + src/CaloDigiWrapper.cc + src/CaloDigiWrapperCollection.cc LIBRARIES PUBLIC Offline::CalorimeterGeom