From 1694b7f23f3f8b0f4edc365a90f6ff33c604c127 Mon Sep 17 00:00:00 2001 From: Andrew Edmonds Date: Mon, 1 Jun 2026 10:31:45 -0500 Subject: [PATCH 1/9] Adding agents.md --- AGENTS.md | 225 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..2ca9c37 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,225 @@ +# AGENTS.md — EventNtuple Coding Agent Instructions + +## Project Overview + +EventNtuple is a Mu2e (Fermilab) art/ROOT analysis ntuple package. It fills a flat +ROOT ntuple from Mu2e reconstruction output (KalSeeds, CaloCluster, CRV, etc.) and +provides a Python/ROOT analysis library (RooUtil) and distributed job runner (roodask). + +**Framework:** `art` (Fermilab) + `cetmodules` CMake layer + `fhiclcpp` configuration. +**Languages:** C++17 (modules, helpers, structs), FHiCL (job config), Python 3.12+ (helpers/tools). + +--- + +## Build Commands + +Environment must be set up via Muse before building: + +```bash +mu2einit +muse setup # or: muse setup AnalysisMDC2020 / AnalysisMDC2025 +muse build -j4 --mu2eCompactPrint +``` + +Alternative Spack-based build: + +```bash +spack develop event-ntuple@main +spack concretize -f && spack install +``` + +Run the ntuple maker: + +```bash +mu2e -c EventNtuple/fcl/from_mcs-mockdata.fcl -S your-art-filelist.txt +``` + +--- + +## Test / Validation Commands + +All validation scripts are in `validation/`. There is no unit test framework; tests +run the full art job and compare histograms. + +```bash +# Quick smoke test: runs from_mcs-mockdata.fcl, creates histograms +bash validation/quick_test.sh + +# Test all FCL files for a campaign +bash validation/test_fcls.sh MDC2020 +bash validation/test_fcls.sh MDC2025 +bash validation/test_fcls.sh Run1B + +# Test RooUtil library +bash validation/test_rooutil.sh + +# Test all RooUtil example macros +bash validation/test_rooutil_examples.sh + +# Test Python ntuplehelper +python validation/ntuplehelper-test.py + +# Test roodask distributed runner +bash validation/roodask_test.sh +``` + +To run a **single FCL test** manually: + +```bash +mu2e -c EventNtuple/fcl/.fcl -S filelist.txt -n 100 +``` + +--- + +## FHiCL Configuration Structure + +### Branch / MC Data Configuration (Key Area for Improvement) + +Branch configuration is defined in `fcl/prolog.fcl`. Each track type is a FHiCL table: + +``` +DeM : { + input : "MergeKKDeM" # input KalSeedPtr collection tag + branch : "dem" # output ROOT branch name + options : { + fillMC : true # toggle MC truth filling for this branch + fillHits : true # toggle hit-level info + genealogyDepth : -1 # MC genealogy depth (-1 = all) + matchDepth : -1 # MC match depth (-1 = all) + } + trkQualTags : ["TrkQualDeM"] + trkPIDTags : ["TrkPIDDeM"] +} +``` + +Global MC switch lives in `EventNtupleMaker` config: `FillMCInfo : true/false`. +Per-branch MC is controlled by `options.fillMC`. Both must be true for MC to fill. + +**Current issue:** Branch on/off and MC on/off are scattered across individual track +tables in `prolog.fcl` and duplicated in every campaign FCL. When adding a new +track type or toggling MC for a subset of branches, edits are required in many places. + +**Preferred direction for improvement:** +- Define a single `BranchOptions` prolog table with canonical defaults. +- Use `@table::` inheritance for per-branch overrides rather than full re-specification. +- Consider a top-level `MCOptions` table that can be overlaid to flip all `fillMC` flags. +- Campaign FCLs should `#include prolog.fcl` and only override what differs. + +--- + +## C++ Code Style + +### File Naming +- Headers: `PascalCase.hh` in `inc/` +- Sources: `PascalCase.cc` in `src/` +- Module plugins: `PascalCase_module.cc` + +### Namespaces +All production code lives in `namespace mu2e {}`. +RooUtil library uses `namespace rooutil {}`. + +### Struct / Class Naming +- Ntuple info structs: `PascalCase` ending in `Info` or `InfoMC` (e.g. `TrkInfo`, `CaloClusterInfoMC`) +- Each struct lives in its own `inc/.hh` header + +### Member Naming +- Module private members: leading underscore (`_conf`, `_fillmc`, `_ntuple`) +- Struct data members: `snake_case` (no underscore suffix); initialized to sentinel values + - Integers: `int status = -1;` + - Floats: `float chisq = -1;` or `float mom = std::numeric_limits::min();` + - Booleans: `bool flag = false;` + +### Info Struct Pattern (required for `ntuplehelper` compatibility) +```cpp +namespace mu2e { + struct FooInfo { + // required comment on every leaf for ntuplehelper autodoc + int status = -1; // fit status + float mom = -1; // momentum at tracker entrance (MeV/c) + + void reset() { *this = FooInfo(); } + }; +} +``` +Every leaf **must** have an inline `//` comment — this is parsed by `ntuplehelper --list-all-branches`. + +### Includes (C++ ordering) +1. Mu2e Offline headers (`Offline/…`) +2. art framework headers (`art/…`, `canvas/…`, `fhiclcpp/…`) +3. ROOT headers +4. Local EventNtuple headers (`EventNtuple/inc/…`) +5. C++ standard library (``, ``, etc.) + +### Error Handling +- Throw via `cet::exception`: `throw cet::exception("EventNtuple") << "message";` +- Do not use raw `std::exception` or `exit()` in art modules +- Warnings via `mf::LogWarning("EventNtuple") << "message";` + +### FHiCL Config Structs (in modules) +```cpp +struct Config { + fhicl::Atom fillMC { Name("FillMCInfo"), Comment("Fill MC info"), true }; + fhicl::Table sub { Name("SubConfig") }; + fhicl::Sequence tags { Name("InputTags") }; +}; +``` + +--- + +## Python Code Style + +- Python 3.12+; no type annotations required but welcome +- `snake_case` for all functions, methods, and variables +- Class names: `PascalCase` +- No f-strings required; format strings acceptable +- `roodask/roodask.py` is intentionally a **single-file script** — do not split it + +--- + +## FHiCL Style Guidelines + +- Use `BEGIN_PROLOG` / `END_PROLOG` for all reusable tables +- Use `@local::` for prolog references; `@table::` for struct inheritance/merging +- Do not duplicate full table bodies — inherit with `@table::Base` then override fields +- One `#include` per dependency; include Offline prologs before EventNtuple prologs +- Comment all numeric constants with units: `MaxDE : 500.0 # MeV` +- Boolean flags: `true` / `false` (lowercase, no quotes) + +--- + +## Adding a New Branch (Developer Checklist) + +See `doc/developers.md` for the full walkthrough. Summary: + +1. Create `inc/FooInfo.hh` with commented struct (see struct pattern above) +2. Add fill logic to `src/InfoStructHelper.cc` (or `InfoMCStructHelper.cc` for MC) +3. Register branch in `src/EventNtupleMaker_module.cc` +4. Add prolog table to `fcl/prolog.fcl` using `@table::` inheritance +5. Regenerate `doc/branches.md`: `ntuplehelper --list-all-branches --export-to-md` +6. Run `bash validation/quick_test.sh` to confirm no runtime errors + +--- + +## Key Files Reference + +| File | Role | +|---|---| +| `src/EventNtupleMaker_module.cc` | Main `art::EDAnalyzer`; branch registration and filling | +| `src/InfoStructHelper.cc` | Reco → struct fill logic | +| `src/InfoMCStructHelper.cc` | MC truth → struct fill logic | +| `inc/*Info*.hh` | One ntuple branch struct per file | +| `fcl/prolog.fcl` | Master FHiCL prolog (track types, branch configs, MC options) | +| `fcl/from_mcs-mockdata.fcl` | Default/reference job FCL | +| `helper/ntuplehelper.py` | Python ntuple inspection tool | +| `rooutil/inc/RooUtil.hh` | ROOT analysis library | +| `rooutil/roodask/roodask.py` | Dask distributed job runner (single-file) | +| `validation/quick_test.sh` | Primary smoke test | +| `doc/developers.md` | Developer guide for adding branches | + +--- + +## roodask Sub-tool (rooutil/roodask/) + +See `rooutil/roodask/.github/copilot-instructions.md` for detailed architecture. +Key points: single-file CLI, auto-generates C++ `main()` wrapper, shared NFS filesystem, +full environment propagated to Dask workers. Do not split `roodask.py` into multiple files. From 2377098809ea2cddcf6c49a184a090e2a4b73ec8 Mon Sep 17 00:00:00 2001 From: Andrew Edmonds Date: Mon, 1 Jun 2026 14:54:12 -0500 Subject: [PATCH 2/9] First pass from Sonnet on this --- fcl/CompareDeTracks.fcl | 2 +- fcl/TrkAnaLineFromDigis.fcl | 9 +- fcl/from_dig-OnSpill.fcl | 16 +- fcl/from_dig-calo.fcl | 41 +- fcl/from_mcs-Run1B.fcl | 10 +- fcl/from_mcs-ceSimRecoVal.fcl | 4 +- fcl/from_mcs-extracted.fcl | 4 +- fcl/from_mcs-mixed_trkQualCompare.fcl | 2 +- fcl/from_mcs-mockdata_crvInf.fcl | 2 +- fcl/from_mcs-mockdata_noMC.fcl | 6 +- fcl/from_mcs-mockdata_separateTrkBranches.fcl | 2 +- fcl/from_mcs-primary_addVDSteps.fcl | 2 +- fcl/from_mcs-reflection.fcl | 12 +- fcl/from_rec-crv-kpp.fcl | 16 +- fcl/from_rec-crv-kpp_withCrvDigis.fcl | 2 +- fcl/prolog.fcl | 171 +-- src/EventNtupleMaker_module.cc | 1020 ++++++++--------- 17 files changed, 612 insertions(+), 709 deletions(-) diff --git a/fcl/CompareDeTracks.fcl b/fcl/CompareDeTracks.fcl index 190695c..7190369 100644 --- a/fcl/CompareDeTracks.fcl +++ b/fcl/CompareDeTracks.fcl @@ -55,5 +55,5 @@ physics.end_paths : [ EndPath ] physics.producers.TrkQualDe.KalSeedPtrCollection : "MergeKKDeCalib" services.TimeTracker.printSummary: true services.TFileService.fileName: "nts.owner.EventNtupleDeCalib.version.sequence.root" -physics.analyzers.EventNtuple.KalSeedMCAssns : @nil # module which created the MC truth matching (KalSeedMC). including both primary and 2ndary tracks. +physics.analyzers.EventNtuple.trk.mc.kalSeedMCAssns : @nil # module which created the MC truth matching (KalSeedMC). including both primary and 2ndary tracks. diff --git a/fcl/TrkAnaLineFromDigis.fcl b/fcl/TrkAnaLineFromDigis.fcl index 8e0f67c..5bcc0ec 100644 --- a/fcl/TrkAnaLineFromDigis.fcl +++ b/fcl/TrkAnaLineFromDigis.fcl @@ -38,17 +38,14 @@ physics : @table::EventNtupleMaker FitType : KinematicLine diagLevel : 2 - FillMCInfo : true - FillTrkPIDInfo : false - FillHitInfo : true FillTriggerInfo : false - branches : [ + trk.branches : [ { input: "KKLine" branch : "kl" - options : { fillMC : true genealogyDepth : 5 } + options : { genealogyDepth : 5 } } ] - ExtraMCStepCollectionTags : [ "compressDigiMCs:protonabsorber", "compressDigiMCs:stoppingtarget" ] + trk.mc.extraMCStepTags : [ "compressDigiMCs:protonabsorber", "compressDigiMCs:stoppingtarget" ] } @table::TrkAnaReco.analyzers diff --git a/fcl/from_dig-OnSpill.fcl b/fcl/from_dig-OnSpill.fcl index d0a8ac2..793c08b 100644 --- a/fcl/from_dig-OnSpill.fcl +++ b/fcl/from_dig-OnSpill.fcl @@ -16,44 +16,44 @@ physics : { # apr EventNtupleTTMCApr : { @table::EventNtupleMakerTTMC - branches : [ { + trk.branches : [ { @table::TTMCBranch input : "MergeTTApr" } ] - KalSeedMCAssns: "TTAprKSFMC" + trk.mc.kalSeedMCAssns : "TTAprKSFMC" RecoCountTag : "TTAprKSFMC" SelectEvents : [ "Digitize:apr_highP*" ] } # tpr EventNtupleTTMCTpr : { @table::EventNtupleMakerTTMC - branches : [ { + trk.branches : [ { @table::TTMCBranch input : "MergeTTTpr" } ] - KalSeedMCAssns: "TTTprDeKSFMC" + trk.mc.kalSeedMCAssns : "TTTprDeKSFMC" RecoCountTag : "TTTprDeKSFMC" SelectEvents : [ "Digitize:tprDe_highP*" ] } # cpr EventNtupleTTMCCpr : { @table::EventNtupleMakerTTMC - branches : [ { + trk.branches : [ { @table::TTMCBranch input : "MergeTTCpr" } ] - KalSeedMCAssns: "TTCprDeKSFMC" + trk.mc.kalSeedMCAssns : "TTCprDeKSFMC" RecoCountTag : "TTCprDeKSFMC" SelectEvents : [ "Digitize:cprDe_highP*" ] } # mpr EventNtupleTTMCMpr : { @table::EventNtupleMakerTTMC - branches : [ { + trk.branches : [ { @table::TTMCBranch input : "MergeTTMpr" } ] - KalSeedMCAssns: "TTMprDeKSFMC" + trk.mc.kalSeedMCAssns : "TTMprDeKSFMC" RecoCountTag : "TTMprDeKSFMC" SelectEvents : [ "Digitize:mprDe_highP*" ] } diff --git a/fcl/from_dig-calo.fcl b/fcl/from_dig-calo.fcl index e7df47e..683815d 100644 --- a/fcl/from_dig-calo.fcl +++ b/fcl/from_dig-calo.fcl @@ -24,34 +24,35 @@ physics.end_paths : [ e1 ] #Tags to fill PBI information #physics.analyzers.EventNtuple.PBTTag : "EWMProducer" -#physics.analyzers.EventNtuple.PBTMCTag : "EWMProducer" +#physics.analyzers.EventNtuple.mc.PBTMCTag : "EWMProducer" physics.analyzers.EventNtuple.RecoCountTag : "" physics.analyzers.EventNtuple.PBTTag : "" -physics.analyzers.EventNtuple.PBTMCTag : "" -physics.analyzers.EventNtuple.SimParticlesTag : "CaloShowerStepMaker" +physics.analyzers.EventNtuple.mc.PBTMCTag : "" +physics.analyzers.EventNtuple.mc.simParticlesTag : "CaloShowerStepMaker" #Turn off tracker and other branches -physics.analyzers.EventNtuple.branches : [ ] -physics.analyzers.EventNtuple.FillTrkQual : false +physics.analyzers.EventNtuple.trk.branches : [ ] +physics.analyzers.EventNtuple.trk.fillTrkQual : false physics.analyzers.EventNtuple.FillTriggerInfo : false -physics.analyzers.EventNtuple.FillHitInfo : false -physics.analyzers.EventNtuple.FillCRVCoincs : false +physics.analyzers.EventNtuple.trk.fillHits : false +physics.analyzers.EventNtuple.crv.fillCoincs : false #Toggle calo branches -physics.analyzers.EventNtuple.FillCaloClusters : false -physics.analyzers.EventNtuple.FillCaloHits : false -physics.analyzers.EventNtuple.FillCaloRecoDigis : false -physics.analyzers.EventNtuple.FillCaloDigis : true +physics.analyzers.EventNtuple.calo.fillClusters : false +physics.analyzers.EventNtuple.calo.fillHits : false +physics.analyzers.EventNtuple.calo.fillRecoDigis : false +physics.analyzers.EventNtuple.calo.fillDigis : true -physics.analyzers.EventNtuple.CaloShowerSimTag : "CaloShowerROMaker" -physics.analyzers.EventNtuple.CaloDigisTag : "CaloDigiMaker" +physics.analyzers.EventNtuple.calo.mc.showerSimTag : "CaloShowerROMaker" +physics.analyzers.EventNtuple.calo.digisTag : "CaloDigiMaker" #Toggle calo MC branches -physics.analyzers.EventNtuple.FillMCInfo : false -physics.analyzers.EventNtuple.FillCaloMC : true -physics.analyzers.EventNtuple.FillCaloClustersMC : false -physics.analyzers.EventNtuple.FillCaloHitsMC : false -physics.analyzers.EventNtuple.FillCaloSimInfos : false -physics.analyzers.EventNtuple.FillCaloDigiSimInfos : true -physics.analyzers.EventNtuple.FillCaloDigisMC : true +# mc.fill is false so tracker/CRV MC and evtinfomc are disabled; +# calo MC is controlled independently via calo.mc.fill (independent of mc.fill) +physics.analyzers.EventNtuple.mc.fill : false +physics.analyzers.EventNtuple.calo.mc.fillClusters : false +physics.analyzers.EventNtuple.calo.mc.fillHits : false +physics.analyzers.EventNtuple.calo.mc.fillSim : false +physics.analyzers.EventNtuple.calo.mc.fillDigiSim : true +physics.analyzers.EventNtuple.calo.mc.fillDigis : true services.TFileService.fileName: "nts.owner.description.version.sequencer.root" diff --git a/fcl/from_mcs-Run1B.fcl b/fcl/from_mcs-Run1B.fcl index 311cc8f..121d3ae 100644 --- a/fcl/from_mcs-Run1B.fcl +++ b/fcl/from_mcs-Run1B.fcl @@ -1,13 +1,9 @@ # we start from mcs-extracted since Run-1B wants the straight line track fit #include "EventNtuple/fcl/from_mcs-extracted.fcl" -physics.analyzers.EventNtuple.FillMCInfo : true -physics.analyzers.EventNtuple.StepPointMCTags : [ "compressRecoMCs:virtualdetector" ] # we add the mcsteps_virtualdetector branch -physics.analyzers.EventNtuple.FillTimeClusterInfo : true -physics.analyzers.EventNtuple.TimeClustersTag : "SimpleTimeCluster" # Store time clusters for straight line track finding -physics.analyzers.EventNtuple.FillCaloMC : true -physics.analyzers.EventNtuple.FillCaloClustersMC : true -physics.analyzers.EventNtuple.FillCaloSimInfos : true +physics.analyzers.EventNtuple.trk.mc.stepPointMCTags : [ "compressRecoMCs:virtualdetector" ] # we add the mcsteps_virtualdetector branch +physics.analyzers.EventNtuple.trk.fillTimeClusters : true +physics.analyzers.EventNtuple.trk.timeClustersTag : "SimpleTimeCluster" # Store time clusters for straight line track finding services.GeometryService.inputFile : "Offline/Mu2eG4/geom/geom_common.txt" # we can use the standard geometry physics.EventNtupleEndPath : [ @sequence::EventNtuple.EndPath ] # add back genCountLogger diff --git a/fcl/from_mcs-ceSimRecoVal.fcl b/fcl/from_mcs-ceSimRecoVal.fcl index 4a5fb3d..0d4f21d 100644 --- a/fcl/from_mcs-ceSimRecoVal.fcl +++ b/fcl/from_mcs-ceSimRecoVal.fcl @@ -1,7 +1,5 @@ #include "EventNtuple/fcl/from_mcs-ceSimReco.fcl" -physics.analyzers.EventNtuple.branches[0].options.fillHits : true -physics.analyzers.EventNtuple.FillHitInfo : true -physics.analyzers.EventNtuple.FillHitCalibInfo : true +physics.analyzers.EventNtuple.trk.fillHitCalibs : true physics.analyzers.EventNtuple.FillTriggerInfo : true physics.analyzers.EventNtuple.TriggerProcessName : "ceTrig" diff --git a/fcl/from_mcs-extracted.fcl b/fcl/from_mcs-extracted.fcl index 98ea00b..5ad9425 100644 --- a/fcl/from_mcs-extracted.fcl +++ b/fcl/from_mcs-extracted.fcl @@ -1,8 +1,8 @@ #include "EventNtuple/fcl/from_mcs-mockdata.fcl" physics.EventNtuplePath : [ @sequence::EventNtuple.PathExt ] # path for extracted position cosmics -physics.analyzers.EventNtuple.branches : [ @local::Ext ] +physics.analyzers.EventNtuple.trk.branches : [ @local::Ext ] physics.analyzers.EventNtuple.FitType : KinematicLine -physics.analyzers.EventNtuple.FillTrkQual : false +physics.analyzers.EventNtuple.trk.fillTrkQual : false services.GeometryService.inputFile: "Production/JobConfig/cosmic/geom_cosmic_extracted.txt" diff --git a/fcl/from_mcs-mixed_trkQualCompare.fcl b/fcl/from_mcs-mixed_trkQualCompare.fcl index 24474ba..f9a4787 100644 --- a/fcl/from_mcs-mixed_trkQualCompare.fcl +++ b/fcl/from_mcs-mixed_trkQualCompare.fcl @@ -14,4 +14,4 @@ physics.EventNtuplePath : [ @sequence::EventNtuple.Path, TrkQualAllV10, TrkQualA physics.analyzers.EventNtuple.branches[0].trkQualTags : [ "TrkQualAllV10", "TrkQualAllV11", "TrkQualAllV2" ] # Removin hits -physics.analyzers.EventNtuple.FillHitInfo : false +physics.analyzers.EventNtuple.trk.fillHits : false diff --git a/fcl/from_mcs-mockdata_crvInf.fcl b/fcl/from_mcs-mockdata_crvInf.fcl index 8fc85d1..4f57491 100644 --- a/fcl/from_mcs-mockdata_crvInf.fcl +++ b/fcl/from_mcs-mockdata_crvInf.fcl @@ -9,4 +9,4 @@ physics.producers.CrvInference : { } physics.EventNtuplePath : [ @sequence::EventNtuple.Path, CrvInference ] -physics.analyzers.EventNtuple.CrvInferenceTag : "CrvInference" +physics.analyzers.EventNtuple.crv.inferenceTag : "CrvInference" diff --git a/fcl/from_mcs-mockdata_noMC.fcl b/fcl/from_mcs-mockdata_noMC.fcl index c51fd75..72698c7 100644 --- a/fcl/from_mcs-mockdata_noMC.fcl +++ b/fcl/from_mcs-mockdata_noMC.fcl @@ -1,9 +1,7 @@ #include "EventNtuple/fcl/from_mcs-mockdata.fcl" -physics.analyzers.EventNtuple.FillMCInfo : false -physics.analyzers.EventNtuple.FillCaloMC : false -physics.analyzers.EventNtuple.FillCaloClustersMC : false -physics.analyzers.EventNtuple.FillCaloSimInfos : false +physics.analyzers.EventNtuple.mc.fill : false +physics.analyzers.EventNtuple.calo.mc.fill : false physics.EventNtuplePath : [ @sequence::EventNtuple.PathNoMC ] physics.EventNtupleEndPath : [ @sequence::EventNtuple.EndPathNoMC ] diff --git a/fcl/from_mcs-mockdata_separateTrkBranches.fcl b/fcl/from_mcs-mockdata_separateTrkBranches.fcl index 75330dc..3e8b2e1 100644 --- a/fcl/from_mcs-mockdata_separateTrkBranches.fcl +++ b/fcl/from_mcs-mockdata_separateTrkBranches.fcl @@ -1,5 +1,5 @@ #include "EventNtuple/fcl/from_mcs-mockdata.fcl" -physics.analyzers.EventNtuple.branches : [ @local::DeM, @local::DeP, @local::UeM, @local::UeP, +physics.analyzers.EventNtuple.trk.branches : [ @local::DeM, @local::DeP, @local::UeM, @local::UeP, @local::DmuM, @local::DmuP, @local::UmuM, @local::UmuP ] physics.EventNtuplePath : [ @sequence::EventNtuple.PathSeparate ] diff --git a/fcl/from_mcs-primary_addVDSteps.fcl b/fcl/from_mcs-primary_addVDSteps.fcl index 85906f2..a5d54c1 100644 --- a/fcl/from_mcs-primary_addVDSteps.fcl +++ b/fcl/from_mcs-primary_addVDSteps.fcl @@ -1,3 +1,3 @@ #include "EventNtuple/fcl/from_mcs-primary.fcl" -physics.analyzers.EventNtuple.StepPointMCTags : [ "compressRecoMCs:virtualdetector" ] +physics.analyzers.EventNtuple.trk.mc.stepPointMCTags : [ "compressRecoMCs:virtualdetector" ] diff --git a/fcl/from_mcs-reflection.fcl b/fcl/from_mcs-reflection.fcl index ae0c176..450f6f9 100644 --- a/fcl/from_mcs-reflection.fcl +++ b/fcl/from_mcs-reflection.fcl @@ -8,15 +8,13 @@ EN : { @table::EventNtupleMaker FitType : LoopHelix diagLevel : 2 - FillMCInfo : true - FillTrkPIDInfo : false - FillHitInfo : false FillTriggerInfo : false - SurfaceStepCollectionTag : "compressRecoMCs" + trk.fillHits : false + trk.fillTrkQual : false + trk.fillTrkPID : false } ENBranch : { branch : "trk" - options : { fillMC : true genealogyDepth : -1 } } END_PROLOG process_name: ENeflect @@ -62,7 +60,7 @@ physics : ENe : { @table::EN SelectEvents : [ "eTrig" ] - branches : [ + trk.branches : [ { @table::ENBranch trkQualTags : ["TrkQualReflecte"] trkPIDTags : ["TrkPIDReflecte"] @@ -73,7 +71,7 @@ physics : ENmu : { @table::EN SelectEvents : [ "muTrig" ] - branches : [ + trk.branches : [ { @table::ENBranch trkQualTags : ["TrkQualReflectmu"] trkPIDTags : ["TrkPIDReflectmu"] diff --git a/fcl/from_rec-crv-kpp.fcl b/fcl/from_rec-crv-kpp.fcl index d8fd9cf..9f2fbf6 100644 --- a/fcl/from_rec-crv-kpp.fcl +++ b/fcl/from_rec-crv-kpp.fcl @@ -1,19 +1,15 @@ #include "EventNtuple/fcl/from_mcs-mockdata_noMC.fcl" -physics.analyzers.EventNtuple.FillCRVDigis : false -physics.analyzers.EventNtuple.FillCRVPulses : false -physics.analyzers.EventNtuple.branches : [ ] # no track branches -physics.analyzers.EventNtuple.FillCaloClusters : false # no calorimeter -physics.analyzers.EventNtuple.FillCaloHits : false # no calorimeter -physics.analyzers.EventNtuple.FillCaloClustersMC : false # no calorimeter -physics.analyzers.EventNtuple.FillCaloSimInfos : false # no calorimeter +physics.analyzers.EventNtuple.trk.branches : [ ] # no track branches +physics.analyzers.EventNtuple.calo.fillClusters : false # no calorimeter +physics.analyzers.EventNtuple.calo.fillHits : false # no calorimeter physics.analyzers.EventNtuple.RecoCountTag : "" physics.analyzers.EventNtuple.PBTTag : "" physics.analyzers.EventNtuple.hasCRV : false #false keeps events that have no CRV coincidences physics.analyzers.EventNtuple.FillTriggerInfo : false -physics.analyzers.EventNtuple.CrvDigisTag : "CrvDigi" -physics.analyzers.EventNtuple.CrvCoincidencesTag: "CrvCoincidenceClusterFinder" -physics.analyzers.EventNtuple.CrvRecoPulsesTag: "CrvRecoPulses" +physics.analyzers.EventNtuple.crv.digisTag : "CrvDigi" +physics.analyzers.EventNtuple.crv.coincidencesTag : "CrvCoincidenceClusterFinder" +physics.analyzers.EventNtuple.crv.recoPulsesTag : "CrvRecoPulses" services.GeometryService.inputFile: "Offline/Mu2eG4/geom/geom_common_extracted.txt" diff --git a/fcl/from_rec-crv-kpp_withCrvDigis.fcl b/fcl/from_rec-crv-kpp_withCrvDigis.fcl index 6cd03e4..1a1e466 100644 --- a/fcl/from_rec-crv-kpp_withCrvDigis.fcl +++ b/fcl/from_rec-crv-kpp_withCrvDigis.fcl @@ -1,3 +1,3 @@ #include "EventNtuple/fcl/from_rec-crv-kpp.fcl" -physics.analyzers.EventNtuple.FillCRVDigis : true +physics.analyzers.EventNtuple.crv.fillDigis : true diff --git a/fcl/prolog.fcl b/fcl/prolog.fcl index 00a4baa..c7971fe 100644 --- a/fcl/prolog.fcl +++ b/fcl/prolog.fcl @@ -97,12 +97,9 @@ TTProducersPath : [ MergeTTApr, MergeTTTpr, MergeTTCpr, MergeTTMpr ] genCountLogger: { module_type: GenEventCountReader } -AllOpt : { - fillMC : true - fillHits : true - genealogyDepth : -1 - matchDepth : -1 -} +# AllOpt is no longer needed: BranchOptConfig C++ defaults now match these values. +# Kept here only for reference / backwards compatibility with any external FCLs. +# AllOpt : { fillMC : true fillHits : true genealogyDepth : -1 matchDepth : -1 } # With move to using KalSeedPtr need to "merge" KalSeeds so that we get KalSeedPtr collections MergeKK : { module_type : MergeKalSeeds } @@ -192,37 +189,31 @@ MergeKKSeparatePath : [ MergeKKDeM, MergeKKUeM, MergeKKDmuM, MergeKKDeP, MergeKK DeM : { input : "MergeKKDeM" branch : "dem" - options : { fillMC : true genealogyDepth : -1 matchDepth : -1 } trkQualTags : ["TrkQualDeM"] trkPIDTags : ["TrkPIDDeM"] } UeM : { input : "MergeKKUeM" branch : "uem" - options : { fillMC : true genealogyDepth : -1 matchDepth : -1 } trkQualTags : [ ] trkPIDTags : [ ] } DmuM : { input : "MergeKKDmuM" branch : "dmm" - options : { fillMC : true genealogyDepth : -1 matchDepth : -1 } trkQualTags : [ ] trkPIDTags : [ ] } UmuM : { input : "MergeKKUmuM" branch : "umm" - options : { fillMC : true genealogyDepth : -1 matchDepth : -1 } trkQualTags : [ ] trkPIDTags : [ ] } DeP : { input : "MergeKKDeP" branch : "dep" - options : { fillMC : true genealogyDepth : -1 } trkQualTags : [ ] trkPIDTags : [ ] } UeP : { input : "MergeKKUeP" branch : "uep" - options : { fillMC : true genealogyDepth : -1 matchDepth : -1 } trkQualTags : [ ] trkPIDTags : [ ] } @@ -233,125 +224,138 @@ DmuP : { input : "MergeKKDmuP" } UmuP : { input : "MergeKKUmuP" branch : "ump" - options : { fillMC : true genealogyDepth : -1 matchDepth : -1 } trkQualTags : [ ] trkPIDTags : [ ] } Ext : { input : "MergeKKLine" branch : "trk" - options : { fillMC : true genealogyDepth : -1 matchDepth : -1 fillHits : true } trkQualTags : [ ] trkPIDTags : [ ] } Off : { input : "MergeKKOff" branch : "trk" - options : { fillMC : true genealogyDepth : -1 matchDepth : -1 fillHits : true } trkQualTags : [ ] trkPIDTags : [ ] } All : { input : "MergeKKAll" branch : "trk" - options : { fillHits : true fillMC : true genealogyDepth : -1 matchDepth : -1 } trkQualTags : ["TrkQualAll"] trkPIDTags : ["TrkPIDAll"] } DeCalib : { input : "MergeKKDeCalib" branch : "trk" - options : { fillMC : true fillHits : true genealogyDepth : -1 matchDepth : -1 } trkQualTags : [ ] trkPIDTags : [ ] } De : { input : "MergeKKDe" branch : "de" - options : { fillMC : true genealogyDepth : -1 matchDepth : -1 } trkQualTags : ["TrkQualDe"] trkPIDTags : ["TrkPIDDe"] } EventNtupleMaker : { module_type : EventNtupleMaker - branches : [ @local::All ] RecoCountTag : "SelectReco" PBITag : "PBISim" PBTTag : "EWMProducer" EWMTag : "EWMProducer" - PBTMCTag : "EWMProducer" - CrvCoincidencesTag : "SelectReco:CrvCoincidenceClusterFinder" - CrvCoincidenceMCsTag : "compressRecoMCs:CrvCoincidenceClusterMatchMC" - CrvRecoPulsesTag : "SelectReco" - CrvStepsTag : "compressRecoMCs" - SimParticlesTag : "compressRecoMCs" - MCTrajectoriesTag : "compressRecoMCs" - TimeClustersTag : "MHDe" - FillTimeClusterInfo : false - CaloClustersTag : "CaloClusterMaker" - CaloHitsTag : "CaloHitMaker" - CaloRecoDigisTag : "CaloRecoDigiMaker" - CaloDigisTag : "SelectReco" - FillCaloClusters : true - FillCaloHits : true - FillCaloRecoDigis : false - FillCaloDigis : false - CrvDigiMCsTag : "compressRecoMCs" - CrvDigisTag : "SelectReco" - CrvCoincidenceClusterMCAssnsTag : "CrvCoincidenceClusterMCAssns" - CrvPlaneY : @local::crvPlaneY.CRV_T - FillMCInfo : true - FillTrkQual : true - FillTrkPIDInfo : false - FillHitInfo : true - FillHitCalibInfo : false FillTriggerInfo : true TriggerProcessName : "Digitize" TriggerPathSuffix : "DigitizePath" - FillCRVCoincs : true - FillCRVPulses : false - FillCRVDigis : false - FillCaloMC : true - FillCaloClustersMC : true - FillCaloHitsMC : true - FillHelixInfo : false - FillCaloSimInfos : true - PrimaryParticleTag : "compressRecoMCs" - KalSeedMCAssns : "SelectReco" - CaloClusterMCTag : "compressRecoMCs" - CaloHitMCTag : "compressRecoMCs" - InfoMCStructHelper : { - SimParticleCollectionTag : "compressRecoMCs" - MinGoodMomFraction : 0.9 - MaxVDDt : 5 # ns - } -# ExtraMCStepCollectionTags : [ "compressRecoMCs:protonabsorber", "compressRecoMCs:stoppingtarget" ] - ExtraMCStepCollectionTags : [] - SurfaceStepCollectionTag : "compressRecoMCs" FitType : LoopHelix - StepPointMCTags : [ ] + # ── Event-level MC (gates tracker MC, CRV MC, and evtinfomc branch) ────── + mc : { + fill : true + PBTMCTag : "EWMProducer" + simParticlesTag : "compressRecoMCs" + mcTrajectoriesTag : "compressRecoMCs" + primaryParticleTag : "compressRecoMCs" + infoMCStructHelper : { + SimParticleCollectionTag : "compressRecoMCs" + MinGoodMomFraction : 0.9 + MaxVDDt : 5 # ns + } + } + # ── Tracker subsystem ───────────────────────────────────────────────────── + trk : { + fillHits : true + fillHitCalibs : false + fillHelices : false + fillTrkQual : true + fillTrkPID : false + fillTimeClusters : false + timeClustersTag : "MHDe" + branches : [ @local::All ] + mc : { + kalSeedMCAssns : "SelectReco" + surfaceStepsTag : "compressRecoMCs" + stepPointMCTags : [ ] + } + } + # ── Calorimeter subsystem ───────────────────────────────────────────────── + # calo.mc.fill is independent of mc.fill: calo-only jobs can fill calo MC + # without loading tracker/event-level MC products. + calo : { + fill : true + fillClusters : true + clustersTag : "CaloClusterMaker" + fillHits : true + hitsTag : "CaloHitMaker" + fillRecoDigis : false + recoDigisTag : "CaloRecoDigiMaker" + fillDigis : false + digisTag : "SelectReco" + mc : { + fill : true + fillTrackMatch : true + fillClusters : true + clusterMCTag : "compressRecoMCs" + fillHits : true + hitMCTag : "compressRecoMCs" + fillSim : true + fillDigis : false + fillDigiSim : false + showerSimTag : "compressRecoMCs" + } + } + # ── CRV subsystem ───────────────────────────────────────────────────────── + crv : { + fill : true + fillCoincs : true + coincidencesTag : "SelectReco:CrvCoincidenceClusterFinder" + recoPulsesTag : "SelectReco" + stepsTag : "compressRecoMCs" + fillPulses : false + fillDigis : false + digisTag : "SelectReco" + planeY : @local::crvPlaneY.CRV_T + mc : { + coincidenceMCsTag : "compressRecoMCs:CrvCoincidenceClusterMatchMC" + digiMCsTag : "compressRecoMCs" + assnsTag : "CrvCoincidenceClusterMCAssns" + } + } } # instance for processing trigger (digitization) output from simulation -EventNtupleMakerTTMC: { +EventNtupleMakerTTMC : { @table::EventNtupleMaker diagLevel : 2 - FillCRVCoincs : false - FillCaloMC : false FillTriggerInfo : true - FillTrkPIDInfo : false - FillHitInfo : true - PrimaryParticleTag: "compressDigiMCs" - MCTrajectoriesTag: "compressDigiMCs" FitType : LoopHelix - TriggerProcessName : "Digitize" - SimParticlesTag : "compressDigiMCs" - ExtraMCStepCollectionTags: [] - InfoMCStructHelper : { - MinGoodMomFraction : 0.9 - MaxVDDt : 5 # ns - SimParticleCollectionTag : "compressDigiMCs" - } + crv.fill : false + calo.mc.fillTrackMatch : false + mc.primaryParticleTag : "compressDigiMCs" + mc.mcTrajectoriesTag : "compressDigiMCs" + mc.simParticlesTag : "compressDigiMCs" + mc.infoMCStructHelper.SimParticleCollectionTag : "compressDigiMCs" + trk.mc.extraMCStepTags : [] } +# TTMCBranch: per-branch config for trigger MC branches. +# No options needed — BranchOptConfig defaults are fillMC:true, fillHits:true, +# genealogyDepth:-1, matchDepth:-1. TTMCBranch : { branch : "trk" - options : { fillMC : true fillHits : true genealogyDepth : -1 matchDepth : -1 } } EventNtuple : { @@ -383,12 +387,11 @@ ENDeCalib : { @table::EventNtupleMaker hasTracks : true FitType : LoopHelix - branches : [ + trk.branches : [ { input: "MergeKKDeCalib" branch : "trk" trkQualTags : ["TrkQualDe"] trkPIDTags : ["TrkPIDDe"] - options : { fillMC : true fillHits : true genealogyDepth : -1 } } ] SelectEvents : [ TriggerPath ] diff --git a/src/EventNtupleMaker_module.cc b/src/EventNtupleMaker_module.cc index f2e15b7..af1aa56 100644 --- a/src/EventNtupleMaker_module.cc +++ b/src/EventNtupleMaker_module.cc @@ -102,107 +102,162 @@ namespace mu2e { public: + // ── Per-branch options (defaults match intended use; omit options in FCL + // unless you want to override a specific field) ────────────────────── struct BranchOptConfig { using Name=fhicl::Name; using Comment=fhicl::Comment; - fhicl::Atom fillmc{Name("fillMC"), Comment("Switch to turn on filling of MC information for this set of tracks"), false}; - fhicl::Atom fillhits{Name("fillHits"), Comment("Switch to turn on filling of hit-level information for this set of tracks"), false}; - fhicl::Atom genealogyDepth{Name("genealogyDepth"), Comment("The depth of the genealogy information you want to keep"), 1}; - fhicl::Atom matchDepth{Name("matchDepth"), Comment("The depth into the MC true particle matching you want to keep"), 1}; + fhicl::Atom fillmc{Name("fillMC"), Comment("Fill MC information for this branch"), true}; + fhicl::Atom fillhits{Name("fillHits"), Comment("Fill hit-level information for this branch"), true}; + fhicl::Atom genealogyDepth{Name("genealogyDepth"), Comment("Depth of MC genealogy to keep (-1 = all)"), -1}; + fhicl::Atom matchDepth{Name("matchDepth"), Comment("Depth of MC truth matching to keep (-1 = all)"), -1}; }; struct BranchConfig { using Name=fhicl::Name; using Comment=fhicl::Comment; - fhicl::Atom input{Name("input"), Comment("KalSeedCollection input tag")}; fhicl::Atom branch{Name("branch"), Comment("Name of output branch")}; + fhicl::Atom enabled{Name("enabled"), Comment("Set false to skip this branch entirely (no collection reads, no output branches)"), true}; fhicl::Sequence trkQualTags{Name("trkQualTags"), Comment("Input tags for MVAResultCollection to use for TrkQuals")}; fhicl::Sequence trkPIDTags{Name("trkPIDTags"), Comment("Input tags for MVAResultCollection to use for TrkPID")}; - fhicl::Table options{Name("options"), Comment("Optional arguments for a branch")}; + fhicl::Table options{Name("options"), Comment("Per-branch fill options")}; + }; + + // ── Event-level MC config (tracker+CRV share these event products) ───── + struct EventMCConfig { + using Name=fhicl::Name; + using Comment=fhicl::Comment; + fhicl::Atom fill{Name("fill"), + Comment("Master gate for tracker MC, CRV MC, and event-level MC info branches. " + "Calo MC is controlled independently via calo.mc.fill."), true}; + fhicl::Atom PBTMCTag{Name("PBTMCTag"), Comment("Tag for ProtonBunchTimeMC object"), art::InputTag()}; + fhicl::Atom simParticlesTag{Name("simParticlesTag"), Comment("SimParticle Collection Tag")}; + fhicl::Atom mcTrajectoriesTag{Name("mcTrajectoriesTag"), Comment("MCTrajectory Collection Tag")}; + fhicl::Atom primaryParticleTag{Name("primaryParticleTag"), Comment("Tag for PrimaryParticle"), art::InputTag()}; + fhicl::Table infoMCStructHelper{Name("infoMCStructHelper"), Comment("Configuration for InfoMCStructHelper")}; + }; + + // ── Tracker subsystem config ─────────────────────────────────────────── + struct TrkConfig { + using Name=fhicl::Name; + using Comment=fhicl::Comment; + // reco flags + fhicl::Atom fillHits{Name("fillHits"), + Comment("Global enable for hit-level branches; per-branch options.fillHits also required"), true}; + fhicl::Atom fillHitCalibs{Name("fillHitCalibs"), Comment("Fill hit calibration branches"), false}; + fhicl::Atom fillHelices{Name("fillHelices"), Comment("Fill helix seed branches"), false}; + fhicl::Atom fillTrkQual{Name("fillTrkQual"), Comment("Fill TrkQual MVA branches"), false}; + fhicl::Atom fillTrkPID{Name("fillTrkPID"), Comment("Fill TrkPID MVA branches"), false}; + fhicl::Atom fillTimeClusters{Name("fillTimeClusters"), Comment("Fill time cluster branch"), false}; + fhicl::Atom timeClustersTag{Name("timeClustersTag"), Comment("Tag for time cluster collection"), art::InputTag()}; + // per-branch configurations + fhicl::Sequence> branches{Name("branches"), Comment("One entry per KalSeed collection to write as a track branch")}; + // tracker MC sub-config + struct MCConfig { + using Name=fhicl::Name; + using Comment=fhicl::Comment; + fhicl::Atom fill{Name("fill"), Comment("Master switch for all tracker MC branches; mc.fill must also be true"), true}; + fhicl::Atom kalSeedMCAssns{Name("kalSeedMCAssns"), Comment("Tag for KalSeedMCAssn"), art::InputTag()}; + fhicl::OptionalSequence extraMCStepTags{Name("extraMCStepTags"), Comment("Tags for extra StepPointMCCollections associated with KalSeeds")}; + fhicl::OptionalAtom surfaceStepsTag{Name("surfaceStepsTag"), Comment("SurfaceStep collection tag; omit to disable surface step branches")}; + fhicl::OptionalSequence stepPointMCTags{Name("stepPointMCTags"), Comment("Tags for StepPointMCCollections written out for all steps (not per-track)")}; + }; + fhicl::Table mc{Name("mc"), Comment("Tracker MC filling options")}; + }; + + // ── Calorimeter subsystem config ─────────────────────────────────────── + // Calo MC is gated solely by calo.mc.fill; it is independent of mc.fill + // so that calo-only jobs can fill calo MC without loading tracker MC products. + struct CaloConfig { + using Name=fhicl::Name; + using Comment=fhicl::Comment; + // master switch + fhicl::Atom fill{Name("fill"), Comment("Enable the calorimeter subsystem entirely"), true}; + // reco flags + collocated tags + fhicl::Atom fillClusters {Name("fillClusters"), Comment("Fill calorimeter cluster branch"), true}; + fhicl::Atom clustersTag {Name("clustersTag"), Comment("Tag for CaloCluster collection"), art::InputTag()}; + fhicl::Atom fillHits {Name("fillHits"), Comment("Fill calorimeter hit branch"), false}; + fhicl::Atom hitsTag {Name("hitsTag"), Comment("Tag for CaloHit collection"), art::InputTag()}; + fhicl::Atom fillRecoDigis{Name("fillRecoDigis"), Comment("Fill calorimeter reco-digi branch"), false}; + fhicl::Atom recoDigisTag {Name("recoDigisTag"), Comment("Tag for CaloRecoDigi collection"), art::InputTag()}; + fhicl::Atom fillDigis {Name("fillDigis"), Comment("Fill calorimeter digi branch"), false}; + fhicl::Atom digisTag {Name("digisTag"), Comment("Tag for CaloDigi collection"), art::InputTag()}; + // MC sub-config + struct MCConfig { + using Name=fhicl::Name; + using Comment=fhicl::Comment; + fhicl::Atom fill{Name("fill"), Comment("Master switch for all calorimeter MC branches; independent of mc.fill"), true}; + // track-associated calo MC (the calohitmc. branch per track type) + fhicl::Atom fillTrackMatch{Name("fillTrackMatch"), Comment("Fill per-track calo cluster MC branch (calohitmc.)"), true}; + // standalone calo MC branches + fhicl::Atom fillClusters{Name("fillClusters"), Comment("Fill standalone caloclustersmc. branch"), true}; + fhicl::Atom clusterMCTag{Name("clusterMCTag"), Comment("Tag for CaloClusterMCCollection"), art::InputTag()}; + fhicl::Atom fillHits {Name("fillHits"), Comment("Fill standalone calohitsmc. branch"), true}; + fhicl::Atom hitMCTag {Name("hitMCTag"), Comment("Tag for CaloHitMCCollection"), art::InputTag()}; + fhicl::Atom fillSim {Name("fillSim"), Comment("Fill calomcsim. (sim particle info) branch"), true}; + fhicl::Atom fillDigis {Name("fillDigis"), Comment("Fill standalone calodigismc. branch"), false}; + fhicl::Atom fillDigiSim {Name("fillDigiSim"), Comment("Fill calodigisim. branch"), false}; + fhicl::Atom showerSimTag{Name("showerSimTag"), Comment("Tag for CaloShowerSim collection"), art::InputTag()}; + }; + fhicl::Table mc{Name("mc"), Comment("Calorimeter MC filling options")}; + }; + + // ── CRV subsystem config ─────────────────────────────────────────────── + struct CRVConfig { + using Name=fhicl::Name; + using Comment=fhicl::Comment; + // master switch + fhicl::Atom fill{Name("fill"), Comment("Enable the CRV subsystem entirely"), false}; + // reco flags + collocated tags + fhicl::Atom fillCoincs {Name("fillCoincs"), Comment("Fill CRV coincidence cluster branches"), false}; + fhicl::Atom coincidencesTag{Name("coincidencesTag"), Comment("Tag for CrvCoincidenceCluster collection"), art::InputTag()}; + fhicl::Atom recoPulsesTag {Name("recoPulsesTag"), Comment("Tag for CrvRecoPulse collection"), art::InputTag()}; + fhicl::Atom stepsTag {Name("stepsTag"), Comment("Tag for CrvStep collection"), art::InputTag()}; + fhicl::Atom fillPulses {Name("fillPulses"), Comment("Fill CRV reco pulse branches"), false}; + fhicl::Atom fillDigis {Name("fillDigis"), Comment("Fill CRV digi branch"), false}; + fhicl::Atom digisTag {Name("digisTag"), Comment("Tag for CrvDigi collection"), art::InputTag()}; + fhicl::Atom planeY {Name("planeY"), Comment("Y of center of top layer of CRV-T counters (mm)"), 2751.485}; + fhicl::OptionalAtom inferenceTag{Name("inferenceTag"), Comment("Tag for CrvInference Assns (art::Assns); omit to disable")}; + // MC sub-config (requires mc.fill also be true) + struct MCConfig { + using Name=fhicl::Name; + using Comment=fhicl::Comment; + fhicl::Atom fill {Name("fill"), Comment("Master switch for CRV MC branches; mc.fill must also be true"), true}; + fhicl::Atom coincidenceMCsTag {Name("coincidenceMCsTag"), Comment("Tag for CrvCoincidenceClusterMC collection"), art::InputTag()}; + fhicl::Atom digiMCsTag {Name("digiMCsTag"), Comment("Tag for CrvDigiMC collection"), art::InputTag()}; + fhicl::Atom assnsTag {Name("assnsTag"), Comment("Tag for CrvCoincidenceClusterMCAssns"), art::InputTag()}; + }; + fhicl::Table mc{Name("mc"), Comment("CRV MC filling options")}; }; struct Config { using Name=fhicl::Name; using Comment=fhicl::Comment; - // General control and config + // General control fhicl::Atom diag{Name("diagLevel"),1}; fhicl::Atom debug{Name("debugLevel"),0}; fhicl::Atom splitlevel{Name("splitlevel"),99}; fhicl::Atom buffsize{Name("buffsize"),32000}; fhicl::Atom hastrks{Name("hasTracks"), Comment("Require >=1 tracks to fill tuple"), false}; fhicl::Atom hascrv{Name("hasCRV"), Comment("Require CRV information to fill tuple"), false}; - // General event info + // General event info fhicl::Atom rctag{Name("RecoCountTag"), Comment("RecoCount"), art::InputTag()}; - fhicl::Atom PBITag{Name("PBITag"), Comment("Tag for ProtonBunchIntensity object") ,art::InputTag()}; - fhicl::Atom PBTTag{Name("PBTTag"), Comment("Tag for ProtonBunchTime object") ,art::InputTag()}; - fhicl::Atom EWMTag{Name("EWMTag"), Comment("Tag for EventWindowMarker object") ,art::InputTag()}; - fhicl::Atom filltrig{Name("FillTriggerInfo"),false}; + fhicl::Atom PBITag{Name("PBITag"), Comment("Tag for ProtonBunchIntensity object"), art::InputTag()}; + fhicl::Atom PBTTag{Name("PBTTag"), Comment("Tag for ProtonBunchTime object"), art::InputTag()}; + fhicl::Atom EWMTag{Name("EWMTag"), Comment("Tag for EventWindowMarker object"), art::InputTag()}; + // Trigger + fhicl::Atom filltrig{Name("FillTriggerInfo"), false}; fhicl::Atom trigProcessName{Name("TriggerProcessName"), Comment("Process name for Trigger")}; - fhicl::Atom trigpathsuffix{Name("TriggerPathSuffix"), "_trigger"}; // all trigger paths have this in the name - // core tracking - fhicl::Sequence > branches{Name("branches"), Comment("All the branches we want to write")}; - // Additional (optional) tracking information - fhicl::Atom fillhits{Name("FillHitInfo"),Comment("Global switch to turn on/off hit-level info"), false}; - fhicl::Atom fillhitcalibs{Name("FillHitCalibInfo"), Comment("Switch to turn on filling of hit-level information for this set of tracks"), false}; - fhicl::Atom fittype{Name("FitType"),Comment("Type of track Fit: LoopHelix, CentralHelix, KinematicLine, or Unknown"),"Unknown"}; - fhicl::Atom helices{Name("FillHelixInfo"),false}; - fhicl::Atom fillTimeClusters{Name("FillTimeClusterInfo"),Comment("Global switch to turn on/off time cluster info"), false}; - fhicl::Atom timeClustersTag{Name("TimeClustersTag"), Comment("Tag for time cluster collection"), art::InputTag()}; - // Calorimeter input - fhicl::Atom caloClustersTag{Name("CaloClustersTag"), Comment("Tag for Calorimeter cluster collection"), art::InputTag()}; - fhicl::Atom caloHitsTag{Name("CaloHitsTag"), Comment("Tag for Calorimeter hit collection"), art::InputTag()}; - fhicl::Atom caloRecoDigisTag{Name("CaloRecoDigisTag"), Comment("Tag for Calorimeter recodigi collection"), art::InputTag()}; - fhicl::Atom caloDigisTag{Name("CaloDigisTag"), Comment("Tag for Calorimeter digi collection"), art::InputTag()}; - fhicl::Atom caloShowerSimTag{Name("CaloShowerSimTag"), Comment("Tag for Calorimeter shower sim collection"), art::InputTag()}; - // Calorimeter flags - fhicl::Atom fillCaloClusters{Name("FillCaloClusters"),Comment("Flag for turning on Calo Clusters branch"), true}; - fhicl::Atom fillCaloHits{Name("FillCaloHits"),Comment("Flag for turning on Calo Hits branch"), false}; - fhicl::Atom fillCaloRecoDigis{Name("FillCaloRecoDigis"),Comment("Flag for turning on Calo RecoDigis branch"), false}; - fhicl::Atom fillCaloDigis{Name("FillCaloDigis"),Comment("Flag for turning on Calo Digis branch"), false}; - fhicl::Atom fillCaloDigisMC{Name("FillCaloDigisMC"),Comment("Flag for turning on Calo Digis MC branch"), false}; - // CRV -- input tags - fhicl::Atom crvCoincidencesTag{Name("CrvCoincidencesTag"), Comment("Tag for CrvCoincidenceCluster Collection"), art::InputTag()}; - fhicl::Atom crvRecoPulsesTag{Name("CrvRecoPulsesTag"), Comment("Tag for CrvRecopPulse Collection"), art::InputTag()}; - fhicl::Atom crvStepsTag{Name("CrvStepsTag"), Comment("Tag for CrvStep Collection"), art::InputTag()}; - fhicl::Atom crvDigiMCsTag{Name("CrvDigiMCsTag"), Comment("Tag for CrvDigiMC Collection"), art::InputTag()}; - fhicl::Atom crvDigisTag{Name("CrvDigisTag"), Comment("Tag for CrvDigi Collection"), art::InputTag()}; - // CRV -- flags - fhicl::Atom fillcrvcoincs{Name("FillCRVCoincs"),Comment("Flag for turning on crv CoincidenceClusterbranches"), false}; - fhicl::Atom fillcrvpulses{Name("FillCRVPulses"),Comment("Flag for turning on crvpulses(mc) branches"), false}; - fhicl::Atom fillcrvdigis{Name("FillCRVDigis"),Comment("Flag for turning on crvdigis branch"), false}; - // CRV -- other - fhicl::Atom crvPlaneY{Name("CrvPlaneY"),Comment("y of center of the top layer of the CRV-T counters"), 2751.485}; //This belongs in KinKalGeom as an intersection plane, together with the rest of the CRV planes FIXME - // CRV inference - fhicl::OptionalAtom crvInferenceTag{Name("CrvInferenceTag"), Comment("Tag for CrvInference associations (art::Assns)")}; - // MC truth - fhicl::Atom fillmc{Name("FillMCInfo"),Comment("Global switch to turn on/off MC info"),true}; - fhicl::Table infoMCStructHelper{Name("InfoMCStructHelper"), Comment("Configuration for the InfoMCStructHelper")}; - fhicl::Atom PBTMCTag{Name("PBTMCTag"), Comment("Tag for ProtonBunchTimeMC object") ,art::InputTag()}; - fhicl::Atom simParticlesTag{Name("SimParticlesTag"), Comment("SimParticle Collection Tag")}; - fhicl::Atom mcTrajectoriesTag{Name("MCTrajectoriesTag"), Comment("MCTrajectory Collection Tag")}; - fhicl::Atom primaryParticleTag{Name("PrimaryParticleTag"), Comment("Tag for PrimaryParticle"), art::InputTag()}; - fhicl::Atom kalSeedMCTag{Name("KalSeedMCAssns"), Comment("Tag for KalSeedMCAssn"), art::InputTag()}; - // extra MC - fhicl::OptionalSequence extraMCStepTags{Name("ExtraMCStepCollectionTags"), Comment("Input tags for any other StepPointMCCollections you want written out. This will only write out steps associated with the KalSeed")}; - // passive elements and Virtual Detector MC information - fhicl::OptionalAtom SurfaceStepsTag{Name("SurfaceStepCollectionTag"), Comment("SurfaceStep Collection")}; - fhicl::OptionalSequence stepPointMCTags{Name("StepPointMCTags"), Comment("Input tags for any other StepPointMCCollections you want written out. This will write out all steps in the collection")}; - // Calo MC - fhicl::Atom fillCaloMC{ Name("FillCaloMC"),Comment("Fill CaloMC information"), true}; - fhicl::Atom fillCaloClustersMC{ Name("FillCaloClustersMC"),Comment("Fill Calo Cluster MC information"), true}; - fhicl::Atom fillCaloHitsMC{ Name("FillCaloHitsMC"),Comment("Fill Calo Hit MC information"), true}; - fhicl::Atom fillCaloSimInfos{ Name("FillCaloSimInfos"),Comment("Fill Sim particles information associated with calo clusters"), true}; - fhicl::Atom fillCaloDigiSimInfos{ Name("FillCaloDigiSimInfos"),Comment("Fill Sim particles information associated with calo digis"), true}; - fhicl::Atom caloClusterMCTag{Name("CaloClusterMCTag"), Comment("Tag for CaloClusterMCCollection") ,art::InputTag()}; - fhicl::Atom caloHitMCTag{Name("CaloHitMCTag"), Comment("Tag for CaloHitMCCollection") ,art::InputTag()}; - // CRV MC - fhicl::Atom crvCoincidenceMCsTag{Name("CrvCoincidenceMCsTag"), Comment("Tag for CrvCoincidenceClusterMC Collection"), art::InputTag()}; - fhicl::Atom crvMCAssnsTag{ Name("CrvCoincidenceClusterMCAssnsTag"), Comment("art::InputTag for CrvCoincidenceClusterMCAssns")}; - // Pre-processed analysis info; are these redundant with the branch config ? - fhicl::Atom filltrkpid{Name("FillTrkPIDInfo"),false}; - fhicl::Atom filltrkqual{Name("FillTrkQual"),false}; + fhicl::Atom trigpathsuffix{Name("TriggerPathSuffix"), "_trigger"}; + // Fit type + fhicl::Atom fittype{Name("FitType"), Comment("Type of track fit: LoopHelix, CentralHelix, KinematicLine, or Unknown"), "Unknown"}; + // ── Subsystems ──────────────────────────────────────────────────────── + fhicl::Table mc {Name("mc"), Comment("Event-level MC config: gates tracker+CRV MC and provides shared event MC products")}; + fhicl::Table trk {Name("trk"), Comment("Tracker subsystem config")}; + fhicl::Table calo{Name("calo"), Comment("Calorimeter subsystem config")}; + fhicl::Table crv {Name("crv"), Comment("CRV subsystem config")}; }; typedef art::EDAnalyzer::Table Parameters; @@ -224,7 +279,7 @@ namespace mu2e { // general event info branch EventInfo _einfo; EventInfoMC _einfomc; - art::InputTag _recoCountTag, _PBITag, _PBTTag, _EWMTag, _PBTMCTag; + art::InputTag _recoCountTag, _PBITag, _PBTTag, _EWMTag; art::Handle _ewmh; // track control bool _hastrks; @@ -241,68 +296,53 @@ namespace mu2e { std::map>> _allLHIs; std::map>> _allCHIs; std::map>> _allKLIs; - std::map> _allTCHIs; // quality branches (inputs) - - std::vector > > _allRQCHs; // outer vector is for each track type, inner vector is all RecoQuals + std::vector > > _allRQCHs; std::vector >> _allTrkQualCHs; std::vector >> _allTrkPIDCHs; - // quality branches (outputs) std::vector _allRQIs; std::map>> _allTrkQualResults; std::map>> _allTrkPIDResults; - // trigger information unsigned _trigbits; std::map _tmap; // map between path and trigger ID. ID should come from trigger itself FIXME! TrigInfo _triggerResults; - // MC truth (fcl parameters) - bool _fillmc; - // MC steps (associated with KalSeed) + // cached optional tracker MC tags std::vector _extraMCStepTags; std::vector> _extraMCStepCollections; std::map>> _extraMCStepInfos; std::map>> _extraMCStepSummaryInfos; - // SurfaceSteps art::InputTag _surfaceStepsTag; std::map>> _surfaceStepInfos; art::Handle _surfaceStepsHandle; - // MC steps (all) std::vector _stepPointMCTags; std::vector> _stepPointMCCollections; std::map _stepPointMCInfos; - - // + // MC truth handles art::Handle _pph; art::Handle _ksmcah; art::Handle _simParticles; art::Handle _mcTrajectories; - // MC truth branches (outputs) + // tracker MC truth branches (outputs) std::map> _allMCTIs; std::map>> _allMCSimTIs; std::map>> _allMCVDInfos; - bool _fillcalomc; art::Handle _ccmcch; art::Handle _chmcch; std::map> _allMCTCHIs; - // hit level info branches std::map>> _allTSHIs; std::map>> _allTSHCIs; std::map>> _allTSMIs; std::map>> _allTSHIMCs; - // time cluster branch art::Handle _tcsHandle; std::vector _tcIs; - bool _filltcs; - // event weights std::vector > _wtHandles; EventWeightInfo _wtinfo; - // Calorimeter art::Handle _caloClusters; art::Handle _caloHits; @@ -314,16 +354,11 @@ namespace mu2e { std::vector _caloRDIs; std::vector _caloDIs; std::vector _caloDigiMCIs; - - bool _fillcaloclusters, _fillcalohits, _fillcalorecodigis, _fillcalodigis, _fillcalodigismc; - // Calorimeter MC - std::vector _caloCIMCs; //Independent from tracker - std::vector _caloHIMCs; //Independent from tracker - std::vector _caloSIMCs; //Sim particle infos associated with calo clusters - std::vector _caloDigiSIMCs; //Sim particle infos associated with calo digis - bool _fillcaloclustersmc, _fillcalohitsmc, _fillcalosiminfos, _fillcalodigisiminfos; - + std::vector _caloCIMCs; + std::vector _caloHIMCs; + std::vector _caloSIMCs; + std::vector _caloDigiSIMCs; // CRV (inputs) std::map>> _allBestCrvAssns; art::Handle _crvMCAssns; @@ -333,16 +368,13 @@ namespace mu2e { art::Handle _crvDigiMCs; art::Handle _crvDigis; art::Handle _crvSteps; - // CRV -- fhicl parameters - bool _fillcrvcoincs, _fillcrvpulses, _fillcrvdigis; - double _crvPlaneY; // needs to move to KinKalGeom FIXME // CRV inference bool _fillCrvInference; art::InputTag _crvInferenceTag; std::vector> _crvInference; // CRV (output) std::vector _crvcoincs; - std::map> _allBestCrvs; // there can be more than one of these per track type + std::map> _allBestCrvs; std::vector _crvcoincsmc; std::map> _allBestCrvMCs; CrvSummaryReco _crvsummary; @@ -363,12 +395,39 @@ namespace mu2e { enum FType{Unknown=0,LoopHelix,CentralHelix,KinematicLine}; FType _ftype = Unknown; std::vector fitNames = {"Unknown", "LoopHelix","CentralHelix","KinematicLine"}; - // for trigger branch: bool firstEvent = true; + + // ── Gating helpers ───────────────────────────────────────────────────── + // Event-level MC gate (simParticles, mcTrajectories, primaryParticle). + // Also gates tracker MC and CRV MC. + bool fillEventMC() const { return _conf.mc().fill(); } + + // Tracker MC: both the global event MC gate and the tracker MC gate must + // be true, plus the per-branch flag. + bool fillTrkMC(const BranchOptConfig& opt) const { + return _conf.mc().fill() && _conf.trk().mc().fill() && opt.fillmc(); + } + + // Calorimeter MC: independent of fillEventMC() — calo MC products do not + // require simParticles/primaryParticle so calo-only jobs can enable this + // while keeping mc.fill false. + bool fillCaloMC() const { return _conf.calo().fill() && _conf.calo().mc().fill(); } + bool fillCaloTrackMatchMC() const { return fillCaloMC() && _conf.calo().mc().fillTrackMatch(); } + bool fillCaloClsMC() const { return fillCaloMC() && _conf.calo().mc().fillClusters(); } + bool fillCaloHitsMC() const { return fillCaloMC() && _conf.calo().mc().fillHits(); } + bool fillCaloSimMC() const { return fillCaloMC() && _conf.calo().mc().fillSim(); } + bool fillCaloDigisMC() const { return fillCaloMC() && _conf.calo().mc().fillDigis(); } + bool fillCaloDigiSimMC() const { return fillCaloMC() && _conf.calo().mc().fillDigiSim(); } + + // CRV MC: needs global event MC gate (CRV uses mcTrajectories/primaryParticle). + bool fillCRVMC() const { + return _conf.mc().fill() && _conf.crv().fill() && _conf.crv().mc().fill(); + } + // helper functions void fillEventInfo(const art::Event& event); - void fillTriggerBranch(const art::Event& event,std::string const& process, bool firstEvent); + void fillTriggerBranch(const art::Event& event, std::string const& process, bool firstEvent); void resetTrackBranches(); void fillTrackBranches(const art::Handle& kspch, BranchIndex i_branch, size_t i_kseedptr); @@ -385,108 +444,72 @@ namespace mu2e { _PBITag(conf().PBITag()), _PBTTag(conf().PBTTag()), _EWMTag(conf().EWMTag()), - _PBTMCTag(conf().PBTMCTag()), _hastrks(conf().hastrks()), _hascrv(conf().hascrv()), - _fillmc(conf().fillmc()), - _fillcalomc(conf().fillCaloMC()), - _filltcs(conf().fillTimeClusters()), - // Calorimeter - _fillcaloclusters(conf().fillCaloClusters()), - _fillcalohits(conf().fillCaloHits()), - _fillcalorecodigis(conf().fillCaloRecoDigis()), - _fillcalodigis(conf().fillCaloDigis()), - _fillcalodigismc(conf().fillCaloDigisMC()), - // Calorimeter MC - _fillcaloclustersmc(conf().fillCaloClustersMC()), - _fillcalohitsmc(conf().fillCaloHitsMC()), - _fillcalosiminfos(conf().fillCaloSimInfos()), - _fillcalodigisiminfos(conf().fillCaloDigiSimInfos()), - // CRV - _fillcrvcoincs(conf().fillcrvcoincs()), - _fillcrvpulses(conf().fillcrvpulses()), - _fillcrvdigis(conf().fillcrvdigis()), - _crvPlaneY(conf().crvPlaneY()), - _infoMCStructHelper(conf().infoMCStructHelper()), + _infoMCStructHelper(conf().mc().infoMCStructHelper()), _buffsize(conf().buffsize()), _splitlevel(conf().splitlevel()) { - _fillCrvInference = conf().crvInferenceTag(_crvInferenceTag); + _fillCrvInference = conf().crv().inferenceTag(_crvInferenceTag); // decode fit type - for(size_t ifit=0;ifit < fitNames.size();++ifit){ - auto const& fname = fitNames[ifit]; - if(_conf.fittype() == fname){ - _ftype= (FType)ifit; + for(size_t ifit = 0; ifit < fitNames.size(); ++ifit){ + if(_conf.fittype() == fitNames[ifit]){ + _ftype = (FType)ifit; break; } } - // Put all the branch configurations together - for(const auto& branch_cfg : _conf.branches()){ + // resolve optional tracker MC tags from trk.mc sub-config + _conf.trk().mc().extraMCStepTags(_extraMCStepTags); + _conf.trk().mc().surfaceStepsTag(_surfaceStepsTag); + _conf.trk().mc().stepPointMCTags(_stepPointMCTags); + + // populate branch list from trk.branches + for(const auto& branch_cfg : _conf.trk().branches()){ _allBranches.push_back(branch_cfg); } - // Create all the info structs - for (BranchIndex i_branch = 0; i_branch < _allBranches.size(); ++i_branch) { - auto i_branchConfig = _allBranches.at(i_branch); - _allTIs[i_branch] = std::vector(); - // fit sampling (KalIntersection) at a surface - _allTSIs[i_branch] = std::vector>(); - // fit-specific branches - _allLHIs[i_branch] = std::vector>(); - _allCHIs[i_branch] = std::vector>(); - _allKLIs[i_branch] = std::vector>(); - - // mc truth info at VDs - _allMCVDInfos[i_branch] = std::vector>(); - - _allTCHIs[i_branch] = std::vector(); - _allMCTIs[i_branch] = std::vector(); - _allMCSimTIs[i_branch] = std::vector>(); - - if(_fillcalomc && _fillmc){ - _allMCTCHIs[i_branch] = std::vector(); + // create per-branch storage (skip disabled branches) + for (BranchIndex i_branch = 0; i_branch < _allBranches.size(); ++i_branch) { + const auto& i_branchConfig = _allBranches.at(i_branch); + if (!i_branchConfig.enabled()) continue; + + _allTIs[i_branch] = {}; + _allTSIs[i_branch] = {}; + _allLHIs[i_branch] = {}; + _allCHIs[i_branch] = {}; + _allKLIs[i_branch] = {}; + _allMCVDInfos[i_branch] = {}; + _allTCHIs[i_branch] = {}; + _allMCTIs[i_branch] = {}; + _allMCSimTIs[i_branch] = {}; + + if(fillCaloTrackMatchMC()){ + _allMCTCHIs[i_branch] = {}; } - RecoQualInfo rqi; - _allRQIs.push_back(rqi); + _allRQIs.push_back(RecoQualInfo{}); + _allTSHIs[i_branch] = {}; + _allTSHCIs[i_branch] = {}; + _allTSMIs[i_branch] = {}; + _allTSHIMCs[i_branch] = {}; - _allTSHIs[i_branch] = std::vector>(); - _allTSHCIs[i_branch] = std::vector>(); - _allTSMIs[i_branch] = std::vector>(); - _allTSHIMCs[i_branch] = std::vector>(); + _allTrkQualResults[i_branch].resize(i_branchConfig.trkQualTags().size()); + _allTrkPIDResults[i_branch].resize(i_branchConfig.trkPIDTags().size()); - std::vector> trkQualResults; - for (size_t i_trkQualTag = 0; i_trkQualTag < i_branchConfig.trkQualTags().size(); ++i_trkQualTag) { - trkQualResults.emplace_back(std::vector()); + for (StepCollIndex ixt = 0; ixt < _extraMCStepTags.size(); ++ixt) { + _extraMCStepInfos[i_branch][ixt] = {}; + _extraMCStepSummaryInfos[i_branch][ixt] = {}; } - _allTrkQualResults[i_branch] = trkQualResults; - - std::vector> trkPIDResults; - for (size_t i_trkPIDTag = 0; i_trkPIDTag < i_branchConfig.trkPIDTags().size(); ++i_trkPIDTag) { - trkPIDResults.emplace_back(std::vector()); + if (!_surfaceStepsTag.empty()) { + _surfaceStepInfos[i_branch] = {}; } - _allTrkPIDResults[i_branch] = trkPIDResults; + } - if(_conf.extraMCStepTags(_extraMCStepTags)){ - for (BranchIndex i_branch = 0; i_branch < _allBranches.size(); ++i_branch) { - for (StepCollIndex i_extraMCStepTag = 0; i_extraMCStepTag < _extraMCStepTags.size(); ++i_extraMCStepTag) { - _extraMCStepInfos[i_branch][i_extraMCStepTag] = std::vector(); - _extraMCStepSummaryInfos[i_branch][i_extraMCStepTag] = std::vector(); - } - } - } - if(_conf.SurfaceStepsTag(_surfaceStepsTag)){ - for (BranchIndex i_branch = 0; i_branch < _allBranches.size(); ++i_branch) { - _surfaceStepInfos[i_branch] = std::vector>(); - } - } - if(_conf.stepPointMCTags(_stepPointMCTags)){ - for (StepCollIndex i_stepPointMCTag = 0; i_stepPointMCTag < _stepPointMCTags.size(); ++i_stepPointMCTag) { - _stepPointMCInfos[i_stepPointMCTag] = MCStepInfos(); - } - } + // global (non-per-branch) MC step storage + for (StepCollIndex icoll = 0; icoll < _stepPointMCTags.size(); ++icoll) { + _stepPointMCInfos[icoll] = MCStepInfos{}; } } @@ -499,136 +522,123 @@ namespace mu2e { _hVersion->GetXaxis()->SetBinLabel(2, "minor"); _hVersion->SetBinContent(2, 11); _hVersion->GetXaxis()->SetBinLabel(3, "patch"); _hVersion->SetBinContent(3, 2); _hProcEvents = tfs->make("n_proc_events", "number of processed events", 1,0,1); - // add event info branch + // event info branch _ntuple->Branch("evtinfo",&_einfo,_buffsize,_splitlevel); - if (_fillmc) { + if (fillEventMC()) { _ntuple->Branch("evtinfomc",&_einfomc,_buffsize,_splitlevel); } // hit counting branch _ntuple->Branch("hitcount",&_hcnt); // track counting branches for (BranchIndex i_branch = 0; i_branch < _allBranches.size(); ++i_branch) { - BranchConfig i_branchConfig = _allBranches.at(i_branch); - std::string leafname = i_branchConfig.branch(); + if (!_allBranches.at(i_branch).enabled()) continue; + std::string leafname = _allBranches.at(i_branch).branch(); _ntuple->Branch(("tcnt.n"+leafname).c_str(),&_tcnt._counts[i_branch]); } // create all track branches for (BranchIndex i_branch = 0; i_branch < _allBranches.size(); ++i_branch) { - BranchConfig i_branchConfig = _allBranches.at(i_branch); + const BranchConfig& i_branchConfig = _allBranches.at(i_branch); + if (!i_branchConfig.enabled()) continue; std::string branch = i_branchConfig.branch(); _ntuple->Branch((branch+".").c_str(),&_allTIs.at(i_branch),_buffsize,_splitlevel); _ntuple->Branch((branch+"segs.").c_str(),&_allTSIs.at(i_branch),_buffsize,_splitlevel); -// add traj-specific branches - if(_ftype == LoopHelix )_ntuple->Branch((branch+"segpars_lh.").c_str(),&_allLHIs.at(i_branch),_buffsize,_splitlevel); - if(_ftype == CentralHelix )_ntuple->Branch((branch+"segpars_ch.").c_str(),&_allCHIs.at(i_branch),_buffsize,_splitlevel); - if(_ftype == KinematicLine )_ntuple->Branch((branch+"segpars_kl.").c_str(),&_allKLIs.at(i_branch),_buffsize,_splitlevel); + // add traj-specific branches + if(_ftype == LoopHelix) _ntuple->Branch((branch+"segpars_lh.").c_str(),&_allLHIs.at(i_branch),_buffsize,_splitlevel); + if(_ftype == CentralHelix) _ntuple->Branch((branch+"segpars_ch.").c_str(),&_allCHIs.at(i_branch),_buffsize,_splitlevel); + if(_ftype == KinematicLine) _ntuple->Branch((branch+"segpars_kl.").c_str(),&_allKLIs.at(i_branch),_buffsize,_splitlevel); // TrkCaloHit: currently only 1 _ntuple->Branch((branch+"calohit.").c_str(),&_allTCHIs.at(i_branch)); for (size_t i_trkQualTag = 0; i_trkQualTag < i_branchConfig.trkQualTags().size(); ++i_trkQualTag) { std::string branchname = "qual"; - if (i_trkQualTag > 0) { - branchname += std::to_string(i_trkQualTag+1); // +1 so that the second trkqual will be "trkqual2" - } + if (i_trkQualTag > 0) branchname += std::to_string(i_trkQualTag+1); _ntuple->Branch((branch+branchname+".").c_str(),&_allTrkQualResults.at(i_branch).at(i_trkQualTag),_buffsize,_splitlevel); } for (size_t i_trkPIDTag = 0; i_trkPIDTag < i_branchConfig.trkPIDTags().size(); ++i_trkPIDTag) { std::string branchname = "pid"; - if (i_trkPIDTag > 0) { - branchname += std::to_string(i_trkPIDTag+1); // +1 so that the second trkpid will be "trkpid2" - } + if (i_trkPIDTag > 0) branchname += std::to_string(i_trkPIDTag+1); _ntuple->Branch((branch+branchname+'.').c_str(),&_allTrkPIDResults.at(i_branch).at(i_trkPIDTag),_buffsize,_splitlevel); } - // optionally add hit-level branches - // (for the time being diagLevel : 2 will still work, but I propose removing this at some point) - if(_conf.diag() > 1 || (_conf.fillhits() && i_branchConfig.options().fillhits())){ + // hit-level branches (global trk.fillHits AND per-branch options.fillHits both required) + if(_conf.diag() > 1 || (_conf.trk().fillHits() && i_branchConfig.options().fillhits())){ _ntuple->Branch((branch+"hits.").c_str(),&_allTSHIs.at(i_branch),_buffsize,_splitlevel); - if (_conf.fillhitcalibs()) + if (_conf.trk().fillHitCalibs()) _ntuple->Branch((branch+"hitcalibs.").c_str(),&_allTSHCIs.at(i_branch),_buffsize,_splitlevel); _ntuple->Branch((branch+"mats.").c_str(),&_allTSMIs.at(i_branch),_buffsize,_splitlevel); } - - // optionally add MC branches - if(_fillmc && i_branchConfig.options().fillmc()){ + // tracker MC branches + if(fillTrkMC(i_branchConfig.options())){ _ntuple->Branch((branch+"mc.").c_str(),&_allMCTIs.at(i_branch),_buffsize,_splitlevel); - _ntuple->Branch((branch+"mcsim.").c_str(),&_allMCSimTIs.at(i_branch),_buffsize,_splitlevel); _ntuple->Branch((branch+"mcvd.").c_str(),&_allMCVDInfos.at(i_branch),_buffsize,_splitlevel); - if(_fillcalomc)_ntuple->Branch((branch+"calohitmc.").c_str(),&_allMCTCHIs.at(i_branch),_buffsize,_splitlevel); - // at hit-level MC information - // (for the time being diagLevel will still work, but I propose removing this at some point) - if(_conf.diag() > 1 || (_conf.fillhits() && i_branchConfig.options().fillhits())){ + if(fillCaloTrackMatchMC()) + _ntuple->Branch((branch+"calohitmc.").c_str(),&_allMCTCHIs.at(i_branch),_buffsize,_splitlevel); + if(_conf.diag() > 1 || (_conf.trk().fillHits() && i_branchConfig.options().fillhits())){ _ntuple->Branch((branch+"hitsmc.").c_str(),&_allTSHIMCs.at(i_branch),_buffsize,_splitlevel); } - // configure extra MCStep branches for this track type - if(_conf.extraMCStepTags(_extraMCStepTags)){ - for(size_t ixtra=0;ixtra < _extraMCStepTags.size(); ++ixtra) { - auto const& tag = _extraMCStepTags[ixtra]; - auto inst = tag.instance(); - std::string mcsiname = branch +"mcsic_" + inst + "."; - std::string mcssiname = branch + "mcssi_" + inst + "."; - _ntuple->Branch(mcsiname.c_str(),&_extraMCStepInfos[i_branch][ixtra],_buffsize,_splitlevel); - _ntuple->Branch(mcssiname.c_str(),&_extraMCStepSummaryInfos[i_branch][ixtra],_buffsize,_splitlevel); - } + // extra MCStep branches per track type + for(size_t ixtra = 0; ixtra < _extraMCStepTags.size(); ++ixtra) { + auto const& tag = _extraMCStepTags[ixtra]; + auto inst = tag.instance(); + _ntuple->Branch((branch+"mcsic_"+inst+".").c_str(),&_extraMCStepInfos[i_branch][ixtra],_buffsize,_splitlevel); + _ntuple->Branch((branch+"mcssi_"+inst+".").c_str(),&_extraMCStepSummaryInfos[i_branch][ixtra],_buffsize,_splitlevel); } - if(_conf.SurfaceStepsTag(_surfaceStepsTag)){ + if(!_surfaceStepsTag.empty()){ _ntuple->Branch((branch+"segsmc.").c_str(),&_surfaceStepInfos[i_branch],_buffsize,_splitlevel); } } } // Time clusters - if(_filltcs) { + if(_conf.trk().fillTimeClusters()) { _ntuple->Branch("timeclusters.",&_tcIs,_buffsize,_splitlevel); } - // Calorimeter - if (_fillcaloclusters){ + // ── Calorimeter reco branches ────────────────────────────────────────── + if(_conf.calo().fill() && _conf.calo().fillClusters()){ _ntuple->Branch("caloclusters.",&_caloCIs,_buffsize,_splitlevel); } - if (_fillcalohits){ + if(_conf.calo().fill() && _conf.calo().fillHits()){ _ntuple->Branch("calohits.",&_caloHIs,_buffsize,_splitlevel); } - if (_fillcalorecodigis){ + if(_conf.calo().fill() && _conf.calo().fillRecoDigis()){ _ntuple->Branch("calorecodigis.",&_caloRDIs,_buffsize,_splitlevel); } - if (_fillcalodigis){ + if(_conf.calo().fill() && _conf.calo().fillDigis()){ _ntuple->Branch("calodigis.",&_caloDIs,_buffsize,_splitlevel); } - if (_fillcalodigismc){ + // ── Calorimeter MC branches ──────────────────────────────────────────── + if(fillCaloDigisMC()){ _ntuple->Branch("calodigismc.",&_caloDigiMCIs,_buffsize,_splitlevel); } - if (_fillcalodigisiminfos){ + if(fillCaloDigiSimMC()){ _ntuple->Branch("calodigisim.",&_caloDigiSIMCs,_buffsize,_splitlevel); } - // Calorimeter MC - if (_fillmc) { - if (_fillcaloclustersmc){ - _ntuple->Branch("caloclustersmc.",&_caloCIMCs,_buffsize,_splitlevel); - } - if (_fillcalohitsmc){ - _ntuple->Branch("calohitsmc.",&_caloHIMCs,_buffsize,_splitlevel); - } - if (_fillcalosiminfos){ - _ntuple->Branch("calomcsim.",&_caloSIMCs,_buffsize,_splitlevel); - } + if(fillCaloClsMC()){ + _ntuple->Branch("caloclustersmc.",&_caloCIMCs,_buffsize,_splitlevel); + } + if(fillCaloHitsMC()){ + _ntuple->Branch("calohitsmc.",&_caloHIMCs,_buffsize,_splitlevel); + } + if(fillCaloSimMC()){ + _ntuple->Branch("calomcsim.",&_caloSIMCs,_buffsize,_splitlevel); } - // general CRV info - if(_fillcrvcoincs) { + // ── CRV reco branches ────────────────────────────────────────────────── + if(_conf.crv().fill() && _conf.crv().fillCoincs()) { _ntuple->Branch("crvsummary",&_crvsummary,_buffsize,_splitlevel); _ntuple->Branch("crvcoincs.",&_crvcoincs,_buffsize,_splitlevel); - if(_fillmc){ + if(fillCRVMC()){ _ntuple->Branch("crvsummarymc",&_crvsummarymc,_buffsize,_splitlevel); _ntuple->Branch("crvcoincsmc.",&_crvcoincsmc,_buffsize,_splitlevel); _ntuple->Branch("crvcoincsmcplane.",&_crvcoincsmcplane,_buffsize,_splitlevel); } } - if(_fillcrvpulses) { + if(_conf.crv().fill() && _conf.crv().fillPulses()) { _ntuple->Branch("crvpulses.",&_crvpulses,_buffsize,_splitlevel); - if(_fillmc) _ntuple->Branch("crvpulsesmc.",&_crvpulsesmc,_buffsize,_splitlevel); + if(fillCRVMC()) _ntuple->Branch("crvpulsesmc.",&_crvpulsesmc,_buffsize,_splitlevel); } - if(_fillcrvdigis) { + if(_conf.crv().fill() && _conf.crv().fillDigis()) { _ntuple->Branch("crvdigis.",&_crvdigis,_buffsize,_splitlevel); } // CRV cosmic inference @@ -636,23 +646,19 @@ namespace mu2e { _ntuple->Branch("crvcosmic.",&_crvInference,_buffsize,_splitlevel); } // helix info - if(_conf.helices()) _ntuple->Branch("helices.",&_hinfos,_buffsize,_splitlevel); - - // all MC information - if (_fillmc) { - if(_conf.stepPointMCTags(_stepPointMCTags)){ - for(size_t icoll=0;icoll < _stepPointMCTags.size(); ++icoll) { - auto const& tag = _stepPointMCTags[icoll]; - auto inst = tag.instance(); - std::string branchname = "mcsteps_" + inst + "."; - _ntuple->Branch(branchname.c_str(),&_stepPointMCInfos[icoll],_buffsize,_splitlevel); - } + if(_conf.trk().fillHelices()) _ntuple->Branch("helices.",&_hinfos,_buffsize,_splitlevel); + + // global MC step branches (all steps, not per-track) + if(fillEventMC()){ + for(size_t icoll = 0; icoll < _stepPointMCTags.size(); ++icoll) { + auto const& tag = _stepPointMCTags[icoll]; + auto inst = tag.instance(); + _ntuple->Branch(("mcsteps_"+inst+".").c_str(),&_stepPointMCInfos[icoll],_buffsize,_splitlevel); } } } void EventNtupleMaker::beginSubRun(const art::SubRun & subrun ) { - // get bfield _infoStructHelper.updateSubRun(); } @@ -668,13 +674,13 @@ namespace mu2e { _hinfos.clear(); // update timing maps for MC - if(_fillmc){ + if(fillEventMC()){ _infoMCStructHelper.updateEvent(event); } // fill event level info fillEventInfo(event); - // need to create and define the event weight branch here because we only now know the EventWeight creating modules that have been run through the Event + // create event weight branch std::vector > eventWeightHandles; _wtHandles = createSpecialBranch(event, "evtwt", eventWeightHandles, _wtinfo, _wtinfo._weights, false); @@ -686,7 +692,7 @@ namespace mu2e { _allTrkPIDCHs.clear(); art::Handle khaH; - if(_conf.helices()){ // find associated Helices + if(_conf.trk().fillHelices()){ BranchConfig i_branchConfig = _allBranches.at(0); art::InputTag kalSeedInputTag = i_branchConfig.input(); event.getByLabel(kalSeedInputTag,khaH); @@ -694,6 +700,14 @@ namespace mu2e { for (BranchIndex i_branch = 0; i_branch < _allBranches.size(); ++i_branch) { BranchConfig i_branchConfig = _allBranches.at(i_branch); + if (!i_branchConfig.enabled()) { + // push empty placeholders to keep index alignment + _allKSPCHs.push_back(art::Handle()); + _allTrkQualCHs.emplace_back(); + _allRQCHs.push_back({}); + _allTrkPIDCHs.emplace_back(); + continue; + } art::Handle kalSeedPtrCollHandle; art::InputTag kalSeedPtrInputTag = i_branchConfig.input(); event.getByLabel(kalSeedPtrInputTag,kalSeedPtrCollHandle); @@ -707,7 +721,6 @@ namespace mu2e { } _allTrkQualCHs.emplace_back(trkQualCollHandles); - // also create the reco qual branches std::vector > recoQualCollHandles; std::vector > selectedRQCHs; selectedRQCHs = createSpecialBranch(event, i_branchConfig.branch()+"qual", recoQualCollHandles, _allRQIs.at(i_branch), _allRQIs.at(i_branch)._qualsAndCalibs, true); @@ -718,7 +731,6 @@ namespace mu2e { } _allRQCHs.push_back(selectedRQCHs); - // TrkCaloHitPID std::vector> trkPIDCollHandles; for (const auto& i_trkPIDTag : i_branchConfig.trkPIDTags()) { art::Handle trkPIDCollHandle; @@ -726,7 +738,6 @@ namespace mu2e { trkPIDCollHandles.push_back(trkPIDCollHandle); } _allTrkPIDCHs.emplace_back(trkPIDCollHandles); - } // trigger information @@ -735,44 +746,49 @@ namespace mu2e { firstEvent=false; } - // MC data - if(_fillmc) { // get MC product collections - event.getByLabel(_conf.primaryParticleTag(),_pph); - event.getByLabel(_conf.kalSeedMCTag(),_ksmcah); - event.getByLabel(_conf.simParticlesTag(),_simParticles); - event.getByLabel(_conf.mcTrajectoriesTag(),_mcTrajectories); - if(_fillcalomc || _fillcaloclustersmc)event.getByLabel(_conf.caloClusterMCTag(),_ccmcch); - if(_fillcalohitsmc)event.getByLabel(_conf.caloHitMCTag(),_chmcch); + // load event-level MC products (tracker + CRV MC) + if(fillEventMC()) { + event.getByLabel(_conf.mc().primaryParticleTag(),_pph); + event.getByLabel(_conf.trk().mc().kalSeedMCAssns(),_ksmcah); + event.getByLabel(_conf.mc().simParticlesTag(),_simParticles); + event.getByLabel(_conf.mc().mcTrajectoriesTag(),_mcTrajectories); } + // load calo MC products (independent of fillEventMC) + if(fillCaloClsMC() || fillCaloTrackMatchMC()){ + event.getByLabel(_conf.calo().mc().clusterMCTag(),_ccmcch); + } + if(fillCaloHitsMC()){ + event.getByLabel(_conf.calo().mc().hitMCTag(),_chmcch); + } + // fill track counts for (BranchIndex i_branch = 0; i_branch < _allBranches.size(); ++i_branch) { + if (!_allBranches.at(i_branch).enabled()) continue; _tcnt._counts[i_branch] = (_allKSPCHs.at(i_branch))->size(); } // find extra MCStep collections _extraMCStepCollections.clear(); for(size_t ixt = 0; ixt < _extraMCStepTags.size(); ixt++){ - auto const& tag = _extraMCStepTags[ixt]; art::Handle mcstepch; - event.getByLabel(tag,mcstepch); + event.getByLabel(_extraMCStepTags[ixt],mcstepch); _extraMCStepCollections.push_back(mcstepch); } event.getByLabel(_surfaceStepsTag,_surfaceStepsHandle); - // find extra MCStep collections + // find global MCStep collections _stepPointMCCollections.clear(); for(size_t icoll = 0; icoll < _stepPointMCTags.size(); icoll++){ - auto const& tag = _stepPointMCTags[icoll]; art::Handle mcstepch; - event.getByLabel(tag,mcstepch); + event.getByLabel(_stepPointMCTags[icoll],mcstepch); _stepPointMCCollections.push_back(mcstepch); } - // loop through all track types unsigned ntrks(0); for (BranchIndex i_branch = 0; i_branch < _allBranches.size(); ++i_branch) { BranchConfig i_branchConfig = _allBranches.at(i_branch); + if (!i_branchConfig.enabled()) continue; _allTIs.at(i_branch).clear(); _allTSIs.at(i_branch).clear(); @@ -793,44 +809,38 @@ namespace mu2e { for (size_t i_trkQualTag = 0; i_trkQualTag < i_branchConfig.trkQualTags().size(); ++i_trkQualTag) { _allTrkQualResults.at(i_branch).at(i_trkQualTag).clear(); } - for (size_t i_trkPIDTag = 0; i_trkPIDTag < i_branchConfig.trkPIDTags().size(); ++i_trkPIDTag) { _allTrkPIDResults.at(i_branch).at(i_trkPIDTag).clear(); } - - for (StepCollIndex i_extraMCStepTag = 0; i_extraMCStepTag < _extraMCStepTags.size(); ++i_extraMCStepTag) { - _extraMCStepInfos.at(i_branch).at(i_extraMCStepTag).clear(); - _extraMCStepSummaryInfos.at(i_branch).at(i_extraMCStepTag).clear(); + for (StepCollIndex ixt = 0; ixt < _extraMCStepTags.size(); ++ixt) { + _extraMCStepInfos.at(i_branch).at(ixt).clear(); + _extraMCStepSummaryInfos.at(i_branch).at(ixt).clear(); } _surfaceStepInfos.at(i_branch).clear(); - for (StepCollIndex i_stepPointMCTag = 0; i_stepPointMCTag < _stepPointMCTags.size(); ++i_stepPointMCTag) { - _stepPointMCInfos.at(i_stepPointMCTag).clear(); + for (StepCollIndex icoll = 0; icoll < _stepPointMCTags.size(); ++icoll) { + _stepPointMCInfos.at(icoll).clear(); } - - if(_fillcalomc) { _allMCTCHIs.at(i_branch).clear(); } + if(fillCaloTrackMatchMC()) { _allMCTCHIs.at(i_branch).clear(); } const auto& kseedptr_coll_h = _allKSPCHs.at(i_branch); const auto& kseedptr_coll = *kseedptr_coll_h; for (size_t i_kseedptr = 0; i_kseedptr < kseedptr_coll.size(); ++i_kseedptr) { - resetTrackBranches(); // reset track branches here so that we don't get information from previous tracks in the next entry - - fillTrackBranches(kseedptr_coll_h, i_branch, i_kseedptr); // fill the info structs for this track - if(_conf.helices()){ + resetTrackBranches(); + fillTrackBranches(kseedptr_coll_h, i_branch, i_kseedptr); + if(_conf.trk().fillHelices()){ auto const& khassns = khaH.product(); - // find the associated HelixSeed to this KalSeed using the assns. auto hptr = (*khassns)[i_kseedptr].second; _infoStructHelper.fillHelixInfo(hptr, _hinfos); } - ntrks++; // count total # of tracks + ntrks++; } } // Time clusters - if(_filltcs) { + if(_conf.trk().fillTimeClusters()) { _tcIs.clear(); - //Get the clusters - event.getByLabel(_conf.timeClustersTag(),_tcsHandle); + event.getByLabel(_conf.trk().timeClustersTag(),_tcsHandle); if(_tcsHandle.isValid()) { for(const auto& tc : *(_tcsHandle)) { _infoStructHelper.fillTimeClusterInfo(tc, _tcIs); @@ -838,299 +848,237 @@ namespace mu2e { } } - // Calorimeter - // Clear lists for this event - if (_fillcaloclustersmc) { _caloCIMCs.clear(); } - if (_fillcalohitsmc) { _caloHIMCs.clear(); } - if (_fillcalosiminfos) { _caloSIMCs.clear(); } - if (_fillcalodigisiminfos) { _caloDigiSIMCs.clear(); } - if (_fillcalodigismc) { _caloDigiMCIs.clear(); } - if (_fillcaloclusters) { _caloCIs.clear(); } - if (_fillcalohits) { _caloHIs.clear(); } - if (_fillcalorecodigis) { _caloRDIs.clear(); } - if (_fillcalodigis) { _caloDIs.clear(); } - - // Fill Calo MC - - // Retrieve CaloShowerSim collection for both caloDigisMC and caloDigiSimInfos branches - if (_fillcalodigismc || _fillcalodigisiminfos) { - event.getByLabel(_conf.caloShowerSimTag(),_caloShowerSim); + // ── Calorimeter ──────────────────────────────────────────────────────── + if(fillCaloClsMC()) { _caloCIMCs.clear(); } + if(fillCaloHitsMC()) { _caloHIMCs.clear(); } + if(fillCaloSimMC()) { _caloSIMCs.clear(); } + if(fillCaloDigiSimMC()){ _caloDigiSIMCs.clear(); } + if(fillCaloDigisMC()) { _caloDigiMCIs.clear(); } + if(_conf.calo().fill() && _conf.calo().fillClusters()) { _caloCIs.clear(); } + if(_conf.calo().fill() && _conf.calo().fillHits()) { _caloHIs.clear(); } + if(_conf.calo().fill() && _conf.calo().fillRecoDigis()){ _caloRDIs.clear(); } + if(_conf.calo().fill() && _conf.calo().fillDigis()) { _caloDIs.clear(); } + + // Calo MC digi branches (need showerSim) + if(fillCaloDigisMC() || fillCaloDigiSimMC()) { + event.getByLabel(_conf.calo().mc().showerSimTag(),_caloShowerSim); } - - // Fill Calo MC Digis branch - if (_fillcalodigismc){ - if (_caloShowerSim.isValid()){ - for (const auto& showerSim : *_caloShowerSim.product()){ + if(fillCaloDigisMC()){ + if(_caloShowerSim.isValid()){ + for(const auto& showerSim : *_caloShowerSim.product()){ _infoMCStructHelper.fillCaloDigiMCInfo(showerSim,_caloDigiMCIs); } } } - - // Fill Calo MC Hits branch - if (_fillcalohitsmc){ - for (const auto& hitmc : *_chmcch.product()){ + if(fillCaloHitsMC()){ + for(const auto& hitmc : *_chmcch.product()){ _infoMCStructHelper.fillCaloHitInfoMC(hitmc,_caloHIMCs); } } - - // Fill Calo MC Clusters branch - if (_fillcaloclustersmc){ - for (const auto& clustermc : *_ccmcch.product()){ - + if(fillCaloClsMC()){ + for(const auto& clustermc : *_ccmcch.product()){ _infoMCStructHelper.fillCaloClusterInfoMC(clustermc,_caloCIMCs); - - //Find and link the existing hits - if (_fillcalohitsmc){ - for (const auto& hitmc : clustermc.caloHitMCs()){ - for (uint hitIdx=0; hitIdx < _caloHIMCs.size(); hitIdx++){ - - if (hitmc && _caloHIMCs[hitIdx] == *hitmc){ - //Update the hit and cluster indexes + if(fillCaloHitsMC()){ + for(const auto& hitmc : clustermc.caloHitMCs()){ + for(uint hitIdx = 0; hitIdx < _caloHIMCs.size(); hitIdx++){ + if(hitmc && _caloHIMCs[hitIdx] == *hitmc){ _caloHIMCs[hitIdx].clusterIdx_ = _caloCIMCs.size()-1; _caloCIMCs.back().hits_.push_back(hitIdx); break; } } } - if (int(_caloCIMCs.back().hits_.size()) != _caloCIMCs.back().nhits){ + if(int(_caloCIMCs.back().hits_.size()) != _caloCIMCs.back().nhits){ throw cet::exception("EventNtuple") << "Could not find one or all CaloHitMCs linked to CaloClusterMC " << _caloCIMCs.size()-1 << "\n"; } } } } - - if (_fillcalosiminfos){ - for (const auto& clustermc : *_ccmcch.product()){ + if(fillCaloSimMC()){ + for(const auto& clustermc : *_ccmcch.product()){ _infoMCStructHelper.fillCaloSimInfos(clustermc,_caloSIMCs); } } - - if (_fillcalodigisiminfos){ - if (_caloShowerSim.isValid()){ - for (const auto& showerSim : *_caloShowerSim.product()){ + if(fillCaloDigiSimMC()){ + if(_caloShowerSim.isValid()){ + for(const auto& showerSim : *_caloShowerSim.product()){ _infoMCStructHelper.fillCaloDigiSimInfos(showerSim,_caloDigiSIMCs); } } } // Calorimeter reco branches - - if (_fillcalodigis){ - //Get the digis - event.getByLabel(_conf.caloDigisTag(),_caloDigis); - for (const auto& digi : *_caloDigis.product()){ + if(_conf.calo().fill() && _conf.calo().fillDigis()){ + event.getByLabel(_conf.calo().digisTag(),_caloDigis); + for(const auto& digi : *_caloDigis.product()){ _infoStructHelper.fillCaloDigiInfo(digi,_caloDIs); } } - - if (_fillcalorecodigis){ - //Get the recodigis - event.getByLabel(_conf.caloRecoDigisTag(),_caloRecoDigis); - for (const auto& recodigi : *_caloRecoDigis.product()){ - + if(_conf.calo().fill() && _conf.calo().fillRecoDigis()){ + event.getByLabel(_conf.calo().recoDigisTag(),_caloRecoDigis); + for(const auto& recodigi : *_caloRecoDigis.product()){ _infoStructHelper.fillCaloRecoDigiInfo(recodigi,_caloRDIs); - - //Find and link the existing digis - if (_fillcalodigis){ + if(_conf.calo().fillDigis()){ const auto& digi = recodigi.caloDigiPtr(); - for (uint digiIdx=0; digiIdx < _caloDIs.size(); digiIdx++){ - - if (_caloDIs[digiIdx] == *digi){ - //Update the digi and recodigi indexes + for(uint digiIdx = 0; digiIdx < _caloDIs.size(); digiIdx++){ + if(_caloDIs[digiIdx] == *digi){ _caloDIs[digiIdx].caloRecoDigiIdx_ = _caloRDIs.size()-1; _caloRDIs.back().caloDigiIdx_ = digiIdx; break; } } - if (_caloRDIs.back().caloDigiIdx_ < 0){ + if(_caloRDIs.back().caloDigiIdx_ < 0){ throw cet::exception("EventNtuple") << "Could not find CaloDigi linked to CaloRecoDigi " << _caloRDIs.size()-1 << "\n"; } } } } - - if (_fillcalohits){ - //Get the hits - event.getByLabel(_conf.caloHitsTag(),_caloHits); - for (const auto& hit : *_caloHits.product()){ - + if(_conf.calo().fill() && _conf.calo().fillHits()){ + event.getByLabel(_conf.calo().hitsTag(),_caloHits); + for(const auto& hit : *_caloHits.product()){ _infoStructHelper.fillCaloHitInfo(hit,_caloHIs); - - //Find and link the existing recodigis - if (_fillcalorecodigis){ - for (const auto& recodigi : hit.recoCaloDigis()){ - for (uint recoDigiIdx=0; recoDigiIdx < _caloRDIs.size(); recoDigiIdx++){ - - if (_caloRDIs[recoDigiIdx] == *recodigi){ - //Update the recodigi and hit indexes + if(_conf.calo().fillRecoDigis()){ + for(const auto& recodigi : hit.recoCaloDigis()){ + for(uint recoDigiIdx = 0; recoDigiIdx < _caloRDIs.size(); recoDigiIdx++){ + if(_caloRDIs[recoDigiIdx] == *recodigi){ _caloRDIs[recoDigiIdx].caloHitIdx_ = _caloHIs.size()-1; _caloHIs.back().recoDigis_.push_back(recoDigiIdx); break; } } } - if (int(_caloHIs.back().recoDigis_.size()) != _caloHIs.back().nSiPMs_){ + if(int(_caloHIs.back().recoDigis_.size()) != _caloHIs.back().nSiPMs_){ throw cet::exception("EventNtuple") << "Could not find one or all CaloRecoDigi linked to CaloHit " << _caloHIs.size()-1 << "\n"; } } } } - - if (_fillcaloclusters){ - //Get the clusters - event.getByLabel(_conf.caloClustersTag(),_caloClusters); - for (const auto& cluster : *_caloClusters.product()){ - + if(_conf.calo().fill() && _conf.calo().fillClusters()){ + event.getByLabel(_conf.calo().clustersTag(),_caloClusters); + for(const auto& cluster : *_caloClusters.product()){ _infoStructHelper.fillCaloClusterInfo(cluster,_caloCIs); - - //Find and link the existing hits - if (_fillcalohits){ - for (const auto& hit : cluster.caloHitsPtrVector()){ - for (uint hitIdx=0; hitIdx < _caloHIs.size(); hitIdx++){ - - if (_caloHIs[hitIdx] == *hit){ - //Update the hit and cluster indexes + if(_conf.calo().fillHits()){ + for(const auto& hit : cluster.caloHitsPtrVector()){ + for(uint hitIdx = 0; hitIdx < _caloHIs.size(); hitIdx++){ + if(_caloHIs[hitIdx] == *hit){ _caloHIs[hitIdx].clusterIdx_ = _caloCIs.size()-1; _caloCIs.back().hits_.push_back(hitIdx); break; } } } - if (_caloCIs.back().hits_.size() != _caloCIs.back().size_){ + if(_caloCIs.back().hits_.size() != _caloCIs.back().size_){ throw cet::exception("EventNtuple") << "Could not find one or all CaloHits linked to CaloCluster " << _caloCIs.size()-1 << "\n"; } } } } - // fill CRV info - if(_fillcrvcoincs){ + // ── CRV ─────────────────────────────────────────────────────────────── + if(_conf.crv().fill() && _conf.crv().fillCoincs()){ _crvcoincs.clear(); _crvcoincsmc.clear(); _crvcoincsmcplane.clear(); - - event.getByLabel(_conf.crvCoincidencesTag(),_crvCoincidences); - event.getByLabel(_conf.crvRecoPulsesTag(),_crvRecoPulses); - event.getByLabel(_conf.crvStepsTag(),_crvSteps); - if(_fillmc) event.getByLabel(_conf.crvCoincidenceMCsTag(),_crvCoincidenceMCs); + event.getByLabel(_conf.crv().coincidencesTag(),_crvCoincidences); + event.getByLabel(_conf.crv().recoPulsesTag(),_crvRecoPulses); + event.getByLabel(_conf.crv().stepsTag(),_crvSteps); + if(fillCRVMC()) event.getByLabel(_conf.crv().mc().coincidenceMCsTag(),_crvCoincidenceMCs); _crvHelper.FillCrvHitInfoCollections( - _crvCoincidences, _crvCoincidenceMCs, - _crvRecoPulses, _crvSteps, _mcTrajectories,_crvcoincs, _crvcoincsmc, - _crvsummary, _crvsummarymc, _crvcoincsmcplane, _crvPlaneY, _pph); + _crvCoincidences, _crvCoincidenceMCs, + _crvRecoPulses, _crvSteps, _mcTrajectories, _crvcoincs, _crvcoincsmc, + _crvsummary, _crvsummarymc, _crvcoincsmcplane, _conf.crv().planeY(), _pph); } - if(_fillcrvpulses){ + if(_conf.crv().fill() && _conf.crv().fillPulses()){ _crvpulses.clear(); _crvpulsesmc.clear(); - event.getByLabel(_conf.crvRecoPulsesTag(),_crvRecoPulses); - if(_fillmc) event.getByLabel(_conf.crvDigiMCsTag(),_crvDigiMCs); + event.getByLabel(_conf.crv().recoPulsesTag(),_crvRecoPulses); + if(fillCRVMC()) event.getByLabel(_conf.crv().mc().digiMCsTag(),_crvDigiMCs); _crvHelper.FillCrvPulseInfoCollections(_crvRecoPulses, _crvDigiMCs, _ewmh, - _crvpulses, _crvpulsesmc); + _crvpulses, _crvpulsesmc); } - if(_fillcrvdigis){ + if(_conf.crv().fill() && _conf.crv().fillDigis()){ _crvdigis.clear(); - event.getByLabel(_conf.crvDigisTag(),_crvDigis); + event.getByLabel(_conf.crv().digisTag(),_crvDigis); _crvHelper.FillCrvDigiInfoCollections(_crvDigis,_crvdigis); } - // fill CRV cosmic inference scores (T x C structure aligned with trk branches) + // CRV cosmic inference if(_fillCrvInference) { _crvInference.clear(); - // Init associations from CrvInference module: KalSeed <-> CrvCoincidenceCluster with MVAResult data product art::Handle> crvInfHandle; - // grab the associations from the art::Event event.getByLabel(_crvInferenceTag, crvInfHandle); - // build a map from KalSeed ptr to scores std::map, std::vector> crvInfMap; - // Get the scores from the associations and fill the map if(crvInfHandle.isValid()) { - // loop through association for(const auto& assn : *crvInfHandle) { MVAResultInfo info; - info.result = assn.data->_value; // the model score - info.valid = true; // true if assns is valid + info.result = assn.data->_value; + info.valid = true; crvInfMap[assn.first].push_back(info); } } - // fill the branch - // iterate over all tracks to keep alignment with trk branches - // this means filling empty vectors for tracks with no coincidence const auto& kseedptr_coll = *_allKSPCHs.at(0); for(size_t i = 0; i < kseedptr_coll.size(); ++i) { auto it = crvInfMap.find(kseedptr_coll[i]); if(it != crvInfMap.end()) { - _crvInference.push_back(it->second); // fill + _crvInference.push_back(it->second); } else { - _crvInference.emplace_back(); // empty vector for tracks with no CRV match + _crvInference.emplace_back(); } } } - // fill MC information unrelated to any reconstructed object - if (_fillmc) { - // fill MCStepCollection branch + // global MC step branches (not per-track) + if(fillEventMC()) { for(size_t icoll = 0; icoll < _stepPointMCTags.size(); icoll++){ auto const& mcsteps = *_stepPointMCCollections[icoll]; - auto& mcstepinfos = _stepPointMCInfos[icoll]; - _infoMCStructHelper.fillStepPointMCInfo(mcsteps, mcstepinfos); + _infoMCStructHelper.fillStepPointMCInfo(mcsteps, _stepPointMCInfos[icoll]); } } // fill this row in the TTree - bool fill = true; // default to fliling event - if(_hastrks && ntrks == 0) { // if we require tracks (_hastrks) but we have none, don't write - fill = false; - } - if (_hascrv && _crvsummary.totalPEs == 0) { // if we require CRV but we have none, don't write - fill = false; - } - if (fill) { + bool fill = true; + if(_hastrks && ntrks == 0) fill = false; + if(_hascrv && _crvsummary.totalPEs == 0) fill = false; + if(fill) { _ntuple->Fill(); } - _hProcEvents->Fill(0); // this is the number of events we have processed, which may be different to the number of events stored in the ntuple + _hProcEvents->Fill(0); } void EventNtupleMaker::fillEventInfo( const art::Event& event) { - // fill basic event information - _einfo.event = event.event(); - _einfo.run = event.run(); + _einfo.event = event.event(); + _einfo.run = event.run(); _einfo.subrun = event.subRun(); - if (_recoCountTag != "") { + if(_recoCountTag != "") { art::Handle recoCountHandle; if(event.getByLabel(_recoCountTag, recoCountHandle)) { - auto recoCount = *recoCountHandle; - _infoStructHelper.fillHitCount(recoCount, _hcnt); + _infoStructHelper.fillHitCount(*recoCountHandle, _hcnt); } } - // currently no reco nproton estimate TODO - if (_PBTTag != "") { + if(_PBTTag != "") { auto PBThandle = event.getValidHandle(_PBTTag); - auto PBT = *PBThandle; - _einfo.pbtime = PBT.pbtime_; - _einfo.pbterr = PBT.pbterr_; + _einfo.pbtime = PBThandle->pbtime_; + _einfo.pbterr = PBThandle->pbterr_; } - if (_EWMTag != "") { + if(_EWMTag != "") { event.getByLabel(_EWMTag, _ewmh); } - if (_fillmc) { - auto PBTMChandle = event.getValidHandle(_PBTMCTag); - auto PBTMC = *PBTMChandle; - _einfomc.pbtime = PBTMC.pbtime_; + if(fillEventMC()) { + auto PBTMChandle = event.getValidHandle(_conf.mc().PBTMCTag()); + _einfomc.pbtime = PBTMChandle->pbtime_; auto PBIhandle = event.getValidHandle(_PBITag); - auto PBI = *PBIhandle; - _einfomc.nprotons = PBI.intensity(); + _einfomc.nprotons = PBIhandle->intensity(); } - // get event weight products std::vector weights; - for (const auto& i_weightHandle : _wtHandles) { - double weight = i_weightHandle->weight(); - weights.push_back(weight); + for(const auto& i_weightHandle : _wtHandles) { + weights.push_back(i_weightHandle->weight()); } _wtinfo.setWeights(weights); } @@ -1141,23 +1089,18 @@ namespace mu2e { const art::TriggerResults* trigResults = trigResultsH.product(); TriggerResultsNavigator tnav(trigResults); - if (firstEvent) { - if (tnav.getTrigPaths().size() > TrigInfo::ntrig_) { + if(firstEvent) { + if(tnav.getTrigPaths().size() > TrigInfo::ntrig_) { throw cet::exception("EventNtuple") << "More trigger paths in TriggerResultsNavigator than maximum allowed by TrigInfo::ntrig_. Increase TrigInfo::ntrig_ and rebuild\n"; } - for (unsigned int i = 0; i < tnav.getTrigPaths().size(); ++i) { - const std::string name = "trig_"+tnav.getTrigPathNameByIndex(i); - _ntuple->Branch(name.c_str(), &_triggerResults._triggerArray[i], _buffsize,_splitlevel); + for(unsigned int i = 0; i < tnav.getTrigPaths().size(); ++i) { + const std::string name = "trig_"+tnav.getTrigPathNameByIndex(i); + _ntuple->Branch(name.c_str(), &_triggerResults._triggerArray[i], _buffsize,_splitlevel); } } - - for (unsigned int i = 0; i < tnav.getTrigPaths().size(); ++i) { - const std::string path = tnav.getTrigPathNameByIndex(i); - bool accepted = tnav.accepted(path); - _triggerResults._triggerArray[i] = accepted; + for(unsigned int i = 0; i < tnav.getTrigPaths().size(); ++i) { + _triggerResults._triggerArray[i] = tnav.accepted(tnav.getTrigPathNameByIndex(i)); } - - } void EventNtupleMaker::fillTrackBranches(const art::Handle& kspch, BranchIndex i_branch, size_t i_kseedptr) { @@ -1166,23 +1109,19 @@ namespace mu2e { const auto& kseed = *kseedptr; // general info _infoStructHelper.fillTrkInfo(kseed,_allTIs.at(i_branch)); - - // fit information at specific points:e _infoStructHelper.fillTrkSegInfo(kseed,_allTSIs.at(i_branch)); - if(_ftype == LoopHelix && kseed.loopHelixFit())_infoStructHelper.fillLoopHelixInfo(kseed,_allLHIs.at(i_branch)); - if(_ftype == CentralHelix && kseed.centralHelixFit())_infoStructHelper.fillCentralHelixInfo(kseed,_allCHIs.at(i_branch)); - if(_ftype == KinematicLine && kseed.kinematicLineFit())_infoStructHelper.fillKinematicLineInfo(kseed,_allKLIs.at(i_branch)); - BranchConfig branchConfig = _allBranches.at(i_branch); - if(_conf.diag() > 1 || (_conf.fillhits() && branchConfig.options().fillhits())){ // want hit level info - _infoStructHelper.fillHitInfo(kseed, _allTSHIs.at(i_branch), _allTSHCIs.at(i_branch), _conf.fillhitcalibs()); + if(_ftype == LoopHelix && kseed.loopHelixFit()) _infoStructHelper.fillLoopHelixInfo(kseed,_allLHIs.at(i_branch)); + if(_ftype == CentralHelix && kseed.centralHelixFit()) _infoStructHelper.fillCentralHelixInfo(kseed,_allCHIs.at(i_branch)); + if(_ftype == KinematicLine && kseed.kinematicLineFit()) _infoStructHelper.fillKinematicLineInfo(kseed,_allKLIs.at(i_branch)); + const BranchConfig& branchConfig = _allBranches.at(i_branch); + if(_conf.diag() > 1 || (_conf.trk().fillHits() && branchConfig.options().fillhits())){ + _infoStructHelper.fillHitInfo(kseed, _allTSHIs.at(i_branch), _allTSHCIs.at(i_branch), _conf.trk().fillHitCalibs()); _infoStructHelper.fillMatInfo(kseed, _allTSMIs.at(i_branch)); } - // calorimeter info - _infoStructHelper.fillTrkCaloHitInfo(kseed, _allTCHIs.at(i_branch)); // fillTrkCaloHitInfo handles whether there is a calo hit or not - if (kseed.hasCaloCluster()) { - _tcnt._ndec = 1; // only 1 possible calo hit at the moment FIXME: should work with the above - // test + _infoStructHelper.fillTrkCaloHitInfo(kseed, _allTCHIs.at(i_branch)); + if(kseed.hasCaloCluster()) { + _tcnt._ndec = 1; if(_conf.debug()>0){ auto const& tch = kseed.caloHit(); auto const& cc = tch.caloCluster(); @@ -1191,61 +1130,49 @@ namespace mu2e { } } - const auto& trkQualHandles = _allTrkQualCHs.at(i_branch); - for (size_t i_trkQualHandle = 0; i_trkQualHandle < trkQualHandles.size(); ++i_trkQualHandle) { + for(size_t i_trkQualHandle = 0; i_trkQualHandle < trkQualHandles.size(); ++i_trkQualHandle) { const auto& trkQualHandle = trkQualHandles.at(i_trkQualHandle); - if (trkQualHandle.isValid()) { // might not have a valid handle - _infoStructHelper.fillTrkQualInfo(kseed, trkQualHandle->at(i_kseedptr) , _allTrkQualResults.at(i_branch).at(i_trkQualHandle)); + if(trkQualHandle.isValid()) { + _infoStructHelper.fillTrkQualInfo(kseed, trkQualHandle->at(i_kseedptr), _allTrkQualResults.at(i_branch).at(i_trkQualHandle)); } } - // all RecoQuals - std::vector recoQuals; // for the output value - for (const auto& i_recoQualHandle : _allRQCHs.at(i_branch)) { - Float_t recoQual = i_recoQualHandle->at(i_kseedptr)._value; - recoQuals.push_back(recoQual); - Float_t recoQualCalib = i_recoQualHandle->at(i_kseedptr)._calib; - recoQuals.push_back(recoQualCalib); + std::vector recoQuals; + for(const auto& i_recoQualHandle : _allRQCHs.at(i_branch)) { + recoQuals.push_back(i_recoQualHandle->at(i_kseedptr)._value); + recoQuals.push_back(i_recoQualHandle->at(i_kseedptr)._calib); } _allRQIs.at(i_branch).setQuals(recoQuals); - // TrkCaloHitPID const auto& trkPIDHandles = _allTrkPIDCHs.at(i_branch); - for (size_t i_trkPIDHandle = 0; i_trkPIDHandle < trkPIDHandles.size(); ++i_trkPIDHandle) { + for(size_t i_trkPIDHandle = 0; i_trkPIDHandle < trkPIDHandles.size(); ++i_trkPIDHandle) { const auto& trkPIDHandle = trkPIDHandles.at(i_trkPIDHandle); - if (trkPIDHandle.isValid()) { // might not have a valid handle - _infoStructHelper.fillTrkPIDInfo(kseed, trkPIDHandle->at(i_kseedptr) , _allTrkPIDResults.at(i_branch).at(i_trkPIDHandle)); + if(trkPIDHandle.isValid()) { + _infoStructHelper.fillTrkPIDInfo(kseed, trkPIDHandle->at(i_kseedptr), _allTrkPIDResults.at(i_branch).at(i_trkPIDHandle)); } } - // fill MC info associated with this track - if(_fillmc && branchConfig.options().fillmc()) { + // fill tracker MC info + if(fillTrkMC(branchConfig.options())) { const PrimaryParticle& primary = *_pph; - // use Assns interface to find the associated KalSeedMC; this uses ptrs - if(_conf.debug() > 1)std::cout << "KalSeedMCMatch has " << _ksmcah->size() << " entries" << std::endl; - for(auto iksmca = _ksmcah->begin(); iksmca!= _ksmcah->end(); iksmca++){ + if(_conf.debug() > 1) std::cout << "KalSeedMCMatch has " << _ksmcah->size() << " entries" << std::endl; + for(auto iksmca = _ksmcah->begin(); iksmca != _ksmcah->end(); iksmca++){ if(_conf.debug() > 2) std::cout << "KalSeed Ptr " << kseedptr << " match Ptr " << iksmca->first << "?" << std::endl; if(iksmca->first == kseedptr) { auto const& kseedmc = *(iksmca->second); _infoMCStructHelper.fillTrkInfoMC(kseed, kseedmc, _surfaceStepsHandle, _allMCTIs.at(i_branch)); - auto& mcvdis = _allMCVDInfos.at(i_branch); - _infoMCStructHelper.fillVDInfo(kseed, kseedmc, mcvdis); + _infoMCStructHelper.fillVDInfo(kseed, kseedmc, _allMCVDInfos.at(i_branch)); _infoMCStructHelper.fillAllSimInfos(kseedmc, primary, _allMCSimTIs.at(i_branch), branchConfig.options().genealogyDepth(), branchConfig.options().matchDepth()); - - if(_conf.diag() > 1 || (_conf.fillhits() && branchConfig.options().fillhits())){ + if(_conf.diag() > 1 || (_conf.trk().fillHits() && branchConfig.options().fillhits())){ _infoMCStructHelper.fillHitInfoMCs(kseed,kseedmc, _allTSHIMCs.at(i_branch)); } - // fill extra MCStep info for this branch for(size_t ixt = 0; ixt < _extraMCStepTags.size(); ixt++){ - auto const& mcsc = *_extraMCStepCollections[ixt]; - auto& mcsic = _extraMCStepInfos[i_branch][ixt]; - auto& mcssi = _extraMCStepSummaryInfos.at(i_branch).at(ixt); - _infoMCStructHelper.fillExtraMCStepInfos(kseedmc,mcsc,mcsic,mcssi); + _infoMCStructHelper.fillExtraMCStepInfos(kseedmc,*_extraMCStepCollections[ixt], + _extraMCStepInfos[i_branch][ixt],_extraMCStepSummaryInfos.at(i_branch).at(ixt)); } - // fill SurfaceStep info if(_surfaceStepsHandle.isValid()){ - if(_conf.debug() > 2)std::cout << "SurfaceSteps from handle " << _surfaceStepsHandle << std::endl; + if(_conf.debug() > 2) std::cout << "SurfaceSteps from handle " << _surfaceStepsHandle << std::endl; auto& ssi = _surfaceStepInfos.at(i_branch); ssi.push_back(std::vector()); _infoMCStructHelper.fillSurfaceStepInfos(kseedmc,*_surfaceStepsHandle,ssi.back()); @@ -1253,65 +1180,56 @@ namespace mu2e { break; } } - if (kseed.hasCaloCluster() && _fillcalomc) { - // fill MC truth of the associated CaloCluster. Use the fact that these are correlated by index with the clusters in that collection + if(kseed.hasCaloCluster() && fillCaloTrackMatchMC()) { auto index = kseed.caloCluster().key(); - auto const& ccmcc = *_ccmcch; - auto const& ccmc = ccmcc[index]; - _infoMCStructHelper.fillCaloClusterInfoMC(ccmc,_allMCTCHIs.at(i_branch)); // currently broken due to CaloMC changes. This needs fixing in compression + auto const& ccmc = (*_ccmcch)[index]; + _infoMCStructHelper.fillCaloClusterInfoMC(ccmc,_allMCTCHIs.at(i_branch)); } } } // some branches can't be made until the analyze() function because we want to write out all data products of a certain type - // these all have an underlying array where we want to name the individual elements in the array with different leaf names template std::vector > EventNtupleMaker::createSpecialBranch(const art::Event& event, const std::string& branchname, - std::vector >& handles, // this parameter is only needed so that the template parameter T can be deduced. There is probably a better way to do this FIXME + std::vector >& handles, TI& infostruct, TIA& array, bool make_individual_branches, const std::string& selection) { std::vector > outputHandles; std::vector > inputHandles = event.getMany(); - if (inputHandles.size()>0) { + if(inputHandles.size()>0) { std::vector labels; - for (const auto& i_handle : inputHandles) { + for(const auto& i_handle : inputHandles) { std::string moduleLabel = i_handle.provenance()->moduleLabel(); - // event.getMany() doesn't have a way to wildcard part of the ModuleLabel, do it ourselves here size_t pos; - if (selection != "") { // if we want to add a selection + if(selection != "") { pos = moduleLabel.find(selection); - - // make sure that the selection (e.g. "DeM") appears at the end of the module label - if (pos == std::string::npos) { - if(_conf.debug() > 3)std::cout << "Selection not found" << std::endl; + if(pos == std::string::npos) { + if(_conf.debug() > 3) std::cout << "Selection not found" << std::endl; continue; } - else if (pos+selection.length() != moduleLabel.size()) { - if(_conf.debug() > 3)std::cout << "Selection wasn't at end of moduleLabel" << std::endl; + else if(pos+selection.length() != moduleLabel.size()) { + if(_conf.debug() > 3) std::cout << "Selection wasn't at end of moduleLabel" << std::endl; continue; } moduleLabel = moduleLabel.erase(pos, selection.length()); } std::string instanceName = i_handle.provenance()->productInstanceName(); - - std::string branchname = moduleLabel; - if (instanceName != "") { - branchname += "_" + instanceName; - } + std::string bname = moduleLabel; + if(instanceName != "") bname += "_" + instanceName; outputHandles.push_back(i_handle); - labels.push_back(branchname); + labels.push_back(bname); } - if (make_individual_branches) { // if we want to make individual branches per leaf (e.g. to avoid branch ambiguities in python such as detrkqual.NActiveHits vs uetrkqual.NActiveHits) + if(make_individual_branches) { const std::vector& leafnames = infostruct.leafnames(labels); int n_leaves = leafnames.size(); - for (int i_leaf = 0; i_leaf < n_leaves; ++i_leaf) { + for(int i_leaf = 0; i_leaf < n_leaves; ++i_leaf) { std::string thisbranchname = (branchname+"."+leafnames.at(i_leaf)); - if (!_ntuple->GetBranch(thisbranchname.c_str())) { // only want to create the branch once + if(!_ntuple->GetBranch(thisbranchname.c_str())) { _ntuple->Branch(thisbranchname.c_str(), &array[i_leaf]); } } } else { - if (!_ntuple->GetBranch((branchname+".").c_str())) { // only want to create the branch once + if(!_ntuple->GetBranch((branchname+".").c_str())) { _ntuple->Branch((branchname+".").c_str(), &infostruct, infostruct.leafname(labels).c_str()); } } @@ -1320,14 +1238,12 @@ namespace mu2e { } void EventNtupleMaker::resetTrackBranches() { - for (BranchIndex i_branch = 0; i_branch < _allBranches.size(); ++i_branch) { - + for(BranchIndex i_branch = 0; i_branch < _allBranches.size(); ++i_branch) { + if (!_allBranches.at(i_branch).enabled()) continue; _allRQIs.at(i_branch).reset(); } } } // end namespace mu2e -// Part of the magic that makes this class a module. -// create an instance of the module. It also registers using mu2e::EventNtupleMaker; DEFINE_ART_MODULE(EventNtupleMaker) From 48844fc45494b56121ec3945136428dbc58b101b Mon Sep 17 00:00:00 2001 From: Andrew Edmonds Date: Mon, 1 Jun 2026 14:54:37 -0500 Subject: [PATCH 3/9] Catching fcl comment syntax error made by AI --- fcl/prolog.fcl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fcl/prolog.fcl b/fcl/prolog.fcl index c7971fe..9ab683f 100644 --- a/fcl/prolog.fcl +++ b/fcl/prolog.fcl @@ -263,7 +263,7 @@ EventNtupleMaker : { TriggerProcessName : "Digitize" TriggerPathSuffix : "DigitizePath" FitType : LoopHelix - # ── Event-level MC (gates tracker MC, CRV MC, and evtinfomc branch) ────── + # -- Event-level MC (gates tracker MC, CRV MC, and evtinfomc branch) ------ mc : { fill : true PBTMCTag : "EWMProducer" @@ -276,7 +276,7 @@ EventNtupleMaker : { MaxVDDt : 5 # ns } } - # ── Tracker subsystem ───────────────────────────────────────────────────── + # -- Tracker subsystem ----------------------------------------------------- trk : { fillHits : true fillHitCalibs : false @@ -292,7 +292,7 @@ EventNtupleMaker : { stepPointMCTags : [ ] } } - # ── Calorimeter subsystem ───────────────────────────────────────────────── + # -- Calorimeter subsystem ------------------------------------------------- # calo.mc.fill is independent of mc.fill: calo-only jobs can fill calo MC # without loading tracker/event-level MC products. calo : { @@ -318,7 +318,7 @@ EventNtupleMaker : { showerSimTag : "compressRecoMCs" } } - # ── CRV subsystem ───────────────────────────────────────────────────────── + # -- CRV subsystem --------------------------------------------------------- crv : { fill : true fillCoincs : true @@ -352,7 +352,7 @@ EventNtupleMakerTTMC : { } # TTMCBranch: per-branch config for trigger MC branches. -# No options needed — BranchOptConfig defaults are fillMC:true, fillHits:true, +# No options needed -- BranchOptConfig defaults are fillMC:true, fillHits:true, # genealogyDepth:-1, matchDepth:-1. TTMCBranch : { branch : "trk" From ddcf397e1b3ecca47f02c693f5c68a560a17be24 Mon Sep 17 00:00:00 2001 From: Andrew Edmonds Date: Thu, 4 Jun 2026 14:52:56 -0500 Subject: [PATCH 4/9] Updates to validation --- validation/README.md | 7 +- validation/commands.txt | 36 ++++++ validation/datasets_MDC2020.txt | 7 ++ validation/datasets_MDC2025.txt | 7 ++ validation/datasets_Run1B.txt | 7 ++ validation/test_fcls.py | 188 +++++++++++++++++++++++++++ validation/test_fcls.sh | 216 -------------------------------- 7 files changed, 250 insertions(+), 218 deletions(-) create mode 100644 validation/commands.txt create mode 100644 validation/datasets_MDC2020.txt create mode 100644 validation/datasets_MDC2025.txt create mode 100644 validation/datasets_Run1B.txt create mode 100644 validation/test_fcls.py delete mode 100644 validation/test_fcls.sh diff --git a/validation/README.md b/validation/README.md index 25853ae..a1f1b97 100644 --- a/validation/README.md +++ b/validation/README.md @@ -8,10 +8,13 @@ We want to make sure that any changes we make to the code don't: From ```EventNtuple/``` directory: ``` -. ./validation/test_fcls.sh [MDC2020 or MDC2025 or Run1B] +python validation/test_fcls.py --tests validation/commands.txt --datasets validation/datasets_XXXXX.txt ``` +where ```XXXXXX``` is any of ```MDC2020```, ```MDC2025```, or ```Run1B```. -This script will run all the supported fcl files over relevant datasets. All tests should report ```OK```. If one reports ```FAIL```, you can find the exact command that failed in the ```test_fcls.log``` file in order to debug. +This script will run all the supported fcl files over relevant datasets. The output should be self-explanatory. + +The reason for separating the commands from the datasets is so that we can easily change to a different set of datasets with new simulation campaigns, as well as update datasets in currently-supported simulation campaigns. ### Creating a Validation File Before making any changes, create an EventNtuple file and run the validation script. This creates a new ROOT file with histograms created from the EventNtuple ntuple: diff --git a/validation/commands.txt b/validation/commands.txt new file mode 100644 index 0000000..9f5e34d --- /dev/null +++ b/validation/commands.txt @@ -0,0 +1,36 @@ +# Test mock datasets with and without MC +mu2e -c fcl/from_mcs-mockdata.fcl -S {mock} --TFileName nts.ntuple.mock.root -n 100 +mu2e -c fcl/from_mcs-mockdata_noMC.fcl -S {mock} --TFileName nts.ntuple.mockNoMC.root -n 100 + +# Test some individual reconstructed datasets +mu2e -c fcl/from_mcs-primary.fcl -S {primary} --TFileName nts.ntuple.primary.root -n 100 +mu2e -c fcl/from_mcs-mixed.fcl -S {mixed} --TFileName nts.ntuple.mixed.root -n 100 +mu2e -c fcl/from_mcs-extracted.fcl -S {extracted} --TFileName nts.ntuple.extracted.root -n 100 + +# Test ceSimReco works +mu2e -c Production/Validation/ceSimReco.fcl -n 10 +mu2e -c fcl/from_mcs-ceSimReco.fcl -s mcs.owner.val-ceSimReco.dsconf.seq.art --TFileName nts.ntuple.ceSimReco.root + +# Create a dataset with trkhitcalib branch +mu2e -c validation/ceSimReco.fcl -n 100 +mu2e -c validation/ceTrig.fcl -s mcs.owner.val-ceSimRecoVal.dsconf.seq.art --TFileName nts.ntuple.ceTrig.roo +mu2e -c fcl/from_mcs-ceSimRecoVal.fcl -s mcs.owner.val-ceTrig.dsconf.seq.art --TFileName nts.ntuple.ceSimRecoVal.root + +# Test some options +mu2e -c fcl/from_mcs-mockdata_separateTrkBranches.fcl -S {mock} --TFileName nts.ntuple.mockSepTrkBranches.root -n 100 +mu2e -c fcl/from_mcs-mockdata_selectorExample.fcl -S {mock} --TFileName nts.ntuple.mockSelector.root -n 100 +mu2e -c fcl/from_mcs-primary_addVDSteps.fcl -S {primary} --TFileName nts.ntuple.primaryVDSteps.root -n 100 + +# Test digi datasets +mu2e -c fcl/from_dig-mockdata.fcl -S {digi} --TFileName nts.ntuple.dig.root -n 100 + +# Create validation histogras +mu2e -c fcl/from_mcs-mockdata.fcl -S {mock} --TFileName nts.ntuple.after.root -n 100 +root -l -b -q validation/create_val_file_rooutil.C\(\"nts.ntuple.after.root\",\"val.ntuple.after.root\"\) + +# CRV KPP (real data) +mu2e -c fcl/from_rec-crv-kpp.fcl -S {crv_kpp} --TFileName nts.ntuple.crv-kpp.root -n 100 +mu2e -c fcl/from_rec-crv-kpp_withCrvDigis.fcl -S {crv_kpp} --TFileName nts.ntuple.crv-kpp_withCrvDigis.root -n 100 + +# DeCalib tests +mu2e -c fcl/from_mcs-DeCalib.fcl -S {mixed} --TFileName nts.ntuple.deCalib.root -n 100 \ No newline at end of file diff --git a/validation/datasets_MDC2020.txt b/validation/datasets_MDC2020.txt new file mode 100644 index 0000000..0965d95 --- /dev/null +++ b/validation/datasets_MDC2020.txt @@ -0,0 +1,7 @@ +# Test Datasets for Validating EventNtuple with MDC2020 +{mock} mcs.mu2e.ensembleMDS2cMix1BBTriggered.MDC2020ba_best_v1_3.art +{primary} mcs.mu2e.CeEndpointOnSpillTriggered.MDC2020aw_best_v1_3.art +{mixed} mcs.mu2e.CeEndpointMix1BBTriggered.MDC2020aw_best_v1_3.art +{extracted} mcs.mu2e.CosmicCRYExtractedTriggered.MDC2020aw.art +{digi} dig.mu2e.DIOtail95OnSpillTriggered.MDC2020au_perfect_v1_3.art +{crv_kpp} N/A \ No newline at end of file diff --git a/validation/datasets_MDC2025.txt b/validation/datasets_MDC2025.txt new file mode 100644 index 0000000..4858ad5 --- /dev/null +++ b/validation/datasets_MDC2025.txt @@ -0,0 +1,7 @@ +# Test Datasets for Validating EventNtuple with MDC2025 +{mock} mcs.mu2e.ensembleMDS3aOnSpillTriggered.MDC2025af_best_v1_3.art +{primary} mcs.mu2e.CeEndpointOnSpillTriggered.MDC2025ae_best_v1_3.art +{mixed} mcs.mu2e.CeMLeadingLogMix1BBTriggered.MDC2025af_best_v1_1.art +{extracted} mcs.mu2e.CosmicCRYExtractedTriggered.MDC2025ae_best_v1_3.art +{digi} dig.mu2e.FlatGammaMix1BBTriggered.MDC2025af_best_v1_1.art +{crv_kpp} rec.mu2e.cosmics_crv.crvreco-004-000.art \ No newline at end of file diff --git a/validation/datasets_Run1B.txt b/validation/datasets_Run1B.txt new file mode 100644 index 0000000..9e8c3ab --- /dev/null +++ b/validation/datasets_Run1B.txt @@ -0,0 +1,7 @@ +# Test Datasets for Validating EventNtuple with MDC2025 +{mock} N/A +{primary} mcs.mu2e.CeEndpointOnSpillTriggerable-KL.Run1Baf_best_v1_4-000.art +{mixed} mcs.mu2e.CeEndpointMix1BB-KL.Run1Bah_best_v1_4-001.art +{extracted} N/A +{digi} N/A +{crv_kpp} N/A \ No newline at end of file diff --git a/validation/test_fcls.py b/validation/test_fcls.py new file mode 100644 index 0000000..7c0f49d --- /dev/null +++ b/validation/test_fcls.py @@ -0,0 +1,188 @@ +#!/usr/bin/env python3 +""" +Test script to run EventNtuple fcl files on datasets. +Similar to test_fcls.sh but in Python for better control and error handling. +""" + +import os +import subprocess +import sys +import argparse +from pathlib import Path + +from enum import Enum + +# Define the enum +class Result(Enum): + FAILED = 0 + PASSED = 1 + SKIPPED = 2 + +def run(cmd, datasets_dict): + """ + Run a test + + Args: + test (str): Command to run + + Returns: + bool: True if successful, False otherwise + """ + """ if not os.path.exists(fcl_file): + print(f"Error: FCL file not found: {fcl_file}") + return False + + filelist_path = Path("../filelists/") / f"{input_dataset}.list" + if not os.path.exists(filelist_path): + # Get the filelist using metacat + cmd = [f"muse setup ops && metacat query files from mu2e:{input_dataset} | mdh print-url -l tape - > {filelist_path}"] + print(f"Creating filelist for dataset: {input_dataset}") + try: + subprocess.run(cmd, shell=True, check=True) + except subprocess.CalledProcessError as e: + print(f"Error: Failed to create filelist for dataset: {input_dataset}") + return False + + # Build mu2e command + cmd = ["mu2e", "-c", fcl_file] + + # Add input dataset + cmd.extend(["-S", filelist_path.as_posix()]) + + # Add output file + cmd.extend(["-o", output_file]) + + # Add max events if specified + if max_events: + cmd.extend(["-n", str(max_events)]) """ + + # Check for a filelists/ directory + filelist_dir = Path("../filelists/") + if not os.path.exists(filelist_dir): + print(f"Target directory does not exist: {filelist_dir}") + reply = input("Would you like to create this new directory? (y/n): ").strip().lower() + + if reply in ('y', 'yes'): + try: + # parents=True creates intermediate folders if missing (like mkdir -p) + filelist_dir.mkdir(parents=True, exist_ok=True) + print(f"Successfully created directory: {filelist_dir}") + except PermissionError: + print(f"Permission denied: Cannot create directory at {filelist_dir}") + except Exception as e: + print(f"Failed to create directory. Error: {e}") + else: + print("Directory creation canceled by user.") + return Result.FAILED + + # Search for dataset name and turn into filelist + input_dataset = cmd.split('-S ') + if len(input_dataset)>1: + input_dataset = input_dataset[1].split()[0] + if input_dataset in datasets_dict: + old_input_dataset = input_dataset + input_dataset = datasets_dict[input_dataset] + if (input_dataset == "N/A"): + print(f"Warning: Dataset name for '{old_input_dataset}' is marked as N/A in datasets file. Skipping test...") + return Result.SKIPPED # returning SKIPPED to avoid counting as a failure, but skipping the test since dataset is not available + cmd = cmd.replace(old_input_dataset, input_dataset) + else: + print(f"Warning: Dataset name '{input_dataset}' not found in datasets file. Using as-is.") + + # Check for filelist + filelist_path = Path("../filelists/") / f"{input_dataset}.list" + if not os.path.exists(filelist_path): + # Get the filelist using metacat + subcmd = [f"muse setup ops && metacat query files from mu2e:{input_dataset} | mdh print-url -l tape - > {filelist_path}"] + print(f"Creating filelist for dataset: {input_dataset}") + try: + subprocess.run(subcmd, shell=True, check=True) + except subprocess.CalledProcessError as e: + print(f"Error: Failed to create filelist for dataset: {input_dataset}") + return FAILED + cmd = cmd.replace(input_dataset, str(filelist_path)) + + print(f"Running: {cmd}") + + try: + result = subprocess.run(cmd.split(), check=True, capture_output=True, text=True) + print(f"✓ Successfully processed: {cmd}") + #print(f" Output: {output_file}") + return Result.PASSED + except subprocess.CalledProcessError as e: + print(f"✗ Error processing {cmd}") + print(f" Stdout: {e.stdout}") + print(f" Stderr: {e.stderr}") + return Result.FAILED + + except FileNotFoundError as e: + print(f"{e}") + return Result.FAILED + + +def main(): + parser = argparse.ArgumentParser( + description="Run EventNtuple fcl files on datasets" + ) + parser.add_argument( + "--tests", + help="Path to file containing list of tests to run (one command per line)", + required=True + ) + parser.add_argument( + "--datasets", + help="Path to file containing list of dataset names", + required=True + ) + + args = parser.parse_args() + + # Check if batch processing requested + datasets = { } + if not os.path.exists(args.datasets): + print(f"Error: Datasets file not found: {args.datasets}") + sys.exit(1) + with open(args.datasets, 'r') as f: + for line in f: + line = line.strip() + if line and not line.startswith('#'): + parts = line.split() + if len(parts) == 2: + datasets[parts[0]] = parts[1] + else: + print(f"Warning: Invalid line in datasets file (skipping): {line}") + + if not os.path.exists(args.tests): + print(f"Error: Tests file not found: {args.tests}") + sys.exit(1) + + results = [] + with open(args.tests, 'r') as f: + tests = [line.strip() for line in f if line.strip() and not line.strip().startswith('#')] + + print(f"Processing {len(tests)} tests...") + + for i, (test) in enumerate(tests, 1): + print(f"\n[{i}/{len(tests)}] Processing: {test}") + result = run(test, datasets) + results.append((test, result)) + + # Print summary + print("\n" + "="*60) + print("TEST PROCESSING SUMMARY") + print("="*60) + passed = sum(1 for _, result in results if result == Result.PASSED) + failed = sum(1 for _, result in results if result == Result.FAILED) + skipped = sum(1 for _, result in results if result == Result.SKIPPED) + print(f"Total: {len(results)}, Passed: {passed}, Failed: {failed}, Skipped: {skipped}") + + if passed < len(results): + print("\nFailed datasets:") + for command, result in results: + if result == Result.FAILED: + print(f" - {command}") + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/validation/test_fcls.sh b/validation/test_fcls.sh deleted file mode 100644 index 3fb89d2..0000000 --- a/validation/test_fcls.sh +++ /dev/null @@ -1,216 +0,0 @@ -# -# test_fcls.sh - runs fcl files to make sure that they complete successfully -# Note: requires relevant filelists in a directory above this one -# -if [ $# -ne 1 ]; then - echo "Usage: . ./validation/test_fcls.sh [MDC2020 / MDC2025 / Run1B]" - return -fi -vMDC=$1 - -log_file="test_fcls.log" -rm ${log_file} - -mock_dataset="" -primary_dataset="" -mixed_dataset="" -extracted_dataset="" -digi_dataset="" -crv_kpp_dataset="temp_crv_kpp" - -if [[ "$vMDC" == "MDC2020" ]]; then - echo "Testing MDC2020 datasets" - mock_dataset="mcs.mu2e.ensembleMDS2cMix1BBTriggered.MDC2020ba_best_v1_3.art" - primary_dataset="mcs.mu2e.CeEndpointOnSpillTriggered.MDC2020aw_best_v1_3.art" - mixed_dataset="mcs.mu2e.CeEndpointMix1BBTriggered.MDC2020aw_best_v1_3.art" - extracted_dataset="mcs.mu2e.CosmicCRYExtractedTriggered.MDC2020aw.art" - digi_dataset="dig.mu2e.DIOtail95OnSpillTriggered.MDC2020au_perfect_v1_3.art" -elif [[ "$vMDC" == "MDC2025" ]]; then - echo "Testing MDC2025 datasets" - mock_dataset="mcs.mu2e.ensembleMDS3aOnSpillTriggered.MDC2025af_best_v1_3.art" - primary_dataset="mcs.mu2e.CeEndpointOnSpillTriggered.MDC2025ae_best_v1_3.art" - mixed_dataset="mcs.mu2e.CeMLeadingLogMix1BBTriggered.MDC2025af_best_v1_1.art" - extracted_dataset="mcs.mu2e.CosmicCRYExtractedTriggered.MDC2025ae_best_v1_3.art" - digi_dataset="dig.mu2e.FlatGammaMix1BBTriggered.MDC2025af_best_v1_1.art" -elif [[ "$vMDC" == "Run1B" ]]; then - echo "Testing Run1B datasets" - echo "No mock datasets for Run1B - some tests will fail..." - mock_dataset="" # "mcs.mu2e.ensembleMDS3aOnSpillTriggered.MDC2025af_best_v1_3.art" - primary_dataset="mcs.mu2e.CeEndpointOnSpillTriggerable-KL.Run1Baf_best_v1_4-000.art" - mixed_dataset="mcs.mu2e.CeEndpointMix1BB-KL.Run1Bah_best_v1_4-001.art" - echo "No extracted datasets for Run1B - some tests will fail..." - extracted_dataset="" # "mcs.mu2e.CosmicCRYExtractedTriggered.MDC2025ae_best_v1_3.art" - echo "No reco+ntuple fcl for Run1B - some tests will fail..." - digi_dataset="" # "dig.mu2e.FlatGammaMix1BBTriggered.MDC2025af_best_v1_1.art" -else - echo "Unsupported option $vMDC" - return -fi - -all_datasets=( $mock_dataset $primary_dataset $mixed_dataset $extracted_dataset $digi_dataset $crv_kpp_dataset ) - -if [ ! -d ../filelists ]; then - echo "Making directory ../filelists/" - mkdir ../filelists/ -fi - -for dataset in "${all_datasets[@]}" -do - if [ ! -f ../filelists/$dataset.list ]; then - echo "File list for $dataset doesn't exist. Creating..." - setup mu2efiletools - mu2eDatasetFileList $dataset > ../filelists/$dataset.list - fi -done - - -echo -n "from_mcs-mockdata.fcl... " -echo "mu2e -c fcl/from_mcs-mockdata.fcl -S ../filelists/$mock_dataset.list --TFileName nts.ntuple.mock.root -n 100" > ${log_file} 2>&1 -mu2e -c fcl/from_mcs-mockdata.fcl -S ../filelists/$mock_dataset.list --TFileName nts.ntuple.mock.root -n 100 >> ${log_file} 2>&1 -if [ $? == 0 ]; then - echo "OK" | tee -a ${log_file} -else - echo "FAIL" | tee -a ${log_file} -fi - -echo -n "from_mcs-mockdata_noMC.fcl... " -echo "mu2e -c fcl/from_mcs-mockdata_noMC.fcl -S ../filelists/$mock_dataset.list --TFileName nts.ntuple.mockNoMC.root -n 100" >> ${log_file} 2>&1 -mu2e -c fcl/from_mcs-mockdata_noMC.fcl -S ../filelists/$mock_dataset.list --TFileName nts.ntuple.mockNoMC.root -n 100 >> ${log_file} 2>&1 -if [ $? == 0 ]; then - echo "OK" | tee -a ${log_file} -else - echo "FAIL" | tee -a ${log_file} -fi - -echo -n "from_mcs-primary.fcl... " -echo "mu2e -c fcl/from_mcs-primary.fcl -S ../filelists/$primary_dataset.list --TFileName nts.ntuple.primary.root -n 100" >> ${log_file} 2>&1 -mu2e -c fcl/from_mcs-primary.fcl -S ../filelists/$primary_dataset.list --TFileName nts.ntuple.primary.root -n 100 >> ${log_file} 2>&1 -if [ $? == 0 ]; then - echo "OK" | tee -a ${log_file} -else - echo "FAIL" | tee -a ${log_file} -fi - -echo -n "from_mcs-mixed.fcl... " -echo "mu2e -c fcl/from_mcs-mixed.fcl -S ../filelists/$mixed_dataset.list --TFileName nts.ntuple.mixed.root -n 100" >> ${log_file} 2>&1 -mu2e -c fcl/from_mcs-mixed.fcl -S ../filelists/$mixed_dataset.list --TFileName nts.ntuple.mixed.root -n 100 >> ${log_file} 2>&1 -if [ $? == 0 ]; then - echo "OK" | tee -a ${log_file} -else - echo "FAIL" | tee -a ${log_file} -fi - -echo -n "from_mcs-extracted.fcl... " -echo "mu2e -c fcl/from_mcs-extracted.fcl -S ../filelists/$extracted_dataset.list --TFileName nts.ntuple.extracted.root -n 100" >> ${log_file} 2>&1 -mu2e -c fcl/from_mcs-extracted.fcl -S ../filelists/$extracted_dataset.list --TFileName nts.ntuple.extracted.root -n 100 >> ${log_file} 2>&1 -if [ $? == 0 ]; then - echo "OK" | tee -a ${log_file} -else - echo "FAIL" | tee -a ${log_file} -fi - -echo -n "from_mcs-ceSimReco.fcl... " -echo "mu2e -c Production/Validation/ceSimReco.fcl -n 10" >> ${log_file} 2>&1 -mu2e -c Production/Validation/ceSimReco.fcl -n 10 >> ${log_file} 2>&1 -echo "mu2e -c fcl/from_mcs-ceSimReco.fcl -s mcs.owner.val-ceSimReco.dsconf.seq.art --TFileName nts.ntuple.ceSimReco.root" >> ${log_file} 2>&1 -mu2e -c fcl/from_mcs-ceSimReco.fcl -s mcs.owner.val-ceSimReco.dsconf.seq.art --TFileName nts.ntuple.ceSimReco.root >> ${log_file} 2>&1 -if [ $? == 0 ]; then - echo "OK" | tee -a ${log_file} -else - echo "FAIL" | tee -a ${log_file} -fi - -echo -n "from_mcs-ceSimRecoVal.fcl... " -echo "mu2e -c validation/ceSimReco.fcl -n 100" >> ${log_file} 2>&1 -mu2e -c validation/ceSimReco.fcl -n 100 >> ${log_file} 2>&1 -echo "mu2e -c validation/ceTrig.fcl -s mcs.owner.val-ceSimRecoVal.dsconf.seq.art --TFileName nts.ntuple.ceTrig.root" >> ${log_file} 2>&1 -mu2e -c validation/ceTrig.fcl -s mcs.owner.val-ceSimRecoVal.dsconf.seq.art --TFileName nts.ntuple.ceSimRecoVal.root >> ${log_file} 2>&1 -echo "mu2e -c fcl/from_mcs-ceSimRecoVal.fcl -s mcs.owner.val-ceTrig.dsconf.seq.art --TFileName nts.ntuple.ceSimRecoVal.root" >> ${log_file} 2>&1 -mu2e -c fcl/from_mcs-ceSimRecoVal.fcl -s mcs.owner.val-ceTrig.dsconf.seq.art --TFileName nts.ntuple.ceTrig.root >> ${log_file} 2>&1 -if [ $? == 0 ]; then - echo "OK" | tee -a ${log_file} -else - echo "FAIL" | tee -a ${log_file} -fi - -echo -n "from_mcs-mockdata_separateTrkBranches.fcl... " -echo "mu2e -c fcl/from_mcs-mockdata_separateTrkBranches.fcl -S ../filelists/${mock_dataset}.list --TFileName nts.ntuple.mockSepTrkBranches.root -n 100" >> ${log_file} 2>&1 -mu2e -c fcl/from_mcs-mockdata_separateTrkBranches.fcl -S ../filelists/${mock_dataset}.list --TFileName nts.ntuple.mockSepTrkBranches.root -n 100 >> ${log_file} 2>&1 -if [ $? == 0 ]; then - echo "OK" | tee -a ${log_file} -else - echo "FAIL" | tee -a ${log_file} -fi - -echo -n "from_mcs-mockdata_selectorExample.fcl... " -echo"mu2e -c fcl/from_mcs-mockdata_selectorExample.fcl -S ../filelists/${mock_dataset}.list --TFileName nts.ntuple.mockSelector.root -n 100" >> ${log_file} 2>&1 -mu2e -c fcl/from_mcs-mockdata_selectorExample.fcl -S ../filelists/${mock_dataset}.list --TFileName nts.ntuple.mockSelector.root -n 100 >> ${log_file} 2>&1 -if [ $? == 0 ]; then - echo "OK" | tee -a ${log_file} -else - echo "FAIL" | tee -a ${log_file} -fi - -echo -n "from_mcs-primary_addVDSteps.fcl... " -echo "mu2e -c fcl/from_mcs-primary_addVDSteps.fcl -S ../filelists/$primary_dataset.list --TFileName nts.ntuple.primaryVDSteps.root -n 100" >> ${log_file} 2>&1 -mu2e -c fcl/from_mcs-primary_addVDSteps.fcl -S ../filelists/$primary_dataset.list --TFileName nts.ntuple.primaryVDSteps.root -n 100 >> ${log_file} 2>&1 -if [ $? == 0 ]; then - echo "OK" | tee -a ${log_file} -else - echo "FAIL" | tee -a ${log_file} -fi - - -echo -n "from_dig-mockdata.fcl... " -echo "mu2e -c fcl/from_dig-mockdata.fcl -S ../filelists/${digi_dataset}.list --TFileName nts.ntuple.dig.root -n 100" >> ${log_file} 2>&1 -mu2e -c fcl/from_dig-mockdata.fcl -S ../filelists/${digi_dataset}.list --TFileName nts.ntuple.dig.root -n 100 >> ${log_file} 2>&1 -if [ $? == 0 ]; then - echo "OK" | tee -a ${log_file} -else - echo "FAIL" | tee -a ${log_file} -fi - -echo -n "creating file for validation script... " -echo "mu2e -c fcl/from_mcs-mockdata.fcl -S ../filelists/${mock_dataset}.list --TFileName nts.ntuple.after.root -n 100" >> ${log_file} 2>&1 -mu2e -c fcl/from_mcs-mockdata.fcl -S ../filelists/${mock_dataset}.list --TFileName nts.ntuple.after.root -n 100 >> ${log_file} 2>&1 -if [ $? == 0 ]; then - echo "OK" | tee -a ${log_file} -else - echo "FAIL" | tee -a ${log_file} -fi - -echo -n "creating validation file... " -echo "root -l -b -q validation/create_val_file_rooutil.C\(\"nts.ntuple.after.root\",\"val.ntuple.after.root\"\)" >> ${log_file} 2>&1 -root -l -b -q validation/create_val_file_rooutil.C\(\"nts.ntuple.after.root\",\"val.ntuple.after.root\"\) >> ${log_file} 2>&1 -if [ $? == 0 ]; then - echo "OK" | tee -a ${log_file} -else - echo "FAIL" | tee -a ${log_file} -fi - -echo -n "from_rec-crv-kpp.fcl... " -echo "mu2e -c fcl/from_rec-crv-kpp.fcl -S ../filelists/${crv_kpp_dataset}.list --TFileName nts.ntuple.crv-kpp.root -n 100" >> ${log_file} 2>&1 -mu2e -c fcl/from_rec-crv-kpp.fcl -S ../filelists/${crv_kpp_dataset}.list --TFileName nts.ntuple.crv-kpp.root -n 100 >> ${log_file} 2>&1 -if [ $? == 0 ]; then - echo "OK" | tee -a ${log_file} -else - echo "FAIL" | tee -a ${log_file} -fi - -echo -n "from_rec-crv-kpp_withCrvDigis.fcl... " -echo "mu2e -c fcl/from_rec-crv-kpp_withCrvDigis.fcl -S ../filelists/${crv_kpp_dataset}.list --TFileName nts.ntuple.crv-kpp_withCrvDigis.root -n 100" >> ${log_file} 2>&1 -mu2e -c fcl/from_rec-crv-kpp_withCrvDigis.fcl -S ../filelists/${crv_kpp_dataset}.list --TFileName nts.ntuple.crv-kpp_withCrvDigis.root -n 100 >> ${log_file} 2>&1 -if [ $? == 0 ]; then - echo "OK" | tee -a ${log_file} -else - echo "FAIL" | tee -a ${log_file} -fi - -echo -n "from_mcs-DeCalib.fcl... " -echo "mu2e -c fcl/from_mcs-DeCalib.fcl -S ../filelists/${mixed_dataset}.list --TFileName nts.ntuple.deCalib.root -n 100" >> ${log_file} 2>&1 -mu2e -c fcl/from_mcs-DeCalib.fcl -S ../filelists/${mixed_dataset}.list --TFileName nts.ntuple.deCalib.root -n 100 >> ${log_file} 2>&1 -if [ $? == 0 ]; then - echo "OK" | tee -a ${log_file} -else - echo "FAIL" | tee -a ${log_file} -fi From 35676bd965158533cc6911a46c5ab887e6a41d92 Mon Sep 17 00:00:00 2001 From: Andrew Edmonds Date: Thu, 4 Jun 2026 14:53:50 -0500 Subject: [PATCH 5/9] Update --- validation/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validation/README.md b/validation/README.md index a1f1b97..244c93c 100644 --- a/validation/README.md +++ b/validation/README.md @@ -16,6 +16,8 @@ This script will run all the supported fcl files over relevant datasets. The out The reason for separating the commands from the datasets is so that we can easily change to a different set of datasets with new simulation campaigns, as well as update datasets in currently-supported simulation campaigns. +You can comment out commands in the ```commands.txt``` with a ```#``` to focus on failing tests + ### Creating a Validation File Before making any changes, create an EventNtuple file and run the validation script. This creates a new ROOT file with histograms created from the EventNtuple ntuple: From 544a606c66f1f2f7593f189c74482ea49c666667 Mon Sep 17 00:00:00 2001 From: Andrew Edmonds Date: Thu, 4 Jun 2026 14:54:51 -0500 Subject: [PATCH 6/9] Fix typo --- validation/commands.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validation/commands.txt b/validation/commands.txt index 9f5e34d..8248b4a 100644 --- a/validation/commands.txt +++ b/validation/commands.txt @@ -13,7 +13,7 @@ mu2e -c fcl/from_mcs-ceSimReco.fcl -s mcs.owner.val-ceSimReco.dsconf.seq.art --T # Create a dataset with trkhitcalib branch mu2e -c validation/ceSimReco.fcl -n 100 -mu2e -c validation/ceTrig.fcl -s mcs.owner.val-ceSimRecoVal.dsconf.seq.art --TFileName nts.ntuple.ceTrig.roo +mu2e -c validation/ceTrig.fcl -s mcs.owner.val-ceSimRecoVal.dsconf.seq.art --TFileName nts.ntuple.ceTrig.root mu2e -c fcl/from_mcs-ceSimRecoVal.fcl -s mcs.owner.val-ceTrig.dsconf.seq.art --TFileName nts.ntuple.ceSimRecoVal.root # Test some options From ee770f7cd2cc33e43fc45fc476f1c46aad5b32de Mon Sep 17 00:00:00 2001 From: Andrew Edmonds Date: Thu, 4 Jun 2026 15:08:38 -0500 Subject: [PATCH 7/9] Improve validation script by skipping tests where dataset was not defined --- validation/test_fcls.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/validation/test_fcls.py b/validation/test_fcls.py index 7c0f49d..5c63a04 100644 --- a/validation/test_fcls.py +++ b/validation/test_fcls.py @@ -87,7 +87,11 @@ def run(cmd, datasets_dict): return Result.SKIPPED # returning SKIPPED to avoid counting as a failure, but skipping the test since dataset is not available cmd = cmd.replace(old_input_dataset, input_dataset) else: - print(f"Warning: Dataset name '{input_dataset}' not found in datasets file. Using as-is.") + if input_dataset.startswith("{"): + print(f"Warning: Dataset name '{input_dataset}' looks like it should be in the datasets file but it can't be found. Skipping test...") + return Result.SKIPPED + else: + print(f"Warning: Dataset name '{input_dataset}' not found in datasets file. Using as-is.") # Check for filelist filelist_path = Path("../filelists/") / f"{input_dataset}.list" From 613335f3e2015f522e240f5dcea8024d48ea3735 Mon Sep 17 00:00:00 2001 From: Andrew Edmonds Date: Thu, 4 Jun 2026 15:40:28 -0500 Subject: [PATCH 8/9] Updates to fhicl configuration everywhere --- fcl/TrkAnaLineFromDigis.fcl | 14 +- fcl/from_dig-OnSpill.fcl | 29 +- fcl/from_dig-calo.fcl | 4 +- fcl/from_mcs-Run1B.fcl | 6 +- fcl/from_mcs-ceSimReco.fcl | 4 +- fcl/from_mcs-ceSimRecoVal.fcl | 2 +- fcl/from_mcs-extracted.fcl | 2 +- fcl/from_mcs-mockdata_separateTrkBranches.fcl | 2 +- fcl/from_mcs-primary_addVDSteps.fcl | 2 +- fcl/from_mcs-reflection.fcl | 35 +- fcl/from_rec-crv-kpp.fcl | 5 +- fcl/prolog.fcl | 79 +-- src/EventNtupleMaker_module.cc | 553 +++++++++--------- 13 files changed, 382 insertions(+), 355 deletions(-) diff --git a/fcl/TrkAnaLineFromDigis.fcl b/fcl/TrkAnaLineFromDigis.fcl index 5bcc0ec..cabea8d 100644 --- a/fcl/TrkAnaLineFromDigis.fcl +++ b/fcl/TrkAnaLineFromDigis.fcl @@ -39,13 +39,6 @@ physics : FitType : KinematicLine diagLevel : 2 FillTriggerInfo : false - trk.branches : [ - { input: "KKLine" - branch : "kl" - options : { genealogyDepth : 5 } - } - ] - trk.mc.extraMCStepTags : [ "compressDigiMCs:protonabsorber", "compressDigiMCs:stoppingtarget" ] } @table::TrkAnaReco.analyzers @@ -78,6 +71,13 @@ physics.producers.KKLine.ModuleSettings.SaveAllFits : true physics.producers.KKLine.ExtensionSettings.BFieldCorrection : false physics.end_paths : [ EndPath ] +physics.analyzers.TrkAnaLine.trk.fits : [ + { input: "KKLine" + branchname : "kl" + options : { genealogyDepth : 5 } + } +] +physics.analyzers.TrkAnaLine.mcsteps.extraMCStepTags : [ "compressDigiMCs:protonabsorber", "compressDigiMCs:stoppingtarget" ] services.TimeTracker.printSummary: true services.TFileService.fileName: "nts.owner.TALineDigis.version.sequence.root" #include "Offline/CRVResponse/fcl/epilog_extracted.fcl" diff --git a/fcl/from_dig-OnSpill.fcl b/fcl/from_dig-OnSpill.fcl index 793c08b..f8b54a1 100644 --- a/fcl/from_dig-OnSpill.fcl +++ b/fcl/from_dig-OnSpill.fcl @@ -16,44 +16,24 @@ physics : { # apr EventNtupleTTMCApr : { @table::EventNtupleMakerTTMC - trk.branches : [ { - @table::TTMCBranch - input : "MergeTTApr" - } ] - trk.mc.kalSeedMCAssns : "TTAprKSFMC" RecoCountTag : "TTAprKSFMC" SelectEvents : [ "Digitize:apr_highP*" ] } # tpr EventNtupleTTMCTpr : { @table::EventNtupleMakerTTMC - trk.branches : [ { - @table::TTMCBranch - input : "MergeTTTpr" - } ] - trk.mc.kalSeedMCAssns : "TTTprDeKSFMC" RecoCountTag : "TTTprDeKSFMC" SelectEvents : [ "Digitize:tprDe_highP*" ] } # cpr EventNtupleTTMCCpr : { @table::EventNtupleMakerTTMC - trk.branches : [ { - @table::TTMCBranch - input : "MergeTTCpr" - } ] - trk.mc.kalSeedMCAssns : "TTCprDeKSFMC" RecoCountTag : "TTCprDeKSFMC" SelectEvents : [ "Digitize:cprDe_highP*" ] } # mpr EventNtupleTTMCMpr : { @table::EventNtupleMakerTTMC - trk.branches : [ { - @table::TTMCBranch - input : "MergeTTMpr" - } ] - trk.mc.kalSeedMCAssns : "TTMprDeKSFMC" RecoCountTag : "TTMprDeKSFMC" SelectEvents : [ "Digitize:mprDe_highP*" ] } @@ -64,6 +44,15 @@ physics : { } #physics.analyzers.TAapr.InfoMCStructHelper.SimParticleCollectionTag: "compressDetStepMCs" +physics.analyzers.EventNtupleTTMCApr.trk.fits : [ { @table::TTMCBranch input : "MergeTTApr" } ] +physics.analyzers.EventNtupleTTMCApr.trk.mc.kalSeedMCAssns : "TTAprKSFMC" +physics.analyzers.EventNtupleTTMCTpr.trk.fits : [ { @table::TTMCBranch input : "MergeTTTpr" } ] +physics.analyzers.EventNtupleTTMCTpr.trk.mc.kalSeedMCAssns : "TTTprDeKSFMC" +physics.analyzers.EventNtupleTTMCCpr.trk.fits : [ { @table::TTMCBranch input : "MergeTTCpr" } ] +physics.analyzers.EventNtupleTTMCCpr.trk.mc.kalSeedMCAssns : "TTCprDeKSFMC" +physics.analyzers.EventNtupleTTMCMpr.trk.fits : [ { @table::TTMCBranch input : "MergeTTMpr" } ] +physics.analyzers.EventNtupleTTMCMpr.trk.mc.kalSeedMCAssns : "TTMprDeKSFMC" + end_paths : [ EndPath ] physics.trigger_paths : [ "TrigPath" ] services.TFileService.fileName: "nts.owner.trkana-triggerMC.version.sequencer.root" diff --git a/fcl/from_dig-calo.fcl b/fcl/from_dig-calo.fcl index 683815d..d3318d7 100644 --- a/fcl/from_dig-calo.fcl +++ b/fcl/from_dig-calo.fcl @@ -30,10 +30,8 @@ physics.analyzers.EventNtuple.PBTTag : "" physics.analyzers.EventNtuple.mc.PBTMCTag : "" physics.analyzers.EventNtuple.mc.simParticlesTag : "CaloShowerStepMaker" #Turn off tracker and other branches -physics.analyzers.EventNtuple.trk.branches : [ ] -physics.analyzers.EventNtuple.trk.fillTrkQual : false +physics.analyzers.EventNtuple.trk.fill : false physics.analyzers.EventNtuple.FillTriggerInfo : false -physics.analyzers.EventNtuple.trk.fillHits : false physics.analyzers.EventNtuple.crv.fillCoincs : false #Toggle calo branches diff --git a/fcl/from_mcs-Run1B.fcl b/fcl/from_mcs-Run1B.fcl index 121d3ae..3f0aad3 100644 --- a/fcl/from_mcs-Run1B.fcl +++ b/fcl/from_mcs-Run1B.fcl @@ -1,9 +1,9 @@ # we start from mcs-extracted since Run-1B wants the straight line track fit #include "EventNtuple/fcl/from_mcs-extracted.fcl" -physics.analyzers.EventNtuple.trk.mc.stepPointMCTags : [ "compressRecoMCs:virtualdetector" ] # we add the mcsteps_virtualdetector branch -physics.analyzers.EventNtuple.trk.fillTimeClusters : true -physics.analyzers.EventNtuple.trk.timeClustersTag : "SimpleTimeCluster" # Store time clusters for straight line track finding +physics.analyzers.EventNtuple.mcsteps.stepPointMCTags : [ "compressRecoMCs:virtualdetector" ] # we add the mcsteps_virtualdetector branch +physics.analyzers.EventNtuple.timeclusters.fill : true +physics.analyzers.EventNtuple.timeclusters.tag : "SimpleTimeCluster" # Store time clusters for straight line track finding services.GeometryService.inputFile : "Offline/Mu2eG4/geom/geom_common.txt" # we can use the standard geometry physics.EventNtupleEndPath : [ @sequence::EventNtuple.EndPath ] # add back genCountLogger diff --git a/fcl/from_mcs-ceSimReco.fcl b/fcl/from_mcs-ceSimReco.fcl index 02bc670..c32c755 100644 --- a/fcl/from_mcs-ceSimReco.fcl +++ b/fcl/from_mcs-ceSimReco.fcl @@ -1,7 +1,7 @@ #include "EventNtuple/fcl/from_mcs-mockdata.fcl" -physics.analyzers.EventNtuple.branches : [ @local::De ] -physics.analyzers.EventNtuple.branches[0].branch : "trk" +physics.analyzers.EventNtuple.trk.fits : [ @local::De ] +physics.analyzers.EventNtuple.trk.fits[0].branchname : "trk" physics.analyzers.EventNtuple.FillTriggerInfo : false physics.EventNtuplePath : [ MergeKKDe, PBIWeight, TrkQualDe, TrkPIDDe ] physics.EventNtupleEndPath : [ EventNtuple, genCountLogger ] diff --git a/fcl/from_mcs-ceSimRecoVal.fcl b/fcl/from_mcs-ceSimRecoVal.fcl index 0d4f21d..3a00f06 100644 --- a/fcl/from_mcs-ceSimRecoVal.fcl +++ b/fcl/from_mcs-ceSimRecoVal.fcl @@ -2,4 +2,4 @@ physics.analyzers.EventNtuple.trk.fillHitCalibs : true physics.analyzers.EventNtuple.FillTriggerInfo : true -physics.analyzers.EventNtuple.TriggerProcessName : "ceTrig" +physics.analyzers.EventNtuple.TriggerProcessName : "ceTrig" \ No newline at end of file diff --git a/fcl/from_mcs-extracted.fcl b/fcl/from_mcs-extracted.fcl index 5ad9425..330f0ef 100644 --- a/fcl/from_mcs-extracted.fcl +++ b/fcl/from_mcs-extracted.fcl @@ -1,7 +1,7 @@ #include "EventNtuple/fcl/from_mcs-mockdata.fcl" physics.EventNtuplePath : [ @sequence::EventNtuple.PathExt ] # path for extracted position cosmics -physics.analyzers.EventNtuple.trk.branches : [ @local::Ext ] +physics.analyzers.EventNtuple.trk.fits : [ @local::Ext ] physics.analyzers.EventNtuple.FitType : KinematicLine physics.analyzers.EventNtuple.trk.fillTrkQual : false diff --git a/fcl/from_mcs-mockdata_separateTrkBranches.fcl b/fcl/from_mcs-mockdata_separateTrkBranches.fcl index 3e8b2e1..84b6d0d 100644 --- a/fcl/from_mcs-mockdata_separateTrkBranches.fcl +++ b/fcl/from_mcs-mockdata_separateTrkBranches.fcl @@ -1,5 +1,5 @@ #include "EventNtuple/fcl/from_mcs-mockdata.fcl" -physics.analyzers.EventNtuple.trk.branches : [ @local::DeM, @local::DeP, @local::UeM, @local::UeP, +physics.analyzers.EventNtuple.trk.fits : [ @local::DeM, @local::DeP, @local::UeM, @local::UeP, @local::DmuM, @local::DmuP, @local::UmuM, @local::UmuP ] physics.EventNtuplePath : [ @sequence::EventNtuple.PathSeparate ] diff --git a/fcl/from_mcs-primary_addVDSteps.fcl b/fcl/from_mcs-primary_addVDSteps.fcl index a5d54c1..2e1ffa2 100644 --- a/fcl/from_mcs-primary_addVDSteps.fcl +++ b/fcl/from_mcs-primary_addVDSteps.fcl @@ -1,3 +1,3 @@ #include "EventNtuple/fcl/from_mcs-primary.fcl" -physics.analyzers.EventNtuple.trk.mc.stepPointMCTags : [ "compressRecoMCs:virtualdetector" ] +physics.analyzers.EventNtuple.mcsteps.stepPointMCTags : [ "compressRecoMCs:virtualdetector" ] diff --git a/fcl/from_mcs-reflection.fcl b/fcl/from_mcs-reflection.fcl index 450f6f9..f116d4d 100644 --- a/fcl/from_mcs-reflection.fcl +++ b/fcl/from_mcs-reflection.fcl @@ -9,10 +9,10 @@ EN : { FitType : LoopHelix diagLevel : 2 FillTriggerInfo : false - trk.fillHits : false - trk.fillTrkQual : false - trk.fillTrkPID : false } +EN.trk.fillHits : false +EN.trk.fillTrkQual : false +EN.trk.fillTrkPID : false ENBranch : { branch : "trk" } @@ -60,25 +60,10 @@ physics : ENe : { @table::EN SelectEvents : [ "eTrig" ] - trk.branches : [ - { @table::ENBranch - trkQualTags : ["TrkQualReflecte"] - trkPIDTags : ["TrkPIDReflecte"] - input: "Reflecte" - } - ] } ENmu : { @table::EN SelectEvents : [ "muTrig" ] - trk.branches : [ - { @table::ENBranch - trkQualTags : ["TrkQualReflectmu"] - trkPIDTags : ["TrkPIDReflectmu"] - input: "Reflectmu" - } - - ] } printModule : { module_type : PrintModule @@ -96,5 +81,19 @@ physics : physics.trigger_paths : [ "eTrig", "muTrig"] physics.end_paths : [ "eEnd", "muEnd", "CLPrint" ] +physics.analyzers.ENe.trk.fits : [ + { @table::ENBranch + trkQualTags : ["TrkQualReflecte"] + trkPIDTags : ["TrkPIDReflecte"] + input: "Reflecte" + } +] +physics.analyzers.ENmu.trk.fits : [ + { @table::ENBranch + trkQualTags : ["TrkQualReflectmu"] + trkPIDTags : ["TrkPIDReflectmu"] + input: "Reflectmu" + } +] services.TimeTracker.printSummary: true services.TFileService.fileName: "nts.owner.ENreflection.version.sequence.root" diff --git a/fcl/from_rec-crv-kpp.fcl b/fcl/from_rec-crv-kpp.fcl index 9f2fbf6..a91c20c 100644 --- a/fcl/from_rec-crv-kpp.fcl +++ b/fcl/from_rec-crv-kpp.fcl @@ -1,8 +1,7 @@ #include "EventNtuple/fcl/from_mcs-mockdata_noMC.fcl" -physics.analyzers.EventNtuple.trk.branches : [ ] # no track branches -physics.analyzers.EventNtuple.calo.fillClusters : false # no calorimeter -physics.analyzers.EventNtuple.calo.fillHits : false # no calorimeter +physics.analyzers.EventNtuple.trk.fill : false +physics.analyzers.EventNtuple.calo.fill : false # no calorimeter physics.analyzers.EventNtuple.RecoCountTag : "" physics.analyzers.EventNtuple.PBTTag : "" physics.analyzers.EventNtuple.hasCRV : false #false keeps events that have no CRV coincidences diff --git a/fcl/prolog.fcl b/fcl/prolog.fcl index 9ab683f..e261866 100644 --- a/fcl/prolog.fcl +++ b/fcl/prolog.fcl @@ -188,67 +188,67 @@ MergeKKSeparatePath : [ MergeKKDeM, MergeKKUeM, MergeKKDmuM, MergeKKDeP, MergeKK DeM : { input : "MergeKKDeM" - branch : "dem" + branchname : "dem" trkQualTags : ["TrkQualDeM"] trkPIDTags : ["TrkPIDDeM"] } UeM : { input : "MergeKKUeM" - branch : "uem" + branchname : "uem" trkQualTags : [ ] trkPIDTags : [ ] } DmuM : { input : "MergeKKDmuM" - branch : "dmm" + branchname : "dmm" trkQualTags : [ ] trkPIDTags : [ ] } UmuM : { input : "MergeKKUmuM" - branch : "umm" + branchname : "umm" trkQualTags : [ ] trkPIDTags : [ ] } DeP : { input : "MergeKKDeP" - branch : "dep" + branchname : "dep" trkQualTags : [ ] trkPIDTags : [ ] } UeP : { input : "MergeKKUeP" - branch : "uep" + branchname : "uep" trkQualTags : [ ] trkPIDTags : [ ] } DmuP : { input : "MergeKKDmuP" - branch : "dmp" + branchname : "dmp" trkQualTags : [ ] trkPIDTags : [ ] } UmuP : { input : "MergeKKUmuP" - branch : "ump" + branchname : "ump" trkQualTags : [ ] trkPIDTags : [ ] } Ext : { input : "MergeKKLine" - branch : "trk" + branchname : "trk" trkQualTags : [ ] trkPIDTags : [ ] } Off : { input : "MergeKKOff" - branch : "trk" + branchname : "trk" trkQualTags : [ ] trkPIDTags : [ ] } All : { input : "MergeKKAll" - branch : "trk" + branchname : "trk" trkQualTags : ["TrkQualAll"] trkPIDTags : ["TrkPIDAll"] } DeCalib : { input : "MergeKKDeCalib" - branch : "trk" + branchname : "trk" trkQualTags : [ ] trkPIDTags : [ ] } De : { input : "MergeKKDe" - branch : "de" + branchname : "de" trkQualTags : ["TrkQualDe"] trkPIDTags : ["TrkPIDDe"] } @@ -263,6 +263,7 @@ EventNtupleMaker : { TriggerProcessName : "Digitize" TriggerPathSuffix : "DigitizePath" FitType : LoopHelix + diagLevel : 0 # -- Event-level MC (gates tracker MC, CRV MC, and evtinfomc branch) ------ mc : { fill : true @@ -278,18 +279,14 @@ EventNtupleMaker : { } # -- Tracker subsystem ----------------------------------------------------- trk : { + fill : true fillHits : true fillHitCalibs : false - fillHelices : false fillTrkQual : true fillTrkPID : false - fillTimeClusters : false - timeClustersTag : "MHDe" - branches : [ @local::All ] + fits : [ @local::All ] mc : { kalSeedMCAssns : "SelectReco" - surfaceStepsTag : "compressRecoMCs" - stepPointMCTags : [ ] } } # -- Calorimeter subsystem ------------------------------------------------- @@ -335,6 +332,19 @@ EventNtupleMaker : { assnsTag : "CrvCoincidenceClusterMCAssns" } } + # -- Helix seeds ----------------------------------------------------------- + helices : { + fill : false + } + # -- Time clusters --------------------------------------------------------- + timeclusters : { + fill : false + tag : "MHDe" + } + # -- MC step collections --------------------------------------------------- + mcsteps : { + surfaceStepsTag : "compressRecoMCs" + } } # instance for processing trigger (digitization) output from simulation EventNtupleMakerTTMC : { @@ -342,20 +352,21 @@ EventNtupleMakerTTMC : { diagLevel : 2 FillTriggerInfo : true FitType : LoopHelix - crv.fill : false - calo.mc.fillTrackMatch : false - mc.primaryParticleTag : "compressDigiMCs" - mc.mcTrajectoriesTag : "compressDigiMCs" - mc.simParticlesTag : "compressDigiMCs" - mc.infoMCStructHelper.SimParticleCollectionTag : "compressDigiMCs" - trk.mc.extraMCStepTags : [] } +EventNtupleMakerTTMC.crv.fill : false +EventNtupleMakerTTMC.calo.mc.fillTrackMatch : false +EventNtupleMakerTTMC.mc.primaryParticleTag : "compressDigiMCs" +EventNtupleMakerTTMC.mc.mcTrajectoriesTag : "compressDigiMCs" +EventNtupleMakerTTMC.mc.simParticlesTag : "compressDigiMCs" +EventNtupleMakerTTMC.mc.infoMCStructHelper.SimParticleCollectionTag : "compressDigiMCs" # TTMCBranch: per-branch config for trigger MC branches. # No options needed -- BranchOptConfig defaults are fillMC:true, fillHits:true, # genealogyDepth:-1, matchDepth:-1. TTMCBranch : { - branch : "trk" + branchname : "trk" + trkQualTags : [ ] + trkPIDTags : [ ] } EventNtuple : { @@ -387,14 +398,14 @@ ENDeCalib : { @table::EventNtupleMaker hasTracks : true FitType : LoopHelix - trk.branches : [ - { input: "MergeKKDeCalib" - branch : "trk" - trkQualTags : ["TrkQualDe"] - trkPIDTags : ["TrkPIDDe"] - } - ] SelectEvents : [ TriggerPath ] } +ENDeCalib.trk.fits : [ + { input: "MergeKKDeCalib" + branchname : "trk" + trkQualTags : ["TrkQualDe"] + trkPIDTags : ["TrkPIDDe"] + } +] END_PROLOG diff --git a/src/EventNtupleMaker_module.cc b/src/EventNtupleMaker_module.cc index af1aa56..ae89f9b 100644 --- a/src/EventNtupleMaker_module.cc +++ b/src/EventNtupleMaker_module.cc @@ -95,7 +95,7 @@ namespace mu2e { // Need this for the BaBar headers. using CLHEP::Hep3Vector; typedef KalSeedCollection::const_iterator KSCIter; - typedef size_t BranchIndex; + typedef size_t TrkFitBranchIndex; typedef size_t StepCollIndex; class EventNtupleMaker : public art::EDAnalyzer { @@ -104,7 +104,7 @@ namespace mu2e { // ── Per-branch options (defaults match intended use; omit options in FCL // unless you want to override a specific field) ────────────────────── - struct BranchOptConfig { + struct TrkFitOptConfig { using Name=fhicl::Name; using Comment=fhicl::Comment; fhicl::Atom fillmc{Name("fillMC"), Comment("Fill MC information for this branch"), true}; @@ -113,15 +113,15 @@ namespace mu2e { fhicl::Atom matchDepth{Name("matchDepth"), Comment("Depth of MC truth matching to keep (-1 = all)"), -1}; }; - struct BranchConfig { + struct TrkFitConfig { using Name=fhicl::Name; using Comment=fhicl::Comment; fhicl::Atom input{Name("input"), Comment("KalSeedCollection input tag")}; - fhicl::Atom branch{Name("branch"), Comment("Name of output branch")}; + fhicl::Atom branchname{Name("branchname"), Comment("Name of output branch")}; fhicl::Atom enabled{Name("enabled"), Comment("Set false to skip this branch entirely (no collection reads, no output branches)"), true}; fhicl::Sequence trkQualTags{Name("trkQualTags"), Comment("Input tags for MVAResultCollection to use for TrkQuals")}; fhicl::Sequence trkPIDTags{Name("trkPIDTags"), Comment("Input tags for MVAResultCollection to use for TrkPID")}; - fhicl::Table options{Name("options"), Comment("Per-branch fill options")}; + fhicl::Table options{Name("options"), Comment("Per-branch fill options")}; }; // ── Event-level MC config (tracker+CRV share these event products) ───── @@ -131,10 +131,10 @@ namespace mu2e { fhicl::Atom fill{Name("fill"), Comment("Master gate for tracker MC, CRV MC, and event-level MC info branches. " "Calo MC is controlled independently via calo.mc.fill."), true}; - fhicl::Atom PBTMCTag{Name("PBTMCTag"), Comment("Tag for ProtonBunchTimeMC object"), art::InputTag()}; + fhicl::Atom PBTMCTag{Name("PBTMCTag"), Comment("Tag for ProtonBunchTimeMC object")}; fhicl::Atom simParticlesTag{Name("simParticlesTag"), Comment("SimParticle Collection Tag")}; fhicl::Atom mcTrajectoriesTag{Name("mcTrajectoriesTag"), Comment("MCTrajectory Collection Tag")}; - fhicl::Atom primaryParticleTag{Name("primaryParticleTag"), Comment("Tag for PrimaryParticle"), art::InputTag()}; + fhicl::Atom primaryParticleTag{Name("primaryParticleTag"), Comment("Tag for PrimaryParticle")}; fhicl::Table infoMCStructHelper{Name("infoMCStructHelper"), Comment("Configuration for InfoMCStructHelper")}; }; @@ -142,30 +142,50 @@ namespace mu2e { struct TrkConfig { using Name=fhicl::Name; using Comment=fhicl::Comment; + // master switch + fhicl::Atom fill{Name("fill"), Comment("Enable the tracker subsystem entirely"), true}; // reco flags fhicl::Atom fillHits{Name("fillHits"), Comment("Global enable for hit-level branches; per-branch options.fillHits also required"), true}; fhicl::Atom fillHitCalibs{Name("fillHitCalibs"), Comment("Fill hit calibration branches"), false}; - fhicl::Atom fillHelices{Name("fillHelices"), Comment("Fill helix seed branches"), false}; fhicl::Atom fillTrkQual{Name("fillTrkQual"), Comment("Fill TrkQual MVA branches"), false}; fhicl::Atom fillTrkPID{Name("fillTrkPID"), Comment("Fill TrkPID MVA branches"), false}; - fhicl::Atom fillTimeClusters{Name("fillTimeClusters"), Comment("Fill time cluster branch"), false}; - fhicl::Atom timeClustersTag{Name("timeClustersTag"), Comment("Tag for time cluster collection"), art::InputTag()}; // per-branch configurations - fhicl::Sequence> branches{Name("branches"), Comment("One entry per KalSeed collection to write as a track branch")}; + fhicl::Sequence> fits{Name("fits"), Comment("KalSeed collections to write into a single track branch")}; // tracker MC sub-config struct MCConfig { using Name=fhicl::Name; using Comment=fhicl::Comment; fhicl::Atom fill{Name("fill"), Comment("Master switch for all tracker MC branches; mc.fill must also be true"), true}; - fhicl::Atom kalSeedMCAssns{Name("kalSeedMCAssns"), Comment("Tag for KalSeedMCAssn"), art::InputTag()}; - fhicl::OptionalSequence extraMCStepTags{Name("extraMCStepTags"), Comment("Tags for extra StepPointMCCollections associated with KalSeeds")}; - fhicl::OptionalAtom surfaceStepsTag{Name("surfaceStepsTag"), Comment("SurfaceStep collection tag; omit to disable surface step branches")}; - fhicl::OptionalSequence stepPointMCTags{Name("stepPointMCTags"), Comment("Tags for StepPointMCCollections written out for all steps (not per-track)")}; + fhicl::Atom kalSeedMCAssns{Name("kalSeedMCAssns"), Comment("Tag for KalSeedMCAssn")}; }; fhicl::Table mc{Name("mc"), Comment("Tracker MC filling options")}; }; + // ── Helix seed config (independent of per-branch track config) ───────── + struct HelixConfig { + using Name=fhicl::Name; + using Comment=fhicl::Comment; + fhicl::Atom fill{Name("fill"), Comment("Fill helix seed branches"), false}; + }; + + // ── Time cluster config (independent of per-branch track config) ─────── + struct TimeClusterConfig { + using Name=fhicl::Name; + using Comment=fhicl::Comment; + fhicl::Atom fill{Name("fill"), Comment("Fill time cluster branch"), false}; + fhicl::Atom tag {Name("tag"), Comment("Tag for time cluster collection")}; + }; + + // ── MC step collections config (independent of per-branch track config) ─ + struct MCStepsConfig { + using Name=fhicl::Name; + using Comment=fhicl::Comment; + fhicl::OptionalSequence extraMCStepTags{Name("extraMCStepTags"), Comment("Tags for extra StepPointMCCollections associated with KalSeeds")}; + fhicl::OptionalAtom surfaceStepsTag{Name("surfaceStepsTag"), Comment("SurfaceStep collection tag; omit to disable surface step branches")}; + fhicl::OptionalSequence stepPointMCTags{Name("stepPointMCTags"), Comment("Tags for global StepPointMCCollections (not per-track)")}; + }; + // ── Calorimeter subsystem config ─────────────────────────────────────── // Calo MC is gated solely by calo.mc.fill; it is independent of mc.fill // so that calo-only jobs can fill calo MC without loading tracker MC products. @@ -176,13 +196,13 @@ namespace mu2e { fhicl::Atom fill{Name("fill"), Comment("Enable the calorimeter subsystem entirely"), true}; // reco flags + collocated tags fhicl::Atom fillClusters {Name("fillClusters"), Comment("Fill calorimeter cluster branch"), true}; - fhicl::Atom clustersTag {Name("clustersTag"), Comment("Tag for CaloCluster collection"), art::InputTag()}; + fhicl::Atom clustersTag {Name("clustersTag"), Comment("Tag for CaloCluster collection")}; fhicl::Atom fillHits {Name("fillHits"), Comment("Fill calorimeter hit branch"), false}; - fhicl::Atom hitsTag {Name("hitsTag"), Comment("Tag for CaloHit collection"), art::InputTag()}; + fhicl::Atom hitsTag {Name("hitsTag"), Comment("Tag for CaloHit collection")}; fhicl::Atom fillRecoDigis{Name("fillRecoDigis"), Comment("Fill calorimeter reco-digi branch"), false}; - fhicl::Atom recoDigisTag {Name("recoDigisTag"), Comment("Tag for CaloRecoDigi collection"), art::InputTag()}; + fhicl::Atom recoDigisTag {Name("recoDigisTag"), Comment("Tag for CaloRecoDigi collection")}; fhicl::Atom fillDigis {Name("fillDigis"), Comment("Fill calorimeter digi branch"), false}; - fhicl::Atom digisTag {Name("digisTag"), Comment("Tag for CaloDigi collection"), art::InputTag()}; + fhicl::Atom digisTag {Name("digisTag"), Comment("Tag for CaloDigi collection")}; // MC sub-config struct MCConfig { using Name=fhicl::Name; @@ -192,13 +212,13 @@ namespace mu2e { fhicl::Atom fillTrackMatch{Name("fillTrackMatch"), Comment("Fill per-track calo cluster MC branch (calohitmc.)"), true}; // standalone calo MC branches fhicl::Atom fillClusters{Name("fillClusters"), Comment("Fill standalone caloclustersmc. branch"), true}; - fhicl::Atom clusterMCTag{Name("clusterMCTag"), Comment("Tag for CaloClusterMCCollection"), art::InputTag()}; + fhicl::Atom clusterMCTag{Name("clusterMCTag"), Comment("Tag for CaloClusterMCCollection")}; fhicl::Atom fillHits {Name("fillHits"), Comment("Fill standalone calohitsmc. branch"), true}; - fhicl::Atom hitMCTag {Name("hitMCTag"), Comment("Tag for CaloHitMCCollection"), art::InputTag()}; + fhicl::Atom hitMCTag {Name("hitMCTag"), Comment("Tag for CaloHitMCCollection")}; fhicl::Atom fillSim {Name("fillSim"), Comment("Fill calomcsim. (sim particle info) branch"), true}; fhicl::Atom fillDigis {Name("fillDigis"), Comment("Fill standalone calodigismc. branch"), false}; fhicl::Atom fillDigiSim {Name("fillDigiSim"), Comment("Fill calodigisim. branch"), false}; - fhicl::Atom showerSimTag{Name("showerSimTag"), Comment("Tag for CaloShowerSim collection"), art::InputTag()}; + fhicl::Atom showerSimTag{Name("showerSimTag"), Comment("Tag for CaloShowerSim collection")}; }; fhicl::Table mc{Name("mc"), Comment("Calorimeter MC filling options")}; }; @@ -211,22 +231,22 @@ namespace mu2e { fhicl::Atom fill{Name("fill"), Comment("Enable the CRV subsystem entirely"), false}; // reco flags + collocated tags fhicl::Atom fillCoincs {Name("fillCoincs"), Comment("Fill CRV coincidence cluster branches"), false}; - fhicl::Atom coincidencesTag{Name("coincidencesTag"), Comment("Tag for CrvCoincidenceCluster collection"), art::InputTag()}; - fhicl::Atom recoPulsesTag {Name("recoPulsesTag"), Comment("Tag for CrvRecoPulse collection"), art::InputTag()}; - fhicl::Atom stepsTag {Name("stepsTag"), Comment("Tag for CrvStep collection"), art::InputTag()}; + fhicl::Atom coincidencesTag{Name("coincidencesTag"), Comment("Tag for CrvCoincidenceCluster collection")}; + fhicl::Atom recoPulsesTag {Name("recoPulsesTag"), Comment("Tag for CrvRecoPulse collection")}; + fhicl::Atom stepsTag {Name("stepsTag"), Comment("Tag for CrvStep collection")}; fhicl::Atom fillPulses {Name("fillPulses"), Comment("Fill CRV reco pulse branches"), false}; fhicl::Atom fillDigis {Name("fillDigis"), Comment("Fill CRV digi branch"), false}; - fhicl::Atom digisTag {Name("digisTag"), Comment("Tag for CrvDigi collection"), art::InputTag()}; - fhicl::Atom planeY {Name("planeY"), Comment("Y of center of top layer of CRV-T counters (mm)"), 2751.485}; + fhicl::Atom digisTag {Name("digisTag"), Comment("Tag for CrvDigi collection")}; + fhicl::Atom planeY {Name("planeY"), Comment("Y of center of top layer of CRV-T counters (mm)")}; fhicl::OptionalAtom inferenceTag{Name("inferenceTag"), Comment("Tag for CrvInference Assns (art::Assns); omit to disable")}; // MC sub-config (requires mc.fill also be true) struct MCConfig { using Name=fhicl::Name; using Comment=fhicl::Comment; fhicl::Atom fill {Name("fill"), Comment("Master switch for CRV MC branches; mc.fill must also be true"), true}; - fhicl::Atom coincidenceMCsTag {Name("coincidenceMCsTag"), Comment("Tag for CrvCoincidenceClusterMC collection"), art::InputTag()}; - fhicl::Atom digiMCsTag {Name("digiMCsTag"), Comment("Tag for CrvDigiMC collection"), art::InputTag()}; - fhicl::Atom assnsTag {Name("assnsTag"), Comment("Tag for CrvCoincidenceClusterMCAssns"), art::InputTag()}; + fhicl::Atom coincidenceMCsTag {Name("coincidenceMCsTag"), Comment("Tag for CrvCoincidenceClusterMC collection")}; + fhicl::Atom digiMCsTag {Name("digiMCsTag"), Comment("Tag for CrvDigiMC collection")}; + fhicl::Atom assnsTag {Name("assnsTag"), Comment("Tag for CrvCoincidenceClusterMCAssns")}; }; fhicl::Table mc{Name("mc"), Comment("CRV MC filling options")}; }; @@ -236,17 +256,17 @@ namespace mu2e { using Comment=fhicl::Comment; // General control - fhicl::Atom diag{Name("diagLevel"),1}; + fhicl::Atom diag{Name("diagLevel")}; fhicl::Atom debug{Name("debugLevel"),0}; fhicl::Atom splitlevel{Name("splitlevel"),99}; fhicl::Atom buffsize{Name("buffsize"),32000}; fhicl::Atom hastrks{Name("hasTracks"), Comment("Require >=1 tracks to fill tuple"), false}; fhicl::Atom hascrv{Name("hasCRV"), Comment("Require CRV information to fill tuple"), false}; // General event info - fhicl::Atom rctag{Name("RecoCountTag"), Comment("RecoCount"), art::InputTag()}; - fhicl::Atom PBITag{Name("PBITag"), Comment("Tag for ProtonBunchIntensity object"), art::InputTag()}; - fhicl::Atom PBTTag{Name("PBTTag"), Comment("Tag for ProtonBunchTime object"), art::InputTag()}; - fhicl::Atom EWMTag{Name("EWMTag"), Comment("Tag for EventWindowMarker object"), art::InputTag()}; + fhicl::Atom rctag{Name("RecoCountTag"), Comment("RecoCount")}; + fhicl::Atom PBITag{Name("PBITag"), Comment("Tag for ProtonBunchIntensity object")}; + fhicl::Atom PBTTag{Name("PBTTag"), Comment("Tag for ProtonBunchTime object")}; + fhicl::Atom EWMTag{Name("EWMTag"), Comment("Tag for EventWindowMarker object")}; // Trigger fhicl::Atom filltrig{Name("FillTriggerInfo"), false}; fhicl::Atom trigProcessName{Name("TriggerProcessName"), Comment("Process name for Trigger")}; @@ -254,10 +274,13 @@ namespace mu2e { // Fit type fhicl::Atom fittype{Name("FitType"), Comment("Type of track fit: LoopHelix, CentralHelix, KinematicLine, or Unknown"), "Unknown"}; // ── Subsystems ──────────────────────────────────────────────────────── - fhicl::Table mc {Name("mc"), Comment("Event-level MC config: gates tracker+CRV MC and provides shared event MC products")}; - fhicl::Table trk {Name("trk"), Comment("Tracker subsystem config")}; - fhicl::Table calo{Name("calo"), Comment("Calorimeter subsystem config")}; - fhicl::Table crv {Name("crv"), Comment("CRV subsystem config")}; + fhicl::Table mc {Name("mc"), Comment("Event-level MC config: gates tracker+CRV MC and provides shared event MC products")}; + fhicl::Table trk {Name("trk"), Comment("Tracker subsystem config")}; + fhicl::Table calo {Name("calo"), Comment("Calorimeter subsystem config")}; + fhicl::Table crv {Name("crv"), Comment("CRV subsystem config")}; + fhicl::Table helices {Name("helices"), Comment("Helix seed branches config")}; + fhicl::Table timeclusters{Name("timeclusters"),Comment("Time cluster branch config")}; + fhicl::Table mcsteps {Name("mcsteps"), Comment("MC step collection branches config")}; }; typedef art::EDAnalyzer::Table Parameters; @@ -271,7 +294,7 @@ namespace mu2e { private: Config _conf; - std::vector _allBranches; // configurations for all track branches + std::vector _allTrkFitBranches; // configurations for all track fit branches // main TTree TTree* _ntuple; TH1I* _hVersion; @@ -291,20 +314,20 @@ namespace mu2e { // track branches (inputs) std::vector > _allKSPCHs; // track branches (outputs) - std::map> _allTIs; - std::map>> _allTSIs; - std::map>> _allLHIs; - std::map>> _allCHIs; - std::map>> _allKLIs; - std::map> _allTCHIs; + std::map> _allTIs; + std::map>> _allTSIs; + std::map>> _allLHIs; + std::map>> _allCHIs; + std::map>> _allKLIs; + std::map> _allTCHIs; // quality branches (inputs) std::vector > > _allRQCHs; std::vector >> _allTrkQualCHs; std::vector >> _allTrkPIDCHs; // quality branches (outputs) std::vector _allRQIs; - std::map>> _allTrkQualResults; - std::map>> _allTrkPIDResults; + std::map>> _allTrkQualResults; + std::map>> _allTrkPIDResults; // trigger information unsigned _trigbits; std::map _tmap; // map between path and trigger ID. ID should come from trigger itself FIXME! @@ -312,10 +335,10 @@ namespace mu2e { // cached optional tracker MC tags std::vector _extraMCStepTags; std::vector> _extraMCStepCollections; - std::map>> _extraMCStepInfos; - std::map>> _extraMCStepSummaryInfos; + std::map>> _extraMCStepInfos; + std::map>> _extraMCStepSummaryInfos; art::InputTag _surfaceStepsTag; - std::map>> _surfaceStepInfos; + std::map>> _surfaceStepInfos; art::Handle _surfaceStepsHandle; std::vector _stepPointMCTags; std::vector> _stepPointMCCollections; @@ -326,17 +349,17 @@ namespace mu2e { art::Handle _simParticles; art::Handle _mcTrajectories; // tracker MC truth branches (outputs) - std::map> _allMCTIs; - std::map>> _allMCSimTIs; - std::map>> _allMCVDInfos; + std::map> _allMCTIs; + std::map>> _allMCSimTIs; + std::map>> _allMCVDInfos; art::Handle _ccmcch; art::Handle _chmcch; - std::map> _allMCTCHIs; + std::map> _allMCTCHIs; // hit level info branches - std::map>> _allTSHIs; - std::map>> _allTSHCIs; - std::map>> _allTSMIs; - std::map>> _allTSHIMCs; + std::map>> _allTSHIs; + std::map>> _allTSHCIs; + std::map>> _allTSMIs; + std::map>> _allTSHIMCs; // time cluster branch art::Handle _tcsHandle; std::vector _tcIs; @@ -360,7 +383,7 @@ namespace mu2e { std::vector _caloSIMCs; std::vector _caloDigiSIMCs; // CRV (inputs) - std::map>> _allBestCrvAssns; + std::map>> _allBestCrvAssns; art::Handle _crvMCAssns; art::Handle _crvCoincidences; art::Handle _crvCoincidenceMCs; @@ -374,9 +397,9 @@ namespace mu2e { std::vector> _crvInference; // CRV (output) std::vector _crvcoincs; - std::map> _allBestCrvs; + std::map> _allBestCrvs; std::vector _crvcoincsmc; - std::map> _allBestCrvMCs; + std::map> _allBestCrvMCs; CrvSummaryReco _crvsummary; CrvSummaryMC _crvsummarymc; std::vector _crvcoincsmcplane; @@ -405,8 +428,8 @@ namespace mu2e { // Tracker MC: both the global event MC gate and the tracker MC gate must // be true, plus the per-branch flag. - bool fillTrkMC(const BranchOptConfig& opt) const { - return _conf.mc().fill() && _conf.trk().mc().fill() && opt.fillmc(); + bool fillTrkMC(const TrkFitOptConfig& opt) const { + return _conf.trk().fill() && _conf.mc().fill() && _conf.trk().mc().fill() && opt.fillmc(); } // Calorimeter MC: independent of fillEventMC() — calo MC products do not @@ -429,7 +452,7 @@ namespace mu2e { void fillEventInfo(const art::Event& event); void fillTriggerBranch(const art::Event& event, std::string const& process, bool firstEvent); void resetTrackBranches(); - void fillTrackBranches(const art::Handle& kspch, BranchIndex i_branch, size_t i_kseedptr); + void fillTrackBranches(const art::Handle& kspch, TrkFitBranchIndex i_trk_fit_branch, size_t i_kseedptr); template std::vector > createSpecialBranch(const art::Event& event, const std::string& branchname, @@ -460,50 +483,50 @@ namespace mu2e { } } - // resolve optional tracker MC tags from trk.mc sub-config - _conf.trk().mc().extraMCStepTags(_extraMCStepTags); - _conf.trk().mc().surfaceStepsTag(_surfaceStepsTag); - _conf.trk().mc().stepPointMCTags(_stepPointMCTags); + // resolve optional MC step tags from top-level mcsteps config + _conf.mcsteps().extraMCStepTags(_extraMCStepTags); + _conf.mcsteps().surfaceStepsTag(_surfaceStepsTag); + _conf.mcsteps().stepPointMCTags(_stepPointMCTags); // populate branch list from trk.branches - for(const auto& branch_cfg : _conf.trk().branches()){ - _allBranches.push_back(branch_cfg); + for(const auto& trk_fit_cfg : _conf.trk().fits()){ + _allTrkFitBranches.push_back(trk_fit_cfg); } // create per-branch storage (skip disabled branches) - for (BranchIndex i_branch = 0; i_branch < _allBranches.size(); ++i_branch) { - const auto& i_branchConfig = _allBranches.at(i_branch); - if (!i_branchConfig.enabled()) continue; - - _allTIs[i_branch] = {}; - _allTSIs[i_branch] = {}; - _allLHIs[i_branch] = {}; - _allCHIs[i_branch] = {}; - _allKLIs[i_branch] = {}; - _allMCVDInfos[i_branch] = {}; - _allTCHIs[i_branch] = {}; - _allMCTIs[i_branch] = {}; - _allMCSimTIs[i_branch] = {}; + for (TrkFitBranchIndex i_trk_fit_branch = 0; i_trk_fit_branch < _allTrkFitBranches.size(); ++i_trk_fit_branch) { + const auto& i_trkFitConfig = _allTrkFitBranches.at(i_trk_fit_branch); + if (!i_trkFitConfig.enabled()) continue; + + _allTIs[i_trk_fit_branch] = {}; + _allTSIs[i_trk_fit_branch] = {}; + _allLHIs[i_trk_fit_branch] = {}; + _allCHIs[i_trk_fit_branch] = {}; + _allKLIs[i_trk_fit_branch] = {}; + _allMCVDInfos[i_trk_fit_branch] = {}; + _allTCHIs[i_trk_fit_branch] = {}; + _allMCTIs[i_trk_fit_branch] = {}; + _allMCSimTIs[i_trk_fit_branch] = {}; if(fillCaloTrackMatchMC()){ - _allMCTCHIs[i_branch] = {}; + _allMCTCHIs[i_trk_fit_branch] = {}; } _allRQIs.push_back(RecoQualInfo{}); - _allTSHIs[i_branch] = {}; - _allTSHCIs[i_branch] = {}; - _allTSMIs[i_branch] = {}; - _allTSHIMCs[i_branch] = {}; + _allTSHIs[i_trk_fit_branch] = {}; + _allTSHCIs[i_trk_fit_branch] = {}; + _allTSMIs[i_trk_fit_branch] = {}; + _allTSHIMCs[i_trk_fit_branch] = {}; - _allTrkQualResults[i_branch].resize(i_branchConfig.trkQualTags().size()); - _allTrkPIDResults[i_branch].resize(i_branchConfig.trkPIDTags().size()); + _allTrkQualResults[i_trk_fit_branch].resize(i_trkFitConfig.trkQualTags().size()); + _allTrkPIDResults[i_trk_fit_branch].resize(i_trkFitConfig.trkPIDTags().size()); for (StepCollIndex ixt = 0; ixt < _extraMCStepTags.size(); ++ixt) { - _extraMCStepInfos[i_branch][ixt] = {}; - _extraMCStepSummaryInfos[i_branch][ixt] = {}; + _extraMCStepInfos[i_trk_fit_branch][ixt] = {}; + _extraMCStepSummaryInfos[i_trk_fit_branch][ixt] = {}; } if (!_surfaceStepsTag.empty()) { - _surfaceStepInfos[i_branch] = {}; + _surfaceStepInfos[i_trk_fit_branch] = {}; } } @@ -530,67 +553,69 @@ namespace mu2e { // hit counting branch _ntuple->Branch("hitcount",&_hcnt); // track counting branches - for (BranchIndex i_branch = 0; i_branch < _allBranches.size(); ++i_branch) { - if (!_allBranches.at(i_branch).enabled()) continue; - std::string leafname = _allBranches.at(i_branch).branch(); - _ntuple->Branch(("tcnt.n"+leafname).c_str(),&_tcnt._counts[i_branch]); + for (TrkFitBranchIndex i_trk_fit_branch = 0; i_trk_fit_branch < _allTrkFitBranches.size(); ++i_trk_fit_branch) { + if (!_allTrkFitBranches.at(i_trk_fit_branch).enabled()) continue; + std::string leafname = _allTrkFitBranches.at(i_trk_fit_branch).branchname(); + _ntuple->Branch(("tcnt.n"+leafname).c_str(),&_tcnt._counts[i_trk_fit_branch]); } // create all track branches - for (BranchIndex i_branch = 0; i_branch < _allBranches.size(); ++i_branch) { - const BranchConfig& i_branchConfig = _allBranches.at(i_branch); - if (!i_branchConfig.enabled()) continue; - std::string branch = i_branchConfig.branch(); - _ntuple->Branch((branch+".").c_str(),&_allTIs.at(i_branch),_buffsize,_splitlevel); - _ntuple->Branch((branch+"segs.").c_str(),&_allTSIs.at(i_branch),_buffsize,_splitlevel); - // add traj-specific branches - if(_ftype == LoopHelix) _ntuple->Branch((branch+"segpars_lh.").c_str(),&_allLHIs.at(i_branch),_buffsize,_splitlevel); - if(_ftype == CentralHelix) _ntuple->Branch((branch+"segpars_ch.").c_str(),&_allCHIs.at(i_branch),_buffsize,_splitlevel); - if(_ftype == KinematicLine) _ntuple->Branch((branch+"segpars_kl.").c_str(),&_allKLIs.at(i_branch),_buffsize,_splitlevel); - // TrkCaloHit: currently only 1 - _ntuple->Branch((branch+"calohit.").c_str(),&_allTCHIs.at(i_branch)); - for (size_t i_trkQualTag = 0; i_trkQualTag < i_branchConfig.trkQualTags().size(); ++i_trkQualTag) { - std::string branchname = "qual"; - if (i_trkQualTag > 0) branchname += std::to_string(i_trkQualTag+1); - _ntuple->Branch((branch+branchname+".").c_str(),&_allTrkQualResults.at(i_branch).at(i_trkQualTag),_buffsize,_splitlevel); - } - for (size_t i_trkPIDTag = 0; i_trkPIDTag < i_branchConfig.trkPIDTags().size(); ++i_trkPIDTag) { - std::string branchname = "pid"; - if (i_trkPIDTag > 0) branchname += std::to_string(i_trkPIDTag+1); - _ntuple->Branch((branch+branchname+'.').c_str(),&_allTrkPIDResults.at(i_branch).at(i_trkPIDTag),_buffsize,_splitlevel); - } - // hit-level branches (global trk.fillHits AND per-branch options.fillHits both required) - if(_conf.diag() > 1 || (_conf.trk().fillHits() && i_branchConfig.options().fillhits())){ - _ntuple->Branch((branch+"hits.").c_str(),&_allTSHIs.at(i_branch),_buffsize,_splitlevel); - if (_conf.trk().fillHitCalibs()) - _ntuple->Branch((branch+"hitcalibs.").c_str(),&_allTSHCIs.at(i_branch),_buffsize,_splitlevel); - _ntuple->Branch((branch+"mats.").c_str(),&_allTSMIs.at(i_branch),_buffsize,_splitlevel); - } - // tracker MC branches - if(fillTrkMC(i_branchConfig.options())){ - _ntuple->Branch((branch+"mc.").c_str(),&_allMCTIs.at(i_branch),_buffsize,_splitlevel); - _ntuple->Branch((branch+"mcsim.").c_str(),&_allMCSimTIs.at(i_branch),_buffsize,_splitlevel); - _ntuple->Branch((branch+"mcvd.").c_str(),&_allMCVDInfos.at(i_branch),_buffsize,_splitlevel); - if(fillCaloTrackMatchMC()) - _ntuple->Branch((branch+"calohitmc.").c_str(),&_allMCTCHIs.at(i_branch),_buffsize,_splitlevel); - if(_conf.diag() > 1 || (_conf.trk().fillHits() && i_branchConfig.options().fillhits())){ - _ntuple->Branch((branch+"hitsmc.").c_str(),&_allTSHIMCs.at(i_branch),_buffsize,_splitlevel); + if (_conf.trk().fill()) { + for (TrkFitBranchIndex i_trk_fit_branch = 0; i_trk_fit_branch < _allTrkFitBranches.size(); ++i_trk_fit_branch) { + const TrkFitConfig& i_trkFitConfig = _allTrkFitBranches.at(i_trk_fit_branch); + if (!i_trkFitConfig.enabled()) continue; + std::string branch = i_trkFitConfig.branchname(); + _ntuple->Branch((branch+".").c_str(),&_allTIs.at(i_trk_fit_branch),_buffsize,_splitlevel); + _ntuple->Branch((branch+"segs.").c_str(),&_allTSIs.at(i_trk_fit_branch),_buffsize,_splitlevel); + // add traj-specific branches + if(_ftype == LoopHelix) _ntuple->Branch((branch+"segpars_lh.").c_str(),&_allLHIs.at(i_trk_fit_branch),_buffsize,_splitlevel); + if(_ftype == CentralHelix) _ntuple->Branch((branch+"segpars_ch.").c_str(),&_allCHIs.at(i_trk_fit_branch),_buffsize,_splitlevel); + if(_ftype == KinematicLine) _ntuple->Branch((branch+"segpars_kl.").c_str(),&_allKLIs.at(i_trk_fit_branch),_buffsize,_splitlevel); + // TrkCaloHit: currently only 1 + _ntuple->Branch((branch+"calohit.").c_str(),&_allTCHIs.at(i_trk_fit_branch)); + for (size_t i_trkQualTag = 0; i_trkQualTag < i_trkFitConfig.trkQualTags().size(); ++i_trkQualTag) { + std::string branchname = "qual"; + if (i_trkQualTag > 0) branchname += std::to_string(i_trkQualTag+1); + _ntuple->Branch((branch+branchname+".").c_str(),&_allTrkQualResults.at(i_trk_fit_branch).at(i_trkQualTag),_buffsize,_splitlevel); } - // extra MCStep branches per track type - for(size_t ixtra = 0; ixtra < _extraMCStepTags.size(); ++ixtra) { - auto const& tag = _extraMCStepTags[ixtra]; - auto inst = tag.instance(); - _ntuple->Branch((branch+"mcsic_"+inst+".").c_str(),&_extraMCStepInfos[i_branch][ixtra],_buffsize,_splitlevel); - _ntuple->Branch((branch+"mcssi_"+inst+".").c_str(),&_extraMCStepSummaryInfos[i_branch][ixtra],_buffsize,_splitlevel); + for (size_t i_trkPIDTag = 0; i_trkPIDTag < i_trkFitConfig.trkPIDTags().size(); ++i_trkPIDTag) { + std::string branchname = "pid"; + if (i_trkPIDTag > 0) branchname += std::to_string(i_trkPIDTag+1); + _ntuple->Branch((branch+branchname+'.').c_str(),&_allTrkPIDResults.at(i_trk_fit_branch).at(i_trkPIDTag),_buffsize,_splitlevel); } - if(!_surfaceStepsTag.empty()){ - _ntuple->Branch((branch+"segsmc.").c_str(),&_surfaceStepInfos[i_branch],_buffsize,_splitlevel); + // hit-level branches (global trk.fillHits AND per-branch options.fillHits both required) + if(_conf.diag() > 1 || (_conf.trk().fillHits() && i_trkFitConfig.options().fillhits())){ + _ntuple->Branch((branch+"hits.").c_str(),&_allTSHIs.at(i_trk_fit_branch),_buffsize,_splitlevel); + if (_conf.trk().fillHitCalibs()) + _ntuple->Branch((branch+"hitcalibs.").c_str(),&_allTSHCIs.at(i_trk_fit_branch),_buffsize,_splitlevel); + _ntuple->Branch((branch+"mats.").c_str(),&_allTSMIs.at(i_trk_fit_branch),_buffsize,_splitlevel); + } + // tracker MC branches + if(fillTrkMC(i_trkFitConfig.options())){ + _ntuple->Branch((branch+"mc.").c_str(),&_allMCTIs.at(i_trk_fit_branch),_buffsize,_splitlevel); + _ntuple->Branch((branch+"mcsim.").c_str(),&_allMCSimTIs.at(i_trk_fit_branch),_buffsize,_splitlevel); + _ntuple->Branch((branch+"mcvd.").c_str(),&_allMCVDInfos.at(i_trk_fit_branch),_buffsize,_splitlevel); + if(fillCaloTrackMatchMC()) + _ntuple->Branch((branch+"calohitmc.").c_str(),&_allMCTCHIs.at(i_trk_fit_branch),_buffsize,_splitlevel); + if(_conf.diag() > 1 || (_conf.trk().fillHits() && i_trkFitConfig.options().fillhits())){ + _ntuple->Branch((branch+"hitsmc.").c_str(),&_allTSHIMCs.at(i_trk_fit_branch),_buffsize,_splitlevel); + } + // extra MCStep branches per track type + for(size_t ixtra = 0; ixtra < _extraMCStepTags.size(); ++ixtra) { + auto const& tag = _extraMCStepTags[ixtra]; + auto inst = tag.instance(); + _ntuple->Branch((branch+"mcsic_"+inst+".").c_str(),&_extraMCStepInfos[i_trk_fit_branch][ixtra],_buffsize,_splitlevel); + _ntuple->Branch((branch+"mcssi_"+inst+".").c_str(),&_extraMCStepSummaryInfos[i_trk_fit_branch][ixtra],_buffsize,_splitlevel); + } + if(!_surfaceStepsTag.empty()){ + _ntuple->Branch((branch+"segsmc.").c_str(),&_surfaceStepInfos[i_trk_fit_branch],_buffsize,_splitlevel); + } } } } // Time clusters - if(_conf.trk().fillTimeClusters()) { + if(_conf.timeclusters().fill()) { _ntuple->Branch("timeclusters.",&_tcIs,_buffsize,_splitlevel); } @@ -646,7 +671,7 @@ namespace mu2e { _ntuple->Branch("crvcosmic.",&_crvInference,_buffsize,_splitlevel); } // helix info - if(_conf.trk().fillHelices()) _ntuple->Branch("helices.",&_hinfos,_buffsize,_splitlevel); + if(_conf.helices().fill()) _ntuple->Branch("helices.",&_hinfos,_buffsize,_splitlevel); // global MC step branches (all steps, not per-track) if(fillEventMC()){ @@ -692,52 +717,54 @@ namespace mu2e { _allTrkPIDCHs.clear(); art::Handle khaH; - if(_conf.trk().fillHelices()){ - BranchConfig i_branchConfig = _allBranches.at(0); - art::InputTag kalSeedInputTag = i_branchConfig.input(); + if(_conf.helices().fill()){ + TrkFitConfig i_trkFitConfig = _allTrkFitBranches.at(0); + art::InputTag kalSeedInputTag = i_trkFitConfig.input(); event.getByLabel(kalSeedInputTag,khaH); } - for (BranchIndex i_branch = 0; i_branch < _allBranches.size(); ++i_branch) { - BranchConfig i_branchConfig = _allBranches.at(i_branch); - if (!i_branchConfig.enabled()) { - // push empty placeholders to keep index alignment - _allKSPCHs.push_back(art::Handle()); - _allTrkQualCHs.emplace_back(); - _allRQCHs.push_back({}); - _allTrkPIDCHs.emplace_back(); - continue; - } - art::Handle kalSeedPtrCollHandle; - art::InputTag kalSeedPtrInputTag = i_branchConfig.input(); - event.getByLabel(kalSeedPtrInputTag,kalSeedPtrCollHandle); - _allKSPCHs.push_back(kalSeedPtrCollHandle); - - std::vector> trkQualCollHandles; - for (const auto& i_trkQualTag : i_branchConfig.trkQualTags()) { - art::Handle trkQualCollHandle; - event.getByLabel(i_trkQualTag,trkQualCollHandle); - trkQualCollHandles.push_back(trkQualCollHandle); - } - _allTrkQualCHs.emplace_back(trkQualCollHandles); - - std::vector > recoQualCollHandles; - std::vector > selectedRQCHs; - selectedRQCHs = createSpecialBranch(event, i_branchConfig.branch()+"qual", recoQualCollHandles, _allRQIs.at(i_branch), _allRQIs.at(i_branch)._qualsAndCalibs, true); - for (const auto& i_selectedRQCH : selectedRQCHs) { - if (i_selectedRQCH->size() != kalSeedPtrCollHandle->size()) { - throw cet::exception("TrkAna") << "Sizes of KalSeedPtrCollection and this RecoQualCollection are inconsistent (" << kalSeedPtrCollHandle->size() << " and " << i_selectedRQCH->size() << " respectively)"; + if (_conf.trk().fill()) { + for (TrkFitBranchIndex i_trk_fit_branch = 0; i_trk_fit_branch < _allTrkFitBranches.size(); ++i_trk_fit_branch) { + TrkFitConfig i_trkFitConfig = _allTrkFitBranches.at(i_trk_fit_branch); + if (!i_trkFitConfig.enabled()) { + // push empty placeholders to keep index alignment + _allKSPCHs.push_back(art::Handle()); + _allTrkQualCHs.emplace_back(); + _allRQCHs.push_back({}); + _allTrkPIDCHs.emplace_back(); + continue; } - } - _allRQCHs.push_back(selectedRQCHs); + art::Handle kalSeedPtrCollHandle; + art::InputTag kalSeedPtrInputTag = i_trkFitConfig.input(); + event.getByLabel(kalSeedPtrInputTag,kalSeedPtrCollHandle); + _allKSPCHs.push_back(kalSeedPtrCollHandle); + + std::vector> trkQualCollHandles; + for (const auto& i_trkQualTag : i_trkFitConfig.trkQualTags()) { + art::Handle trkQualCollHandle; + event.getByLabel(i_trkQualTag,trkQualCollHandle); + trkQualCollHandles.push_back(trkQualCollHandle); + } + _allTrkQualCHs.emplace_back(trkQualCollHandles); + + std::vector > recoQualCollHandles; + std::vector > selectedRQCHs; + selectedRQCHs = createSpecialBranch(event, i_trkFitConfig.branchname()+"qual", recoQualCollHandles, _allRQIs.at(i_trk_fit_branch), _allRQIs.at(i_trk_fit_branch)._qualsAndCalibs, true); + for (const auto& i_selectedRQCH : selectedRQCHs) { + if (i_selectedRQCH->size() != kalSeedPtrCollHandle->size()) { + throw cet::exception("TrkAna") << "Sizes of KalSeedPtrCollection and this RecoQualCollection are inconsistent (" << kalSeedPtrCollHandle->size() << " and " << i_selectedRQCH->size() << " respectively)"; + } + } + _allRQCHs.push_back(selectedRQCHs); - std::vector> trkPIDCollHandles; - for (const auto& i_trkPIDTag : i_branchConfig.trkPIDTags()) { - art::Handle trkPIDCollHandle; - event.getByLabel(i_trkPIDTag,trkPIDCollHandle); - trkPIDCollHandles.push_back(trkPIDCollHandle); + std::vector> trkPIDCollHandles; + for (const auto& i_trkPIDTag : i_trkFitConfig.trkPIDTags()) { + art::Handle trkPIDCollHandle; + event.getByLabel(i_trkPIDTag,trkPIDCollHandle); + trkPIDCollHandles.push_back(trkPIDCollHandle); + } + _allTrkPIDCHs.emplace_back(trkPIDCollHandles); } - _allTrkPIDCHs.emplace_back(trkPIDCollHandles); } // trigger information @@ -762,9 +789,11 @@ namespace mu2e { } // fill track counts - for (BranchIndex i_branch = 0; i_branch < _allBranches.size(); ++i_branch) { - if (!_allBranches.at(i_branch).enabled()) continue; - _tcnt._counts[i_branch] = (_allKSPCHs.at(i_branch))->size(); + if (_conf.trk().fill()) { + for (TrkFitBranchIndex i_trk_fit_branch = 0; i_trk_fit_branch < _allTrkFitBranches.size(); ++i_trk_fit_branch) { + if (!_allTrkFitBranches.at(i_trk_fit_branch).enabled()) continue; + _tcnt._counts[i_trk_fit_branch] = (_allKSPCHs.at(i_trk_fit_branch))->size(); + } } // find extra MCStep collections @@ -786,61 +815,63 @@ namespace mu2e { // loop through all track types unsigned ntrks(0); - for (BranchIndex i_branch = 0; i_branch < _allBranches.size(); ++i_branch) { - BranchConfig i_branchConfig = _allBranches.at(i_branch); - if (!i_branchConfig.enabled()) continue; - - _allTIs.at(i_branch).clear(); - _allTSIs.at(i_branch).clear(); - _allLHIs.at(i_branch).clear(); - _allCHIs.at(i_branch).clear(); - _allKLIs.at(i_branch).clear(); - _allTCHIs.at(i_branch).clear(); - - _allTSHIs.at(i_branch).clear(); - _allTSHCIs.at(i_branch).clear(); - _allTSMIs.at(i_branch).clear(); - _allTSHIMCs.at(i_branch).clear(); - - _allMCTIs.at(i_branch).clear(); - _allMCVDInfos.at(i_branch).clear(); - _allMCSimTIs.at(i_branch).clear(); - - for (size_t i_trkQualTag = 0; i_trkQualTag < i_branchConfig.trkQualTags().size(); ++i_trkQualTag) { - _allTrkQualResults.at(i_branch).at(i_trkQualTag).clear(); + for (TrkFitBranchIndex i_trk_fit_branch = 0; i_trk_fit_branch < _allTrkFitBranches.size(); ++i_trk_fit_branch) { + TrkFitConfig i_trkFitConfig = _allTrkFitBranches.at(i_trk_fit_branch); + if (!i_trkFitConfig.enabled()) continue; + + _allTIs.at(i_trk_fit_branch).clear(); + _allTSIs.at(i_trk_fit_branch).clear(); + _allLHIs.at(i_trk_fit_branch).clear(); + _allCHIs.at(i_trk_fit_branch).clear(); + _allKLIs.at(i_trk_fit_branch).clear(); + _allTCHIs.at(i_trk_fit_branch).clear(); + + _allTSHIs.at(i_trk_fit_branch).clear(); + _allTSHCIs.at(i_trk_fit_branch).clear(); + _allTSMIs.at(i_trk_fit_branch).clear(); + _allTSHIMCs.at(i_trk_fit_branch).clear(); + + _allMCTIs.at(i_trk_fit_branch).clear(); + _allMCVDInfos.at(i_trk_fit_branch).clear(); + _allMCSimTIs.at(i_trk_fit_branch).clear(); + + for (size_t i_trkQualTag = 0; i_trkQualTag < i_trkFitConfig.trkQualTags().size(); ++i_trkQualTag) { + _allTrkQualResults.at(i_trk_fit_branch).at(i_trkQualTag).clear(); } - for (size_t i_trkPIDTag = 0; i_trkPIDTag < i_branchConfig.trkPIDTags().size(); ++i_trkPIDTag) { - _allTrkPIDResults.at(i_branch).at(i_trkPIDTag).clear(); + for (size_t i_trkPIDTag = 0; i_trkPIDTag < i_trkFitConfig.trkPIDTags().size(); ++i_trkPIDTag) { + _allTrkPIDResults.at(i_trk_fit_branch).at(i_trkPIDTag).clear(); } for (StepCollIndex ixt = 0; ixt < _extraMCStepTags.size(); ++ixt) { - _extraMCStepInfos.at(i_branch).at(ixt).clear(); - _extraMCStepSummaryInfos.at(i_branch).at(ixt).clear(); + _extraMCStepInfos.at(i_trk_fit_branch).at(ixt).clear(); + _extraMCStepSummaryInfos.at(i_trk_fit_branch).at(ixt).clear(); } - _surfaceStepInfos.at(i_branch).clear(); + _surfaceStepInfos.at(i_trk_fit_branch).clear(); for (StepCollIndex icoll = 0; icoll < _stepPointMCTags.size(); ++icoll) { _stepPointMCInfos.at(icoll).clear(); } - if(fillCaloTrackMatchMC()) { _allMCTCHIs.at(i_branch).clear(); } - - const auto& kseedptr_coll_h = _allKSPCHs.at(i_branch); - const auto& kseedptr_coll = *kseedptr_coll_h; - for (size_t i_kseedptr = 0; i_kseedptr < kseedptr_coll.size(); ++i_kseedptr) { - resetTrackBranches(); - fillTrackBranches(kseedptr_coll_h, i_branch, i_kseedptr); - if(_conf.trk().fillHelices()){ - auto const& khassns = khaH.product(); - auto hptr = (*khassns)[i_kseedptr].second; - _infoStructHelper.fillHelixInfo(hptr, _hinfos); + if(fillCaloTrackMatchMC()) { _allMCTCHIs.at(i_trk_fit_branch).clear(); } + + if (_conf.trk().fill()) { + const auto& kseedptr_coll_h = _allKSPCHs.at(i_trk_fit_branch); + const auto& kseedptr_coll = *kseedptr_coll_h; + for (size_t i_kseedptr = 0; i_kseedptr < kseedptr_coll.size(); ++i_kseedptr) { + resetTrackBranches(); + fillTrackBranches(kseedptr_coll_h, i_trk_fit_branch, i_kseedptr); + if(_conf.helices().fill()){ + auto const& khassns = khaH.product(); + auto hptr = (*khassns)[i_kseedptr].second; + _infoStructHelper.fillHelixInfo(hptr, _hinfos); + } + ntrks++; } - ntrks++; } } // Time clusters - if(_conf.trk().fillTimeClusters()) { + if(_conf.timeclusters().fill()) { _tcIs.clear(); - event.getByLabel(_conf.trk().timeClustersTag(),_tcsHandle); + event.getByLabel(_conf.timeclusters().tag(),_tcsHandle); if(_tcsHandle.isValid()) { for(const auto& tc : *(_tcsHandle)) { _infoStructHelper.fillTimeClusterInfo(tc, _tcIs); @@ -1103,23 +1134,23 @@ namespace mu2e { } } - void EventNtupleMaker::fillTrackBranches(const art::Handle& kspch, BranchIndex i_branch, size_t i_kseedptr) { + void EventNtupleMaker::fillTrackBranches(const art::Handle& kspch, TrkFitBranchIndex i_trk_fit_branch, size_t i_kseedptr) { const auto& kseedptr = (kspch->at(i_kseedptr)); const auto& kseed = *kseedptr; // general info - _infoStructHelper.fillTrkInfo(kseed,_allTIs.at(i_branch)); - _infoStructHelper.fillTrkSegInfo(kseed,_allTSIs.at(i_branch)); - if(_ftype == LoopHelix && kseed.loopHelixFit()) _infoStructHelper.fillLoopHelixInfo(kseed,_allLHIs.at(i_branch)); - if(_ftype == CentralHelix && kseed.centralHelixFit()) _infoStructHelper.fillCentralHelixInfo(kseed,_allCHIs.at(i_branch)); - if(_ftype == KinematicLine && kseed.kinematicLineFit()) _infoStructHelper.fillKinematicLineInfo(kseed,_allKLIs.at(i_branch)); - const BranchConfig& branchConfig = _allBranches.at(i_branch); - if(_conf.diag() > 1 || (_conf.trk().fillHits() && branchConfig.options().fillhits())){ - _infoStructHelper.fillHitInfo(kseed, _allTSHIs.at(i_branch), _allTSHCIs.at(i_branch), _conf.trk().fillHitCalibs()); - _infoStructHelper.fillMatInfo(kseed, _allTSMIs.at(i_branch)); - } - - _infoStructHelper.fillTrkCaloHitInfo(kseed, _allTCHIs.at(i_branch)); + _infoStructHelper.fillTrkInfo(kseed,_allTIs.at(i_trk_fit_branch)); + _infoStructHelper.fillTrkSegInfo(kseed,_allTSIs.at(i_trk_fit_branch)); + if(_ftype == LoopHelix && kseed.loopHelixFit()) _infoStructHelper.fillLoopHelixInfo(kseed,_allLHIs.at(i_trk_fit_branch)); + if(_ftype == CentralHelix && kseed.centralHelixFit()) _infoStructHelper.fillCentralHelixInfo(kseed,_allCHIs.at(i_trk_fit_branch)); + if(_ftype == KinematicLine && kseed.kinematicLineFit()) _infoStructHelper.fillKinematicLineInfo(kseed,_allKLIs.at(i_trk_fit_branch)); + const TrkFitConfig& trkFitConfig = _allTrkFitBranches.at(i_trk_fit_branch); + if(_conf.diag() > 1 || (_conf.trk().fillHits() && trkFitConfig.options().fillhits())){ + _infoStructHelper.fillHitInfo(kseed, _allTSHIs.at(i_trk_fit_branch), _allTSHCIs.at(i_trk_fit_branch), _conf.trk().fillHitCalibs()); + _infoStructHelper.fillMatInfo(kseed, _allTSMIs.at(i_trk_fit_branch)); + } + + _infoStructHelper.fillTrkCaloHitInfo(kseed, _allTCHIs.at(i_trk_fit_branch)); if(kseed.hasCaloCluster()) { _tcnt._ndec = 1; if(_conf.debug()>0){ @@ -1130,50 +1161,50 @@ namespace mu2e { } } - const auto& trkQualHandles = _allTrkQualCHs.at(i_branch); + const auto& trkQualHandles = _allTrkQualCHs.at(i_trk_fit_branch); for(size_t i_trkQualHandle = 0; i_trkQualHandle < trkQualHandles.size(); ++i_trkQualHandle) { const auto& trkQualHandle = trkQualHandles.at(i_trkQualHandle); if(trkQualHandle.isValid()) { - _infoStructHelper.fillTrkQualInfo(kseed, trkQualHandle->at(i_kseedptr), _allTrkQualResults.at(i_branch).at(i_trkQualHandle)); + _infoStructHelper.fillTrkQualInfo(kseed, trkQualHandle->at(i_kseedptr), _allTrkQualResults.at(i_trk_fit_branch).at(i_trkQualHandle)); } } std::vector recoQuals; - for(const auto& i_recoQualHandle : _allRQCHs.at(i_branch)) { + for(const auto& i_recoQualHandle : _allRQCHs.at(i_trk_fit_branch)) { recoQuals.push_back(i_recoQualHandle->at(i_kseedptr)._value); recoQuals.push_back(i_recoQualHandle->at(i_kseedptr)._calib); } - _allRQIs.at(i_branch).setQuals(recoQuals); + _allRQIs.at(i_trk_fit_branch).setQuals(recoQuals); - const auto& trkPIDHandles = _allTrkPIDCHs.at(i_branch); + const auto& trkPIDHandles = _allTrkPIDCHs.at(i_trk_fit_branch); for(size_t i_trkPIDHandle = 0; i_trkPIDHandle < trkPIDHandles.size(); ++i_trkPIDHandle) { const auto& trkPIDHandle = trkPIDHandles.at(i_trkPIDHandle); if(trkPIDHandle.isValid()) { - _infoStructHelper.fillTrkPIDInfo(kseed, trkPIDHandle->at(i_kseedptr), _allTrkPIDResults.at(i_branch).at(i_trkPIDHandle)); + _infoStructHelper.fillTrkPIDInfo(kseed, trkPIDHandle->at(i_kseedptr), _allTrkPIDResults.at(i_trk_fit_branch).at(i_trkPIDHandle)); } } // fill tracker MC info - if(fillTrkMC(branchConfig.options())) { + if(fillTrkMC(trkFitConfig.options())) { const PrimaryParticle& primary = *_pph; if(_conf.debug() > 1) std::cout << "KalSeedMCMatch has " << _ksmcah->size() << " entries" << std::endl; for(auto iksmca = _ksmcah->begin(); iksmca != _ksmcah->end(); iksmca++){ if(_conf.debug() > 2) std::cout << "KalSeed Ptr " << kseedptr << " match Ptr " << iksmca->first << "?" << std::endl; if(iksmca->first == kseedptr) { auto const& kseedmc = *(iksmca->second); - _infoMCStructHelper.fillTrkInfoMC(kseed, kseedmc, _surfaceStepsHandle, _allMCTIs.at(i_branch)); - _infoMCStructHelper.fillVDInfo(kseed, kseedmc, _allMCVDInfos.at(i_branch)); - _infoMCStructHelper.fillAllSimInfos(kseedmc, primary, _allMCSimTIs.at(i_branch), branchConfig.options().genealogyDepth(), branchConfig.options().matchDepth()); - if(_conf.diag() > 1 || (_conf.trk().fillHits() && branchConfig.options().fillhits())){ - _infoMCStructHelper.fillHitInfoMCs(kseed,kseedmc, _allTSHIMCs.at(i_branch)); + _infoMCStructHelper.fillTrkInfoMC(kseed, kseedmc, _surfaceStepsHandle, _allMCTIs.at(i_trk_fit_branch)); + _infoMCStructHelper.fillVDInfo(kseed, kseedmc, _allMCVDInfos.at(i_trk_fit_branch)); + _infoMCStructHelper.fillAllSimInfos(kseedmc, primary, _allMCSimTIs.at(i_trk_fit_branch), trkFitConfig.options().genealogyDepth(), trkFitConfig.options().matchDepth()); + if(_conf.diag() > 1 || (_conf.trk().fillHits() && trkFitConfig.options().fillhits())){ + _infoMCStructHelper.fillHitInfoMCs(kseed,kseedmc, _allTSHIMCs.at(i_trk_fit_branch)); } for(size_t ixt = 0; ixt < _extraMCStepTags.size(); ixt++){ _infoMCStructHelper.fillExtraMCStepInfos(kseedmc,*_extraMCStepCollections[ixt], - _extraMCStepInfos[i_branch][ixt],_extraMCStepSummaryInfos.at(i_branch).at(ixt)); + _extraMCStepInfos[i_trk_fit_branch][ixt],_extraMCStepSummaryInfos.at(i_trk_fit_branch).at(ixt)); } if(_surfaceStepsHandle.isValid()){ if(_conf.debug() > 2) std::cout << "SurfaceSteps from handle " << _surfaceStepsHandle << std::endl; - auto& ssi = _surfaceStepInfos.at(i_branch); + auto& ssi = _surfaceStepInfos.at(i_trk_fit_branch); ssi.push_back(std::vector()); _infoMCStructHelper.fillSurfaceStepInfos(kseedmc,*_surfaceStepsHandle,ssi.back()); } @@ -1183,7 +1214,7 @@ namespace mu2e { if(kseed.hasCaloCluster() && fillCaloTrackMatchMC()) { auto index = kseed.caloCluster().key(); auto const& ccmc = (*_ccmcch)[index]; - _infoMCStructHelper.fillCaloClusterInfoMC(ccmc,_allMCTCHIs.at(i_branch)); + _infoMCStructHelper.fillCaloClusterInfoMC(ccmc,_allMCTCHIs.at(i_trk_fit_branch)); } } } @@ -1238,9 +1269,9 @@ namespace mu2e { } void EventNtupleMaker::resetTrackBranches() { - for(BranchIndex i_branch = 0; i_branch < _allBranches.size(); ++i_branch) { - if (!_allBranches.at(i_branch).enabled()) continue; - _allRQIs.at(i_branch).reset(); + for(TrkFitBranchIndex i_trk_fit_branch = 0; i_trk_fit_branch < _allTrkFitBranches.size(); ++i_trk_fit_branch) { + if (!_allTrkFitBranches.at(i_trk_fit_branch).enabled()) continue; + _allRQIs.at(i_trk_fit_branch).reset(); } } } // end namespace mu2e From 6b816028dc65e4c3db2af0a883f2f1abf938075f Mon Sep 17 00:00:00 2001 From: Andrew Edmonds Date: Thu, 4 Jun 2026 15:41:24 -0500 Subject: [PATCH 9/9] Add a few more validation tests --- validation/commands.txt | 7 ++++++- validation/datasets_Run1B.txt | 3 ++- validation/test_fcls.py | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/validation/commands.txt b/validation/commands.txt index 8248b4a..1ae791c 100644 --- a/validation/commands.txt +++ b/validation/commands.txt @@ -23,6 +23,8 @@ mu2e -c fcl/from_mcs-primary_addVDSteps.fcl -S {primary} --TFileName nts.ntuple. # Test digi datasets mu2e -c fcl/from_dig-mockdata.fcl -S {digi} --TFileName nts.ntuple.dig.root -n 100 +mu2e -c fcl/from_dig-OnSpill.fcl -S {digi} --TFileName nts.ntuple.digOnSpill.root -n 100 +mu2e -c fcl/from_dig-calo.fcl -S {digi} --TFileName nts.ntuple.digCalo.root -n 100 # Create validation histogras mu2e -c fcl/from_mcs-mockdata.fcl -S {mock} --TFileName nts.ntuple.after.root -n 100 @@ -33,4 +35,7 @@ mu2e -c fcl/from_rec-crv-kpp.fcl -S {crv_kpp} --TFileName nts.ntuple.crv-kpp.roo mu2e -c fcl/from_rec-crv-kpp_withCrvDigis.fcl -S {crv_kpp} --TFileName nts.ntuple.crv-kpp_withCrvDigis.root -n 100 # DeCalib tests -mu2e -c fcl/from_mcs-DeCalib.fcl -S {mixed} --TFileName nts.ntuple.deCalib.root -n 100 \ No newline at end of file +mu2e -c fcl/from_mcs-DeCalib.fcl -S {mixed} --TFileName nts.ntuple.deCalib.root -n 100 + +# Campaign-specific +mu2e -c fcl/from_mcs-Run1B.fcl -S {Run1B} --TFileName nts.ntuple.Run1B.root -n 100 \ No newline at end of file diff --git a/validation/datasets_Run1B.txt b/validation/datasets_Run1B.txt index 9e8c3ab..db5da2b 100644 --- a/validation/datasets_Run1B.txt +++ b/validation/datasets_Run1B.txt @@ -4,4 +4,5 @@ {mixed} mcs.mu2e.CeEndpointMix1BB-KL.Run1Bah_best_v1_4-001.art {extracted} N/A {digi} N/A -{crv_kpp} N/A \ No newline at end of file +{crv_kpp} N/A +{Run1B} mcs.mu2e.CeEndpointOnSpillTriggerable-KL.Run1Baf_best_v1_4-000.art \ No newline at end of file diff --git a/validation/test_fcls.py b/validation/test_fcls.py index 5c63a04..e285242 100644 --- a/validation/test_fcls.py +++ b/validation/test_fcls.py @@ -181,7 +181,7 @@ def main(): print(f"Total: {len(results)}, Passed: {passed}, Failed: {failed}, Skipped: {skipped}") if passed < len(results): - print("\nFailed datasets:") + print("\nFailed commands:") for command, result in results: if result == Result.FAILED: print(f" - {command}")