9#include <geometry/bfieldmap/BFieldComponent3d.h>
10#include <geometry/bfieldmap/BFieldComponentBeamline.h>
12#include <framework/utilities/FileSystem.h>
13#include <framework/logging/Logger.h>
15#include <boost/iostreams/filtering_stream.hpp>
16#include <boost/iostreams/device/file.hpp>
17#include <boost/iostreams/filter/gzip.hpp>
25namespace io = boost::iostreams;
32 B2ERROR(
"The filename for the 3d magnetic field component is empty !");
37 B2ERROR(
"The 3d magnetic field map file '" <<
m_mapFilename <<
"' could not be found !");
43 B2ERROR(
"BField3d:: enabled coordinates must be \"rphiz\", \"rphi\", \"phiz\" or \"rz\"");
52 B2DEBUG(100,
"BField3d:: initial input parameters");
53 B2DEBUG(100, Form(
" map filename: %s",
m_mapFilename.c_str()));
54 B2DEBUG(100, Form(
" map dimension: %s",
m_mapEnable.c_str()));
55 if (
m_interpolate) { B2DEBUG(100, Form(
" map interpolation: on")); }
56 else { B2DEBUG(100, Form(
" map interpolation: off")); }
58 B2DEBUG(100, Form(
" map phi pitch: %.2e deg",
m_gridPitch[1] * 180 / M_PI));
67 io::filtering_istream fieldMapFile;
68 fieldMapFile.push(io::gzip_decompressor());
69 fieldMapFile.push(io::file_source(fullPath));
77 fieldMapFile.getline(tmp, 256);
80 Br = strtod(tmp + 33, &next);
81 Bphi = strtod(next, &next);
82 Bz = strtod(next,
nullptr);
83 m_bmap.emplace_back(-Br, -Bphi, -Bz);
96 ROOT::Math::XYZVector& B = *it;
109 B2DEBUG(100, Form(
"BField3d:: final map region & pitch: r [%.2e,%.2e] %.2e, phi %.2e, z [%.2e,%.2e] %.2e",
112 B2DEBUG(100,
"Memory consumption: " <<
m_bmap.size()*
sizeof(ROOT::Math::XYZVector) / (1024 * 1024.) <<
" Mb");
131 template<
int ORDER = 4>
constexpr double fast_atan2_minimax(
double y,
double x)
133 static_assert(ORDER >= 1 && ORDER <= 6,
"fast_atan2_minimax: Only orders 1-6 are supported");
134 constexpr double pi4 = M_PI / 4, pi2 = M_PI / 2;
135 const double ax = std::abs(x), ay = std::abs(y);
136 const double z = (ax - ay) / (ay + ax);
137 const double v = std::abs(z), v2 = v * v;
141 }
else if (ORDER == 3) {
144 }
else if (ORDER == 4) {
147 constexpr double c4[] = {
153 p0 = c4[0] + v2 * c4[2];
154 p1 = c4[1] + v2 * c4[3];
155 }
else if (ORDER == 5) {
158 constexpr double c5[] = {
162 -0.02778537455524869,
165 p0 = c5[0] + v2 * (c5[2] + v2 * c5[4]);
166 p1 = c5[1] + v2 * (c5[3]);
167 }
else if (ORDER == 6) {
170 constexpr double c6[] = {
178 p0 = c6[0] + v2 * (c6[2] + v2 * (c6[4]));
179 p1 = c6[1] + v2 * (c6[3] + v2 * (c6[5]));
181 double phi = (z + 1) * pi4 - (z * (v - 1)) * (p0 + v * p1);
182 phi = pi2 - copysign(phi, x);
183 return copysign(phi, y);
189 auto getPhiIndexWeight = [
this](
double y,
double x,
double & wphi) ->
unsigned int {
190 double phi = fast_atan2_minimax<4>(y, x);
192 auto iphi =
static_cast<unsigned int>(wphi);
193 iphi = min(iphi,
static_cast<unsigned int>(
m_mapSize[1] - 2));
198 ROOT::Math::XYZVector B(0, 0, 0);
207 double z = point.Z();
211 double r2 = point.Perp2();
221 unsigned int iz =
static_cast<int>(wz);
222 iz = min(iz,
static_cast<unsigned int>(
m_mapSize[2] - 2));
230 auto ir =
static_cast<unsigned int>(wr);
231 ir = min(ir,
static_cast<unsigned int>(
m_mapSize[0] - 2));
235 double ay = std::abs(point.Y());
237 unsigned int iphi = getPhiIndexWeight(ay, point.X(), wphi);
240 ROOT::Math::XYZVector b =
interpolate(ir, iphi, iz, wr, wphi, wz);
242 double s = ay * norm, c = point.X() * norm;
244 const double sgny = (point.Y() >= 0) - (point.Y() < 0);
246 B.SetXYZ(-(b.X() * c - b.Y() * s), -sgny * (b.X() * s + b.Y() * c), b.Z());
260 double wr1,
double wphi1,
double wz1)
const
263 const unsigned int strideR =
m_mapSize[1];
265 const double wz0 = 1 - wz1, wr0 = 1 - wr1, wphi0 = 1 - wphi1;
266 const unsigned int j000 = iz * strideZ + ir * strideR + iphi;
267 const unsigned int j001 = j000 + 1;
268 const unsigned int j010 = j000 + strideR;
269 const unsigned int j011 = j001 + strideR;
270 const unsigned int j100 = j000 + strideZ;
271 const unsigned int j101 = j001 + strideZ;
272 const unsigned int j110 = j010 + strideZ;
273 const unsigned int j111 = j011 + strideZ;
274 const double w00 = wphi0 * wr0;
275 const double w10 = wphi0 * wr1;
276 const double w01 = wphi1 * wr0;
277 const double w11 = wphi1 * wr1;
278 const vector<ROOT::Math::XYZVector>& B =
m_bmap;
280 (B[j000] * w00 + B[j001] * w01 + B[j010] * w10 + B[j011] * w11) * wz0 +
281 (B[j100] * w00 + B[j101] * w01 + B[j110] * w10 + B[j111] * w11) * wz1;
double m_exRegionR[2]
The min and max boundaries of the excluded region in r.
ROOT::Math::XYZVector interpolate(unsigned int ir, unsigned int iphi, unsigned int iz, double wr, double wphi, double wz) const
Interpolate the value of B-field between (ir, iphi, iz) and (ir+1, iphi+1, iz+1) using weights (wr,...
double m_errRegionR[2]
The min and max boundaries of the region in r to apply error.
virtual void initialize() override
Initializes the magnetic field component.
bool m_interpolate
Flag to switch on/off interpolation >
double m_gridPitch[3]
The grid pitch in r,phi,z.
std::string m_mapFilename
The filename of the magnetic field map.
virtual void terminate() override
Terminates the magnetic field component.
double m_mapRegionZ[2]
The min and max boundaries of the map region in z.
int m_mapSize[3]
The size of the map in r, phi and z.
virtual ROOT::Math::XYZVector calculate(const ROOT::Math::XYZVector &point) const override
Calculates the magnetic field vector at the specified space point.
double m_igridPitch[3]
The inverted grid pitch in r,phi,z.
bool m_exRegion
Flag to indicate whether there is a region to exclude.
std::vector< ROOT::Math::XYZVector > m_bmap
The memory buffer for the magnetic field map.
double m_mapRegionR[2]
The min and max boundaries of the map region in r.
double m_exRegionZ[2]
The min and max boundaries of the excluded region in z.
double m_errB[3]
The error Br, Bphi, Bz as a scale factor (B_new = m_errB * B_old).
std::string m_mapEnable
Enable different dimension, "rphiz", "rphi", "phiz" or "rz" >
static std::string findFile(const std::string &path, bool silent=false)
Search for given file or directory in local or central release directory, and return absolute path if...
static bool fileExists(const std::string &filename)
Check if the file with given filename exists.
static BFieldComponentBeamline & Instance()
BFieldComponentBeamline instance.
Abstract base class for different kinds of events.