ATLAS Offline Software
Loading...
Searching...
No Matches
AtlasFieldMap.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
6// AtlasMTFieldSvc.cxx, (c) ATLAS Detector software
8
9// ISF_Services include
11
12// PathResolver
14
15// ROOT
16#include "TFile.h"
17#include "TTree.h"
18
19
20
21//
22// read the map from a ROOT file.
23// returns 0 if successful.
24//
25bool
27 float solenoidCurrent,
28 float toroidCurrent)
29{
30 // save currents
33
34 // open the tree
35 TTree* tree = (TTree*)rootfile->Get("BFieldMap");
36 // if ( tree == 0 ) {
37 // // no tree
38 // ATH_MSG_ERROR("readMap(): TTree 'BFieldMap' does not exist in ROOT
39 // field map"); return StatusCode::FAILURE;
40 // }
41 int id;
42 double zmin;
43 double zmax;
44 double rmin;
45 double rmax;
46 double phimin;
47 double phimax;
48 double bscale;
49 int ncond;
50 bool* finite;
51 double* p1x;
52 double* p1y;
53 double* p1z;
54 double* p2x;
55 double* p2y;
56 double* p2z;
57 double* curr;
58 int nmeshz;
59 int nmeshr;
60 int nmeshphi;
61 double* meshz;
62 double* meshr;
63 double* meshphi;
64 int nfield;
65 short* fieldz;
66 short* fieldr;
67 short* fieldphi;
68 // define the fixed-sized branches first
69 tree->SetBranchAddress("id", &id);
70 tree->SetBranchAddress("zmin", &zmin);
71 tree->SetBranchAddress("zmax", &zmax);
72 tree->SetBranchAddress("rmin", &rmin);
73 tree->SetBranchAddress("rmax", &rmax);
74 tree->SetBranchAddress("phimin", &phimin);
75 tree->SetBranchAddress("phimax", &phimax);
76 tree->SetBranchAddress("bscale", &bscale);
77 tree->SetBranchAddress("ncond", &ncond);
78 tree->SetBranchAddress("nmeshz", &nmeshz);
79 tree->SetBranchAddress("nmeshr", &nmeshr);
80 tree->SetBranchAddress("nmeshphi", &nmeshphi);
81 tree->SetBranchAddress("nfield", &nfield);
82 // prepare arrays - need to know the maximum sizes
83 // open the tree of buffer sizes (may not exist in old maps)
84 unsigned maxcond(0);
85
86 unsigned maxmeshz(0);
87
88 unsigned maxmeshr(0);
89
90 unsigned maxmeshphi(0);
91
92 unsigned maxfield(0);
93 TTree* tmax = (TTree*)rootfile->Get("BFieldMapSize");
94 if (tmax != nullptr) {
95 tmax->SetBranchAddress("maxcond", &maxcond);
96 tmax->SetBranchAddress("maxmeshz", &maxmeshz);
97 tmax->SetBranchAddress("maxmeshr", &maxmeshr);
98 tmax->SetBranchAddress("maxmeshphi", &maxmeshphi);
99 tmax->SetBranchAddress("maxfield", &maxfield);
100 tmax->GetEntry(0);
101 } else { // "BFieldMapSize" tree does not exist
102 for (int i = 0; i < tree->GetEntries(); i++) {
103 tree->GetEntry(i);
104 maxcond = std::max(maxcond, (unsigned)ncond);
105 maxmeshz = std::max(maxmeshz, (unsigned)nmeshz);
106 maxmeshr = std::max(maxmeshr, (unsigned)nmeshr);
107 maxmeshphi = std::max(maxmeshphi, (unsigned)nmeshphi);
108 maxfield = std::max(maxfield, (unsigned)nfield);
109 }
110 }
111 finite = new bool[maxcond];
112 p1x = new double[maxcond];
113 p1y = new double[maxcond];
114 p1z = new double[maxcond];
115 p2x = new double[maxcond];
116 p2y = new double[maxcond];
117 p2z = new double[maxcond];
118 curr = new double[maxcond];
119 meshz = new double[maxmeshz];
120 meshr = new double[maxmeshr];
121 meshphi = new double[maxmeshphi];
122 fieldz = new short[maxfield];
123 fieldr = new short[maxfield];
124 fieldphi = new short[maxfield];
125 // define the variable length branches
126 tree->SetBranchAddress("finite", finite);
127 tree->SetBranchAddress("p1x", p1x);
128 tree->SetBranchAddress("p1y", p1y);
129 tree->SetBranchAddress("p1z", p1z);
130 tree->SetBranchAddress("p2x", p2x);
131 tree->SetBranchAddress("p2y", p2y);
132 tree->SetBranchAddress("p2z", p2z);
133 tree->SetBranchAddress("curr", curr);
134 tree->SetBranchAddress("meshz", meshz);
135 tree->SetBranchAddress("meshr", meshr);
136 tree->SetBranchAddress("meshphi", meshphi);
137 tree->SetBranchAddress("fieldz", fieldz);
138 tree->SetBranchAddress("fieldr", fieldr);
139 tree->SetBranchAddress("fieldphi", fieldphi);
140
141 // reserve the space for m_zone so that it won't move as the vector grows
142 m_zone.reserve(tree->GetEntries());
143 // read all tree and store
144 for (int i = 0; i < tree->GetEntries(); i++) {
145 tree->GetEntry(i);
146 BFieldZone z(id, zmin, zmax, rmin, rmax, phimin, phimax, bscale);
147 m_zone.push_back(z);
148 m_zone.back().reserve(nmeshz, nmeshr, nmeshphi);
149 for (int j = 0; j < ncond; j++) {
150 double p1[3];
151
152 double p2[3];
153 p1[0] = p1x[j];
154 p1[1] = p1y[j];
155 p1[2] = p1z[j];
156 p2[0] = p2x[j];
157 p2[1] = p2y[j];
158 p2[2] = p2z[j];
159 BFieldCond cond(finite[j], p1, p2, curr[j]);
160 m_zone.back().appendCond(cond);
161 }
162 for (int j = 0; j < nmeshz; j++) {
163 m_zone.back().appendMesh(0, meshz[j]);
164 }
165 for (int j = 0; j < nmeshr; j++) {
166 m_zone.back().appendMesh(1, meshr[j]);
167 }
168 for (int j = 0; j < nmeshphi; j++) {
169 m_zone.back().appendMesh(2, meshphi[j]);
170 }
171 for (int j = 0; j < nfield; j++) {
172 BFieldVector<short> field(fieldz[j], fieldr[j], fieldphi[j]);
173 m_zone.back().appendField(field);
174 }
175 }
176 // clean up
177 tree->Delete();
178 delete[] finite;
179 delete[] p1x;
180 delete[] p1y;
181 delete[] p1z;
182 delete[] p2x;
183 delete[] p2y;
184 delete[] p2z;
185 delete[] curr;
186 delete[] meshz;
187 delete[] meshr;
188 delete[] meshphi;
189 delete[] fieldz;
190 delete[] fieldr;
191 delete[] fieldphi;
192 // build the LUTs
193 buildLUT();
194 buildZR();
195
196 // setup id for solenoid bfield zone
197 BFieldZone* solezone = findZoneSlow(0.0, 0.0, 0.0);
198 if (solezone) {
199 m_solenoidZoneId = solezone->id();
200 }
201
202 return true;
203}
204
205//
206// Search for the zone that contains a point (z, r, phi)
207// This is a linear-search version, used only to construct the LUT.
208//
211{
212 for (int j = m_zone.size() - 1; j >= 0; --j) {
213 if (m_zone[j].inside(z, r, phi)) {
214 return &m_zone[j];
215 }
216 }
217 return nullptr;
218}
219
220//
221// Build the look-up table used by FindZone().
222// Called by readMap()
223// It also calls buildLUT() for all zones.
224//
225void
227{
228
229 // make lists of (z,r,phi) edges of all zones
230 for (int j = 0; j < 3; j++) { // z, r, phi
231 for (unsigned i = 0; i < m_zone.size(); i++) {
232 double e[2];
233 e[0] = m_zone[i].min(j);
234 e[1] = m_zone[i].max(j);
235 for (int k = 0; k < 2; k++) {
236 // for the phi edge, fit into [-pi,pi]
237 if (j == 2 && e[k] > M_PI) {
238 e[k] -= 2.0 * M_PI;
239 }
240 m_edge[j].push_back(e[k]);
241 }
242 }
243 // add -pi and +pi to phi, just in case
244 m_edge[2].push_back(-M_PI);
245 m_edge[2].push_back(M_PI);
246 // sort
247 sort(m_edge[j].begin(), m_edge[j].end());
248 // remove duplicates
249 // must do this by hand to allow small differences due to rounding in phi
250 int i = 0;
251 for (unsigned k = 1; k < m_edge[j].size(); k++) {
252 if (fabs(m_edge[j][i] - m_edge[j][k]) < 1.0e-6) {
253 continue;
254 }
255 m_edge[j][++i] = m_edge[j][k];
256 }
257 m_edge[j].resize(i + 1);
258 // because of the small differences allowed in the comparison above,
259 // m_edge[][] values do not exactly match the m_zone[] boundaries.
260 // we have to fix this up in order to avoid invalid field values
261 // very close to the zone boundaries.
262 for (unsigned i = 0; i < m_zone.size(); i++) {
263 for (unsigned k = 0; k < m_edge[j].size(); k++) {
264 if (fabs(m_zone[i].min(j) - m_edge[j][k]) < 1.0e-6) {
265 m_zone[i].adjustMin(j, m_edge[j][k]);
266 }
267 if (fabs(m_zone[i].max(j) - m_edge[j][k]) < 1.0e-6) {
268 m_zone[i].adjustMax(j, m_edge[j][k]);
269 }
270 }
271 }
272 }
273 // build LUT for edge finding
274 for (int j = 0; j < 3; j++) { // z, r, phi
275 // find the size of the smallest interval
276 const double width = m_edge[j].back() - m_edge[j].front();
277 double q(width);
278 for (unsigned i = 0; i < m_edge[j].size() - 1; i++) {
279 q = std::min(q, m_edge[j][i + 1] - m_edge[j][i]);
280 }
281 // find the number of cells in the LUT
282 int n = int(width / q) + 1;
283 q = width / (n + 0.5);
284 m_invq[j] = 1.0 / q;
285 n++;
286 // fill the LUT
287 int m = 0;
288 for (int i = 0; i < n; i++) { // index of LUT
289 if (q * i + m_edge[j].front() > m_edge[j][m + 1]) {
290 m++;
291 }
292 m_edgeLUT[j].push_back(m);
293 }
294 }
295 // store min/max for speedup
296 m_zmin = m_edge[0].front();
297 m_zmax = m_edge[0].back();
298 m_rmax = m_edge[1].back();
299 // build LUT for zone finding
300 m_nz = m_edge[0].size() - 1;
301 m_nr = m_edge[1].size() - 1;
302 m_nphi = m_edge[2].size() - 1;
303 m_zoneLUT.reserve(m_nz * m_nr * m_nphi);
304 for (int iz = 0; iz < m_nz; iz++) {
305 const double z = 0.5 * (m_edge[0][iz] + m_edge[0][iz + 1]);
306 for (int ir = 0; ir < m_nr; ir++) {
307 const double r = 0.5 * (m_edge[1][ir] + m_edge[1][ir + 1]);
308 for (int iphi = 0; iphi < m_nphi; iphi++) {
309 const double phi = 0.5 * (m_edge[2][iphi] + m_edge[2][iphi + 1]);
310 const BFieldZone* zone = findZoneSlow(z, r, phi);
311 m_zoneLUT.push_back(zone);
312 }
313 }
314 }
315 // build LUT in each zone
316 for (unsigned i = 0; i < m_zone.size(); i++) {
317 m_zone[i].buildLUT();
318 }
319}
320
321//
322// Build the z-r 2d map for fast solenoid field
323//
324void
326{
327 // delete if previously allocated
328 delete m_meshZR;
329
330 // find the solenoid zone
331 // solenoid zone always covers 100 < R < 1000, but not necessarily R < 100
332 // so we search for the zone that contains a point at R = 200, Z = 0
333 const BFieldZone* solezone = findBFieldZone(0.0, 200.0, 0.0);
334
335 // instantiate the new ZR map with the same external coverage as the solenoid
336 // zone make sure R = 0 is covered
337 m_meshZR =
338 new BFieldMeshZR(solezone->zmin(), solezone->zmax(), 0.0, solezone->rmax());
339
340 // reserve the right amount of memroy
341 unsigned nmeshz = solezone->nmesh(0);
342 unsigned nmeshr = solezone->nmesh(1);
343 if (solezone->rmin() > 0.0) {
344 nmeshr++;
345 }
346 m_meshZR->reserve(nmeshz, nmeshr);
347
348 // copy the mesh structure in z/r
349 // take care of R = 0 first
350 if (solezone->rmin() > 0.0) {
351 m_meshZR->appendMesh(1, 0.0);
352 }
353 // copy the rest
354 for (int i = 0; i < 2; i++) { // z, r
355 for (unsigned j = 0; j < solezone->nmesh(i); j++) { // loop over mesh points
356 m_meshZR->appendMesh(i, solezone->mesh(i, j));
357 }
358 }
359
360 // loop through the mesh and compute the phi-averaged field
361 for (unsigned iz = 0; iz < m_meshZR->nmesh(0); iz++) { // loop over z
362 double z = m_meshZR->mesh(0, iz);
363 for (unsigned ir = 0; ir < m_meshZR->nmesh(1); ir++) { // loop over r
364 double r = m_meshZR->mesh(1, ir);
365 const int nphi(200); // number of phi slices to average
366 double Br = 0.0;
367 double Bz = 0.0;
368 for (int iphi = 0; iphi < nphi; iphi++) {
369 double phi = double(iphi) / double(nphi) * 2. * M_PI;
370 double xyz[3];
371 xyz[0] = r * cos(phi);
372 xyz[1] = r * sin(phi);
373 xyz[2] = z;
374 double B[3];
375 solezone->getB(xyz, B, nullptr);
376 Br += B[0] * cos(phi) + B[1] * sin(phi);
377 Bz += B[2];
378 }
379 Br *= 1.0 / double(nphi);
380 Bz *= 1.0 / double(nphi);
381 m_meshZR->appendField(BFieldVectorZR(Bz, Br));
382 }
383 }
384
385 // build the internal LUT
386 m_meshZR->buildLUT();
387}
388
389//
390// Approximate memory footprint
391//
392int
394{
395 int size = 0;
396 size += sizeof(BFieldCache);
397 size += sizeof(BFieldCacheZR);
398 for (unsigned i = 0; i < m_zone.size(); i++) {
399 size += m_zone[i].memSize();
400 }
401 for (int i = 0; i < 3; i++) {
402 size += sizeof(double) * m_edge[i].capacity();
403 size += sizeof(int) * m_edgeLUT[i].capacity();
404 }
405 size += sizeof(BFieldZone*) * m_zoneLUT.capacity();
406 if (m_meshZR) {
407 size += m_meshZR->memSize();
408 }
409 return size;
410}
#define M_PI
Scalar phi() const
phi method
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
const double width
#define xyz
#define z
#define min(a, b)
Definition cfImp.cxx:40
#define max(a, b)
Definition cfImp.cxx:41
BFieldCache.h.
Definition BFieldCache.h:25
void getB(const double *ATH_RESTRICT xyz, double *ATH_RESTRICT B, double *ATH_RESTRICT deriv=nullptr) const
get the bfield given a point in xyz
double rmax() const
maximum in r
unsigned nmesh(size_t axis) const
number of cells along each axis = 0 (z), 1 (r), 2 (phi)
double zmax() const
maximum in z
double mesh(size_t axis, size_t index) const
coordinate along axis (0 (z), 1 (r), 2 (phi)) of the cell at index (0 to nmesh-1)
double zmin() const
minimum in z
double rmin() const
minimun in r
int id() const
float toroidCurrent() const
std::vector< BFieldZone > m_zone
std::vector< double > m_edge[3]
BFieldMeshZR * m_meshZR
float solenoidCurrent() const
const BFieldZone * findBFieldZone(double z, double r, double phi) const
BFieldZone * findZoneSlow(double z, double r, double phi)
std::vector< const BFieldZone * > m_zoneLUT
std::vector< int > m_edgeLUT[3]
int memSize() const
approximate memory footprint in bytes
bool initializeMap(TFile *rootfile, float solenoidCurrent, float toroidCurrent)
int ir
counter of the current depth
Definition fastadd.cxx:49
int r
Definition globals.cxx:22
static std::vector< std::string > rootfile
Definition iLumiCalc.h:30
TChain * tree