ATLAS Offline Software
BFieldCorFunc.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 */
4 
6 
8 #include "GaudiKernel/MsgStream.h"
12 #include "GeoModelHelpers/throwExcept.h"
13 #include "cmath"
14 
15 using namespace MuonCalib;
16 
17 //*****************************************************************************
18 
19 
20 BFieldCorFunc::BFieldCorFunc(const std::string &quality, const CalibFunc::ParVec &parameters, const IRtRelation *rt) :
22  init(quality, parameters, rt);
23 }
24 
27  init(std::string("medium"), parameters, rt);
28 }
29 
30 void BFieldCorFunc::init(const std::string &quality, const CalibFunc::ParVec &params, const IRtRelation *rt) {
32  // PARAMETERS //
34  m_quality = quality;
35  m_param = params;
36 
38  // CONSISTENCY CHECK //
40  if (m_param.size() != 2) {
41  THROW_EXCEPTION("Wrong number of parameters!");
42  return;
43  }
44 
46  // VARIABLES //
48  unsigned int nb_points(31); // number of sample points for the integral
49  // in the correction function
50  double step{0.}; // r step size
51  double time{0.}; // auxiliary time variable
52  BaseFunctionFitter fitter(6); // 6 fit parameters for the integral by
53  // default ("medium quality")
54  LegendrePolynomial legendre{};
55 
57  // QUALITY SETTING //
59  if (m_quality == "high") {
60  fitter.set_number_of_coefficients(8);
61  nb_points = 31;
62  m_step_size = 0.02;
63  }
64  if (m_quality == "medium") {
65  fitter.set_number_of_coefficients(8);
66  nb_points = 31;
67  m_step_size = 0.06;
68  }
69  if (m_quality == "low") {
70  fitter.set_number_of_coefficients(8);
71  nb_points = 31;
72  m_step_size = 0.12;
73  }
74  // sample points for the integral factor in the correction function
75  std::vector<SamplePoint> sample_points(nb_points);
76 
78  // CALCULATE THE INTEGRAL PART OF THE CORRECTION FUNCTION //
80  m_t_min = (rt)->tLower();
81  m_t_max = (rt)->tUpper();
82 
83  // minimum and maximum radius //
84  m_r_min = 0.025 * CLHEP::mm; // minimum radius
85  m_r_max = rt->radius(m_t_max); // maximum radius
86  if (m_r_max > 17.0 || m_r_max < m_r_min) {
87  MsgStream log(Athena::getMessageSvc(), "BFieldCorFunc");
88  log << MSG::INFO << "UNPHYSICAL MAXIMUM DRIFT RADIUS OF " << m_r_max << ", WILL BE SET TO 17.0!" << endmsg;
89  m_r_max = 17.0;
90  }
91  step = ((m_r_max - m_r_min) / static_cast<double>(nb_points - 1));
92 
93  // set the sample points //
94  double prev_r = 0;
95  double prev_integral = 0;
96  for (unsigned int k = 0; k < nb_points; k++) {
97  time = t_from_r(m_r_min + k * step, rt);
98  sample_points[k].set_x1(2 * (time - 0.5 * (m_t_min + m_t_max)) / (m_t_max - m_t_min));
99  double new_r = rt->radius(time);
100  double new_integral = 1.0e9 * integral(prev_r, new_r, rt) + prev_integral;
101  sample_points[k].set_x2(new_integral);
102  sample_points[k].set_error(1.0);
103  prev_r = new_r;
104  prev_integral = new_integral;
105  }
106 
107  // perform the fit //
108  fitter.fit_parameters(sample_points, 1, nb_points, legendre);
109  m_alpha = fitter.coefficients();
110 
111 } // end BFieldCorFunc::init
112 double BFieldCorFunc::t_from_r(const double r, const IRtRelation *rt) const {
114  // VARIABLES //
116  constexpr double precision{0.010}; // spatial precision of the inversion
117  double t_max{m_t_max}; // upper time search limit
118  double t_min{m_t_min}; // lower time search limit
119  double r_max{m_r_max}; // upper radius search limit
120  double r_min{m_r_min}; // lower radius search limit
122  // SEARCH FOR THE CORRESPONDING DRIFT TIME //
124  double t_guess, r_guess;
125 
126  do {
127  t_guess = t_min + (t_max - t_min) / (r_max - r_min) * (r - r_min);
128  r_guess = rt->radius(t_guess);
129  if (r_guess > r) {
130  r_max = r_guess;
131  t_max = t_guess;
132  } else {
133  r_min = r_guess;
134  t_min = t_guess;
135  }
136  } while (t_max - t_min > 0.1 && std::abs(r_guess - r) > precision);
137  return t_guess;
138 } // end BFieldCorFunc::t_from_r
139 
140 double BFieldCorFunc::integral(const double r_min, const double r_max, const IRtRelation *rt) const {
141  // catch fp exceptions//
142  if (m_r_min < 1e-10 || r_min < m_r_min) return 0.0;
143 
145  // VARIABLES //
147  const double E0{m_param[0] / std::log(m_r_max / m_r_min)}; // E(r)=E0/r
148  double radius{r_max};
149  double rp{r_min}; // auxiliary radius variables
150  double integ{0.0}; // current value of the integral
151  // double step(0.010); // integration step size [mm]
152  double step{m_step_size}; // integration step size [mm]
153  double time{0.}; // drift time
154 
156  // r IN [m_r_min, m_r_max]? //
158  if (r_max < r_min) { return 0.0; }
159  if (r_max > m_r_max) { radius = m_r_max; }
160 
162  // INTEGRATION //
164  double delta = step;
165  while (rp < radius) {
166  time = t_from_r(rp, rt);
167  if (rp + step > radius) delta = radius - rp;
168  integ += 1.0e-3 * delta * std::pow(std::abs(rt->driftVelocity(time)) * 1.0e6, 1.0 - m_param[1]) /
169  std::pow(E0 / (rp * 1.0e-3), 2.0 - m_param[1]);
170  rp += step;
171  }
172 
173  return integ;
174 } // end BFieldCorFunc::integral
175 double BFieldCorFunc::epsilon() const { return m_param[1]; }
177  init(m_quality, m_param, &rt);
178 }
179 
180 std::string BFieldCorFunc::name() const { return std::string("BFieldCorFunc"); }
181 
182 double BFieldCorFunc::correction(double t, double B_wire, double B_mu) const {
184  // VARIABLES //
186  double B_perp{std::hypot(B_wire, B_mu)}; // B orthogonal to the
187  // electron drift path
188  double B_factor{std::pow(B_perp, 2.0 - m_param[1])};
189  double precision{0.1}; // precision of the correction in ns
190  double t_max{t}; // upper time search limit
191  double t_min{t - 2 * correction_to_B(t, B_wire, B_mu, B_factor)}; // lower time search limit
192  if (t_min < m_t_min) t_min = m_t_min;
193  double time{t}; // auxiliary time variable
194  double integ{0.0}; // integral
195  double tmean{0.5 * (m_t_min + m_t_max)}; // mean time
196  double tlength{m_t_max - m_t_min}; // length of drift-time interval
197 
199  // DRIFT TIME CHECK //
201  if (t <= m_t_min) { return 0.0; }
202  if (t > m_t_max) {
203  t_max = m_t_max;
204  time = m_t_max;
205  }
206 
208  // SEARCH FOR THE CORRECTED DRIFT TIME //
210  while (t_max - t_min > precision) {
211  integ = 0.0;
212  for (int k = 0; k < m_alpha.rows(); k++) {
213  integ += m_alpha[k] * std::legendre(k, 2 * (0.5 * (t_min + t_max) - tmean) / tlength);
214  }
215  if (0.5 * (t_min + t_max) + B_factor * integ > time) {
216  t_max = 0.5 * (t_min + t_max);
217  } else {
218  t_min = 0.5 * (t_min + t_max);
219  }
220  }
221 
222  return B_factor * integ;
223 } // end BFieldCorFunc::correction
224 
225 double BFieldCorFunc::correction_to_B(double t, double B_wire, double B_mu, double B_factor) const {
227  // VARIABLES //
229  if (B_factor < 0) {
230  const double B_perp{std::hypot(B_wire, B_mu)};
231  // B orthogonal to the electron drift path
232  B_factor = std::pow(B_perp, 2.0 - m_param[1]);
233  }
234  double time{t};
235  double integ{0.0}; // integral
236  double tmean{0.5 * (m_t_min + m_t_max)}; // mean time
237  double tlength{m_t_max - m_t_min}; // length of drift-time interval
238 
240  // DRIFT TIME CHECK //
242  if (t <= m_t_min) { return 0.0; }
243  if (t > m_t_max) { time = m_t_max; }
244 
246  // CALCULATE THE CORRECTION //
248  for (int k = 0; k < m_alpha.rows(); k++) {
249  integ += m_alpha[k] * std::legendre(k, 2 * (time - tmean) / tlength);
250  }
251 
252  return B_factor * integ;
253 } // end BFieldCorFunc::correction_to_B
MuonCalib::BFieldCorFunc::m_r_max
double m_r_max
Definition: BFieldCorFunc.h:120
AllowedVariables::e
e
Definition: AsgElectronSelectorTool.cxx:37
beamspotman.r
def r
Definition: beamspotman.py:676
LArSamples::FitterData::fitter
const ShapeFitter * fitter
Definition: ShapeFitter.cxx:23
MuonCalib::BFieldCorFunc::correction
double correction(double t, double B_wire, double B_mu) const
get t(r, !=0)-t(r, =0); t = drift time t [ns] for B=0; B_wire = magnetic field parallel to the anode ...
Definition: BFieldCorFunc.cxx:182
MuonCalib::BFieldCorFunc::m_t_max
double m_t_max
Definition: BFieldCorFunc.h:117
MuonCalib::BFieldCorFunc::m_t_min
double m_t_min
Definition: BFieldCorFunc.h:116
getMessageSvc.h
singleton-like access to IMessageSvc via open function and helper
MuonCalib::BFieldCorFunc::init
void init(const std::string &quality, const CalibFunc::ParVec &params, const IRtRelation *rt)
Definition: BFieldCorFunc.cxx:30
conifer::pow
constexpr int pow(int x)
Definition: conifer.h:20
MuonCalib::BFieldCorFunc::correction_to_B
double correction_to_B(double t, double B_wire, double B_mu, double B_factor=-1.0) const
Definition: BFieldCorFunc.cxx:225
MuonCalib::IMdtBFieldCorFunc
generic interface for b-field correction functions
Definition: IMdtBFieldCorFunc.h:14
read_hist_ntuple.t
t
Definition: read_hist_ntuple.py:5
THROW_EXCEPTION
#define THROW_EXCEPTION(MSG)
Definition: MMReadoutElement.cxx:48
BFieldCorFunc.h
Athena::getMessageSvc
IMessageSvc * getMessageSvc(bool quiet=false)
Definition: getMessageSvc.cxx:20
MuonCalib::BFieldCorFunc::name
std::string name() const
get the class name
Definition: BFieldCorFunc.cxx:180
MuonCalib::BaseFunctionFitter
Definition: BaseFunctionFitter.h:39
MuonCalib::BFieldCorFunc::BFieldCorFunc
BFieldCorFunc(const std::string &quality, const CalibFunc::ParVec &parameters, const IRtRelation *rt)
Constructor: quality = "high", slow but accurate initialization initialization of the correction func...
Definition: BFieldCorFunc.cxx:20
MuonCalib::BFieldCorFunc::epsilon
double epsilon() const
< get the parameter of the B-field correction function
Definition: BFieldCorFunc.cxx:175
endmsg
#define endmsg
Definition: AnalysisConfig_Ntuple.cxx:63
MuonCalib::BFieldCorFunc::t_from_r
double t_from_r(const double r, const IRtRelation *rt) const
Definition: BFieldCorFunc.cxx:112
MuonCalib::LegendrePolynomial
Definition: LegendrePolynomial.h:19
MuonCalib
CscCalcPed - algorithm that finds the Cathode Strip Chamber pedestals from an RDO.
Definition: CscCalcPed.cxx:22
MuonCalib::CalibFunc::ParVec
std::vector< double > ParVec
Definition: CalibFunc.h:35
MuonCalib::BFieldCorFunc::m_alpha
Amg::VectorX m_alpha
Definition: BFieldCorFunc.h:109
BaseFunctionFitter.h
MuonCalib::IRtRelation::radius
virtual double radius(double t) const =0
returns drift radius for a given time
MuonCalib::BFieldCorFunc::m_step_size
double m_step_size
Definition: BFieldCorFunc.h:106
MuonCalib::IRtRelation::driftVelocity
virtual double driftVelocity(double t) const =0
Returns the drift velocity for a given time.
ParticleGun_SamplingFraction.radius
radius
Definition: ParticleGun_SamplingFraction.py:96
python.SystemOfUnits.mm
int mm
Definition: SystemOfUnits.py:83
MuonCalib::BFieldCorFunc::m_r_min
double m_r_min
Definition: BFieldCorFunc.h:119
MuonCalib::CalibFunc::parameters
const ParVec & parameters() const
Definition: CalibFunc.h:40
IRtRelation.h
python.CaloCondTools.log
log
Definition: CaloCondTools.py:20
LArCellBinning.step
step
Definition: LArCellBinning.py:158
physics_parameters.parameters
parameters
Definition: physics_parameters.py:144
MuonCalib::BFieldCorFunc::m_param
std::vector< double > m_param
Definition: BFieldCorFunc.h:102
MuonCalib::BFieldCorFunc::setRtRelationship
void setRtRelationship(const IRtRelation &rt)
< set the parameter of the B-field correction function = eps
Definition: BFieldCorFunc.cxx:176
MuonCalib::BFieldCorFunc::m_quality
std::string m_quality
Definition: BFieldCorFunc.h:105
MuonCalib::BFieldCorFunc::integral
double integral(const double r_min, const double r_max, const IRtRelation *rt) const
Definition: BFieldCorFunc.cxx:140
PowhegControl_ttFCNC_NLO.params
params
Definition: PowhegControl_ttFCNC_NLO.py:226
rp
ReadCards * rp
Definition: IReadCards.cxx:26
LegendrePolynomial.h
MuonCalib::IRtRelation
generic interface for a rt-relation
Definition: IRtRelation.h:15
fitman.k
k
Definition: fitman.py:528