LDMX Software
MagneticFieldMap3D.cxx
2
3#include "Framework/Exception/Exception.h"
4
5// STL
6#include <cmath>
7#include <fstream>
8#include <iostream>
9#include <string>
10
11// Geant4
12#include "G4SystemOfUnits.hh"
13
14using namespace std;
15
16namespace simcore {
17MagneticFieldMap3D::MagneticFieldMap3D(const char* filename, double xOffset,
18 double yOffset, double zOffset)
19 : nx_(0),
20 ny_(0),
21 nz_(0),
22 x_offset_(xOffset),
23 y_offset_(yOffset),
24 z_offset_(zOffset),
25 invert_x_(false),
26 invert_y_(false),
27 invert_z_(false) {
28 ifstream file(filename); // Open the file for reading.
29
30 // Throw an error if file does not exist.
31 if (!file.good()) {
32 EXCEPTION_RAISE("FileDNE", "The field map file '" + std::string(filename) +
33 "' does not exist!");
34 }
35
36 ldmx_log(trace)
37 << "-----------------------------------------------------------";
38 ldmx_log(trace) << " Magnetic Field Map 3D";
39 ldmx_log(trace)
40 << "-----------------------------------------------------------";
41
42 ldmx_log(trace) << "Reading the field grid from " << filename << " ... ";
43 ldmx_log(trace) << " Offsets: " << xOffset << " " << yOffset << " "
44 << zOffset;
45
46 // Ignore first blank line
47 char buffer[256];
48 file.getline(buffer, 256);
49
50 // Read table dimensions
51 file >> nx_ >> ny_ >> nz_; // Note dodgy order
52
53 ldmx_log(trace) << " Number of values: " << nx_ << " " << ny_ << " " << nz_;
54
55 // Set up storage space for table
56 x_field_.resize(nx_);
57 y_field_.resize(nx_);
58 z_field_.resize(nx_);
59 int ix, iy, iz;
60 for (ix = 0; ix < nx_; ix++) {
61 x_field_[ix].resize(ny_);
62 y_field_[ix].resize(ny_);
63 z_field_[ix].resize(ny_);
64 for (iy = 0; iy < ny_; iy++) {
65 x_field_[ix][iy].resize(nz_);
66 y_field_[ix][iy].resize(nz_);
67 z_field_[ix][iy].resize(nz_);
68 }
69 }
70
71 // Ignore other header information
72 // The first line whose second character is '0' is considered to
73 // be the last line of the header.
74 do {
75 file.getline(buffer, 256);
76 } while (buffer[1] != '0');
77
78 // Read in the data
79 double xval, yval, zval, bx, by, bz;
80 for (ix = 0; ix < nx_; ix++) {
81 for (iy = 0; iy < ny_; iy++) {
82 for (iz = 0; iz < nz_; iz++) {
83 file >> xval >> yval >> zval >> bx >> by >> bz;
84 if (ix == 0 && iy == 0 && iz == 0) {
85 minx_ = xval;
86 miny_ = yval;
87 minz_ = zval;
88 }
89 x_field_[ix][iy][iz] = bx;
90 y_field_[ix][iy][iz] = by;
91 z_field_[ix][iy][iz] = bz;
92 }
93 }
94 }
95 file.close();
96
97 maxx_ = xval;
98 maxy_ = yval;
99 maxz_ = zval;
100
101 ldmx_log(trace) << " ... done reading ";
102 ldmx_log(trace) << "Read values of field from file " << filename;
103 ldmx_log(trace) << " Assumed the order: x_, y_, z_, Bx, By, Bz";
104 ldmx_log(trace) << " Min values: " << minx_ << " " << miny_ << " " << minz_
105 << " mm ";
106 ldmx_log(trace) << " Max values: " << maxx_ << " " << maxy_ << " " << maxz_
107 << " mm ";
108 ldmx_log(trace) << " Field offsets: " << x_offset_ << " " << y_offset_ << " "
109 << z_offset_ << " mm ";
110
111 // Should really check that the limits are not the wrong way around.
112 if (maxx_ < minx_) {
113 swap(maxx_, minx_);
114 invert_x_ = true;
115 }
116 if (maxy_ < miny_) {
117 swap(maxy_, miny_);
118 invert_y_ = true;
119 }
120 if (maxz_ < minz_) {
121 swap(maxz_, minz_);
122 invert_z_ = true;
123 }
124
125 ldmx_log(trace) << "After reordering if necessary";
126 ldmx_log(trace) << " Min values: " << minx_ << " " << miny_ << " " << minz_
127 << " mm ";
128 ldmx_log(trace) << " Max values: " << maxx_ << " " << maxy_ << " " << maxz_
129 << " mm ";
130 ;
131
132 dx_ = maxx_ - minx_;
133 dy_ = maxy_ - miny_;
134 dz_ = maxz_ - minz_;
135
136 ldmx_log(trace) << " Range of values: " << dx_ << " " << dy_ << " " << dz_
137 << " mm";
138 ldmx_log(trace) << "Done loading field map";
139 ldmx_log(trace)
140 << "-----------------------------------------------------------";
141}
142
143void MagneticFieldMap3D::GetFieldValue(const double point[4],
144 double* bfield) const {
145 double x = point[0] - x_offset_;
146 double y = point[1] - y_offset_;
147 double z = point[2] - z_offset_;
148 double eps = 1E-6;
149
150 // Check that the point is within the defined region
151 if ((x >= minx_ && (x < maxx_ - eps)) && (y >= miny_ && (y < maxy_ - eps)) &&
152 (z >= minz_ && (z < maxz_ - eps))) {
153 // Position of given point within region, normalized to the range
154 // [0,1]
155 double xfraction = (x - minx_) / dx_;
156 double yfraction = (y - miny_) / dy_;
157 double zfraction = (z - minz_) / dz_;
158
159 if (invert_x_) {
160 xfraction = 1 - xfraction;
161 }
162 if (invert_y_) {
163 yfraction = 1 - yfraction;
164 }
165 if (invert_z_) {
166 zfraction = 1 - zfraction;
167 }
168
169 // Need addresses of these to pass to modf below.
170 // modf uses its second argument as an OUTPUT argument.
171 double xdindex, ydindex, zdindex;
172
173 // Position of the point within the cuboid defined by the
174 // nearest surrounding tabulated points
175 double xlocal = (std::modf(xfraction * (nx_ - 1), &xdindex));
176 double ylocal = (std::modf(yfraction * (ny_ - 1), &ydindex));
177 double zlocal = (std::modf(zfraction * (nz_ - 1), &zdindex));
178
179 // The indices of the nearest tabulated point whose coordinates
180 // are all less than those of the given point
181 int xindex = static_cast<int>(xdindex);
182 int yindex = static_cast<int>(ydindex);
183 int zindex = static_cast<int>(zdindex);
184
185#ifdef DEBUG_INTERPOLATING_FIELD
186 ldmx_log(trace) << "Local x_,y_,z_: " << xlocal << " " << ylocal << " "
187 << zlocal;
188 ldmx_log(trace) << "Index x_,y_,z_: " << xindex << " " << yindex << " "
189 << zindex;
190 double valx0z0, mulx0z0, valx1z0, mulx1z0;
191 double valx0z1, mulx0z1, valx1z1, mulx1z1;
192 valx0z0 = table[xindex][0][zindex];
193 mulx0z0 = (1 - xlocal) * (1 - zlocal);
194 valx1z0 = table[xindex + 1][0][zindex];
195 mulx1z0 = xlocal * (1 - zlocal);
196 valx0z1 = table[xindex][0][zindex + 1];
197 mulx0z1 = (1 - xlocal) * zlocal;
198 valx1z1 = table[xindex + 1][0][zindex + 1];
199 mulx1z1 = xlocal * zlocal;
200#endif
201
202 // Full 3-dimensional version
203 bfield[0] =
204 x_field_[xindex][yindex][zindex] * (1 - xlocal) * (1 - ylocal) *
205 (1 - zlocal) +
206 x_field_[xindex][yindex][zindex + 1] * (1 - xlocal) * (1 - ylocal) *
207 zlocal +
208 x_field_[xindex][yindex + 1][zindex] * (1 - xlocal) * ylocal *
209 (1 - zlocal) +
210 x_field_[xindex][yindex + 1][zindex + 1] * (1 - xlocal) * ylocal *
211 zlocal +
212 x_field_[xindex + 1][yindex][zindex] * xlocal * (1 - ylocal) *
213 (1 - zlocal) +
214 x_field_[xindex + 1][yindex][zindex + 1] * xlocal * (1 - ylocal) *
215 zlocal +
216 x_field_[xindex + 1][yindex + 1][zindex] * xlocal * ylocal *
217 (1 - zlocal) +
218 x_field_[xindex + 1][yindex + 1][zindex + 1] * xlocal * ylocal * zlocal;
219 bfield[1] =
220 y_field_[xindex][yindex][zindex] * (1 - xlocal) * (1 - ylocal) *
221 (1 - zlocal) +
222 y_field_[xindex][yindex][zindex + 1] * (1 - xlocal) * (1 - ylocal) *
223 zlocal +
224 y_field_[xindex][yindex + 1][zindex] * (1 - xlocal) * ylocal *
225 (1 - zlocal) +
226 y_field_[xindex][yindex + 1][zindex + 1] * (1 - xlocal) * ylocal *
227 zlocal +
228 y_field_[xindex + 1][yindex][zindex] * xlocal * (1 - ylocal) *
229 (1 - zlocal) +
230 y_field_[xindex + 1][yindex][zindex + 1] * xlocal * (1 - ylocal) *
231 zlocal +
232 y_field_[xindex + 1][yindex + 1][zindex] * xlocal * ylocal *
233 (1 - zlocal) +
234 y_field_[xindex + 1][yindex + 1][zindex + 1] * xlocal * ylocal * zlocal;
235 bfield[2] =
236 z_field_[xindex][yindex][zindex] * (1 - xlocal) * (1 - ylocal) *
237 (1 - zlocal) +
238 z_field_[xindex][yindex][zindex + 1] * (1 - xlocal) * (1 - ylocal) *
239 zlocal +
240 z_field_[xindex][yindex + 1][zindex] * (1 - xlocal) * ylocal *
241 (1 - zlocal) +
242 z_field_[xindex][yindex + 1][zindex + 1] * (1 - xlocal) * ylocal *
243 zlocal +
244 z_field_[xindex + 1][yindex][zindex] * xlocal * (1 - ylocal) *
245 (1 - zlocal) +
246 z_field_[xindex + 1][yindex][zindex + 1] * xlocal * (1 - ylocal) *
247 zlocal +
248 z_field_[xindex + 1][yindex + 1][zindex] * xlocal * ylocal *
249 (1 - zlocal) +
250 z_field_[xindex + 1][yindex + 1][zindex + 1] * xlocal * ylocal * zlocal;
251
252 } else {
253 bfield[0] = 0.0;
254 bfield[1] = 0.0;
255 bfield[2] = 0.0;
256 }
257}
258
259} // namespace simcore
Class for defining a global 3D magnetic field.
void GetFieldValue(const double point[4], double *bfield) const
Implementation of primary virtual method from G4MagneticField interface.
MagneticFieldMap3D(const char *filename, double xOffset, double yOffset, double zOffset)
Class constructor.
Dynamically loadable photonuclear models either from SimCore or external libraries implementing this ...