ATLAS Offline Software
Loading...
Searching...
No Matches
BFieldMesh.icc
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include "CxxUtils/vec.h"
6// constructor
7template<class T>
8BFieldMesh<T>::BFieldMesh(double zmin,
9 double zmax,
10 double rmin,
11 double rmax,
12 double phimin,
13 double phimax,
14 double bscale)
15 : m_scale(bscale)
16 , m_nomScale(bscale)
17{
18 m_min = { zmin, rmin, phimin };
19 m_max = { zmax, rmax, phimax };
20}
21// set ranges
22template<class T>
23void
24BFieldMesh<T>::setRange(double zmin,
25 double zmax,
26 double rmin,
27 double rmax,
28 double phimin,
29 double phimax)
30{
31 m_min = { zmin, rmin, phimin };
32 m_max = { zmax, rmax, phimax };
33}
34
35// set bscale
36template<class T>
37void
38BFieldMesh<T>::setBscale(double bscale)
39{
40 m_scale = m_nomScale = bscale;
41}
42
43// scale bscale by a factor
44template<class T>
45void
46BFieldMesh<T>::scaleBscale(double factor)
47{
48 m_scale = factor * m_nomScale;
49}
50
51//
52// Reserve space in the vectors to avoid unnecessary memory re-allocations.
53//
54template<class T>
55void
56BFieldMesh<T>::reserve(int nz, int nr, int nphi, int nfield)
57{
58 m_mesh[0].reserve(nz);
59 m_mesh[1].reserve(nr);
60 m_mesh[2].reserve(nphi);
61 m_field.reserve(nfield);
62}
63
64template<class T>
65void
66BFieldMesh<T>::reserve(int nz, int nr, int nphi)
67{
68 reserve(nz, nr, nphi, nz * nr * nphi);
69}
70
71// add elements to vectors
72template<class T>
73void
74BFieldMesh<T>::appendMesh(int axis, double value)
75{
76 m_mesh[axis].push_back(value);
77}
78
79template<class T>
80void
81BFieldMesh<T>::appendField(const BFieldVector<T>& field)
82{
83 m_field.push_back(field);
84}
85
86//
87// Construct the look-up table to accelerate bin-finding.
88//
89template<class T>
90void
91BFieldMesh<T>::buildLUT()
92{
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();
99 double q(width);
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]);
102 }
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
107 ++n;
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]) {
111 m++;
112 }
113 m_LUT[j].push_back(m);
114 }
115 }
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
118}
119
120template<class T>
121int
122BFieldMesh<T>::memSize() const
123{
124 int size = 0;
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();
130 }
131 size += sizeof(BFieldVector<T>) * m_field.capacity();
132 return size;
133}
134
135//
136// Test if a point (z,r,phi) is inside this mesh region.
137//
138template<class T>
139bool
140BFieldMesh<T>::inside(double z, double r, double phi) const
141{
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()) {
146 phi += 2.0 * M_PI;
147 }
148 return (phi >= phimin() && phi <= phimax() && z >= zmin() && z <= zmax() &&
149 r >= rmin() && r <= rmax());
150}
151
152//
153// Find and return the cache of the bin containing (z,r,phi)
154//
155template<class T>
156void
157BFieldMesh<T>::getCache(double z,
158 double r,
159 double phi,
160 BFieldCache& cache,
161 double scaleFactor) const
162{
163 // make sure phi is inside this zone
164 if (phi < phimin()) {
165 phi += 2.0 * M_PI;
166 }
167 // find the mesh, and relative location in the mesh
168 // z
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]);
173 // r
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]);
178 // phi
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
184 cache.setRange(
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;
189 // store the B scale
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];
199
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]};
205
206
207 CxxUtils::vec<int, 8> field2I = {fvec0[1], fvec1[1], fvec2[1], fvec3[1],
208 fvec4[1], fvec5[1], fvec6[1], fvec7[1]};
209
210
211 CxxUtils::vec<int, 8> field3I = {fvec0[2], fvec1[2], fvec2[2], fvec3[2],
212 fvec4[2], fvec5[2], fvec6[2], fvec7[2]};
213
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);
220
221 cache.setField(sf * field1, sf * field2, sf * field3);
222 } else {
223 CxxUtils::vec<double, 8> field1 = {fvec0[0], fvec1[0], fvec2[0], fvec3[0],
224 fvec4[0], fvec5[0], fvec6[0], fvec7[0]};
225
226 CxxUtils::vec<double, 8> field2 = {fvec0[1], fvec1[1], fvec2[1], fvec3[1],
227 fvec4[1], fvec5[1], fvec6[1], fvec7[1]};
228
229 CxxUtils::vec<double, 8> field3 = {fvec0[2], fvec1[2], fvec2[2], fvec3[2],
230 fvec4[2], fvec5[2], fvec6[2], fvec7[2]};
231
232 cache.setField(sf * field1, sf * field2, sf * field3);
233 }
234}
235
236//
237// Compute the magnetic field (and the derivatives) without caching
238//
239template<class T>
240void
241BFieldMesh<T>::getB(const double* ATH_RESTRICT xyz,
242 double* ATH_RESTRICT B,
243 double* ATH_RESTRICT deriv) const
244{
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()) {
252 phi += 2.0 * M_PI;
253 }
254 // is it inside this map?
255 if (!inside(z, r, phi)) { // no
256 B[0] = B[1] = B[2] = 0.0;
257 if (deriv) {
258 for (int i = 0; i < 9; ++i) {
259 deriv[i] = 0.0;
260 }
261 }
262 return;
263 }
264 BFieldCache cache;
265 this->getCache(z, r, phi, cache, 1.0);
266 cache.getB(xyz, r, phi, B, deriv);
267}
268// accessors
269template<class T>
270double
271BFieldMesh<T>::min(size_t axis) const
272{
273 return m_min[axis];
274}
275
276template<class T>
277double
278BFieldMesh<T>::max(size_t axis) const
279{
280 return m_max[axis];
281}
282
283template<class T>
284double
285BFieldMesh<T>::zmin() const
286{
287 return m_min[0];
288}
289
290template<class T>
291double
292BFieldMesh<T>::zmax() const
293{
294 return m_max[0];
295}
296
297template<class T>
298double
299BFieldMesh<T>::rmin() const
300{
301 return m_min[1];
302}
303
304template<class T>
305double
306BFieldMesh<T>::rmax() const
307{
308 return m_max[1];
309}
310
311template<class T>
312double
313BFieldMesh<T>::phimin() const
314{
315 return m_min[2];
316}
317
318template<class T>
319double
320BFieldMesh<T>::phimax() const
321{
322 return m_max[2];
323}
324
325template<class T>
326unsigned
327BFieldMesh<T>::nmesh(size_t axis) const
328{
329 return m_mesh[axis].size();
330}
331
332template<class T>
333double
334BFieldMesh<T>::mesh(size_t axis, size_t index) const
335{
336 return m_mesh[axis][index];
337}
338
339template<class T>
340unsigned
341BFieldMesh<T>::nfield() const
342{
343 return m_field.size();
344}
345
346template<class T>
347const BFieldVector<T>&
348BFieldMesh<T>::field(size_t index) const
349{
350 return m_field[index];
351}
352
353template<class T>
354double
355BFieldMesh<T>::bscale() const
356{
357 return m_scale;
358}
359