9#include <geometry/bfieldmap/BFieldComponentBeamline.h>
11#include <framework/utilities/FileSystem.h>
12#include <framework/logging/Logger.h>
14#include <boost/iostreams/filtering_stream.hpp>
15#include <boost/iostreams/device/file.hpp>
16#include <boost/iostreams/filter/gzip.hpp>
22namespace io = boost::iostreams;
88 void init(vector<xy_t>& points, vector<triangle_t>& triangles,
double d)
92 const double inf = numeric_limits<double>::infinity();
93 double xmin = inf, xmax = -inf;
94 double ymin = inf, ymax = -inf;
95 auto limit = [&xmin, &xmax, &ymin, &ymax](
const xy_t & p) ->
void {
96 xmin = std::min(xmin, p.x); xmax = std::max(xmax, p.x);
97 ymin = std::min(ymin, p.y); ymax = std::max(ymax, p.y);
104 double xw = xmax - xmin;
105 double yw = ymax - ymin;
107 xmin -= xw * (1. / 256), xmax += xw * (1. / 256);
108 ymin -= yw * (1. / 256), ymax += yw * (1. / 256);
109 int nx = lrint(xw * (1 + 1. / 128) / d), ny = lrint(yw * (1 + 1. / 128) / d);
110 nx = std::max(nx, 2);
111 ny = std::max(ny, 2);
112 makeIndex(nx, xmin, xmax, ny, ymin, ymax);
123 return {(p0.
x + p1.x + p2.x)* (1. / 3), (p0.
y + p1.y + p2.y)* (1. / 3)};
136 void makeIndex(
int nx,
double xmin,
double xmax,
int ny,
double ymin,
double ymax)
140 double dx = (xmax - xmin) / (nx - 1), dy = (ymax - ymin) / (ny - 1);
147 auto getTriangleArea = [
this](
const triangle_t& p) ->
double{
149 double d21x = p2.x - p1.x, d21y = p2.y - p1.y;
150 double d01x = p0.
x - p1.x, d01y = p0.
y - p1.y;
151 return 1 / (d21x * d01y - d21y * d01x);
156 for (
int ix = 0; ix < nx; ix++) {
157 double x = xmin + ix * dx;
158 for (
int iy = 0; iy < ny; iy++) {
159 double y = ymin + iy * dy;
160 int imin = -1;
double dmin = 1e100;
163 double d = pow(p.x - x, 2) + pow(p.y - y, 2);
164 if (d < dmin) {imin = i; dmin = d;}
166 int k = iy + ny * ix;
181 [[nodiscard]]
short int sideCross(
short int prev,
short int curr,
const xy_t& r,
const xy_t& v0)
const
183 const double vx = r.x - v0.
x, vy = r.y - v0.
y;
184 auto isCrossed = [&vx, &vy, &v0](
const xy_t & p1,
const xy_t & p0) ->
bool {
185 double u0x = p0.x, u0y = p0.y;
186 double ux = p1.x - u0x, uy = p1.y - u0y;
187 double dx = u0x - v0.
x, dy = u0y - v0.
y;
188 double D = uy * vx - ux * vy;
189 double t = dx * vy - dy * vx;
190 double s = dx * uy - dy * ux;
191 return ((t < D) != (t < 0)) && ((s < D) != (s < 0));
196 if (p.n0 != prev && isCrossed(p1, p2))
return p.n0;
197 if (p.n1 != prev && isCrossed(p2, p0))
return p.n1;
198 if (p.n2 != prev && isCrossed(p0, p1))
return p.n2;
211 void weights(
short int i,
const xy_t& r,
double& w0,
double& w1,
double& w2)
const
215 double dx2 = p2.x - r.x, dy2 = p2.y - r.y;
216 double d21x = p2.x - p1.x, d21y = p2.y - p1.y;
217 double d02x = p0.
x - p2.x, d02y = p0.
y - p2.y;
238 short int prev = end;
240 short int next =
sideCross(prev, curr, r, r0);
241 if (next == end)
break;
310 void init(
const string& fieldmapname,
const string& interpolname,
double validRadius)
312 if (fieldmapname.empty()) {
313 B2ERROR(
"The filename for the beamline magnetic field component is empty !");
318 if (interpolname.empty()) {
319 B2ERROR(
"The filename for the triangulation of the beamline magnetic field component is empty !");
326 B2DEBUG(50,
"Delaunay triangulation of the beamline field map: " << l_interpolname);
327 B2DEBUG(50,
"Beamline field map: " << l_fieldmapname);
330 ifstream INd(l_interpolname);
332 B2DEBUG(50,
"Total number of triangles: " << nts);
333 vector<triangle_t> ts;
338 while (INd >> nts >> p.j0 >> p.j1 >> p.j2 >> p.n0 >> p.n1 >> p.n2) ts.push_back(p);
342 io::filtering_istream IN;
343 IN.push(io::gzip_decompressor());
344 IN.push(io::file_source(l_fieldmapname));
359 struct cs_t {
double c, s;};
360 vector<cs_t> cs(nrphi);
362 vector<ROOT::Math::XYZVector> tbc;
364 char cbuf[256]; IN.getline(cbuf, 256);
366 for (
int j = 0; j < nrphi; j++) {
367 IN.getline(cbuf, 256);
369 double r = strtod(next, &next);
370 double phi = strtod(next, &next);
372 double Br = strtod(next, &next);
373 double Bphi = strtod(next, &next);
374 double Bz = strtod(next,
nullptr);
376 rmax = std::max(r, rmax);
379 }
else if (phi == 180) {
383 cs[j] = {cos(phi), sin(phi)};
385 double x = r * cs[j].c, y = r * cs[j].s;
386 pc.push_back({x, y});
387 if (cs[j].s == 0) Bphi = 0;
388 double Bx = Br * cs[j].c - Bphi * cs[j].s;
389 double By = Br * cs[j].s + Bphi * cs[j].c;
390 tbc.emplace_back(Bx, By, Bz);
403 ip.resize(nrphi,
false);
404 vector<bool> it(ts.size(),
false);
405 auto inside = [
this](
const xy_t & p)->
bool{
409 for (
int i = 0, imax = ts.size(); i < imax; i++) {
411 const xy_t& p0 = pc[p.j0], &p1 = pc[p.j1], &p2 = pc[p.j2];
412 if (inside(p0) || inside(p1) || inside(p2)) {
420 vector<short int> pindx(nrphi, -1);
422 for (
int i = 0, imax = ip.size(); i < imax; i++) {
423 if (ip[i]) pindx[i] = rnp++;
427 for (
int i = 0, imax = pc.size(); i < imax; i++) {
428 if (ip[i]) rpc.push_back(pc[i]);
431 vector<short int> tindx(ts.size(), -1);
433 for (
int i = 0, imax = it.size(); i < imax; i++) {
434 if (it[i]) tindx[i] = rnt++;
436 vector<triangle_t> rts;
438 short int nt = ts.size();
439 auto newind = [&nt, &tindx, &rnt](
short int n) ->
short int {
return (n < nt) ? tindx[n] : rnt;};
440 for (
int i = 0, imax = ts.size(); i < imax; i++) {
443 rts.push_back({pindx[t.j0], pindx[t.j1], pindx[t.j2], newind(t.n0), newind(t.n1), newind(t.n2)});
447 B2DEBUG(50,
"Reduce map size to cover only region R<" <<
m_rmax <<
" cm: Ntriangles=" << rnt <<
" Nxypoints = " << rnp <<
448 " Nzslices=" <<
m_nz <<
" NBpoints = " << rnp *
m_nz);
452 ip.resize(nrphi,
true);
458 vector<ROOT::Math::XYZVector> bc(
m_nxy *
m_nz);
459 unsigned int count = 0;
460 for (
int i = 0; i < nrphi; i++) {
461 if (ip[i]) bc[count++] = ROOT::Math::XYZVector(tbc[i]);
464 for (
int i = 1; i <
m_nz; ++i) {
465 for (
int j = 0; j < nrphi; j++) {
466 IN.getline(cbuf, 256);
467 if (!ip[j])
continue;
469 next = strchr(next,
' ');
470 next = strchr(next + 1,
' ');
471 next = strchr(next + 1,
' ');
472 double Br = strtod(next, &next);
473 double Bphi = strtod(next, &next);
474 double Bz = strtod(next,
nullptr);
475 if (cs[j].s == 0) Bphi = 0;
476 double Bx = Br * cs[j].c - Bphi * cs[j].s;
477 double By = Br * cs[j].s + Bphi * cs[j].c;
478 bc[count++].SetXYZ(Bx, By, Bz);
481 assert(count == bc.size());
496 if (std::abs(z) >
m_zmax)
return -1;
501 }
else if (z <
m_zj) {
508 int jz =
static_cast<int>(fz);
527 [[nodiscard]]
bool inRange(
const ROOT::Math::XYZVector& v)
const
529 if (std::abs(v.Z()) >
m_zmax)
return false;
530 double R2 = v.X() * v.X() + v.Y() * v.Y();
546 ROOT::Math::XYZVector res = {0, 0, 0};
547 double R2 = v.X() * v.X() + v.Y() * v.Y();
551 if (iz < 0)
return res;
552 double wz0 = 1 - wz1;
555 xy_t xy = {v.X(), std::abs(v.Y())};
560 int j0 = t->j0, j1 = t->j1, j2 = t->j2;
561 const ROOT::Math::XYZVector* B =
m_B.data() +
m_nxy * iz;
562 ROOT::Math::XYZVector b = (B[j0] * w0 + B[j1] * w1 + B[j2] * w2) * wz0;
564 b += (B[j0] * w0 + B[j1] * w1 + B[j2] * w2) * wz1;
567 double r =
sqrt(R2), phi = atan2(std::abs(v.Y()), v.X());
571 int ir =
static_cast<int>(fr);
572 int iphi =
static_cast<int>(fphi);
577 double wr1 = fr - ir, wr0 = 1 - wr1;
578 double wphi1 = fphi - iphi, wphi0 = 1 - wphi1;
580 int j00 =
m_nxy - nr1 * (nphi1 - iphi) + ir;
585 double w00 = wr0 * wphi0, w01 = wphi0 * wr1, w10 = wphi1 * wr0, w11 = wphi1 * wr1;
586 const ROOT::Math::XYZVector* B =
m_B.data() +
m_nxy * iz;
587 ROOT::Math::XYZVector b = (B[j00] * w00 + B[j01] * w01 + B[j10] * w10 + B[j11] * w11) * wz0;
589 b += (B[j00] * w00 + B[j01] * w01 + B[j10] * w10 + B[j11] * w11) * wz1;
592 if (v.Y() < 0) res.SetY(-res.Y());
597 vector<ROOT::Math::XYZVector>
m_B;
654 ROOT::Math::XYZVector v = -p;
655 double xc = v.X() * c, zs = v.Z() * s, zc = v.Z() * c, xs = v.X() * s;
656 ROOT::Math::XYZVector hv{xc - zs, v.Y(), zc + xs};
657 ROOT::Math::XYZVector lv{xc + zs, v.Y(), zc - xs};
663 ROOT::Math::XYZVector res;
665 ROOT::Math::XYZVector v = -p;
666 double xc = v.X() * c, zs = v.Z() * s, zc = v.Z() * c, xs = v.X() * s;
667 ROOT::Math::XYZVector hv{xc - zs, v.Y(), zc + xs};
668 ROOT::Math::XYZVector lv{xc + zs, v.Y(), zc - xs};
671 ROOT::Math::XYZVector rhb{hb.X()* c + hb.Z()* s, hb.Y(), hb.Z()* c - hb.X()* s};
672 ROOT::Math::XYZVector rlb{lb.X()* c - lb.Z()* s, lb.Y(), lb.Z()* c + lb.X()* s};
674 double mhb = std::abs(rhb.X()) + std::abs(rhb.Y()) + std::abs(rhb.Z());
675 double mlb = std::abs(rlb.X()) + std::abs(rlb.Y()) + std::abs(rlb.Z());
677 if (mhb < 1e-10) res = rlb;
678 else if (mlb < 1e-10) res = rhb;
680 res = 0.5 * (rlb + rhb);
700 if (*gInstance ==
nullptr) {
710 if (*gInstance !=
nullptr) {
711 B2WARNING(
"BFieldComponentBeamline: object already instantiated");
The BFieldComponentBeamline class.
std::string m_mapFilename_ler
The filename of the magnetic field map.
BeamlineFieldMapInterpolation * m_ler
Actual magnetic field interpolation object for LER.
BeamlineFieldMapInterpolation * m_her
Actual magnetic field interpolation object for HER.
double m_sinBeamCrossAngle
The sin of the crossing angle of the beams
double m_cosBeamCrossAngle
The cos of the crossing angle of the beams
std::string m_interFilename_ler
The filename of the map for interpolation.
std::string m_mapFilename_her
Parameter to set Angle of the beam.
std::string m_interFilename_her
The filename of the map for interpolation.
double m_mapRegionR[2]
The min and max boundaries of the map region in r.
The BeamlineFieldMapInterpolation class.
const TriangularInterpolation & getTriangularInterpolation() const
Expose the triangular interpolation to outside.
double m_rj
Separation radius between triangular and cylindrical meshes.
bool inRange(const ROOT::Math::XYZVector &v) const
Check the space point if the interpolation exists.
double m_idphi
Repciprocal of Phi grid.
int zIndexAndWeight(double z, double &w1) const
For a given Z coordinate calculate the index of Z slice and corresponding weight.
double m_idz1
Inverse of finer Z grid pitch.
int m_nphi
Number of grid points in Phi direction.
int m_nr
Number of grid points in R direction.
double m_zmax
Maximal Z where interpolation is still valid.
double m_rj2
Square of the separation radius between triangular and cylindrical meshes.
int m_nz
Number of field slices in Z direction.
ROOT::Math::XYZVector interpolateField(const ROOT::Math::XYZVector &v) const
Interpolate the magnetic field vector at the specified space point.
double m_dz1
Finer Z grid pitch.
int m_nz2
End Z slice number for the finer Z grid.
vector< ROOT::Math::XYZVector > m_B
Buffer for the magnetic field map.
int m_nxy
Number of field points in XY plane.
double m_idz0
Inverse of coarse Z grid pitch.
TriangularInterpolation m_triInterpol
Object to locate point in a triangular mesh.
void init(const string &fieldmapname, const string &interpolname, double validRadius)
Initializes the magnetic field component.
double m_rmax
Maximal radius where interpolation is still valid.
double m_idr
Repciprocal of R grid.
BeamlineFieldMapInterpolation()=default
Default constructor.
~BeamlineFieldMapInterpolation()=default
Default destructor.
int m_nz1
Start Z slice number for the finer Z grid.
double m_dz0
Coarse Z grid pitch.
double m_zj
Z border of finer Z grid.
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...
The TriangularInterpolation class.
vector< short int > m_spatialIndex
Spatial index.
double m_xmin
Border of the region where the spatial index is constructed.
unsigned int m_ny
Spatial index grid size.
double m_ixnorm
Reciprocals to speedup the index calculation.
~TriangularInterpolation()=default
Destructor.
TriangularInterpolation(vector< xy_t > &pc, vector< triangle_t > &ts, double d)
More complex constructor.
vector< triangle_t > m_triangles
Triangle list.
vector< xy_t > m_points
Vertex list.
void init(vector< xy_t > &points, vector< triangle_t > &triangles, double d)
Calculate extents of a triangular mesh and build spatial index.
xy_t triangleCenter(const triangle_t &p) const
Calculate triangle center.
double m_ymin
Border of the region where the spatial index is constructed.
vector< xy_t > m_triangleCenters
Triangle centers.
short int sideCross(short int prev, short int curr, const xy_t &r, const xy_t &v0) const
Determine which triangle side is crossed by a line segment defined by r and v0 points.
const vector< triangle_t > & getTriangles() const
returns list of triangles
double m_xmax
Border of the region where the spatial index is constructed.
void makeIndex(int nx, double xmin, double xmax, int ny, double ymin, double ymax)
Make spatial index.
const vector< xy_t > & getPoints() const
returns list of verticies
vector< double > m_triangleAreas
Triangle areas.
unsigned int m_nx
Spatial index grid size.
short int findTriangle(const xy_t &r0) const
Find the triangle which contain the point.
TriangularInterpolation()=default
Default constructor.
void weights(short int i, const xy_t &r, double &w0, double &w1, double &w2) const
Calculate barycentric coordinates of a point inside triangle.
double m_ymax
Border of the region where the spatial index is constructed.
double m_iynorm
Reciprocals to speedup the index calculation.
double sqrt(double a)
sqrt for double
virtual void initialize() override
Initializes the magnetic field component.
BFieldComponentBeamline ** GetInstancePtr()
Static function holding the instance.
bool isInRange(const ROOT::Math::XYZVector &point) const
Check presence of beamline field at the specific space point in the detector coordinate frame.
virtual void terminate() override
Terminates the magnetic field component.
virtual ROOT::Math::XYZVector calculate(const ROOT::Math::XYZVector &point) const override
Calculates the magnetic field vector at the specified space point.
virtual ~BFieldComponentBeamline()
The BFieldComponentBeamline destructor.
static BFieldComponentBeamline & Instance()
BFieldComponentBeamline instance.
BFieldComponentBeamline()
The BFieldComponentBeamline constructor.
Abstract base class for different kinds of events.
short int n1
2nd adjacent triangle in a list of triangles
short int j1
2nd vertex index in a list of xy-points
short int n2
3rd adjacent triangle in a list of triangles
short int j0
1st vertex index in a list of xy-points
short int n0
1st adjacent triangle in a list of triangles
short int j2
3rd vertex index in a list of xy-points
A simple 2d vector stucture.