From 261b11235c4f397fa51f1f54d5cc8a8d8cf7f655 Mon Sep 17 00:00:00 2001
From: FASER Reco <faserrec@lxplus928.cern.ch>
Date: Sun, 3 Nov 2024 00:52:43 +0100
Subject: [PATCH] Fixes to ntuple

---
 .../Reconstruction/scripts/faser_reco.py      |   4 +-
 .../scripts/faser_ntuple_maker.py             |  12 +-
 .../NtupleDumper/src/NtupleDumperAlg.cxx      | 109 +++++++++++++++---
 .../NtupleDumper/src/NtupleDumperAlg.h        |   3 +
 4 files changed, 105 insertions(+), 23 deletions(-)

diff --git a/Control/CalypsoExample/Reconstruction/scripts/faser_reco.py b/Control/CalypsoExample/Reconstruction/scripts/faser_reco.py
index f2d32291..c5fc6d5f 100755
--- a/Control/CalypsoExample/Reconstruction/scripts/faser_reco.py
+++ b/Control/CalypsoExample/Reconstruction/scripts/faser_reco.py
@@ -188,7 +188,9 @@ if len(args.cond):
 
 if useCKF:
     # Enable ACTS material corrections, this crashes testbeam geometries
-    configFlags.TrackingGeometry.MaterialSource = "/cvmfs/faser.cern.ch/repo/sw/database/DBRelease/current/acts/material-maps.json"
+    # Use alma-9 specific file
+    print(">>> Using alma9 specific ACTS material file! <<<")
+    configFlags.TrackingGeometry.MaterialSource = "/cvmfs/faser.cern.ch/repo/sw/database/DBRelease/current/acts/material-maps-alma9.json"
 
 # Must use original input string here, as pathlib mangles double // in path names
 configFlags.Input.Files = [ args.file_path ]
diff --git a/PhysicsAnalysis/NtupleDumper/scripts/faser_ntuple_maker.py b/PhysicsAnalysis/NtupleDumper/scripts/faser_ntuple_maker.py
index 83d6e54c..f137bc27 100755
--- a/PhysicsAnalysis/NtupleDumper/scripts/faser_ntuple_maker.py
+++ b/PhysicsAnalysis/NtupleDumper/scripts/faser_ntuple_maker.py
@@ -348,16 +348,19 @@ if args.isMC:
 else:
     acc.merge(NtupleDumperAlgCfg(configFlags, outfile, DoBlinding=(not args.unblind), OnlyBlinded=args.onlyblind, DoScintFilter = args.scintFilt, DoTrackFilter = (not args.NoTrackFilt), DoTrigFilter = args.trigFilt, StableOnly = (not args.no_stable), DoRandomFilter = args.randomTrigFilt, DoRandomOnlyFilter=args.randomOnlyTrigFilt ,**grl_kwargs))
 
+from AthenaConfiguration.ComponentFactory import CompFactory
+AthenaEventLoopMgr = CompFactory.AthenaEventLoopMgr()
+
 if not args.verbose:
-    from AthenaConfiguration.ComponentFactory import CompFactory
-    AthenaEventLoopMgr = CompFactory.AthenaEventLoopMgr()
     AthenaEventLoopMgr.EventPrintoutInterval=1000
-    acc.addService(AthenaEventLoopMgr)
 
 else:
     nd = acc.getEventAlgo("NtupleDumperAlg")
     nd.OutputLevel = VERBOSE
+    AthenaEventLoopMgr.EventPrintoutInterval=1
 
+acc.addService(AthenaEventLoopMgr)
+    
 # Hack to avoid problem with our use of MC databases when isMC = False
 if not args.isMC:
     replicaSvc = acc.getService("DBReplicaSvc")
@@ -368,11 +371,12 @@ if not args.isMC:
 
 if args.verbose:
     log.setLevel(VERBOSE)
+    acc.getService("MessageSvc").debugLimit = 100000
     acc.printConfig(withDetails=True)
     configFlags.dump()
 else:
     log.setLevel(INFO)
-
+    
 acc.getService("MessageSvc").Format = "% F%40W%S%7W%R%T %0W%M"
 
 # Execute and finish
diff --git a/PhysicsAnalysis/NtupleDumper/src/NtupleDumperAlg.cxx b/PhysicsAnalysis/NtupleDumper/src/NtupleDumperAlg.cxx
index d964b1d2..02c4a266 100644
--- a/PhysicsAnalysis/NtupleDumper/src/NtupleDumperAlg.cxx
+++ b/PhysicsAnalysis/NtupleDumper/src/NtupleDumperAlg.cxx
@@ -47,25 +47,32 @@ void NtupleDumperAlg::addBranch(const std::string &name,
   m_tree->Branch(name.c_str(),var,(name+"/I").c_str());
 }
 
-// Have to declare this cost to call during execute
-void NtupleDumperAlg::defineWaveBranches() const {
+std::map<std::string, std::list<int>>&
+NtupleDumperAlg::getChannelMap() const {
 
-  ATH_MSG_DEBUG("defineWaveBranches called");
-  
   // Use waveform map to find all defined waveform channels
   auto mapping = m_mappingTool->getCableMapping();
   ATH_MSG_DEBUG("Cable mapping contains " << mapping.size() << " entries");
 
   // mapping is std::map<int, std::pair<std::string, Identifier> >
   // use this to fill my own map of channel lists keyed by type
-
-  std::map<std::string, std::list<int>> wave_map;
+  static std::map<std::string, std::list<int>> wave_map;
 
   for (const auto& [key, value] : mapping) {
     wave_map[value.first].push_back(key);
     ATH_MSG_DEBUG("Found mapping " << value.first << " chan " << key);
   }
 
+  return wave_map;
+}
+
+// Have to declare this cost to call during execute
+void NtupleDumperAlg::defineWaveBranches() const {
+
+  ATH_MSG_DEBUG("defineWaveBranches called");
+
+  auto wave_map = getChannelMap();
+  
   // Now go through found types and define ntuple entries
   // Keys are defined in cable map and used by RawWaveformDecoder
   for (const auto& [key, value] : wave_map) {
@@ -574,6 +581,10 @@ StatusCode NtupleDumperAlg::initialize()
     ATH_MSG_INFO("Blinding will NOT be enforced for real data.");
   }
 
+  // Make sure charge histogram pointers are empty
+  for (unsigned int chan = 0; chan<max_chan; chan++)
+    m_HistRandomCharge[chan] = NULL;
+  
   return StatusCode::SUCCESS;
 }
 
@@ -593,7 +604,6 @@ StatusCode NtupleDumperAlg::execute(const EventContext &ctx) const
   if (truthEventContainer.isValid() && truthEventContainer->size() > 0)
   {
     isMC = true;
-
   }
 
   SG::ReadHandle<McEventCollection> mcEventContainer {m_mcEventContainer, ctx};
@@ -732,8 +742,10 @@ StatusCode NtupleDumperAlg::execute(const EventContext &ctx) const
       // Fill histograms
       for (unsigned int chan = 0; chan<max_chan; chan++) {
 	// Only fill histograms that have been defined
-	if (m_HistRandomCharge[chan])
+	if (m_HistRandomCharge[chan]) {
+	  ATH_MSG_DEBUG("Filling random charge histogram chan= " << chan);
 	  m_HistRandomCharge[chan]->Fill(m_wave_raw_charge[chan]);
+	}
       }
     }
 
@@ -770,18 +782,81 @@ StatusCode NtupleDumperAlg::execute(const EventContext &ctx) const
 
   }
 
+
     if (m_doScintFilter) {
+      // Get channel mapping
+      auto wave_map = getChannelMap();
+
       // filter events, but use waveform peak cuts instead of triggers, as triggers could miss signals slightly out of time
       // digitizer channels described here: https://twiki.cern.ch/twiki/bin/viewauth/FASER/CaloScintillator
-      bool calo_trig = (m_wave_raw_peak[0] > 3.0 || m_wave_raw_peak[1] > 3.0 || m_wave_raw_peak[2] > 3.0 || m_wave_raw_peak[3] > 3.0);
-      bool vetoNu_trig = (m_wave_raw_peak[4] > 25.0 && m_wave_raw_peak[5] > 25.0);
-      bool vetoSt2_trig = (m_wave_raw_peak[6] > 25.0 && m_wave_raw_peak[7] > 25.0);
-      bool timingScint_trig = ((m_wave_raw_peak[8] > 25.0 && m_wave_raw_peak[9] > 25.0) || (m_wave_raw_peak[10] > 25.0 && m_wave_raw_peak[11] > 25.0));
-      bool preshower_trig = (m_wave_raw_peak[12] > 3.0 && m_wave_raw_peak[13] > 3.0);
-      bool vetoSt1_trig = (m_wave_raw_peak[14] > 25.0);
+      // Make calorimeter trigger, use CaloHi if it exists
+      bool calo_trig = false;
+      if (wave_map.contains(std::string("calo2"))) {
+	  for (auto chan : wave_map[std::string("calo2")]) {
+	    calo_trig |= m_wave_raw_peak[chan] > 3.0;
+	  }
+      }
+      else if (wave_map.contains(std::string("calo"))) {
+	  for (auto chan : wave_map[std::string("calo")]) {
+	    calo_trig |= m_wave_raw_peak[chan] > 3.0;
+	  }
+      }
 
-      bool veto_OR_trig = (vetoNu_trig || vetoSt1_trig || vetoSt2_trig);
+      // VetoNu trigger
+      bool vetoNu_trig = true;
+      if (wave_map.contains(std::string("vetonu"))) {
+	  for (auto chan : wave_map[std::string("vetonu")]) {
+	    vetoNu_trig &= m_wave_raw_peak[chan] > 25.0;
+	  }
+      } else {
+	vetoNu_trig = false;
+      }
 
+      // Veto Station 2
+      bool vetoSt1_trig = true;
+      bool vetoSt2_trig = true;
+      if (wave_map.contains(std::string("veto"))) {
+	int ncount = 0; 
+	for (auto chan : wave_map[std::string("veto")]) {
+	  if (++ncount < 3) {
+	    vetoSt2_trig &= m_wave_raw_peak[chan] > 25.0;
+	  } else {
+	    vetoSt1_trig &= m_wave_raw_peak[chan] > 25.0;
+	  }
+	}
+      } else {
+	vetoSt1_trig = false;
+	vetoSt2_trig = false;
+      }
+      bool veto_OR_trig = vetoNu_trig || vetoSt1_trig || vetoSt2_trig;
+      
+      // Timing layer (either top or bottom)      
+      bool timingScint_trig  = true;
+      bool timingScint_trig1 = true;
+      bool timingScint_trig2 = true;
+      if (wave_map.contains(std::string("trigger"))) {
+	int ncount = 0;
+	for (auto chan : wave_map[std::string("trigger")]) {
+	  if (++ncount < 3) {
+	    timingScint_trig1 &= m_wave_raw_peak[chan] > 25.0;
+	  } else {
+	    timingScint_trig2 &= m_wave_raw_peak[chan] > 25.0;
+	  }
+	}
+	timingScint_trig = timingScint_trig1 || timingScint_trig2;
+      } else {
+	timingScint_trig = false;
+      }
+      
+      bool preshower_trig = true;
+      if (wave_map.contains(std::string("preshower"))) {
+	for (auto chan : wave_map[std::string("preshower")]) {
+	  preshower_trig &= m_wave_raw_peak[chan] > 3.0;
+	}
+      } else {
+	preshower_trig = false;
+      }
+      
       bool passes_ScintFilter = false;
       if (calo_trig) {
         passes_ScintFilter = true;
@@ -1052,7 +1127,6 @@ StatusCode NtupleDumperAlg::execute(const EventContext &ctx) const
     m_calo_total_E_EM_fudged = m_calo_total_E_EM_fudged * m_caloMC_FudgeFactor;
   }
 
-
   // load in calibrated preshower container
   SG::ReadHandle<xAOD::CalorimeterHitContainer> preshowerCalibratedContainer { m_preshowerCalibratedContainer, ctx };
   ATH_CHECK(preshowerCalibratedContainer.isValid());
@@ -1066,8 +1140,7 @@ StatusCode NtupleDumperAlg::execute(const EventContext &ctx) const
 
     ATH_MSG_DEBUG("Calibrated preshower: ch is " << ch << ", edep is " << hit->E_dep() << ", E_EM is " << hit->E_EM() << ", Nmip is " << hit->Nmip() << ", fit_to_raw_ratio is " << hit->fit_to_raw_ratio());
   }
- 
-  
+
   // enforce blinding such that events that miss the veto layers and have a large calo signal are skipped and not in the output root file
   // Only blind colliding BCIDs (+/- 1)
   bool blinded_event = false;
diff --git a/PhysicsAnalysis/NtupleDumper/src/NtupleDumperAlg.h b/PhysicsAnalysis/NtupleDumper/src/NtupleDumperAlg.h
index c5051ae7..85d36d67 100644
--- a/PhysicsAnalysis/NtupleDumper/src/NtupleDumperAlg.h
+++ b/PhysicsAnalysis/NtupleDumper/src/NtupleDumperAlg.h
@@ -71,6 +71,9 @@ private:
   void addCalibratedBranches(const std::string &name, int nchannels, int first);
   double radius(const Acts::Vector3 &position) const;
 
+  // Return map with string as key and list<int> as value
+  std::map<std::string, std::list<int>>& getChannelMap() const;
+
   ServiceHandle <ITHistSvc> m_histSvc;
 
   SG::ReadHandleKey<xAOD::TruthEventContainer> m_truthEventContainer { this, "EventContainer", "TruthEvents", "Truth event container name." };
-- 
GitLab