ATLAS Offline Software
AtlasFieldMap.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2021 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 //
25 bool
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 //
209 BFieldZone*
210 MagField::AtlasFieldMap::findZoneSlow(double z, double r, double phi)
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 //
225 void
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  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  double z = 0.5 * (m_edge[0][iz] + m_edge[0][iz + 1]);
306  for (int ir = 0; ir < m_nr; ir++) {
307  double r = 0.5 * (m_edge[1][ir] + m_edge[1][ir + 1]);
308  for (int iphi = 0; iphi < m_nphi; iphi++) {
309  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 //
324 void
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 //
392 int
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 }
AllowedVariables::e
e
Definition: AsgElectronSelectorTool.cxx:37
beamspotman.r
def r
Definition: beamspotman.py:676
python.SystemOfUnits.m
int m
Definition: SystemOfUnits.py:91
max
#define max(a, b)
Definition: cfImp.cxx:41
BFieldMeshZR
Definition: BFieldMeshZR.h:24
CaloCellPos2Ntuple.int
int
Definition: CaloCellPos2Ntuple.py:24
PixelAthClusterMonAlgCfg.zmin
zmin
Definition: PixelAthClusterMonAlgCfg.py:169
MagField::AtlasFieldMap::m_solenoidZoneId
int m_solenoidZoneId
Definition: AtlasFieldMap.h:90
tree
TChain * tree
Definition: tile_monitor.h:30
TRTCalib_cfilter.p1
p1
Definition: TRTCalib_cfilter.py:130
PlotCalibFromCool.begin
begin
Definition: PlotCalibFromCool.py:94
M_PI
#define M_PI
Definition: ActiveFraction.h:11
xyz
#define xyz
ReadOfcFromCool.field
field
Definition: ReadOfcFromCool.py:48
drawFromPickle.cos
cos
Definition: drawFromPickle.py:36
MagField::AtlasFieldMap::buildLUT
void buildLUT()
Definition: AtlasFieldMap.cxx:226
BFieldMesh::getB
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
LArCalib_HVScale2NtupleConfig.rootfile
string rootfile
Definition: LArCalib_HVScale2NtupleConfig.py:74
mergePhysValFiles.end
end
Definition: DataQuality/DataQualityUtils/scripts/mergePhysValFiles.py:93
BFieldZone::id
int id() const
python.setupRTTAlg.size
int size
Definition: setupRTTAlg.py:39
Br
Definition: VP1BPhysConvertor.h:14
TRTCalib_cfilter.p2
p2
Definition: TRTCalib_cfilter.py:131
lumiFormat.i
int i
Definition: lumiFormat.py:85
z
#define z
beamspotman.n
n
Definition: beamspotman.py:731
BFieldMesh::zmax
double zmax() const
maximum in z
MagField::AtlasFieldMap::buildZR
void buildZR()
Definition: AtlasFieldMap.cxx:325
BFieldMesh::mesh
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)
PixelAthClusterMonAlgCfg.zmax
zmax
Definition: PixelAthClusterMonAlgCfg.py:169
MagField::AtlasFieldMap::toroidCurrent
float toroidCurrent() const
Definition: AtlasFieldMap.h:61
BFieldZone
Definition: BFieldZone.h:29
BFieldMesh::nmesh
unsigned nmesh(size_t axis) const
number of cells along each axis = 0 (z), 1 (r), 2 (phi)
BFieldCacheZR
Definition: BFieldCacheZR.h:22
xAOD::double
double
Definition: CompositeParticle_v1.cxx:159
BFieldCache
BFieldCache.h.
Definition: BFieldCache.h:25
min
#define min(a, b)
Definition: cfImp.cxx:40
BFieldCond
Definition: BFieldCond.h:22
PathResolver.h
MagField::AtlasFieldMap::m_zone
std::vector< BFieldZone > m_zone
Definition: AtlasFieldMap.h:93
python.draw_obj.zone
def zone(nx, ny)
Definition: draw_obj.py:288
id
SG::auxid_t id
Definition: Control/AthContainers/Root/debug.cxx:220
MagField::AtlasFieldMap::memSize
int memSize() const
approximate memory footprint in bytes
Definition: AtlasFieldMap.cxx:393
AtlasFieldMap.h
MagField::AtlasFieldMap::m_solenoidCurrent
float m_solenoidCurrent
Definition: AtlasFieldMap.h:88
ir
int ir
counter of the current depth
Definition: fastadd.cxx:49
Trk::inside
@ inside
Definition: PropDirection.h:29
BFieldMesh::zmin
double zmin() const
minimum in z
Base_Fragment.width
width
Definition: Sherpa_i/share/common/Base_Fragment.py:59
BFieldVector< short >
MagField::AtlasFieldMap::findZoneSlow
BFieldZone * findZoneSlow(double z, double r, double phi)
Definition: AtlasFieldMap.cxx:210
extractSporadic.q
list q
Definition: extractSporadic.py:98
BFieldMesh::rmax
double rmax() const
maximum in r
drawFromPickle.sin
sin
Definition: drawFromPickle.py:36
MagField::AtlasFieldMap::m_toroidCurrent
float m_toroidCurrent
Definition: AtlasFieldMap.h:89
MagField::AtlasFieldMap::solenoidCurrent
float solenoidCurrent() const
Definition: AtlasFieldMap.h:60
MagField::AtlasFieldMap::initializeMap
bool initializeMap(TFile *rootfile, float solenoidCurrent, float toroidCurrent)
Definition: AtlasFieldMap.cxx:26
BFieldVectorZR
Definition: BFieldVectorZR.h:19
fitman.k
k
Definition: fitman.py:528
BFieldMesh::rmin
double rmin() const
minimun in r