ATLAS Offline Software
Loading...
Searching...
No Matches
AFP_ProtonRecoAnalytical.cxx
Go to the documentation of this file.
1/*
2Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7
8AFP_ProtonRecoAnalytical::AFP_ProtonRecoAnalytical (const std::string &type, const std::string &name, const IInterface *parent)
9 : AFP_ProtonRecoBase(type, name, parent)
10{
11 ATH_MSG_DEBUG("in AFP_ProtonRecoAnalytical constructor");
12}
13
14
16{
17 ATH_MSG_INFO("----- AFP_ProtonRecoAnalytical -----");
18
19 ATH_MSG_INFO("\tNear AFP position [m]: " << m_detectorPositionNear );
20 ATH_MSG_INFO("\tFar AFP position [m]: " << m_detectorPositionFar );
21 ATH_MSG_INFO("\tSingle station reconstruction: " << m_allowSingleStationReco );
22 ATH_MSG_INFO("\tCuts:\n");
23 ATH_MSG_INFO("\t\ttrackDistance [mm]: " << m_trackDistance );
24
25 ATH_MSG_INFO("\tparametrizationFileName = " << m_parametrizationFileName);
26 ATH_MSG_INFO("\tparametrizationPosition = " << m_parametrizationPosition);
27 ATH_MSG_INFO("\tparametrizationEnergy = " << m_parametrizationEnergy);
28
29 return StatusCode::SUCCESS;
30}
31
32
34{
35
36 CHECK( m_trackContainerKey.initialize() );
37
38 if(m_detectorPositions.empty())
39 {
40 if(m_side==0)
41 {
44 }
45 else if(m_side==1)
46 {
49 }
50 else
51 {
52 ATH_MSG_ERROR("unknown side id "<<m_side<<", allowed values are 0 (for A) and 1 (for C)");
53 return StatusCode::FAILURE;
54 }
55 }
56 else if(m_detectorPositions.size()==2)
57 {
59 {
62 }
63 else
64 {
67 }
68 }
69 else
70 {
71 ATH_MSG_ERROR("there are "<<m_detectorPositions.size()<<" entries for m_detectorPositions, we have only 2 detectors on each side");
72 return StatusCode::FAILURE;
73 }
74
76 {
77 ATH_MSG_ERROR("parametrizationFileName is not set");
78 return StatusCode::FAILURE;
79 }
80
81 const std::string parametrization = PathResolverFindDataFile(m_parametrizationFileName);
82 if(parametrization.empty())
83 {
85 return StatusCode::FAILURE;
86 }
87
88 m_parametrization = std::make_unique<AFP::Parameterization>(parametrization);
89 m_parametrizationPosition = m_parametrization->parametrizationPosition();
92
93 return StatusCode::SUCCESS;
94}
95
96
97double AFP_ProtonRecoAnalytical::bisection (double (AFP_ProtonRecoAnalytical::*fun)(double, const Measurement&, std::vector<double>&, std::vector<double>&) const, const Measurement& my_measAFP, std::vector<double>& my_slopeCalculated, std::vector<double>& my_positionCalculated) const {
98
99 // Alias to minimized function
100 auto fn = [this, fun, my_slopeCalculated, my_positionCalculated](double x, const Measurement& m, std::vector<double>& s, std::vector<double>& p) { return (this->*fun)(x,m,s,p); };
101
102 constexpr double tol = 1e-3; // 1 MeV
103 double eMin = m_parametrizationEnergy - 2000.; // ~30% xi
104 double eMax = m_parametrizationEnergy;
105
106 if (fn(eMax, my_measAFP, my_slopeCalculated, my_positionCalculated) * fn(eMin, my_measAFP, my_slopeCalculated, my_positionCalculated) >= 0) { // Cannot use bisection method
107
108 ATH_MSG_DEBUG("Cannot use bisection method");
109
110 // Return value closest to zero
111 return (fn(eMin, my_measAFP, my_slopeCalculated, my_positionCalculated) < 0) ? std::max(fn(eMin, my_measAFP, my_slopeCalculated, my_positionCalculated), fn(eMax, my_measAFP, my_slopeCalculated, my_positionCalculated)) : std::min(fn(eMin, my_measAFP, my_slopeCalculated, my_positionCalculated), fn(eMax, my_measAFP, my_slopeCalculated, my_positionCalculated));
112 }
113
114 ATH_MSG_VERBOSE("==== eMin\teMax\te\tfun(eMin)\tfun(eMax)\tfun(E) ====");
115
116 double e = eMin;
117
118 // Bisection method
119 while (eMax - eMin > tol) {
120 e = (eMin + eMax)/2.0;
121 ATH_MSG_VERBOSE("* " << eMin << "\t" << eMax << "\t" << e << "\t" << fn(e, my_measAFP, my_slopeCalculated, my_positionCalculated) << "\t" << fn(eMin, my_measAFP, my_slopeCalculated, my_positionCalculated) << "\t" << fn(eMax, my_measAFP, my_slopeCalculated, my_positionCalculated));
122 if (fn(eMax, my_measAFP, my_slopeCalculated, my_positionCalculated) * fn(e, my_measAFP, my_slopeCalculated, my_positionCalculated) < 0)
123 eMin = e;
124 else if (fn(eMin, my_measAFP, my_slopeCalculated, my_positionCalculated) * fn(e, my_measAFP, my_slopeCalculated, my_positionCalculated) < 0)
125 eMax = e;
126 else {
127 eMin = e;
128 eMax = e;
129 }
130 }
131
132 ATH_MSG_DEBUG("Bisection energy: " << e);
133
134 return e;
135}
136
137
138xAOD::AFPProton * AFP_ProtonRecoAnalytical::reco (const xAOD::AFPTrack* trackNear, const xAOD::AFPTrack* trackFar, std::unique_ptr<xAOD::AFPProtonContainer>& outputContainer) const {
139
141 const Measurement my_measAFP = Measurement(trackNear->xLocal(), trackNear->yLocal(), trackFar->xLocal(), trackFar->yLocal());
142
143 std::vector<double> my_slopeCalculated = {0, 0};
144 std::vector<double> my_positionCalculated = {0, 0};
145
146 my_slopeCalculated.at(0) = (my_measAFP.xF - my_measAFP.xN)/m_distanceBetweenStations;
147 my_slopeCalculated.at(1) = (my_measAFP.yF - my_measAFP.yN)/m_distanceBetweenStations;
148 my_positionCalculated.at(0) = my_measAFP.xN + my_slopeCalculated.at(0)*(m_parametrizationPosition - m_detectorPositionNear);
149 my_positionCalculated.at(1) = my_measAFP.yN + my_slopeCalculated.at(1)*(m_parametrizationPosition - m_detectorPositionNear);
150
151 ATH_MSG_DEBUG("Reconstructing proton with bisection method...");
152 ATH_MSG_DEBUG("Tracks (xNear, yNear; xFar, yFar): " << my_measAFP.xN << ", " << my_measAFP.yN << "; "
153 << my_measAFP.xF << ", " << my_measAFP.yF);
154
155 const double energy = bisection(&AFP_ProtonRecoAnalytical::bothStations, my_measAFP, my_slopeCalculated, my_positionCalculated);
156 const double slopeX = calculateXslope(energy,my_slopeCalculated);
157 const double slopeY = calculateYslope(energy,my_slopeCalculated);
158
159 const double px = energy * slopeX;
160 const double py = energy * slopeY;
161 const double pz = energy * sqrt(1. - slopeX*slopeX - slopeY*slopeY);
162
163 return createProton({px, py, pz}, my_measAFP, xAOD::AFPProtonRecoAlgID::analytical, outputContainer);
164}
165
166
167xAOD::AFPProton * AFP_ProtonRecoAnalytical::reco (const xAOD::AFPTrack* trackFar, std::unique_ptr<xAOD::AFPProtonContainer>& outputContainer) const {
168
169 const Measurement my_measAFP = Measurement(0., 0., trackFar->xLocal(), trackFar->yLocal());
170
171 ATH_MSG_DEBUG("Reconstructing proton with bisection method (single station)...");
172 ATH_MSG_DEBUG("Tracks (xFar, yFar): " << my_measAFP.xF << ", " << my_measAFP.yF);
173
174 std::vector<double> my_slopeCalculated = {0, 0};
175 std::vector<double> my_positionCalculated = {0, 0};
176
177 const double energy = bisection(&AFP_ProtonRecoAnalytical::singleStation, my_measAFP, my_slopeCalculated, my_positionCalculated);
178
179 return createProton({0., 0., energy}, my_measAFP, xAOD::AFPProtonRecoAlgID::analytical, outputContainer);
180}
181
182
183double AFP_ProtonRecoAnalytical::bothStations (double energy, const Measurement& /*my_measAFP*/, std::vector<double>& my_slopeCalculated, std::vector<double>& my_positionCalculated) const {
184
185 const double xi = 1.0 - energy / m_parametrizationEnergy;
186
187 return
188 (my_positionCalculated.at(0)
189 - m_parametrization->getEquation(0)->getPolynomial(0)->Eval(xi)
190 - m_vertexIP.at(0)*m_parametrization->getEquation(0)->getPolynomial(1)->Eval(xi)
191 - m_vertexIP.at(2)*m_parametrization->getEquation(0)->getPolynomial(3)->Eval(xi)
192 )
193 *(
194 m_parametrization->getEquation(2)->getPolynomial(4)->Eval(xi)
195 + m_vertexIP.at(2)*m_parametrization->getEquation(2)->getPolynomial(6)->Eval(xi)
196 )
197 - (
198 my_slopeCalculated.at(0)
199 - m_parametrization->getEquation(2)->getPolynomial(0)->Eval(xi)
200 - m_vertexIP.at(0)*m_parametrization->getEquation(2)->getPolynomial(1)->Eval(xi)
201 - m_vertexIP.at(2)*m_parametrization->getEquation(2)->getPolynomial(3)->Eval(xi)
202 )
203 *(
204 m_parametrization->getEquation(0)->getPolynomial(4)->Eval(xi)
205 + m_vertexIP.at(2)*m_parametrization->getEquation(0)->getPolynomial(6)->Eval(xi)
206 );
207}
208
209
210double AFP_ProtonRecoAnalytical::singleStation (double energy, const Measurement& my_measAFP, std::vector<double>& /*my_slopeCalculated*/, std::vector<double>& /*my_positionCalculated*/) const {
211
212 const double xi = 1.0 - energy / m_parametrizationEnergy;
213 const double xNear = my_measAFP.xF - m_distanceBetweenStations * m_parametrization->sx(m_vertexIP.at(0), m_vertexIP.at(1), m_vertexIP.at(2), 0, 0, energy);
214
215 const double Ax = m_parametrization->getEquation(0)->getPolynomial(0)->Eval(xi);
216 const double Bx = m_parametrization->getEquation(0)->getPolynomial(1)->Eval(xi);
217 const double Dx = m_parametrization->getEquation(0)->getPolynomial(3)->Eval(xi);
218
219 return xNear - Ax - m_vertexIP.at(0)*Bx - m_vertexIP.at(2)*Dx;
220}
221
222
223double AFP_ProtonRecoAnalytical::calculateSlope (double energy, int XorY, std::vector<double>& my_slopeCalculated) const { // 0 - X, 1 - Y
224
225 const double xi = 1.0 - energy / m_parametrizationEnergy;
226
227 const double Ax = m_parametrization->getEquation(2 + XorY)->getPolynomial(0)->Eval(xi);
228 const double Bx = m_parametrization->getEquation(2 + XorY)->getPolynomial(4 + XorY)->Eval(xi);
229 const double Cx = m_parametrization->getEquation(2 + XorY)->getPolynomial(1 + XorY)->Eval(xi);
230 const double Dx = m_parametrization->getEquation(2 + XorY)->getPolynomial(6 + XorY)->Eval(xi);
231 const double Ex = m_parametrization->getEquation(2 + XorY)->getPolynomial(3)->Eval(xi);
232
233 const double Fx = my_slopeCalculated.at(0 + XorY) - Ax - Cx*m_vertexIP.at(0 + XorY) - Ex*m_vertexIP.at(2);
234 const double Gx = Bx + m_vertexIP.at(2)*Dx;
235 const double slp = (Gx == 0) ? 0. : Fx/Gx;
236
237 return slp;
238}
239
240
241double AFP_ProtonRecoAnalytical::calculateXslope (double energy, std::vector<double>& my_slopeCalculated) const {
242
243 return calculateSlope(energy, 0, my_slopeCalculated);
244}
245
246
247double AFP_ProtonRecoAnalytical::calculateYslope (double energy, std::vector<double>& my_slopeCalculated) const {
248
249 return calculateSlope(energy, 1, my_slopeCalculated);
250}
251
252
253double AFP_ProtonRecoAnalytical::chi2 (double px, double py, double pz, const Measurement& my_measAFP) const {
254
255 const double energy = sqrt(px*px + py*py + pz*pz);
256 const double sx = px/energy;
257 const double sy = py/energy;
258
259 const double xNear = m_parametrization->x(m_vertexIP.at(0), m_vertexIP.at(1), m_vertexIP.at(2), sx, sy, energy);
260 const double yNear = m_parametrization->y(m_vertexIP.at(0), m_vertexIP.at(1), m_vertexIP.at(2), sx, sy, energy);
261 const double xFar = xNear + m_distanceBetweenStations * m_parametrization->sx(m_vertexIP.at(0), m_vertexIP.at(1), m_vertexIP.at(2), sx, sy, energy);
262 const double yFar = yNear + m_distanceBetweenStations * m_parametrization->sy(m_vertexIP.at(0), m_vertexIP.at(1), m_vertexIP.at(2), sx, sy, energy);
263
264 if (m_allowSingleStationReco and my_measAFP.xN == 0 and my_measAFP.yN == 0) {
265 const double dx2 = my_measAFP.xF - xFar;
266 const double dy2 = my_measAFP.yF - yFar;
267
268 const double chi2x2 = dx2 * dx2 / (m_xSigma * m_xSigma);
269 const double chi2y2 = (m_parametrization->yIsUsed()) ? dy2 * dy2 / (m_ySigma * m_ySigma) : 0.;
270
271 return chi2x2 + chi2y2;
272 }
273
274 const double dx1 = my_measAFP.xN - xNear;
275 const double dx2 = my_measAFP.xF - xFar;
276 const double dy1 = my_measAFP.yN - yNear;
277 const double dy2 = my_measAFP.yF - yFar;
278
279 const double chi2x1 = dx1 * dx1 / (m_xSigma * m_xSigma);
280 const double chi2x2 = dx2 * dx2 / (m_xSigma * m_xSigma);
281 const double chi2y1 = (m_parametrization->yIsUsed()) ? dy1 * dy1 / (m_ySigma * m_ySigma) : 0.;
282 const double chi2y2 = (m_parametrization->yIsUsed()) ? dy2 * dy2 / (m_ySigma * m_ySigma) : 0.;
283
284 return chi2x1 + chi2y1 + chi2x2 + chi2y2;
285}
286
287
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_DEBUG(x)
#define CHECK(...)
Evaluate an expression and check for errors.
std::string PathResolverFindDataFile(const std::string &logical_file_name)
#define x
double m_parametrizationEnergy
Parameterization energy.
virtual double chi2(double energy, double sx, double sy, const Measurement &my_measAFP) const override
Calculates chi2 for reconstructed proton.
Gaudi::Property< std::string > m_parametrizationFileName
Name of the file containing parameterization.
double bothStations(double energy, const Measurement &my_measAFP, std::vector< double > &my_slopeCalculated, std::vector< double > &my_positionCalculated) const
Function obtained from parameterization equation.
double m_parametrizationPosition
Position for which parameterization was performed.
double calculateXslope(double energy, std::vector< double > &my_slopeCalculated) const
Calculates initial horizontal slope Calls calculateSlope(energy, 0)
double m_distanceBetweenStations
Distance between near and far station.
std::unique_ptr< AFP::Parameterization > m_parametrization
Pointer to parameterization.
double calculateSlope(double energy, int XorY, std::vector< double > &my_slopeCalculated) const
Calculates ininial slope based on measurements and reconstructed energy.
virtual xAOD::AFPProton * reco(const xAOD::AFPTrack *trkNear, const xAOD::AFPTrack *trkFar, std::unique_ptr< xAOD::AFPProtonContainer > &outputContainer) const override
Reconstructs single proton from pair of tracks.
double singleStation(double energy, const Measurement &my_measAFP, std::vector< double > &my_slopeCalculated, std::vector< double > &my_positionCalculated) const
Function obtained from parameterization equation.
AFP_ProtonRecoAnalytical(const std::string &type, const std::string &name, const IInterface *parent)
Default constructor.
double bisection(double(AFP_ProtonRecoAnalytical::*fun)(double, const Measurement &, std::vector< double > &, std::vector< double > &) const, const Measurement &my_measAFP, std::vector< double > &my_slopeCalculated, std::vector< double > &my_positionCalculated) const
Calculates root of given function.
double calculateYslope(double energy, std::vector< double > &my_slopeCalculated) const
Calculates initial vertical slope Calls calculateSlope(energy, 1)
StatusCode initialize() override
Loads parameterization.
double m_detectorPositionFar
Default position of AFP far station.
double m_detectorPositionNear
Default position of AFP near station.
Gaudi::Property< double > m_trackDistance
Gaudi::Property< bool > m_allowSingleStationReco
const std::vector< double > m_vertexIP
Vertex position.
Gaudi::Property< int > m_side
AFP_ProtonRecoBase(const std::string &type, const std::string &name, const IInterface *parent)
Default constructor.
static constexpr double m_ySigma
y-Sigma value
SG::ReadHandleKey< xAOD::AFPTrackContainer > m_trackContainerKey
Gaudi::Property< std::vector< double > > m_detectorPositions
static constexpr double m_xSigma
x-Sigma value
xAOD::AFPProton * createProton(const Momentum &momentum, const Measurement &my_measAFP, const int algID, std::unique_ptr< xAOD::AFPProtonContainer > &outputContainer) const
Creates and sets up a proton.
static constexpr int analytical
analytical algorithm id=0
float xLocal() const
Track position along X axis in station local coordinate system.
float yLocal() const
Track position along Y axis in station local coordinate system.
AFPTrack_v2 AFPTrack
Definition AFPTrack.h:12
AFPProton_v1 AFPProton
Definition AFPProton.h:11
Local class for storing tracks positions.