2 Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
5 #include "CxxUtils/vec.h"
8 BFieldMesh<T>::BFieldMesh(double zmin,
18 m_min = { zmin, rmin, phimin };
19 m_max = { zmax, rmax, phimax };
24 BFieldMesh<T>::setRange(double zmin,
31 m_min = { zmin, rmin, phimin };
32 m_max = { zmax, rmax, phimax };
38 BFieldMesh<T>::setBscale(double bscale)
40 m_scale = m_nomScale = bscale;
43 // scale bscale by a factor
46 BFieldMesh<T>::scaleBscale(double factor)
48 m_scale = factor * m_nomScale;
52 // Reserve space in the vectors to avoid unnecessary memory re-allocations.
56 BFieldMesh<T>::reserve(int nz, int nr, int nphi, int nfield)
58 m_mesh[0].reserve(nz);
59 m_mesh[1].reserve(nr);
60 m_mesh[2].reserve(nphi);
61 m_field.reserve(nfield);
66 BFieldMesh<T>::reserve(int nz, int nr, int nphi)
68 reserve(nz, nr, nphi, nz * nr * nphi);
71 // add elements to vectors
74 BFieldMesh<T>::appendMesh(int axis, double value)
76 m_mesh[axis].push_back(value);
81 BFieldMesh<T>::appendField(const BFieldVector<T>& field)
83 m_field.push_back(field);
87 // Construct the look-up table to accelerate bin-finding.
91 BFieldMesh<T>::buildLUT()
93 for (int j = 0; j < 3; ++j) { // z, r, phi
94 // align the m_mesh edges to m_min/m_max
95 m_mesh[j].front() = m_min[j];
96 m_mesh[j].back() = m_max[j];
97 // determine the unit size, q, to be used in the LUTs
98 const double width = m_mesh[j].back() - m_mesh[j].front();
100 for (unsigned i = 0; i < m_mesh[j].size() - 1; ++i) {
101 q = std::min(q, m_mesh[j][i + 1] - m_mesh[j][i]);
103 // find the number of units in the LUT
104 int n = int(width / q) + 1;
105 q = width / (n + 0.5);
106 m_invUnit[j] = 1.0 / q; // new unit size
108 int m = 0; // mesh number
109 for (int i = 0; i < n; ++i) { // LUT index
110 if (i * q + m_mesh[j].front() > m_mesh[j][m + 1]) {
113 m_LUT[j].push_back(m);
116 m_roff = m_mesh[2].size(); // index offset for incrementing r by 1
117 m_zoff = m_roff * m_mesh[1].size(); // index offset for incrementing z by 1
122 BFieldMesh<T>::memSize() const
125 size += sizeof(double) * 10;
126 size += sizeof(int) * 2;
127 for (int i = 0; i < 3; ++i) {
128 size += sizeof(double) * m_mesh[i].capacity();
129 size += sizeof(int) * m_LUT[i].capacity();
131 size += sizeof(BFieldVector<T>) * m_field.capacity();
136 // Test if a point (z,r,phi) is inside this mesh region.
140 BFieldMesh<T>::inside(double z, double r, double phi) const
142 // assume phi is in [-pi,pi].
143 // phimax() is in [0,2pi], but phimin() may be < 0 if the range crosses phi =
144 // 0. we have to test twice to get all possible cases.
145 if (phi < phimin()) {
148 return (phi >= phimin() && phi <= phimax() && z >= zmin() && z <= zmax() &&
149 r >= rmin() && r <= rmax());
153 // Find and return the cache of the bin containing (z,r,phi)
157 BFieldMesh<T>::getCache(double z,
161 double scaleFactor) const
163 // make sure phi is inside this zone
164 if (phi < phimin()) {
167 // find the mesh, and relative location in the mesh
169 const std::vector<double>& mz(m_mesh[0]);
170 int iz = static_cast<int>((z - zmin()) * m_invUnit[0]); // index to LUT
171 iz = m_LUT[0][iz]; // tentative mesh index from LUT
172 iz += (z > mz[iz + 1]);
174 const std::vector<double>& mr(m_mesh[1]);
175 int ir = static_cast<int>((r - rmin()) * m_invUnit[1]); // index to LUT
176 ir = m_LUT[1][ir]; // tentative mesh index from LUT
177 ir += (r > mr[ir + 1]);
179 const std::vector<double>& mphi(m_mesh[2]);
180 int iphi = static_cast<int>((phi - phimin()) * m_invUnit[2]); // index to LUT
181 iphi = m_LUT[2][iphi]; // tentative mesh index from LUT
182 iphi += (phi > mphi[iphi + 1]);
183 // store the bin edges
185 mz[iz], mz[iz + 1], mr[ir], mr[ir + 1], mphi[iphi], mphi[iphi + 1]);
186 // store the B field at the 8 corners of the bin in the cache
187 const int im0 = iz * m_zoff + ir * m_roff + iphi; // index of the first corner
188 const double sf = scaleFactor;
190 cache.setBscale(m_scale);
191 const BFieldVector<T>& fvec0 = m_field[im0];
192 const BFieldVector<T>& fvec1 = m_field[im0 + m_roff];
193 const BFieldVector<T>& fvec2 = m_field[im0 + m_zoff];
194 const BFieldVector<T>& fvec3 = m_field[im0 + m_zoff + m_roff];
195 const BFieldVector<T>& fvec4 = m_field[im0 + 1];
196 const BFieldVector<T>& fvec5 = m_field[im0 + m_roff + 1];
197 const BFieldVector<T>& fvec6 = m_field[im0 + m_zoff + 1];
198 const BFieldVector<T>& fvec7 = m_field[im0 + m_zoff + m_roff + 1];
200 // In the usual case the m_field is of type short int
201 // else (special case) can be double
202 if constexpr (std::is_same<T, short>::value) {
203 CxxUtils::vec<int, 8> field1I = {fvec0[0], fvec1[0], fvec2[0], fvec3[0],
204 fvec4[0], fvec5[0], fvec6[0], fvec7[0]};
207 CxxUtils::vec<int, 8> field2I = {fvec0[1], fvec1[1], fvec2[1], fvec3[1],
208 fvec4[1], fvec5[1], fvec6[1], fvec7[1]};
211 CxxUtils::vec<int, 8> field3I = {fvec0[2], fvec1[2], fvec2[2], fvec3[2],
212 fvec4[2], fvec5[2], fvec6[2], fvec7[2]};
214 CxxUtils::vec<double, 8> field1;
215 CxxUtils::vec<double, 8> field2;
216 CxxUtils::vec<double, 8> field3;
217 CxxUtils::vconvert(field1, field1I);
218 CxxUtils::vconvert(field2, field2I);
219 CxxUtils::vconvert(field3, field3I);
221 cache.setField(sf * field1, sf * field2, sf * field3);
223 CxxUtils::vec<double, 8> field1 = {fvec0[0], fvec1[0], fvec2[0], fvec3[0],
224 fvec4[0], fvec5[0], fvec6[0], fvec7[0]};
226 CxxUtils::vec<double, 8> field2 = {fvec0[1], fvec1[1], fvec2[1], fvec3[1],
227 fvec4[1], fvec5[1], fvec6[1], fvec7[1]};
229 CxxUtils::vec<double, 8> field3 = {fvec0[2], fvec1[2], fvec2[2], fvec3[2],
230 fvec4[2], fvec5[2], fvec6[2], fvec7[2]};
232 cache.setField(sf * field1, sf * field2, sf * field3);
237 // Compute the magnetic field (and the derivatives) without caching
241 BFieldMesh<T>::getB(const double* ATH_RESTRICT xyz,
242 double* ATH_RESTRICT B,
243 double* ATH_RESTRICT deriv) const
245 // cylindrical coordinates
246 const double x = xyz[0];
247 const double y = xyz[1];
248 const double z = xyz[2];
249 const double r = sqrt(x * x + y * y);
250 double phi = std::atan2(y, x);
251 if (phi < phimin()) {
254 // is it inside this map?
255 if (!inside(z, r, phi)) { // no
256 B[0] = B[1] = B[2] = 0.0;
258 for (int i = 0; i < 9; ++i) {
265 this->getCache(z, r, phi, cache, 1.0);
266 cache.getB(xyz, r, phi, B, deriv);
271 BFieldMesh<T>::min(size_t axis) const
278 BFieldMesh<T>::max(size_t axis) const
285 BFieldMesh<T>::zmin() const
292 BFieldMesh<T>::zmax() const
299 BFieldMesh<T>::rmin() const
306 BFieldMesh<T>::rmax() const
313 BFieldMesh<T>::phimin() const
320 BFieldMesh<T>::phimax() const
327 BFieldMesh<T>::nmesh(size_t axis) const
329 return m_mesh[axis].size();
334 BFieldMesh<T>::mesh(size_t axis, size_t index) const
336 return m_mesh[axis][index];
341 BFieldMesh<T>::nfield() const
343 return m_field.size();
347 const BFieldVector<T>&
348 BFieldMesh<T>::field(size_t index) const
350 return m_field[index];
355 BFieldMesh<T>::bscale() const