ATLAS Offline Software
BFieldCache.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 #include "CxxUtils/vec.h"
7 #include "CxxUtils/features.h"
8 #include <cmath>
9 
10 namespace {
11 #if HAVE_TARGET_CLONES
12 [[gnu::target_clones("avx2","default")]]
13 #endif
14 void getBzrphi(double Bzrphi[4],
15  const double field[3][8],
16  const double fz,
17  const double gz,
18  const double fr,
19  const double gr,
20  const double fphi,
21  const double gphi,
22  const double scale) {
23  /*
24  The following implement this calculation
25  const double* field = m_field[i];
26  Bzrphi[i] = scale * (gz * ( gr * (gphi * field[0] + fphi * field[4]) +
27  fr * (gphi * field[1] + fphi * field[5])) +
28  fz * (gr * (gphi * field[2] + fphi * field[6]) +
29  fr * (gphi * field[3] + fphi * field[7])));
30  in SIMD fashion.
31  The "lanes" are
32  ( field[0], field[1], field[2], field[3])
33  ( field[4], field[5], field[6], field[7])
34  aka the "vertical" part of the inermost parenthesis.
35 
36  Then we work our way out. Following the formula in a "vertical"
37  manner.
38 
39  The following code keeps the same order as operation as the
40  above formula. As we want identical results.
41  */
42  CxxUtils::vec<double, 4> rInterCoeff = {gr, fr, gr, fr};
43  // Load Bz at 8 corners of the bin
44  CxxUtils::vec<double, 4> field1_z = {field[0][0], field[0][1], field[0][2],
45  field[0][3]};
46  CxxUtils::vec<double, 4> field2_z = {field[0][4], field[0][5], field[0][6],
47  field[0][7]};
48  // Load Br at 8 corners of the bin
49  CxxUtils::vec<double, 4> field1_r = {field[1][0], field[1][1], field[1][2],
50  field[1][3]};
51  CxxUtils::vec<double, 4> field2_r = {field[1][4], field[1][5], field[1][6],
52  field[1][7]};
53  // Load Bphi at 8 corners of the bin
54  CxxUtils::vec<double, 4> field1_phi = {field[2][0], field[2][1], field[2][2],
55  field[2][3]};
56  CxxUtils::vec<double, 4> field2_phi = {field[2][4], field[2][5], field[2][6],
57  field[2][7]};
58 
59  CxxUtils::vec<double, 4> gPhiM_z = field1_z * gphi;
60  CxxUtils::vec<double, 4> fPhiM_z = field2_z * fphi;
61  CxxUtils::vec<double, 4> interp_z = (gPhiM_z + fPhiM_z) * rInterCoeff;
62 
63  CxxUtils::vec<double, 4> gPhiM_r = field1_r * gphi;
64  CxxUtils::vec<double, 4> fPhiM_r = field2_r * fphi;
65  CxxUtils::vec<double, 4> interp_r = (gPhiM_r + fPhiM_r) * rInterCoeff;
66 
67  CxxUtils::vec<double, 4> gPhiM_phi = field1_phi * gphi;
68  CxxUtils::vec<double, 4> fPhiM_phi = field2_phi * fphi;
69  CxxUtils::vec<double, 4> interp_phi = (gPhiM_phi + fPhiM_phi) * rInterCoeff;
70 
71  // We end up with
72  // 3 (z,r,phi) size 4 SIMD vectors :
73  // The entries of each of the 3 SIMD vectors are :
74  // 0 : gr * (gphi * field[0] + fphi * field[4]) ,
75  // 1 : fr * (gphi * field[1] + fphi * field[5]) ,
76  // 2 : gr * (gphi * field[2] + fphi * field[6]) ,
77  // 3 : fr * (gphi * field[3] + fphi * field[7]) ,
78 
79  // Switch to 4 vector of 3 entries (z,r,phi)
80  CxxUtils::vec<double, 4> Bzrphivec0 = {interp_z[0], interp_r[0],
81  interp_phi[0], 0};
82  CxxUtils::vec<double, 4> Bzrphivec1 = {interp_z[1], interp_r[1],
83  interp_phi[1], 0};
84  CxxUtils::vec<double, 4> Bzrphivec2 = {interp_z[2], interp_r[2],
85  interp_phi[2], 0};
86  CxxUtils::vec<double, 4> Bzrphivec3 = {interp_z[3], interp_r[3],
87  interp_phi[3], 0};
88 
89  // Do the final step for all 3 Bz,Br,Bphi at once
90  CxxUtils::vec<double, 4> Bzrphi1 = (Bzrphivec0 + Bzrphivec1) * gz;
91  CxxUtils::vec<double, 4> Bzrphi2 = (Bzrphivec2 + Bzrphivec3) * fz;
92  // now create the final (r,z,phi) values in one pass
93  CxxUtils::vec<double, 4> BzrphiV = (Bzrphi1 + Bzrphi2) * scale;
94  CxxUtils::vstore(Bzrphi, BzrphiV);
95 }
96 } // namespace
97 
98 void
100  double r,
101  double phi,
102  double* ATH_RESTRICT B,
103  double* ATH_RESTRICT deriv) const {
104 
105  const double x = xyz[0];
106  const double y = xyz[1];
107  const double z = xyz[2];
108 
109  // make sure phi is inside [m_phimin,m_phimax]
110  if (phi < m_phimin) {
111  phi += 2 * M_PI;
112  }
113  // fractional position inside this bin
114  const double fz = (z - m_zmin) * m_invz;
115  const double gz = 1.0 - fz;
116  const double fr = (r - m_rmin) * m_invr;
117  const double gr = 1.0 - fr;
118  const double fphi = (phi - m_phimin) * m_invphi;
119  const double gphi = 1.0 - fphi;
120 
121  // get B in Z,r,phi
122  double Bzrphi[4];
123  getBzrphi(Bzrphi, m_field, fz, gz, fr, gr, fphi, gphi, m_scale);
124  // convert (Bz,Br,Bphi) to (Bx,By,Bz)
125  double invr;
126  double c;
127  double s;
128  if (r > 0.0) {
129  invr = 1.0 / r;
130  c = x * invr;
131  s = y * invr;
132  } else {
133  invr = 0.0;
134  c = cos(m_phimin);
135  s = sin(m_phimin);
136  }
137  B[0] = Bzrphi[1] * c - Bzrphi[2] * s;
138  B[1] = Bzrphi[1] * s + Bzrphi[2] * c;
139  B[2] = Bzrphi[0];
140 
141  // compute field derivatives if requested
142  if (deriv) {
143  const double sz = m_scale * m_invz;
144  const double sr = m_scale * m_invr;
145  const double sphi = m_scale * m_invphi;
146 
147  std::array<double, 3> dBdz{};
148  std::array<double, 3> dBdr{};
149  std::array<double, 3> dBdphi{};
150 
151  for (int j = 0; j < 3; ++j) { // Bz, Br, Bphi components
152  const double* field = m_field[j];
153  dBdz[j] =
154  sz *
155  (gr * (gphi * (field[2] - field[0]) + fphi * (field[6] - field[4])) +
156  fr * (gphi * (field[3] - field[1]) + fphi * (field[7] - field[5])));
157  dBdr[j] =
158  sr *
159  (gz * (gphi * (field[1] - field[0]) + fphi * (field[5] - field[4])) +
160  fz * (gphi * (field[3] - field[2]) + fphi * (field[7] - field[6])));
161  dBdphi[j] =
162  sphi * (gz * (gr * (field[4] - field[0]) + fr * (field[5] - field[1])) +
163  fz * (gr * (field[6] - field[2]) + fr * (field[7] - field[3])));
164  }
165 
166  // convert to cartesian coordinates
167  const double cc = c * c;
168  const double cs = c * s;
169  const double ss = s * s;
170  const double ccinvr = cc * invr;
171  const double csinvr = cs * invr;
172  const double ssinvr = ss * invr;
173  const double sinvr = s * invr;
174  const double cinvr = c * invr;
175  deriv[0] = cc * dBdr[1] - cs * dBdr[2] - csinvr * dBdphi[1] +
176  ssinvr * dBdphi[2] + sinvr * B[1];
177  deriv[1] = cs * dBdr[1] - ss * dBdr[2] + ccinvr * dBdphi[1] -
178  csinvr * dBdphi[2] - cinvr * B[1];
179  deriv[2] = c * dBdz[1] - s * dBdz[2];
180  deriv[3] = cs * dBdr[1] + cc * dBdr[2] - ssinvr * dBdphi[1] -
181  csinvr * dBdphi[2] - sinvr * B[0];
182  deriv[4] = ss * dBdr[1] + cs * dBdr[2] + csinvr * dBdphi[1] +
183  ccinvr * dBdphi[2] + cinvr * B[0];
184  deriv[5] = s * dBdz[1] + c * dBdz[2];
185  deriv[6] = c * dBdr[0] - sinvr * dBdphi[0];
186  deriv[7] = s * dBdr[0] + cinvr * dBdphi[0];
187  deriv[8] = dBdz[0];
188  }
189 }
190 
beamspotman.r
def r
Definition: beamspotman.py:676
BFieldCache::m_phimin
double m_phimin
Definition: BFieldCache.h:67
features.h
Some additional feature test macros.
BFieldCache::m_invphi
double m_invphi
Definition: BFieldCache.h:72
python.SystemOfUnits.s
int s
Definition: SystemOfUnits.py:131
fitman.sz
sz
Definition: fitman.py:527
PowhegControl_ttHplus_NLO.ss
ss
Definition: PowhegControl_ttHplus_NLO.py:83
phi
Scalar phi() const
phi method
Definition: AmgMatrixBasePlugin.h:67
BFieldCache.h
M_PI
#define M_PI
Definition: ActiveFraction.h:11
xyz
#define xyz
BFieldCache::getB
void getB(const double *ATH_RESTRICT xyz, double r, double phi, double *ATH_RESTRICT B, double *ATH_RESTRICT deriv=nullptr) const
Definition: BFieldCache.cxx:99
gr
#define gr
ReadOfcFromCool.field
field
Definition: ReadOfcFromCool.py:48
drawFromPickle.cos
cos
Definition: drawFromPickle.py:36
CxxUtils::vstore
ATH_ALWAYS_INLINE void vstore(vec_type_t< VEC > *dst, const VEC &src)
Definition: vec.h:290
yodamerge_tmp.scale
scale
Definition: yodamerge_tmp.py:138
BFieldCache::m_invr
double m_invr
Definition: BFieldCache.h:71
x
#define x
BFieldCache::m_scale
double m_scale
Definition: BFieldCache.h:73
ATH_RESTRICT
#define ATH_RESTRICT
Definition: restrict.h:31
CxxUtils::vec
typename vecDetail::vec_typedef< T, N >::type vec
Define a nice alias for the vectorized type.
Definition: vec.h:207
BFieldCache::m_zmin
double m_zmin
Definition: BFieldCache.h:61
python.SystemOfUnits.sr
int sr
Definition: SystemOfUnits.py:113
z
#define z
BFieldCache::m_rmin
double m_rmin
Definition: BFieldCache.h:64
dqt_zlumi_alleff_HIST.B
B
Definition: dqt_zlumi_alleff_HIST.py:110
BFieldCache::m_invz
double m_invz
Definition: BFieldCache.h:70
y
#define y
vec.h
Vectorization helpers.
drawFromPickle.sin
sin
Definition: drawFromPickle.py:36
grepfile.fr
fr
Definition: grepfile.py:32
python.compressB64.c
def c
Definition: compressB64.py:93
python.handimod.cc
int cc
Definition: handimod.py:523
BFieldCache::m_field
double m_field[3][8]
Definition: BFieldCache.h:74