EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
BeastMagneticField.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file BeastMagneticField.cc
1 
2 #include <set>
3 
4 #include <stdio.h>
5 #include <string.h>
6 #include <assert.h>
7 
8 // Well, one can of course determine this from the input data, but what's the point?;
9 #define _CELL_SIZE_ (2.0)
10 
11 // See the original solenoid.C script; prefer to indicate a cutoff;
12 //#define _CRYOSTAT_INNER_RADIUS_ (137.0)
13 
14 #include <BeastMagneticField.h>
15 
16 // For the time being keep this code, which imports the original
17 // 5.7MB Elmer file with the extra columns and odd formatting and dumps the simplified ASCII file;
18 //#define _USE_ORIGINAL_ELMER_FILE_
19 
20 // --------------------------------------------------------------------------------------
21 // --------------------------------------------------------------------------------------
22 
23 BeastMagneticField::BeastMagneticField(const char *fname, bool enforce_axial_symmetry):
24  mCellSize(_CELL_SIZE_), mScale(1.0), mRdim(0), mZdim(0), mRmin(0.0), mZmin(0.0),
25  mUseInterpolation(false), mFieldMap(0)
26 {
27  FILE *fmap = fopen(fname, "r");
28  if (!fmap) {
29  printf("Failed to open '%s' for reading!\n", fname);
30  return;
31  } //if
32 #ifdef _USE_ORIGINAL_ELMER_FILE_
33  FILE *fout = fopen("mfield.4col.dat", "w");
34 #endif
35 
36  {
37  // I kind of know that the strings in this file are short, right?;
38  char buffer[1024];
39  std::vector<BeastMagneticFieldCell> cells;
40  std::set<double> rset, zset;
41 
42  // Prefer to import everything, and only after this start handling data;
43  while (fgets(buffer, 1024-1, fmap)) {
44  double r, z, br, bz;
45  // C-style, sorry;
46 #ifdef _USE_ORIGINAL_ELMER_FILE_
47  double dummy;
48  sscanf(buffer, "%le %lf %lf %le %le %le %le", &dummy, &dummy, &dummy, &r, &z, &br, &bz);
49 
50  // Convert [m] to [cm]; store the values;
51  r *= 100.0; z *= 100.0;
52  fprintf(fout, "%6.1f %6.1f %7.4f %7.4f\n", r, z, br, bz);
53 #else
54  sscanf(buffer, "%lf %lf %lf %lf", &r, &z, &br, &bz);
55 #endif
56 
57  // Elmer gives a (very) small radial component on the symmetry axis; fix this;
58  if (!r && enforce_axial_symmetry) br = 0.0;
59 
60  rset.insert(r); zset.insert(z);
61 
62  cells.push_back(BeastMagneticFieldCell(r, z, br, bz));
63  } // while
64 
65  mRdim = (int)rint((*rset.rbegin() - *rset.begin())/mCellSize) + 1;
66  mZdim = (int)rint((*zset.rbegin() - *zset.begin())/mCellSize) + 1;
67  mRmin = *rset.begin(); mZmin = *zset.begin();
68 
69  // Sanity check;
70  if (mRdim*mZdim != cells.size()) {
71  // And mFieldMap[] in this case will remain NULL;
72  printf("Line count in the input file (%d) does not match the grid size (%d x %d)\n",
73  (int)cells.size(), mRdim, mZdim);
74  return;
75  } //if
76 
77  // Populate the internal array;
78  {
79  unsigned dim = mRdim*mZdim;
80  bool ok[dim]; memset(ok, false, sizeof(ok));
81  mFieldMap = new std::pair<double, double>[dim];
82 
83  for(auto cell: cells) {
84  // Want the closest value here -> use rint();
85  int ir = (int)rint((cell.mR - mRmin)/mCellSize);
86  int iz = (int)rint((cell.mZ - mZmin)/mCellSize);
87  // FIXME: do it better; should not happen anyway;
88  assert(ir >=0 && ir < (int)mRdim && iz >= 0 && iz < (int)mZdim);
89 
90  // Calculate 1D index;
91  unsigned id = ir*mZdim + iz;
92  // Check for double-counting; if never happens, all the cells are filled; good;
93  if (ok[id]) {
94  printf("Duplicate cells in the map file (%d,%d)!\n", ir, iz);
95  return;
96  } //if
97  ok[id] = true; mFieldMap[id] = std::make_pair(cell.mBR, cell.mBZ);
98  } //for cell
99  }
100  }
101 
102  fclose(fmap);
103 #ifdef _USE_ORIGINAL_ELMER_FILE_
104  fclose(fout);
105 #endif
106 } // BeastMagneticField::BeastMagneticField()
107 
108 // --------------------------------------------------------------------------------------
109 
110 // Ignore the z-coordinate I guess?;
111 //bool BeastMagneticField::IsInsideTheBore(double x, double y/*, double z*/) const
112 //{
113 //return (sqrt(x*x+y*y) < _CRYOSTAT_INNER_RADIUS_);
114 //} // BeastMagneticField::IsInsideTheBore()
115 
116 // --------------------------------------------------------------------------------------
117 
118 bool BeastMagneticField::GetFieldValue(double x, double y, double z,
119  double &bx, double &by, double &bz) const
120 {
121  double r = sqrt(x*x + y*y), br;
122 
123  bool ret = GetFieldValue(r, z, br, bz);
124  if (!ret) return false;
125 
126  double fi = atan2(y, x);
127  bx = br*cos(fi); by = br*sin(fi);
128 
129  return true;
130 } // BeastMagneticField::GetFieldValue()
131 
132 // --------------------------------------------------------------------------------------
133 
134 bool BeastMagneticField::GetFieldValue(double r, double z, double &br, double &bz) const
135 {
136  // Reset per default, in one place;
137  br = bz = 0.0;
138 
139  // Sanity check;
140  if (r < 0.0) return false;
141 
142  // Well, this is not exactly clean, but kind of makes sense;
143  if (mUseInterpolation) {
144  // Want a 2x2 cell group here -> use floor();
145  int ir = (int)floor((r - mRmin)/mCellSize);
146  int iz = (int)floor((z - mZmin)/mCellSize);
147 
148  // Range check; NB: watch '-1' in this case;
149  if (ir < 0 || ir >= (int)mRdim-1 || iz < 0 || iz >= (int)mZdim-1) return false;
150 
151  // Arrange by hand something like a 2D linear interpolation;
152  double qdr = (r - mRmin - ir*mCellSize)/mCellSize, qdz = (z - mZmin - iz*mCellSize)/mCellSize;
153  double wt[2][2] = {{(1.0-qdr)*(1.0-qdz), (1.0-qdr)*qdz},
154  { qdr *(1.0-qdz), qdr *qdz}};
155  double wtsum = 0.0;
156  for(unsigned ip=0; ip<2; ip++)
157  for(unsigned iq=0; iq<2; iq++)
158  wtsum += wt[ip][iq];
159  for(unsigned ip=0; ip<2; ip++)
160  for(unsigned iq=0; iq<2; iq++)
161  wt[ip][iq] /= wtsum;
162 
163  for(unsigned ip=0; ip<2; ip++)
164  for(unsigned iq=0; iq<2; iq++) {
165  const std::pair<double, double> &cell = mFieldMap[(ir+ip)*mZdim + iz+iq];
166 
167  br += wt[ip][iq]*cell.first;
168  bz += wt[ip][iq]*cell.second;
169  } //for ip..iq
170  } else {
171  // Want the closest value here -> use rint();
172  int ir = (int) rint((r - mRmin)/mCellSize);
173  int iz = (int) rint((z - mZmin)/mCellSize);
174 
175  // Range check;
176  if (ir < 0 || ir >= (int)mRdim || iz < 0 || iz >= (int)mZdim) return false;
177 
178  unsigned id = ir*mZdim + iz;
179  const std::pair<double, double> &cell = mFieldMap[id];
180  br = cell.first; bz = cell.second;
181  } //if
182 
183  // Rescale in a single place;
184  br *= mScale; bz *= mScale;
185 
186  return true;
187 } // BeastMagneticField::GetFieldValue()
188 
189 // --------------------------------------------------------------------------------------
190 // --------------------------------------------------------------------------------------