ATLAS Offline Software
Loading...
Searching...
No Matches
LArParabolaPeakRecoTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
6
8
9#include "CLHEP/Matrix/Matrix.h"
10#include "CLHEP/Matrix/Vector.h"
11#include <cmath>
12#include <fstream>
13
14using CLHEP::HepMatrix;
15using CLHEP::HepVector;
16
17
18LArParabolaPeakRecoTool::LArParabolaPeakRecoTool(const std::string& type, const std::string& name,
19 const IInterface* parent)
20 : AthAlgTool(type, name, parent),
21 m_correctBias(true),
22 m_fileShapeName("parabola_Shape.dat"),
23 m_fileADCcorName("parabola_adccor.dat")
24
25{
26 declareProperty("correctBias",m_correctBias);
29 declareInterface<LArParabolaPeakRecoTool>(this);
30}
31
33{
34 if(!m_correctBias){
35 return StatusCode::SUCCESS;
36 }
37 ATH_MSG_INFO( "LArParabolaPeakRecoTool: correctBias flag is ON ");
38 // if want to correct bias, open files
39 std::string shapeFilePath = PathResolver::find_file (m_fileShapeName, "DATAPATH");
40 std::string adcCorFilePath = PathResolver::find_file (m_fileADCcorName, "DATAPATH");
41 if (shapeFilePath.empty()) {
42 ATH_MSG_ERROR("Could not resolve shape file: " << m_fileShapeName);
43 return StatusCode::FAILURE;
44 }
45 if (adcCorFilePath.empty()) {
46 ATH_MSG_ERROR("Could not resolve ADC correction file: " << m_fileADCcorName);
47 return StatusCode::FAILURE;
48 }
49 m_fileShapeName = std::move(shapeFilePath);
50 m_fileADCcorName = std::move(adcCorFilePath);
51 std::ifstream in{m_fileShapeName};
52 if (!in) {
53 ATH_MSG_ERROR("Failed to open shape file: " << m_fileShapeName);
54 return StatusCode::FAILURE;
55 }
56 std::ifstream adcin{m_fileADCcorName};
57 if (!adcin) {
58 ATH_MSG_ERROR("Failed to open ADC correction file: " << m_fileADCcorName);
59 return StatusCode::FAILURE;
60 }
61 //
62 int idelay{-1}, ilayer{-1};
63 float timeValue{};
64 while (in >> idelay >> ilayer >> timeValue) {
65 if (ilayer < 0 || ilayer >= 4 || idelay < 0 || idelay >= 25) {
66 continue;
67 }
68 m_QT_Shape[ilayer][idelay] = timeValue;
69 if (idelay == 0 && m_QT_Shape[ilayer][0] != 0.F) {
70 m_QT_Shape[ilayer][25] = m_QT_Shape[ilayer][0] + 25.F;
71 }
72 }
73 //reset variables
74 idelay = -1;
75 ilayer = -1;
76 float adcCorValue{};
77 while (adcin >> idelay >> ilayer >> adcCorValue) {
78 if (ilayer < 0 || ilayer >= 4 || idelay < 0 || idelay >= 25) {
79 continue;
80 }
81 m_QT_ADCcor[ilayer][idelay] = adcCorValue;
82 }
83 return StatusCode::SUCCESS;
84}
85
87{return StatusCode::SUCCESS;}
88
89std::vector<float> LArParabolaPeakRecoTool::peak (const std::vector<float>& samples) const
90{
91 return peak(samples, -1, -1.);
92}
93
94std::vector<float> LArParabolaPeakRecoTool::peak (const std::vector<short>& samples) const
95{
96 std::vector<float> newsamples;
97 for(unsigned int i=0;i<samples.size();i++)
98 {
99 newsamples.push_back((float)samples[i]);
100 }
101 return peak(newsamples, -1, -1.);
102}
103
104
105std::vector<float> LArParabolaPeakRecoTool::peak (const std::vector<short>& samples, int layer, float pedestal) const
106{
107
108 std::vector<float> newsamples;
109 for(unsigned int i=0;i<samples.size();i++)
110 {
111 newsamples.push_back((float)samples[i]);
112 }
113 return peak(newsamples, layer, pedestal);
114
115}
116
117std::vector<float> LArParabolaPeakRecoTool::peak (const std::vector<float>& samples, int layer, float pedestal) const
118{//const float dt=25.0;//ns
119 std::vector<float> solution;
120
121 const std::vector<float>::const_iterator it_max=max_element(samples.begin(),samples.end());
122 if (it_max==samples.end()) {
123 ATH_MSG_ERROR( "Maximum ADC sample not found!" );
124 return solution;
125 }
126 if (it_max==samples.begin() || it_max==samples.end()-1)
127 {
128 solution.push_back(*it_max);
129 return solution;
130 }
131
132 // Fit a+bx+cx^2
133 HepMatrix alpha(3,3);
134 HepVector beta(3);
135 for (int i=0;i<3;i++)
136 {beta[i]=*(it_max-1+i);
137 for (int j=0;j<3;j++)
138 alpha[i][j]=pow(-1+i,j);
139 }
140
141 float retval=0, tmax=0, traw=0, trec=0;
142 if(!m_correctBias){
143
144 HepVector comp=solve(alpha,beta);
145 //solve b+2cx=0 to get maximum
146 tmax=-comp[1]/(2*comp[2]);
147 //substitute-back
148 retval=comp[0]-comp[1]*comp[1]/(4*comp[2]);
149
150 }else{
151
152 // obtain time as in EMTB
153 traw = 25./2.*(beta[0]-beta[2])/(beta[0] - beta[1] + beta[2] - beta[1]);
154
155 // normalize back to the reference scheme
156 traw += ( it_max-samples.begin() - 3 )*25.;
157
158 if(layer < 0 || layer > 3) {
159 ATH_MSG_ERROR( "Layer index is wrong ! Layer = " << layer );
160 return solution;
161 }else{
162 // get true time
163 trec = ParabolaRawToTrueTime(traw, layer);
164 // get true ADC
165 if(pedestal<0) ATH_MSG_ERROR( "Pedestal is wrong ! Ped = " << pedestal );
166 retval = ParabolaRawToTrueADC(trec, beta[1], pedestal, layer);
167 }
168 }
169
170 solution.push_back(retval);
171 if(!m_correctBias){
172 solution.push_back(tmax);
173 }else{
174 // if corrected bias, return both uncorrected and corrected times
175 solution.push_back(traw);
176 solution.push_back(trec);
177 }
178 return solution;
179}
180
181// function taken from EMTB to obtaine the true time from the biased time
182float LArParabolaPeakRecoTool::ParabolaRawToTrueTime(float& QT_fittime, int& layer) const
183{
184 int iOffset;
185 float QT_true_lower;
186 float QT_raw_lower;
187 float QT_raw_upper;
188 float QT_true_time;
189 int idelay;
190 int ilayer;
191
192 /*
193 * initialize
194 */
195
196 ilayer = layer;
197
198 QT_true_lower = -999.;
199 QT_raw_lower = -999.;
200 QT_raw_upper = -999.;
201 iOffset = 0;
202
203 /*
204 * the transfer function is defined from 0 to 25 ns
205 * the function has a periodicity of 25 ns, adapted
206 * the input value to the nominal regime and correct
207 * afterwards
208 */
209 while ( QT_fittime < m_QT_Shape[ilayer][0] )
210 {
211 QT_fittime +=25;
212 iOffset++;
213 }
214
215 while ( QT_fittime > m_QT_Shape[ilayer][25] )
216 {
217 QT_fittime -= 25;
218 iOffset--;
219 }
220
221 /*
222 * now find the correct bin to do the correction
223 */
224
225 for ( idelay=0; idelay < 25; idelay++ )
226 {
227 if ( QT_fittime >= m_QT_Shape[ilayer][idelay]
228 && QT_fittime < m_QT_Shape[ilayer][idelay+1])
229 {
230 QT_true_lower = (float) (idelay - iOffset * 25.);
231 QT_raw_lower = m_QT_Shape[ilayer][idelay];
232 QT_raw_upper = m_QT_Shape[ilayer][idelay+1];
233 }
234 }
235
236 /*
237 * from lower and upper bounds calculate the true time (linear extrapolation)
238 */
239
240 if ( QT_true_lower == -999. )
241 {
242 QT_true_time = -999.;
243 }
244 else
245 {
246 QT_true_time = QT_true_lower +
247 (QT_fittime-QT_raw_lower)/(QT_raw_upper - QT_raw_lower);
248 }
249 /*
250 * return the true time
251 */
252
253 return QT_true_time;
254
255}
256
257// function taken from EMTB to obtaine the true ADC from the biased ADC
258float LArParabolaPeakRecoTool::ParabolaRawToTrueADC(float& QT_true_time, double& ADCref, float& PEDref, int& layer) const
259{
260 int ichoosedelay;
261 float QT_true_ADC;
262 float QT_correct_ADC;
263 int ilayer;
264
265 /*
266 * save in local variable because of extensive use
267 */
268
269 ilayer = layer;
270
271 /*
272 * now transform the time into a positive value to
273 * make the calculation easier
274 */
275
276 if ( QT_true_time < 0. )
277 {
278 QT_true_time += ( ( (int) std::abs(QT_true_time / 25)) + 1)*25;
279 }
280
281 /*
282 * determine the bin (==delay) of the reference signal
283 */
284
285 ichoosedelay = (int) QT_true_time % 25;
286
287 /*
288 * make sure that we are in-bounds for the correction matrix
289 */
290
291 if ( ilayer >=0 && ilayer< 4 )
292 {
293 if ( ichoosedelay < 25 - 1 ){
294 QT_correct_ADC= m_QT_ADCcor[ilayer][ichoosedelay]
295 + (m_QT_ADCcor[ilayer][ichoosedelay+1]-m_QT_ADCcor[ilayer][ichoosedelay])
296 * (QT_true_time - (int) QT_true_time);
297 }
298 else {
299 QT_correct_ADC= m_QT_ADCcor[ilayer][ichoosedelay]
300 + (m_QT_ADCcor[ilayer][0]-m_QT_ADCcor[ilayer][ichoosedelay])
301 * (QT_true_time - (int) QT_true_time);
302 }
303 }
304 else
305 {
306 QT_correct_ADC = 100.;
307 }
308
309 /*
310 * for consistency reasons:
311 * - subtract pedestal
312 * - correct to ADCmax
313 * - add pedestal (subtraction in EMTB later on)
314 */
315
316 QT_true_ADC = ADCref - PEDref;
317 QT_true_ADC = QT_true_ADC / QT_correct_ADC * 100.;
318 QT_true_ADC += PEDref;
319
320 /*
321 * the corrected time is returned
322 */
323
324 return QT_true_ADC;
325}
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
float ParabolaRawToTrueTime(float &QT_fittime, int &layer) const
LArParabolaPeakRecoTool(const std::string &type, const std::string &name, const IInterface *parent)
std::vector< float > peak(const std::vector< float > &samples) const
float ParabolaRawToTrueADC(float &QT_true_time, double &ADCref, float &PEDref, int &layer) const
static std::string find_file(const std::string &logical_file_name, const std::string &search_path)