ATLAS Offline Software
VMM_Shaper.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
3 */
4 
6 
7 #include <algorithm>
8 #include <cmath>
9 
10 namespace {
11  // VMM shaper parameters provided by G. Iakovidis
12  constexpr double K0 = 1.584;
13  constexpr double Re_K1 = -0.792;
14  constexpr double Im_K1 = -0.115;
15 
16  constexpr double chargeScaleFactor = 1 / 0.411819;
17 
18  constexpr double mmIonFlowTime = 150.; // ns
19 } // namespace
20 
21 VMM_Shaper::VMM_Shaper(const float peakTime, const float lowerTimeWindow, const float upperTimeWindow) :
22  m_peakTime(peakTime), m_lowerTimeWindow(lowerTimeWindow), m_upperTimeWindow(upperTimeWindow), m_timeStep(0.1) {
24  initialize();
25 }
26 
28  // hardcoded vmm shaper values are provided by G. Iakovidis
29  m_a = (m_peakTime * (1e-9)) / 1.5;
30  m_pole0 = 1.263 / m_a;
31  m_re_pole1 = 1.149 / m_a;
32  m_im_pole1 = -0.786 / m_a;
34  m_k1_abs = std::sqrt(Re_K1 * Re_K1 + Im_K1 * Im_K1);
35  m_argK1 = std::atan2(Im_K1, Re_K1);
36 
37  // scale factor for charge taking into account the mm ion flow time of ~150ns
38  // if the peaking time is lower then that, only a fration of the total charge is integrated
39  m_peakTimeChargeScaling = (m_peakTime < mmIonFlowTime ? 1.0 * m_peakTime / mmIonFlowTime : 1.0);
40 
41  // preCalculate factor to avoid recalculating for each electron
43 
44  m_pole0_ns = m_pole0 * (1e-9);
45  m_re_pole1_ns = m_re_pole1 * (1e-9);
46  m_im_pole1_ns = m_im_pole1 * (1e-9);
47 }
48 
49 double VMM_Shaper::vmmResponse(const std::vector<float> &effectiveCharge, const std::vector<float> &electronsTime, double time) const {
50  double response = 0;
51  for (unsigned int i_electron = 0; i_electron < effectiveCharge.size(); i_electron++) {
52  if (time < electronsTime.at(i_electron)) continue;
53  double t = (time - electronsTime.at(i_electron));
54  // now follows the vmm shaper response function provided by G. Iakovidis
55  // It is described in section 7.1.3 of https://cds.cern.ch/record/1955475
56  double st =
57  effectiveCharge.at(i_electron) * m_preCalculationVMMShaper *
58  ((K0 * std::exp(-t * m_pole0_ns)) + (2. * m_k1_abs * std::exp(-t * m_re_pole1_ns) * std::cos(-t * m_im_pole1_ns + m_argK1)));
59  response += st;
60  }
61  return response;
62 }
63 
64 bool VMM_Shaper::vmmPeakResponse(const std::vector<float> &effectiveCharge, const std::vector<float> &electronsTime,
65  const double electronicsThreshold, double &amplitudeFirstPeak, double &timeFirstPeak) const {
66  double t_peak = findPeak(effectiveCharge, electronsTime, electronicsThreshold);
67 
68  if (t_peak == -9999) return false; // no peak found
69 
70  amplitudeFirstPeak = vmmResponse(effectiveCharge, electronsTime, t_peak);
71  timeFirstPeak = t_peak;
72  return true;
73 }
74 
75 bool VMM_Shaper::vmmThresholdResponse(const std::vector<float> &effectiveCharge, const std::vector<float> &electronsTime,
76  const double electronicsThreshold, double &amplitudeAtFirstPeak, double &timeAtThreshold) const {
77  if (!aboveThresholdSimple(effectiveCharge, electronsTime, electronicsThreshold)) return false;
78 
79  if (effectiveCharge.empty()) return false; // protect min_element
81  double minElectronTime = *std::min_element(electronsTime.begin(), electronsTime.end());
82  if (startTime < minElectronTime)
83  startTime = minElectronTime; // if smallest strip times are higher then the lower time window, just start the loop from the
84  // smallest electron time
85 
86  double tmpTimeAtThreshold = -9999;
87 
88  for (double time = startTime; time < minElectronTime + 0.9 * m_peakTime;
89  time += 10 * m_timeStep) { // quick search till the first possible peak
90  if (vmmResponse(effectiveCharge, electronsTime, time) <= electronicsThreshold) continue;
91  for (double fineTime = time; fineTime >= time - 10 * m_timeStep;
92  fineTime -=
93  m_timeStep) { // since value above threshold was found, loop back in time to find the crossing with the timeStep precission
94  if (vmmResponse(effectiveCharge, electronsTime, fineTime) >= electronicsThreshold) continue;
95  tmpTimeAtThreshold = fineTime + 0.5 * m_timeStep; // get time between time above and time below threshold
96  break;
97  }
98  break;
99  }
100 
101  if (tmpTimeAtThreshold == -9999) { // threshold crossing not yet found
102  // check if first possible peak was before start time
103  double tmpStartTime = std::max(minElectronTime + 0.9 * m_peakTime, startTime);
104  for (double time = tmpStartTime; time < m_upperTimeWindow; time += m_timeStep) {
105  if (vmmResponse(effectiveCharge, electronsTime, time) >= electronicsThreshold) {
106  tmpTimeAtThreshold = time;
107  break;
108  }
109  }
110  }
111 
112  if (tmpTimeAtThreshold == -9999) return false;
113 
114  double t_peak = findPeak(effectiveCharge, electronsTime, electronicsThreshold);
115  if (t_peak == -9999) return false;
116 
117  timeAtThreshold = tmpTimeAtThreshold;
118  amplitudeAtFirstPeak = vmmResponse(effectiveCharge, electronsTime, t_peak);
119  return true;
120 }
121 
122 double VMM_Shaper::findPeak(const std::vector<float> &effectiveCharge, const std::vector<float> &electronsTime,
123  const double electronicsThreshold) const {
124  if (effectiveCharge.empty()) return -9999; // protect min_element
125  double startTime = m_lowerTimeWindow;
126  double minElectronTime = *std::min_element(electronsTime.begin(), electronsTime.end());
127 
128  minElectronTime += 0.8 * m_peakTime; // only start looking for the peak close to the first possible peak
129  if (startTime < minElectronTime)
130  startTime = minElectronTime; // if smallest strip times are higher then the lower time window, just start the loop from the
131  // smallest electron time
132 
133  double oldResponse = 0;
134  // double currentDerivative = 0;
135 
136  double timeStepScaleFactor = 5.0;
137 
138  for (double time = startTime; time < m_upperTimeWindow; time += m_timeStep * timeStepScaleFactor) {
139  double response = vmmResponse(effectiveCharge, electronsTime, time);
140  if (oldResponse < response) {
141  oldResponse = response;
142  continue;
143  }
144  oldResponse = response;
145 
146  int searchWindow = 5;
147 
148  std::vector<double> tmpTime, tmpResponse;
149 
150  tmpTime.reserve(2 * timeStepScaleFactor);
151  tmpResponse.reserve(2 * timeStepScaleFactor);
152 
153  for (double fineTime = (time - 1.5 * m_timeStep * timeStepScaleFactor); fineTime < time + 0.5 * m_timeStep * timeStepScaleFactor;
154  fineTime += m_timeStep) {
155  tmpTime.push_back(fineTime);
156  tmpResponse.push_back(vmmResponse(effectiveCharge, electronsTime, fineTime));
157  }
158 
159  int nBins = tmpTime.size();
160 
161  for (int i_time = 1; i_time < nBins - 1; i_time++) {
162  if (tmpResponse.at(i_time) < tmpResponse.at(i_time + 1)) continue;
163 
164  if (tmpResponse.at(i_time) < electronicsThreshold) break;
165 
166  bool checkTimeWindow = false;
167  for (int i_timeOfPeak = i_time - searchWindow + 1; i_timeOfPeak <= i_time + searchWindow; i_timeOfPeak++) {
168  if (i_timeOfPeak < 1 || i_timeOfPeak == nBins - 1) continue;
169 
170  double oldDerivative = (tmpResponse.at(i_time) - tmpResponse.at(i_time - 1));
171  double newDerivative = (tmpResponse.at(i_time + 1) - tmpResponse.at(i_time));
172  if (newDerivative > oldDerivative) {
173  checkTimeWindow = false;
174  break;
175  } else {
176  checkTimeWindow = true;
177  }
178  }
179  if (checkTimeWindow) return tmpTime.at(i_time);
180  }
181  }
182  return -9999; // no peak found
183 }
184 
185 bool VMM_Shaper::hasChargeAboveThreshold(const std::vector<float> &effectiveCharge, const std::vector<float> &electronsTime,
186  const double electronicsThreshold) const {
187  if (!aboveThresholdSimple(effectiveCharge, electronsTime, electronicsThreshold)) return false;
188 
189  if (effectiveCharge.empty()) return false; // protect min_element
190  double startTime = m_lowerTimeWindow;
191  double minElectronTime = *std::min_element(electronsTime.begin(), electronsTime.end());
192  // since we are only checking if signal is above threshold, we can start searching close to the peak
193  minElectronTime += m_peakTime * 0.8;
194  if (startTime < minElectronTime)
195  startTime = minElectronTime; // if smallest strip times are higher then the lower time window, just start the loop from the
196  // smallest electron time
197 
198  for (double time = startTime; time < m_upperTimeWindow; time += m_timeStep) {
199  if (vmmResponse(effectiveCharge, electronsTime, time) >= electronicsThreshold) { return true; }
200  }
201  return false;
202 }
203 
204 bool VMM_Shaper::aboveThresholdSimple(const std::vector<float> &effectiveCharge, const std::vector<float> &electronsTime,
205  const double electronicsThreshold) const {
206  // check if total strip charge is above threshold, otherwise skip VMM
207  float chargeSum = 0;
208  for (unsigned int i_elec = 0; i_elec < effectiveCharge.size(); i_elec++) {
209  if (electronsTime.at(i_elec) >= m_lowerTimeWindow - m_peakTime && electronsTime.at(i_elec) <= m_upperTimeWindow) {
210  chargeSum += effectiveCharge.at(i_elec) * m_peakTimeChargeScaling;
211  }
212  }
213  return chargeSum >= electronicsThreshold;
214 }
VMM_Shaper::m_peakTimeChargeScaling
double m_peakTimeChargeScaling
Definition: VMM_Shaper.h:42
max
#define max(a, b)
Definition: cfImp.cxx:41
VMM_Shaper::hasChargeAboveThreshold
bool hasChargeAboveThreshold(const std::vector< float > &effectiveCharge, const std::vector< float > &electronsTime, const double electronicsThreshold) const
Definition: VMM_Shaper.cxx:185
VMM_Shaper.h
response
MDT_Response response
Definition: MDT_ResponseTest.cxx:28
conifer::pow
constexpr int pow(int x)
Definition: conifer.h:20
VMM_Shaper::aboveThresholdSimple
bool aboveThresholdSimple(const std::vector< float > &effectiveCharge, const std::vector< float > &electronsTime, const double electronicsThreshold) const
Definition: VMM_Shaper.cxx:204
VMM_Shaper::vmmResponse
double vmmResponse(const std::vector< float > &effectiveCharge, const std::vector< float > &electronsTime, double time) const
Definition: VMM_Shaper.cxx:49
lumiFormat.startTime
startTime
Definition: lumiFormat.py:102
VMM_Shaper::vmmPeakResponse
bool vmmPeakResponse(const std::vector< float > &effectiveCharge, const std::vector< float > &electronsTime, const double electronicsThreshold, double &amplitudeFirstPeak, double &timeFirstPeak) const
Definition: VMM_Shaper.cxx:64
VMM_Shaper::m_inverseTimeStep
double m_inverseTimeStep
Definition: VMM_Shaper.h:31
VMM_Shaper::vmmThresholdResponse
bool vmmThresholdResponse(const std::vector< float > &effectiveCharge, const std::vector< float > &electronsTime, const double electronicsThreshold, double &amplitudeAtFirstPeak, double &timeAtThreshold) const
Definition: VMM_Shaper.cxx:75
read_hist_ntuple.t
t
Definition: read_hist_ntuple.py:5
drawFromPickle.cos
cos
Definition: drawFromPickle.py:36
drawFromPickle.exp
exp
Definition: drawFromPickle.py:36
VMM_Shaper::m_pole1_square
double m_pole1_square
Definition: VMM_Shaper.h:39
VMM_Shaper::m_peakTime
double m_peakTime
Definition: VMM_Shaper.h:26
VMM_Shaper::m_upperTimeWindow
double m_upperTimeWindow
Definition: VMM_Shaper.h:28
VMM_Shaper::m_im_pole1
double m_im_pole1
Definition: VMM_Shaper.h:38
VMM_Shaper::m_re_pole1
double m_re_pole1
Definition: VMM_Shaper.h:37
VMM_Shaper::m_preCalculationVMMShaper
double m_preCalculationVMMShaper
Definition: VMM_Shaper.h:33
VMM_Shaper::m_a
double m_a
Definition: VMM_Shaper.h:35
VMM_Shaper::m_re_pole1_ns
double m_re_pole1_ns
Definition: VMM_Shaper.h:50
VMM_Shaper::m_timeStep
double m_timeStep
Definition: VMM_Shaper.h:30
dumpTgcDigiJitter.nBins
list nBins
Definition: dumpTgcDigiJitter.py:29
VMM_Shaper::m_im_pole1_ns
double m_im_pole1_ns
Definition: VMM_Shaper.h:51
DiTauMassTools::MaxHistStrategyV2::e
e
Definition: PhysicsAnalysis/TauID/DiTauMassTools/DiTauMassTools/HelperFunctions.h:26
VMM_Shaper::VMM_Shaper
VMM_Shaper(const float peakTime, const float lowerTimeWindow, const float upperTimeWindow)
Definition: VMM_Shaper.cxx:21
VMM_Shaper::m_pole0
double m_pole0
Definition: VMM_Shaper.h:36
CaloSwCorrections.time
def time(flags, cells_name, *args, **kw)
Definition: CaloSwCorrections.py:242
VMM_Shaper::m_k1_abs
double m_k1_abs
Definition: VMM_Shaper.h:40
VMM_Shaper::m_argK1
double m_argK1
Definition: VMM_Shaper.h:41
VMM_Shaper::m_pole0_ns
double m_pole0_ns
Definition: VMM_Shaper.h:49
VMM_Shaper::findPeak
double findPeak(const std::vector< float > &effectiveCharge, const std::vector< float > &electronsTime, const double electronicsThreshold) const
Definition: VMM_Shaper.cxx:122
VMM_Shaper::initialize
void initialize()
Definition: VMM_Shaper.cxx:27
VMM_Shaper::m_lowerTimeWindow
double m_lowerTimeWindow
Definition: VMM_Shaper.h:27