Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PHField3DCartesian.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file PHField3DCartesian.cc
1 #include "PHField3DCartesian.h"
2 
3 #include <phool/phool.h>
4 
5 #include <TDirectory.h> // for TDirectory, gDirectory
6 #include <TFile.h>
7 #include <TNtuple.h>
8 #include <TSystem.h>
9 
10 #include <Geant4/G4SystemOfUnits.hh>
11 
12 // stacktrace gives a shadow warning
13 #pragma GCC diagnostic push
14 #pragma GCC diagnostic ignored "-Wshadow"
15 #include <boost/stacktrace.hpp>
16 #pragma GCC diagnostic pop
17 
18 #include <cassert>
19 #include <cmath>
20 #include <cstdlib>
21 #include <iostream>
22 #include <iterator>
23 #include <set>
24 #include <utility>
25 
26 PHField3DCartesian::PHField3DCartesian(const std::string &fname, const float magfield_rescale, const float innerradius, const float outerradius, const float size_z)
27  : filename(fname)
28 {
29  for (int i = 0; i < 2; i++)
30  {
31  for (int j = 0; j < 2; j++)
32  {
33  for (int k = 0; k < 2; k++)
34  {
35  for (int l = 0; l < 3; l++)
36  {
37  xyz[i][j][k][l] = NAN;
38  bf[i][j][k][l] = NAN;
39  }
40  }
41  }
42  }
43  std::cout << "\n================ Begin Construct Mag Field =====================" << std::endl;
44  std::cout << "\n-----------------------------------------------------------"
45  << "\n Magnetic field Module - Verbosity:"
46  << "\n-----------------------------------------------------------";
47 
48  // open file
49  TFile *rootinput = TFile::Open(filename.c_str());
50  if (!rootinput)
51  {
52  std::cout << "\n could not open " << filename << " exiting now" << std::endl;
53  gSystem->Exit(1);
54  exit(1);
55  }
56  std::cout << "\n ---> "
57  "Reading the field grid from "
58  << filename << " ... " << std::endl;
59 
60  // get root NTuple objects
61  TNtuple *field_map = nullptr;
62  rootinput->GetObject("fieldmap", field_map);
63  if (field_map == nullptr)
64  {
65  std::cout << PHWHERE << " Could not load fieldmap ntuple from "
66  << filename << " exiting now" << std::endl;
67  gSystem->Exit(1);
68  exit(1);
69  }
70  Float_t ROOT_X, ROOT_Y, ROOT_Z;
71  Float_t ROOT_BX, ROOT_BY, ROOT_BZ;
72  field_map->SetBranchAddress("x", &ROOT_X);
73  field_map->SetBranchAddress("y", &ROOT_Y);
74  field_map->SetBranchAddress("z", &ROOT_Z);
75  field_map->SetBranchAddress("bx", &ROOT_BX);
76  field_map->SetBranchAddress("by", &ROOT_BY);
77  field_map->SetBranchAddress("bz", &ROOT_BZ);
78  for (int i = 0; i < field_map->GetEntries(); i++)
79  {
80  field_map->GetEntry(i);
81  trio coord_key(ROOT_X * cm, ROOT_Y * cm, ROOT_Z * cm);
82  trio field_val(ROOT_BX * tesla * magfield_rescale, ROOT_BY * tesla * magfield_rescale, ROOT_BZ * tesla * magfield_rescale);
83  xvals.insert(ROOT_X * cm);
84  yvals.insert(ROOT_Y * cm);
85  zvals.insert(ROOT_Z * cm);
86  if ((std::sqrt(ROOT_X * cm * ROOT_X * cm + ROOT_Y * cm * ROOT_Y * cm) >= innerradius &&
87  std::sqrt(ROOT_X * cm * ROOT_X * cm + ROOT_Y * cm * ROOT_Y * cm) <= outerradius) ||
88  std::abs(ROOT_Z * cm) > size_z)
89  {
90  fieldmap[coord_key] = field_val;
91  }
92  }
93  xmin = *(xvals.begin());
94  xmax = *(xvals.rbegin());
95 
96  ymin = *(yvals.begin());
97  ymax = *(yvals.rbegin());
98  if (ymin != xmin || ymax != xmax)
99  {
100  std::cout << "PHField3DCartesian: Compiler bug!!!!!!!! Do not use inlining!!!!!!" << std::endl;
101  std::cout << "exiting now - recompile with -fno-inline" << std::endl;
102  exit(1);
103  }
104 
105  zmin = *(zvals.begin());
106  zmax = *(zvals.rbegin());
107 
108  xstepsize = (xmax - xmin) / (xvals.size() - 1);
109  ystepsize = (ymax - ymin) / (yvals.size() - 1);
110  zstepsize = (zmax - zmin) / (zvals.size() - 1);
111 
112  delete field_map;
113  delete rootinput;
114  std::cout << "\n================= End Construct Mag Field ======================\n"
115  << std::endl;
116 }
117 
119 {
120  if (Verbosity() > 0)
121  {
122  std::cout << "PHField3DCartesian: cache hits: " << cache_hits
123  << " cache misses: " << cache_misses
124  << std::endl;
125  }
126 }
127 
128 void PHField3DCartesian::GetFieldValue(const double point[4], double *Bfield) const
129 {
130  static double xsav = -1000000.;
131  static double ysav = -1000000.;
132  static double zsav = -1000000.;
133 
134  double x = point[0];
135  double y = point[1];
136  double z = point[2];
137 
138  Bfield[0] = 0.0;
139  Bfield[1] = 0.0;
140  Bfield[2] = 0.0;
141  if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(z))
142  {
143  static int ifirst = 0;
144  if (ifirst < 10)
145  {
146  std::cout << "PHField3DCartesian::GetFieldValue: "
147  << "Invalid coordinates: "
148  << "x: " << x / cm
149  << ", y: " << y / cm
150  << ", z: " << z / cm
151  << " bailing out returning zero bfield"
152  << std::endl;
153  std::cout << "previous point: "
154  << "x: " << xsav / cm
155  << ", y: " << ysav / cm
156  << ", z: " << zsav / cm
157  << std::endl;
158  std::cout << "Here is the stacktrace: " << std::endl;
159  std::cout << boost::stacktrace::stacktrace();
160  std::cout << "This is not a segfault. Check the stacktrace for the guilty party (typically #2)" << std::endl;
161  ifirst++;
162  }
163  return;
164  }
165  xsav = x;
166  ysav = y;
167  zsav = z;
168 
169  if (point[0] < xmin || point[0] > xmax ||
170  point[1] < ymin || point[1] > ymax ||
171  point[2] < zmin || point[2] > zmax)
172  {
173  return;
174  }
175  double xkey[2];
176  std::set<float>::const_iterator it = xvals.lower_bound(x);
177  xkey[0] = *it;
178  if (it == xvals.begin())
179  {
180  xkey[1] = *it;
181  if (x < xkey[0])
182  {
183  std::cout << PHWHERE << ": This should not happen! x too small - outside range: " << x / cm << std::endl;
184  return;
185  }
186  }
187  else
188  {
189  --it;
190  xkey[1] = *it;
191  }
192 
193  double ykey[2];
194  it = yvals.lower_bound(y);
195  ykey[0] = *it;
196  if (it == yvals.begin())
197  {
198  ykey[1] = *it;
199  if (y < ykey[0])
200  {
201  std::cout << PHWHERE << ": This should not happen! y too small - outside range: " << y / cm << std::endl;
202  return;
203  }
204  }
205  else
206  {
207  --it;
208  ykey[1] = *it;
209  }
210  double zkey[2];
211  it = zvals.lower_bound(z);
212  zkey[0] = *it;
213  if (it == zvals.begin())
214  {
215  zkey[1] = *it;
216  if (z < zkey[0])
217  {
218  std::cout << PHWHERE << ": This should not happen! z too small - outside range: " << z / cm << std::endl;
219  return;
220  }
221  }
222  else
223  {
224  --it;
225  zkey[1] = *it;
226  }
227  if (xkey_save != xkey[0] ||
228  ykey_save != ykey[0] ||
229  zkey_save != zkey[0])
230  {
231  cache_misses++;
232  xkey_save = xkey[0];
233  ykey_save = ykey[0];
234  zkey_save = zkey[0];
235 
236  std::map<std::tuple<float, float, float>, std::tuple<float, float, float> >::const_iterator magval;
237  trio key;
238  for (int i = 0; i < 2; i++)
239  {
240  for (int j = 0; j < 2; j++)
241  {
242  for (int k = 0; k < 2; k++)
243  {
244  key = std::make_tuple(xkey[i], ykey[j], zkey[k]);
245  magval = fieldmap.find(key);
246  if (magval == fieldmap.end())
247  {
248  std::cout << PHWHERE << " could not locate key in " << filename
249  << " value: x: " << xkey[i] / cm
250  << ", y: " << ykey[j] / cm
251  << ", z: " << zkey[k] / cm << std::endl;
252  return;
253  }
254  xyz[i][j][k][0] = std::get<0>(magval->first);
255  xyz[i][j][k][1] = std::get<1>(magval->first);
256  xyz[i][j][k][2] = std::get<2>(magval->first);
257  bf[i][j][k][0] = std::get<0>(magval->second);
258  bf[i][j][k][1] = std::get<1>(magval->second);
259  bf[i][j][k][2] = std::get<2>(magval->second);
260  if (Verbosity() > 0)
261  {
262  std::cout << "read x/y/z: " << xyz[i][j][k][0] / cm << "/"
263  << xyz[i][j][k][1] / cm << "/"
264  << xyz[i][j][k][2] / cm << " bx/by/bz: "
265  << bf[i][j][k][0] / tesla << "/"
266  << bf[i][j][k][1] / tesla << "/"
267  << bf[i][j][k][2] / tesla << std::endl;
268  }
269  }
270  }
271  }
272  }
273  else
274  {
275  cache_hits++;
276  }
277 
278  // how far are we away from the reference point
279  double xinblock = point[0] - xkey[1];
280  double yinblock = point[1] - ykey[1];
281  double zinblock = point[2] - zkey[1];
282  // normalize distance to step size
283  double fractionx = xinblock / xstepsize;
284  double fractiony = yinblock / ystepsize;
285  double fractionz = zinblock / zstepsize;
286  if (Verbosity() > 0)
287  {
288  std::cout << "x/y/z stepsize: " << xstepsize / cm << "/" << ystepsize / cm << "/" << zstepsize / cm << std::endl;
289  std::cout << "x/y/z inblock: " << xinblock / cm << "/" << yinblock / cm << "/" << zinblock / cm << std::endl;
290  std::cout << "x/y/z fraction: " << fractionx << "/" << fractiony << "/" << fractionz << std::endl;
291  }
292 
293  // linear extrapolation in cube:
294 
295  // Vxyz =
296  // V000 * x * y * z +
297  // V100 * (1 - x) * y * z +
298  // V010 * x * (1 - y) * z +
299  // V001 * x y * (1 - z) +
300  // V101 * (1 - x) * y * (1 - z) +
301  // V011 * x * (1 - y) * (1 - z) +
302  // V110 * (1 - x) * (1 - y) * z +
303  // V111 * (1 - x) * (1 - y) * (1 - z)
304 
305  for (int i = 0; i < 3; i++)
306  {
307  Bfield[i] = bf[0][0][0][i] * fractionx * fractiony * fractionz +
308  bf[1][0][0][i] * (1. - fractionx) * fractiony * fractionz +
309  bf[0][1][0][i] * fractionx * (1. - fractiony) * fractionz +
310  bf[0][0][1][i] * fractionx * fractiony * (1. - fractionz) +
311  bf[1][0][1][i] * (1. - fractionx) * fractiony * (1. - fractionz) +
312  bf[0][1][1][i] * fractionx * (1. - fractiony) * (1. - fractionz) +
313  bf[1][1][0][i] * (1. - fractionx) * (1. - fractiony) * fractionz +
314  bf[1][1][1][i] * (1. - fractionx) * (1. - fractiony) * (1. - fractionz);
315  }
316 
317  return;
318 }