From 5b1e1e91d15d7488222f733d3b7e39d37e47d3c3 Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Wed, 6 Dec 2023 11:48:11 +0100
Subject: [PATCH] Add tof to waveform times

---
 Calorimeter/CaloDigiAlgs/CMakeLists.txt       |   2 +-
 .../CaloDigiAlgs/python/CaloDigiAlgsConfig.py |   3 +
 .../CaloDigiAlgs/src/CaloWaveformDigiAlg.cxx  | 223 +++++++++++++++---
 .../CaloDigiAlgs/src/CaloWaveformDigiAlg.h    |  10 +
 .../Digitization/scripts/faser_digi.py        |   6 +-
 .../Digitization/scripts/faser_digi_merge.py  |   6 +-
 Scintillator/ScintDigiAlgs/CMakeLists.txt     |   2 +-
 .../python/ScintDigiAlgsConfig.py             |  14 +-
 .../src/ScintWaveformDigiAlg.cxx              | 142 ++++++++---
 .../ScintDigiAlgs/src/ScintWaveformDigiAlg.h  |   6 +-
 .../WaveDigiTools/IWaveformDigitisationTool.h |   6 +-
 .../IWaveformDigitisationTool.icc             |   3 +-
 .../src/WaveformDigitisationTool.cxx          |  18 +-
 .../src/WaveformDigitisationTool.h            |  17 ++
 14 files changed, 367 insertions(+), 91 deletions(-)

diff --git a/Calorimeter/CaloDigiAlgs/CMakeLists.txt b/Calorimeter/CaloDigiAlgs/CMakeLists.txt
index 89d20eae8..baa67edad 100644
--- a/Calorimeter/CaloDigiAlgs/CMakeLists.txt
+++ b/Calorimeter/CaloDigiAlgs/CMakeLists.txt
@@ -11,7 +11,7 @@ atlas_add_component( CaloDigiAlgs
                      src/components/*.cxx
                      LINK_LIBRARIES AthenaBaseComps Identifier FaserCaloIdentifier  
 		     WaveformConditionsToolsLib StoreGateLib WaveRawEvent 
-		     FaserCaloSimEvent WaveDigiToolsLib)
+		     CaloReadoutGeometry FaserCaloSimEvent WaveDigiToolsLib)
 
 atlas_install_python_modules( python/*.py )
 
diff --git a/Calorimeter/CaloDigiAlgs/python/CaloDigiAlgsConfig.py b/Calorimeter/CaloDigiAlgs/python/CaloDigiAlgsConfig.py
index 85b56fe61..9f5b1355d 100644
--- a/Calorimeter/CaloDigiAlgs/python/CaloDigiAlgsConfig.py
+++ b/Calorimeter/CaloDigiAlgs/python/CaloDigiAlgsConfig.py
@@ -44,6 +44,9 @@ def CaloWaveformDigiCfg(flags, name="CaloWaveformDigiAlg", **kwargs):
 
     acc = ComponentAccumulator()
 
+    # Need this later
+    #adv_time = kwargs.pop('advancedTiming')
+
     tool = CompFactory.WaveformDigitisationTool(name="CaloWaveformDigtisationTool")
     kwargs.setdefault("WaveformDigitisationTool", tool)
 
diff --git a/Calorimeter/CaloDigiAlgs/src/CaloWaveformDigiAlg.cxx b/Calorimeter/CaloDigiAlgs/src/CaloWaveformDigiAlg.cxx
index c3f5313c0..7e9b6f485 100644
--- a/Calorimeter/CaloDigiAlgs/src/CaloWaveformDigiAlg.cxx
+++ b/Calorimeter/CaloDigiAlgs/src/CaloWaveformDigiAlg.cxx
@@ -1,9 +1,12 @@
 #include "CaloWaveformDigiAlg.h"
 
-#include "Identifier/Identifier.h"
-
 #include "FaserCaloSimEvent/CaloHitIdHelper.h"
 
+#include "CaloReadoutGeometry/EcalDetectorManager.h"
+
+#include "CaloReadoutGeometry/CaloDetectorElement.h"
+#include "GaudiKernel/PhysicalConstants.h"
+
 #include <map>
 #include <utility>
 #include <cmath>
@@ -95,49 +98,178 @@ CaloWaveformDigiAlg::execute(const EventContext& ctx) const {
     // Also save the baseline parameters
     m_base_mean = m_digiCondTool->base_mean(ctx); 
     m_base_rms  = m_digiCondTool->base_rms(ctx); 
+
+    // And print out our timing simulation
+    if (m_advancedTiming) {
+      ATH_MSG_INFO("Using improved digitization timing");
+    } else {
+      ATH_MSG_INFO("Using simple digitization timing");
+    }
+  }
+
+  // Create TOF values
+  if (!m_time_of_flight.size()) {
+
+    // Detector manager to find global location
+    const CaloDD::EcalDetectorManager* detman;
+    ATH_CHECK(detStore()->retrieve(detman, "Ecal"));
+    m_time_of_flight = create_tof_map(m_ecalID, detman);
+
   }
 
   // Create structure to store pulse for each channel
-  std::map<Identifier, std::vector<uint16_t>> waveforms = m_digiTool->create_waveform_map(m_ecalID);
+  std::map<Identifier, std::vector<uint16_t>> waveforms;
+
+  // This gives us empty vectors
+  waveforms = m_digiTool->create_waveform_map(m_ecalID);
+
+  // Identifiers we have seen hits from
+  std::set<Identifier> id_set;
 
   // Sum energy for each channel (i.e. identifier)
-  std::map<unsigned int, float> esum;  
+  std::map<Identifier, float> esum;  
+
+  // Histograms of E vs. t, make sure this is empty
+  m_digiTool->clear_evst_hist(m_evst_hist);
+
   for (const auto& hit : *caloHitHandle) { 
-    esum[hit.identify()] += hit.energyLoss();
-  }
 
-  // Loop over time samples
-  for (const auto& tk : m_timekernel) {
-    std::map<unsigned int, float> counts;    
+    float tof;
 
-    // Convolve hit energy with evaluated kernel and sum for each hit id (i.e. channel)
-    //for (const auto& hit : *caloHitHandle) { 
-    //  counts[hit.identify()] += tk * hit.energyLoss();
-    //}
+    Identifier id = CaloHitIdHelper::GetHelper()->getIdentifier(hit.identify());
+    //id = hit.identify();
+    id_set.insert(id);
+    esum[id] += hit.energyLoss();
+    tof = m_time_of_flight[id];
 
-    // Convolve summed energy with evaluated kernel for each hit id (i.e. channel)
-    for (const auto& e : esum) {
-      counts[e.first] = tk * e.second;
-    }
+    m_digiTool->fill_evst_hist(m_evst_hist, id, hit.meanTime()-tof, hit.energyLoss());
 
-    // Subtract count from basleine and add result to correct waveform vector
-    for (const auto& c : counts) {
+    // Print out hit times
+    ATH_MSG_DEBUG("Scint Hit: " << id << " E: " << hit.energyLoss() 
+		  << " t: " << hit.meanTime()
+		  << " x: " << hit.localStartPosition().x()
+		  << " y: " << hit.localStartPosition().y()
+		  << " z: " << hit.localStartPosition().z()
+		  << " tof: " << tof
+		  );
 
-      float baseline = m_digiTool->generate_baseline(m_base_mean, m_base_rms);
-      int value = std::round(baseline - c.second);
+  } // Done with loop over hits
 
-      if (value < 0) {
-	ATH_MSG_WARNING("Found pulse " << c.second << " larger than baseline " << c.first);
-	value = 0; // Protect against scaling signal above baseline
+  // Choose how we construct the waveform
+  if (m_advancedTiming) {
+
+    // Loop over seen identifiers
+    for (const auto& id : id_set) {
+
+      // Convolve histogram with time kernel
+
+      // Use this vector to sum our values
+      std::vector<double> dwave;
+
+      // Loop over bins and fill with baseline values
+      int i = m_digiTool->digitizer_samples();
+      while(i--) { // Use while to avoid unused variable warning
+
+	// Push back baseline value so we can index this
+	float baseline = m_digiTool->generate_baseline(m_base_mean, m_base_rms);
+	// vector starts empty, push back each baseline element here
+	dwave.push_back(baseline);
+      } // End of loop over bins
+
+      // Get the histogram
+      auto it = m_evst_hist.find(id);
+      if (it == m_evst_hist.end()) {
+	ATH_MSG_WARNING("Didn't find EvsT hist for id " << id <<"!");
+	continue;
       }
 
-      // Convert hit id to Identifier and store 
-      Identifier id = CaloHitIdHelper::GetHelper()->getIdentifier(c.first);
-      waveforms[id].push_back(value);
+      // Histogram of E vs. t filled above
+      auto h = it->second;
+
+      // Now, do it again and convolute any signals with the time kernal
+      for(unsigned int ibin=1; int(ibin) <= h->GetNbinsX(); ibin++) {
+
+	float value = h->GetBinContent(ibin);
+
+	// If bin is empty, move on
+	if (value <= 0.) continue;
+
+	// Location of histogram bin in digitizer array
+	// Must divide by oversampling 
+	unsigned int jbin = (ibin-1)/m_digiTool->over_samples();
+
+	// Histogram doesn't start at t=0, must subtract pre_samples
+	int ik = jbin - m_digiTool->pre_samples();
+
+	// Convolute the histogram value with our time kernel
+	for (const auto& tk : m_timekernel) {
+
+	  // Don't write off the end
+	  if (ik < 0) {
+	    ik++;
+	    continue;
+	  }
+
+	  if (ik >= int(dwave.size())) break;
+ 
+	  dwave[ik] -= (value * tk);
+
+	  ik++;  // Iterate
+	}
+      } // End of loop over histogram bins
+
+      // Finally protect against underflows and 'digitize' the values
+      for(unsigned int i=0; i<dwave.size(); i++) {
+
+	// waveforms is initialized empty, must push back each element here
+	if (dwave[i] < 0.) {
+	  waveforms[id].push_back(0);
+	} else {
+	  waveforms[id].push_back(std::round(dwave[i]));
+	}
+
+	// Debug weird overflow values
+	// if (waveforms[id][i] > m_base_mean + 5*m_base_rms) {
+	//  ATH_MSG_WARNING("Found waveform id " << id << " bin " << i << " value " << waveforms[id][i] << "!");
+	// }
+
+      }
+
+      // Check what we have done
+      ATH_MSG_DEBUG("Waveform for ID " << id);
+      for(unsigned int i=400; i<450; i++) 
+	ATH_MSG_DEBUG(2*i << "ns -> " << waveforms[id][i]);
+
+    } // End of loop over ids
+
+  } else {
+
+    // Loop over time samples
+    for (const auto& tk : m_timekernel) {
+      std::map<Identifier, float> counts;    
+
+      // Convolve summed energy with evaluated kernel for each hit id (i.e. channel)
+      for (const auto& e : esum) {
+	counts[e.first] = tk * e.second;
+      }
+
+      // Subtract count from basleine and add result to correct waveform vector
+      for (const auto& c : counts) {
+
+	float baseline = m_digiTool->generate_baseline(m_base_mean, m_base_rms);
+	int value = std::round(baseline - c.second);
+
+	if (value < 0) {
+	  ATH_MSG_WARNING("Found pulse " << c.second << " larger than baseline " << c.first);
+	  value = 0; // Protect against scaling signal above baseline
+	}
+
+	// Convert hit id to Identifier and store 
+	waveforms[c.first].push_back(value);
+      }
     }
   }
 
-
   // This is a bit of a hack to make sure all waveforms have
   // at least baseline entries.  Should really add this to the 
   // logic above
@@ -147,7 +279,7 @@ CaloWaveformDigiAlg::execute(const EventContext& ctx) const {
     // Waveform was empty, fill with baseline
     int channel = m_mappingTool->getChannelMapping(w.first);
     ATH_MSG_DEBUG("Writing baseline into empty waveform in channel "<< channel);
-    int i = m_digiTool->nsamples();
+    int i = m_digiTool->digitizer_samples();
     while(i--) {  // Use while to avoid unused variable warning with for
       int baseline = m_digiTool->generate_baseline(m_base_mean, m_base_rms);
       waveforms[w.first].push_back(baseline);
@@ -158,13 +290,13 @@ CaloWaveformDigiAlg::execute(const EventContext& ctx) const {
   //m_chrono->chronoStart("Write");
 
   // Loop over wavefrom vectors to make and store waveform
-  unsigned int nsamples = m_digiTool->nsamples();
+  unsigned int digitizer_samples = m_digiTool->digitizer_samples();
   for (const auto& w : waveforms) {
     RawWaveform* wfm = new RawWaveform();
     wfm->setWaveform(0, w.second);
     wfm->setIdentifier(w.first);
     wfm->setChannel(m_mappingTool->getChannelMapping(w.first));
-    wfm->setSamples(nsamples);
+    wfm->setSamples(digitizer_samples);
     waveformContainerHandle->push_back(wfm);
   }
 
@@ -172,5 +304,34 @@ CaloWaveformDigiAlg::execute(const EventContext& ctx) const {
 
   ATH_MSG_DEBUG("WaveformsHitContainer " << waveformContainerHandle.name() << "' filled with "<< waveformContainerHandle->size() <<" items");
 
+  // Debugging printout 
+  for (auto it : m_evst_hist) {
+    ATH_MSG_DEBUG("Nonzero bins Evst hist id = " << it.first);
+    for (unsigned int ibin=0; int(ibin) <= it.second->GetNbinsX(); ibin++) {
+      if (it.second->GetBinContent(ibin) == 0) continue;
+      ATH_MSG_DEBUG(" bin: " << ibin << " t:" << it.second->GetBinCenter(ibin) << " val: " << it.second->GetBinContent(ibin));
+    }
+  }
+
+  // Cleanup any histograms we made
+  m_digiTool->clear_evst_hist(m_evst_hist);
+
   return StatusCode::SUCCESS;
 }
+
+template <class ID, class DM>
+std::map<Identifier, float> 
+CaloWaveformDigiAlg::create_tof_map(const ID* idHelper, const DM* detman) const {
+
+  std::map<Identifier, float> time_of_flight;
+  for (auto itr = idHelper->pmt_begin(); itr != idHelper->pmt_end(); ++itr) {
+    const ExpandedIdentifier& extId = *itr;
+    Identifier pmtid = idHelper->pmt_id(extId);
+
+    CaloDD::CaloDetectorElement* element = detman->getDetectorElement(pmtid);
+    time_of_flight[pmtid] = element->center().z() / CLHEP::c_light;
+
+    ATH_MSG_DEBUG("Found TOF for " << pmtid << " = " << time_of_flight[pmtid]);
+  }
+  return time_of_flight;  
+}
diff --git a/Calorimeter/CaloDigiAlgs/src/CaloWaveformDigiAlg.h b/Calorimeter/CaloDigiAlgs/src/CaloWaveformDigiAlg.h
index 7ee25a271..c8d381ec2 100644
--- a/Calorimeter/CaloDigiAlgs/src/CaloWaveformDigiAlg.h
+++ b/Calorimeter/CaloDigiAlgs/src/CaloWaveformDigiAlg.h
@@ -23,6 +23,7 @@
 
 // Helpers
 #include "FaserCaloIdentifier/EcalID.h"
+#include "Identifier/Identifier.h"
 
 // ROOT
 #include "TF1.h"
@@ -45,6 +46,10 @@ class CaloWaveformDigiAlg: public AthReentrantAlgorithm {
   virtual StatusCode finalize() override;
   //@}
 
+  //
+  // Simulate detailed timing of waveforms
+  BooleanProperty m_advancedTiming{this, "AdvancedTiming", true};
+
  private:
 
   /** @name Disallow default instantiation, copy, assignment */
@@ -63,6 +68,8 @@ class CaloWaveformDigiAlg: public AthReentrantAlgorithm {
   //@{
   mutable TF1*                            m_kernel;
   mutable std::vector<float>              m_timekernel;
+  mutable EvstHistMap                     m_evst_hist;
+  mutable std::map<Identifier, float>     m_time_of_flight; 
   //@}
 
   /// Detector ID helper
@@ -105,6 +112,9 @@ class CaloWaveformDigiAlg: public AthReentrantAlgorithm {
     {this, "WaveformContainerKey", ""};
   //@}
 
+  template <class ID, class DM>
+  std::map<Identifier, float> create_tof_map(const ID* idHelper, const DM* detman) const;
+
 };
 
 
diff --git a/Control/CalypsoExample/Digitization/scripts/faser_digi.py b/Control/CalypsoExample/Digitization/scripts/faser_digi.py
index 0da1361ce..81a097617 100755
--- a/Control/CalypsoExample/Digitization/scripts/faser_digi.py
+++ b/Control/CalypsoExample/Digitization/scripts/faser_digi.py
@@ -27,6 +27,8 @@ parser.add_argument("-t", "--tag", default="",
                     help="Specify digi tag (to append to output filename)")
 parser.add_argument("--subtractTime", type=float, default=-999.,
                     help="Subtract time parameter for SCT RDOs")
+parser.add_argument("--simpleTiming", action="store_true",
+                    help="Use simple waveform time digitization")
 parser.add_argument("--digiTag", default="",
                     help="Specify tag for waveform digi folder")
 parser.add_argument("--short", default="",
@@ -169,10 +171,10 @@ pualg.PileUpTools['FaserSCT_DigitizationTool'].SurfaceChargesGenerator.SubtractT
 
 # Pass something to set folder tag
 from CaloDigiAlgs.CaloDigiAlgsConfig import CaloWaveformDigitizationCfg
-acc.merge(CaloWaveformDigitizationCfg(ConfigFlags, digiTag=args.digiTag))
+acc.merge(CaloWaveformDigitizationCfg(ConfigFlags, digiTag=args.digiTag, AdvancedTiming=(not args.simpleTiming)))
 
 from ScintDigiAlgs.ScintDigiAlgsConfig import ScintWaveformDigitizationCfg
-acc.merge(ScintWaveformDigitizationCfg(ConfigFlags, digiTag=args.digiTag))
+acc.merge(ScintWaveformDigitizationCfg(ConfigFlags, digiTag=args.digiTag, AdvancedTiming=(not args.simpleTiming)))
 
 # Configure verbosity    
 if args.verbose:
diff --git a/Control/CalypsoExample/Digitization/scripts/faser_digi_merge.py b/Control/CalypsoExample/Digitization/scripts/faser_digi_merge.py
index b945ffbbd..9d931d3d2 100755
--- a/Control/CalypsoExample/Digitization/scripts/faser_digi_merge.py
+++ b/Control/CalypsoExample/Digitization/scripts/faser_digi_merge.py
@@ -35,6 +35,8 @@ parser.add_argument("-t", "--tag", default="",
                     help="Specify digi tag (to append to output filename)")
 parser.add_argument("--subtractTime", type=float, default=-999.,
                     help="Subtract time parameter for SCT RDOs")
+parser.add_argument("--simpleTiming", action="store_true",
+                    help="Use simple waveform time digitization")
 parser.add_argument("--digiTag", default="",
                     help="Specify tag for waveform digi folder")
 parser.add_argument("--short", default="",
@@ -239,10 +241,10 @@ pualg.PileUpTools['FaserSCT_DigitizationTool'].SurfaceChargesGenerator.SubtractT
 
 # Pass something to set folder tag
 from CaloDigiAlgs.CaloDigiAlgsConfig import CaloWaveformDigitizationCfg
-acc.merge(CaloWaveformDigitizationCfg(ConfigFlags, digiTag=args.digiTag))
+acc.merge(CaloWaveformDigitizationCfg(ConfigFlags, digiTag=args.digiTag, AdvancedTiming=(not args.simpleTiming)))
 
 from ScintDigiAlgs.ScintDigiAlgsConfig import ScintWaveformDigitizationCfg
-acc.merge(ScintWaveformDigitizationCfg(ConfigFlags, digiTag=args.digiTag))
+acc.merge(ScintWaveformDigitizationCfg(ConfigFlags, digiTag=args.digiTag, AdvancedTiming=(not args.simpleTiming)))
 
 # Configure verbosity    
 if args.verbose:
diff --git a/Scintillator/ScintDigiAlgs/CMakeLists.txt b/Scintillator/ScintDigiAlgs/CMakeLists.txt
index 5c1874e25..31950e073 100644
--- a/Scintillator/ScintDigiAlgs/CMakeLists.txt
+++ b/Scintillator/ScintDigiAlgs/CMakeLists.txt
@@ -11,7 +11,7 @@ atlas_add_component( ScintDigiAlgs
                      src/components/*.cxx
                      LINK_LIBRARIES AthenaBaseComps Identifier ScintIdentifier 
 		     WaveformConditionsToolsLib StoreGateLib WaveRawEvent 
-		     ScintSimEvent WaveDigiToolsLib)
+		     ScintReadoutGeometry ScintSimEvent WaveDigiToolsLib)
 
 atlas_install_python_modules( python/*.py )
 
diff --git a/Scintillator/ScintDigiAlgs/python/ScintDigiAlgsConfig.py b/Scintillator/ScintDigiAlgs/python/ScintDigiAlgsConfig.py
index 538f8d2a3..5ed331105 100644
--- a/Scintillator/ScintDigiAlgs/python/ScintDigiAlgsConfig.py
+++ b/Scintillator/ScintDigiAlgs/python/ScintDigiAlgsConfig.py
@@ -20,13 +20,13 @@ def ScintWaveformDigitizationCfg(flags, **kwargs):
     kwargs.pop("digiTag")
 
     if "TB" in flags.GeoModel.FaserVersion:
-        acc.merge(ScintWaveformDigiCfg(flags, "VetoWaveformDigiAlg", "Veto"))
-        acc.merge(ScintWaveformDigiCfg(flags, "PreshowerWaveformDigiAlg", "Preshower"))
+        acc.merge(ScintWaveformDigiCfg(flags, "VetoWaveformDigiAlg", "Veto", **kwargs))
+        acc.merge(ScintWaveformDigiCfg(flags, "PreshowerWaveformDigiAlg", "Preshower", **kwargs))
     else:
-        acc.merge(ScintWaveformDigiCfg(flags, "TriggerWaveformDigiAlg", "Trigger"))
-        acc.merge(ScintWaveformDigiCfg(flags, "VetoWaveformDigiAlg", "Veto"))
-        acc.merge(ScintWaveformDigiCfg(flags, "VetoNuWaveformDigiAlg", "VetoNu"))
-        acc.merge(ScintWaveformDigiCfg(flags, "PreshowerWaveformDigiAlg", "Preshower"))
+        acc.merge(ScintWaveformDigiCfg(flags, "TriggerWaveformDigiAlg", "Trigger", **kwargs))
+        acc.merge(ScintWaveformDigiCfg(flags, "VetoWaveformDigiAlg", "Veto", **kwargs))
+        acc.merge(ScintWaveformDigiCfg(flags, "VetoNuWaveformDigiAlg", "VetoNu", **kwargs))
+        acc.merge(ScintWaveformDigiCfg(flags, "PreshowerWaveformDigiAlg", "Preshower", **kwargs))
 
     acc.merge(ScintWaveformDigitizationOutputCfg(flags))
     acc.merge(WaveformCableMappingCfg(flags))
@@ -39,7 +39,7 @@ def ScintWaveformDigiCfg(flags, name="ScintWaveformDigiAlg", source="", **kwargs
 
     acc = ComponentAccumulator()
 
-    tool = CompFactory.WaveformDigitisationTool(name=source+"WaveformDigtisationTool", **kwargs)
+    tool = CompFactory.WaveformDigitisationTool(name=source+"WaveformDigtisationTool")
     kwargs.setdefault("WaveformDigitisationTool", tool)
     
     kwargs.setdefault("ScintHitContainerKey", source+"Hits")
diff --git a/Scintillator/ScintDigiAlgs/src/ScintWaveformDigiAlg.cxx b/Scintillator/ScintDigiAlgs/src/ScintWaveformDigiAlg.cxx
index 33bd45d7d..c007f61ba 100644
--- a/Scintillator/ScintDigiAlgs/src/ScintWaveformDigiAlg.cxx
+++ b/Scintillator/ScintDigiAlgs/src/ScintWaveformDigiAlg.cxx
@@ -1,6 +1,13 @@
 #include "ScintWaveformDigiAlg.h"
 
-#include "ScintSimEvent/ScintHitIdHelper.h"
+#include "ScintReadoutGeometry/VetoDetectorManager.h"
+#include "ScintReadoutGeometry/VetoNuDetectorManager.h"
+#include "ScintReadoutGeometry/TriggerDetectorManager.h"
+#include "ScintReadoutGeometry/PreshowerDetectorManager.h"
+
+#include "ScintReadoutGeometry/ScintDetectorElement.h"
+
+#include "GaudiKernel/PhysicalConstants.h"
 
 #include <map>
 #include <cmath>
@@ -103,14 +110,13 @@ ScintWaveformDigiAlg::execute(const EventContext& ctx) const {
       ATH_MSG_INFO("Using simple digitization timing");
     }
   }
-  
+
   // Create structure to store pulse for each channel
   std::map<Identifier, std::vector<uint16_t>> waveforms;
-
-  // This gives us empty vectors
+  
   auto first = *scintHitHandle->begin();
   if (first.isVeto()) {
-    waveforms = m_digiTool->create_waveform_map(m_vetoID);
+    waveforms = m_digiTool->create_waveform_map(m_vetoID); 
   } else if (first.isVetoNu()) {
     waveforms = m_digiTool->create_waveform_map(m_vetoNuID); 
   } else if (first.isTrigger()) {
@@ -119,7 +125,35 @@ ScintWaveformDigiAlg::execute(const EventContext& ctx) const {
     waveforms = m_digiTool->create_waveform_map(m_preshowerID);
   }
 
+  // Create TOF values
+  if (!m_time_of_flight.size()) {
+    
+    // Detector manager to find global location
+    if (first.isVeto()) {
+      const ScintDD::VetoDetectorManager* detman;
+      ATH_CHECK(detStore()->retrieve(detman, "Veto"));
+      m_time_of_flight = create_tof_map(m_vetoID, detman);
+
+    } else if (first.isVetoNu()) {
+      const ScintDD::VetoNuDetectorManager* detman;
+      ATH_CHECK(detStore()->retrieve(detman, "VetoNu"));
+      m_time_of_flight = create_tof_map(m_vetoNuID, detman);
+
+    } else if (first.isTrigger()) {
+      const ScintDD::TriggerDetectorManager* detman;
+      ATH_CHECK(detStore()->retrieve(detman, "Trigger"));
+      m_time_of_flight = create_tof_map(m_triggerID, detman);
+
+    } else if (first.isPreshower()) {
+      const ScintDD::PreshowerDetectorManager* detman;
+      ATH_CHECK(detStore()->retrieve(detman, "Preshower"));
+      m_time_of_flight = create_tof_map(m_preshowerID, detman);
+
+    }
+  }
+
   // Identifiers we have seen hits from
+  Identifier id;
   std::set<Identifier> id_set;
 
   // Sum energy for each channel (i.e. identifier)
@@ -128,12 +162,11 @@ ScintWaveformDigiAlg::execute(const EventContext& ctx) const {
   // Histograms of E vs. t, make sure this is empty
   m_digiTool->clear_evst_hist(m_evst_hist);
 
-  Identifier id;
-
   // Loop over all hits and make histograms of E vs. t for each channel
   for (const auto& hit : *scintHitHandle) { 
 
     float dtime; // Time offset due to scint. geometry
+    float tof;
 
     // Trigger plane, horizontal readout
     if (first.isTrigger()) {
@@ -148,13 +181,16 @@ ScintWaveformDigiAlg::execute(const EventContext& ctx) const {
       id = m_triggerID->pmt_id(plate_id, 0); // ID for PMT 0
       id_set.insert(id);
       esum[id] += hit.energyLoss();
-      m_digiTool->fill_evst_hist(m_evst_hist, id, hit.meanTime()+dtime, hit.energyLoss());
-      id_set.insert(id);
+      tof = m_time_of_flight[id];
+
+      m_digiTool->fill_evst_hist(m_evst_hist, id, hit.meanTime()+dtime-tof, hit.energyLoss());
 
       id = m_triggerID->pmt_id(plate_id, 1); // ID for PMT 1
       id_set.insert(id);
       esum[id] += hit.energyLoss();
-      m_digiTool->fill_evst_hist(m_evst_hist, id, hit.meanTime()-dtime, hit.energyLoss());
+      tof = m_time_of_flight[id];
+
+      m_digiTool->fill_evst_hist(m_evst_hist, id, hit.meanTime()-dtime-tof, hit.energyLoss());
 
     } else {
       // All others have only 1 PMT
@@ -162,19 +198,22 @@ ScintWaveformDigiAlg::execute(const EventContext& ctx) const {
       id = hit.getIdentifier();
       id_set.insert(id);
       esum[id] += hit.energyLoss();
+      tof = m_time_of_flight[id];
 
       // +y means shorter times
       dtime = -m_digiCondTool->time_slope(ctx) * (hit.localStartPosition().y() + hit.localEndPosition().y()) / 2.;
-      m_digiTool->fill_evst_hist(m_evst_hist, id, hit.meanTime()+dtime, hit.energyLoss());  
+      m_digiTool->fill_evst_hist(m_evst_hist, id, hit.meanTime()+dtime-tof, hit.energyLoss());  
     }
 
+
     // Print out hit times
     ATH_MSG_DEBUG("Scint Hit: " << id << " E: " << hit.energyLoss() 
-		 << " t: " << hit.meanTime()
-		 << " x: " << hit.localStartPosition().x()
-		 << " y: " << hit.localStartPosition().y()
-		 << " dt: " << dtime
-		 );
+		  << " t: " << hit.meanTime()
+		  << " x: " << hit.localStartPosition().x()
+		  << " y: " << hit.localStartPosition().y()
+		  << " dt: " << dtime
+		  << " tof: " << tof
+		  );
 
   } // Done with loop over hits
 
@@ -186,43 +225,57 @@ ScintWaveformDigiAlg::execute(const EventContext& ctx) const {
 
       // Convolve histogram with time kernel
 
-      // Get the histogram
-      auto it = m_evst_hist.find(id);
-      if (it == m_evst_hist.end()) {
-	ATH_MSG_WARNING("Didn't find EvsT hist for id " << id <<"!");
-	continue;
-      }
-      auto h = it->second;
-
       // Use this vector to sum our values
       std::vector<double> dwave;
 
       // Loop over bins and fill with baseline values
-      for(unsigned int ibin=1; ibin <= h->GetNbinsX(); ibin++) {
+      int i = m_digiTool->digitizer_samples();
+      while(i--) {  // Use while to avoid unused variable warning with for
 
 	// Push back baseline value so we can index this
 	float baseline = m_digiTool->generate_baseline(m_base_mean, m_base_rms);
-	// Starts empty, push back each element here
+	// vector starts empty, push back each baseline element here
 	dwave.push_back(baseline);
-
       } // End of loop over bins
 
+      // Get the histogram
+      auto it = m_evst_hist.find(id);
+      if (it == m_evst_hist.end()) {
+	ATH_MSG_WARNING("Didn't find EvsT hist for id " << id <<"!");
+	continue;
+      }
+
+      // Histogram of E vs. t filled above
+      auto h = it->second;
+
       // Now, do it again and convolute any signals with the time kernal
-      // Because root histos start with bin=1, subtract 1 from ibin
-      for(unsigned int ibin=1; ibin <= h->GetNbinsX(); ibin++) {
+      for(unsigned int ibin=1; int(ibin) <= h->GetNbinsX(); ibin++) {
 
 	float value = h->GetBinContent(ibin);
 
 	// If bin is empty, move on
 	if (value <= 0.) continue;
 
+	// Location of histogram bin in digitizer array
+	// Must divide by oversampling 
+	unsigned int jbin = (ibin-1)/m_digiTool->over_samples();
+
+	// Histogram doesn't start at t=0, must subtract pre_samples
+	int ik = jbin - m_digiTool->pre_samples();
+	
 	// Convolute the histogram value with our time kernel
-	unsigned int ik = 0;
 	for (const auto& tk : m_timekernel) {
+
 	  // Don't write off the end
-	  if ((ibin + ik - 1) >= dwave.size()) break;
+	  if (ik < 0) {
+	    ik++;
+	    continue;
+	  }
+
+	  if (ik >= int(dwave.size())) break;
  
-	  dwave[ibin+ik-1] -= (value * tk);
+	  dwave[ik] -= (value * tk);
+
 	  ik++;  // Iterate
 	}
       } // End of loop over histogram bins
@@ -291,7 +344,7 @@ ScintWaveformDigiAlg::execute(const EventContext& ctx) const {
     // Waveform was empty, fill with baseline
     int channel = m_mappingTool->getChannelMapping(w.first);
     ATH_MSG_DEBUG("Writing baseline into empty waveform in channel "<< channel);
-    int i = m_digiTool->nsamples();
+    int i = m_digiTool->digitizer_samples();
     while(i--) {  // Use while to avoid unused variable warning with for
       float baseline = m_digiTool->generate_baseline(m_base_mean, m_base_rms);
       waveforms[w.first].push_back(std::round(baseline));
@@ -299,7 +352,7 @@ ScintWaveformDigiAlg::execute(const EventContext& ctx) const {
   }
 
   // Loop over waveform vectors to make and store raw waveform
-  unsigned int nsamples = m_digiTool->nsamples();
+  unsigned int nsamples = m_digiTool->digitizer_samples();
   for (const auto& w : waveforms) {
     RawWaveform* wfm = new RawWaveform();
     wfm->setWaveform(0, w.second);
@@ -321,9 +374,9 @@ ScintWaveformDigiAlg::execute(const EventContext& ctx) const {
   // Debugging printout 
   for (auto it : m_evst_hist) {
     ATH_MSG_DEBUG("Nonzero bins Evst hist id = " << it.first);
-    for (unsigned int ibin=0; ibin <= it.second->GetNbinsX(); ibin++) {
+    for (unsigned int ibin=0; int(ibin) <= it.second->GetNbinsX(); ibin++) {
       if (it.second->GetBinContent(ibin) == 0) continue;
-      ATH_MSG_DEBUG(" bin: " << ibin << " val: " << it.second->GetBinContent(ibin));
+      ATH_MSG_DEBUG(" bin: " << ibin << " t:" << it.second->GetBinCenter(ibin) << " val: " << it.second->GetBinContent(ibin));
     }
   }
 
@@ -334,3 +387,20 @@ ScintWaveformDigiAlg::execute(const EventContext& ctx) const {
 }
 
 
+template <class ID, class DM>
+std::map<Identifier, float> 
+ScintWaveformDigiAlg::create_tof_map(const ID* idHelper, const DM* detman) const {
+
+  std::map<Identifier, float> time_of_flight;
+  for (auto itr = idHelper->pmt_begin(); itr != idHelper->pmt_end(); ++itr) {
+    const ExpandedIdentifier& extId = *itr;
+    Identifier pmtid = idHelper->pmt_id(extId);
+
+    ScintDD::ScintDetectorElement* element = detman->getDetectorElement(pmtid);
+    time_of_flight[pmtid] = element->center().z() / CLHEP::c_light;
+
+    ATH_MSG_DEBUG("Found TOF for " << pmtid << " = " << time_of_flight[pmtid]);
+  }
+  return time_of_flight;  
+}
+
diff --git a/Scintillator/ScintDigiAlgs/src/ScintWaveformDigiAlg.h b/Scintillator/ScintDigiAlgs/src/ScintWaveformDigiAlg.h
index 7f76328a3..f439e982f 100644
--- a/Scintillator/ScintDigiAlgs/src/ScintWaveformDigiAlg.h
+++ b/Scintillator/ScintDigiAlgs/src/ScintWaveformDigiAlg.h
@@ -26,10 +26,8 @@
 #include "ScintIdentifier/VetoNuID.h"
 #include "ScintIdentifier/TriggerID.h"
 #include "ScintIdentifier/PreshowerID.h"
-#include "ScintSimEvent/ScintHitIdHelper.h"
 #include "Identifier/Identifier.h"
 
-
 // ROOT
 #include "TF1.h"
 
@@ -75,6 +73,7 @@ class ScintWaveformDigiAlg : public AthReentrantAlgorithm {
   mutable TF1*                            m_kernel;
   mutable std::vector<float>              m_timekernel;
   mutable EvstHistMap                     m_evst_hist;
+  mutable std::map<Identifier, float>     m_time_of_flight;  
   //mutable std::map<Identifier, TH1D*>     m_evst_hist;
   //@}
 
@@ -121,6 +120,9 @@ class ScintWaveformDigiAlg : public AthReentrantAlgorithm {
     {this, "WaveformContainerKey", ""};
   //@}
 
+  template <class ID, class DM>
+  std::map<Identifier, float> create_tof_map(const ID* idHelper, const DM* detman) const;
+
 };
 
 
diff --git a/Waveform/WaveDigiTools/WaveDigiTools/IWaveformDigitisationTool.h b/Waveform/WaveDigiTools/WaveDigiTools/IWaveformDigitisationTool.h
index 2009b495d..814b25cd6 100644
--- a/Waveform/WaveDigiTools/WaveDigiTools/IWaveformDigitisationTool.h
+++ b/Waveform/WaveDigiTools/WaveDigiTools/IWaveformDigitisationTool.h
@@ -60,7 +60,10 @@ public:
   std::map<Identifier, std::vector<uint16_t>> create_waveform_map(const T* idHelper) const;
 
   /// Number of time samples
-  unsigned int nsamples() const { return m_nsamples; }
+  virtual unsigned int digitizer_samples() const = 0;
+  virtual float digitizer_period() const = 0;  // in ns
+  virtual unsigned int over_samples() const = 0;
+  virtual unsigned int pre_samples() const = 0;
 
   /// Fill histograms
   virtual void fill_evst_hist(EvstHistMap& map, const Identifier& id, float time, float energy) const = 0;
@@ -73,7 +76,6 @@ private:
 
 protected:
   TRandom3*                       m_random;
-  unsigned int                    m_nsamples;
 
 };
 
diff --git a/Waveform/WaveDigiTools/WaveDigiTools/IWaveformDigitisationTool.icc b/Waveform/WaveDigiTools/WaveDigiTools/IWaveformDigitisationTool.icc
index fd50ecfcf..140e4c5eb 100644
--- a/Waveform/WaveDigiTools/WaveDigiTools/IWaveformDigitisationTool.icc
+++ b/Waveform/WaveDigiTools/WaveDigiTools/IWaveformDigitisationTool.icc
@@ -10,10 +10,9 @@ std::map<Identifier, std::vector<uint16_t>>  IWaveformDigitisationTool::create_w
     const ExpandedIdentifier& extId = *itr;
     Identifier id = idHelper->pmt_id(extId);
     waveforms[id] = std::vector<uint16_t>();
-    waveforms[id].reserve(m_nsamples);
+    waveforms[id].reserve(digitizer_samples());
   }
 
   return waveforms;
 }
 
-
diff --git a/Waveform/WaveDigiTools/src/WaveformDigitisationTool.cxx b/Waveform/WaveDigiTools/src/WaveformDigitisationTool.cxx
index 1b9ad0f44..a8f6207eb 100644
--- a/Waveform/WaveDigiTools/src/WaveformDigitisationTool.cxx
+++ b/Waveform/WaveDigiTools/src/WaveformDigitisationTool.cxx
@@ -21,7 +21,10 @@ StatusCode
 WaveformDigitisationTool::initialize() {
   ATH_MSG_INFO( name() << "::initalize()" );
 
-  m_nsamples = 600;
+  ATH_MSG_INFO( m_digitizerPeriod);
+  ATH_MSG_INFO( m_digitizerSamples);
+  ATH_MSG_INFO( m_overSamples);
+
   m_random = new TRandom3(0);
 
   return StatusCode::SUCCESS;
@@ -32,10 +35,10 @@ std::vector<float>
 WaveformDigitisationTool::evaluate_timekernel(TF1* kernel) const {
   
   std::vector<float> timekernel;
-  timekernel.reserve(m_nsamples);
+  timekernel.reserve(m_digitizerSamples);
   
-  for (unsigned int i=0; i<m_nsamples; i++) {
-    timekernel.push_back(kernel->Eval(2.*i));  
+  for (unsigned int i=0; int(i) < m_digitizerSamples; i++) {
+    timekernel.push_back(kernel->Eval(m_digitizerPeriod*i));  
   }
   
   return timekernel;
@@ -48,14 +51,19 @@ WaveformDigitisationTool::generate_baseline(float mean, float rms) const {
 
 
 /// Fill EvsT histograms
+/// Time should be in ns
 void 
 WaveformDigitisationTool::fill_evst_hist(EvstHistMap& map, const Identifier& id, float time, float energy) const {
 
   if (map.find(id) == map.end()) {
     ATH_MSG_DEBUG("Creating EvsT hist for channel" << id);
-    map[id] = new TH1D("", "", m_nsamples, 0., 2.*m_nsamples);
+    // Start histogram before zero to pick up any early arriving hits
+    map[id] = new TH1D("", "", m_overSamples * (m_digitizerSamples+m_preSamples), -m_digitizerPeriod*m_preSamples, m_digitizerPeriod*m_digitizerSamples);
   }
 
+  if (time < (-m_digitizerPeriod*m_preSamples))
+    ATH_MSG_WARNING("ID " << id << " hit found with time " << time << " E " << energy << "!");
+
   map[id]->Fill(time, energy);
 }
 
diff --git a/Waveform/WaveDigiTools/src/WaveformDigitisationTool.h b/Waveform/WaveDigiTools/src/WaveformDigitisationTool.h
index ba73b3c8d..b36765493 100644
--- a/Waveform/WaveDigiTools/src/WaveformDigitisationTool.h
+++ b/Waveform/WaveDigiTools/src/WaveformDigitisationTool.h
@@ -39,6 +39,23 @@ class WaveformDigitisationTool: public extends<AthAlgTool, IWaveformDigitisation
 
   void clear_evst_hist(EvstHistMap& map) const;
 
+  /// Waveform digitization parameters
+  FloatProperty m_digitizerPeriod { this, "DigitizerPeriod", 2.0, "Duration of one sample (in ns)" };
+  IntegerProperty m_digitizerSamples { this, "DigitizerSamples", 600, "Number of digitizer samples" };
+
+  /// This is used to set the time scale over which the hit energy 
+  /// is histogramed before convoluting with the time kernel
+  IntegerProperty m_overSamples { this, "OverSamples", 8, "Oversampling of hit times compared to digitizer period" };
+
+  /// Digitizer samples to start before t0 (time = preSamples * digiPeriod)
+  IntegerProperty  m_preSamples { this, "PreSamples", 10, "Presamples for energy histogram" };
+
+  /// Access functions for parameters
+  unsigned int digitizer_samples() const { return m_digitizerSamples; }
+  float digitizer_period() const { return m_digitizerPeriod; }
+  unsigned int over_samples() const { return m_overSamples; }
+  unsigned int pre_samples() const {return m_preSamples; }
+
  private:
   /// None
 };
-- 
GitLab