ATLAS Offline Software
Loading...
Searching...
No Matches
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
10namespace {
11#if HAVE_TARGET_CLONES
12[[gnu::target_clones("avx2","default")]]
13#endif
14void 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
98void
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
#define M_PI
Scalar phi() const
phi method
#define gr
static Double_t sz
static Double_t ss
#define y
#define xyz
#define x
#define z
double m_field[3][8]
Definition BFieldCache.h:74
double m_invphi
Definition BFieldCache.h:72
double m_rmin
Definition BFieldCache.h:64
double m_phimin
Definition BFieldCache.h:67
void getB(const double *ATH_RESTRICT xyz, double r, double phi, double *ATH_RESTRICT B, double *ATH_RESTRICT deriv=nullptr) const
double m_invr
Definition BFieldCache.h:71
double m_zmin
Definition BFieldCache.h:61
double m_scale
Definition BFieldCache.h:73
double m_invz
Definition BFieldCache.h:70
Some additional feature test macros.
int r
Definition globals.cxx:22
typename vecDetail::vec_typedef< T, N >::type vec
Define a nice alias for the vectorized type.
Definition vec.h:207
ATH_ALWAYS_INLINE void vstore(vec_type_t< VEC > *dst, const VEC &src)
Definition vec.h:290
#define ATH_RESTRICT
Definition restrict.h:31
Vectorization helpers.