Belle II Software  release-05-02-19
BFieldComponentQuad.cc
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2010-2011 Belle II Collaboration *
4  * *
5  * Author: The Belle II Collaboration *
6  * Contributors: Hiroyuki Nakayama *
7  * *
8  * This software is provided "as is" without any warranty. *
9  **************************************************************************/
10 
11 #include <geometry/bfieldmap/BFieldComponentQuad.h>
12 
13 #include <framework/utilities/FileSystem.h>
14 #include <framework/logging/Logger.h>
15 #include <framework/gearbox/Unit.h>
16 #include <framework/gearbox/Const.h>
17 
18 #include <boost/iostreams/filtering_stream.hpp>
19 #include <boost/iostreams/device/file.hpp>
20 
21 #include <cmath>
22 
23 using namespace std;
24 using namespace Belle2;
25 namespace io = boost::iostreams;
26 
35 template <class ForwardIterator, class T, class Compare>
36 ForwardIterator linear_sentinel(ForwardIterator it, const T& val, Compare comp)
37 {
38  do {
39  if (comp(val, *it)) break;
40  ++it;
41  } while (true);
42  return it;
43 }
44 
45 void BFieldComponentQuad::initialize()
46 {
47  // check if input name is not empty
48  if (m_mapFilenameHER.empty()) {
49  B2FATAL("The filename for the HER quadrupole magnetic field component is empty !");
50  return;
51  }
52  if (m_mapFilenameLER.empty()) {
53  B2FATAL("The filename for the LER quadrupole magnetic field component is empty !");
54  return;
55  }
56  if (m_apertFilenameHER.empty()) {
57  B2FATAL("The filename for the HER beam pipe aperture is empty !");
58  return;
59  }
60  if (m_apertFilenameLER.empty()) {
61  B2FATAL("The filename for the LER beam pipe aperture is empty !");
62  return;
63  }
64 
65  // check if input files exsits
66  string fullPathMapHER = FileSystem::findFile("/data/" + m_mapFilenameHER);
67  if (!FileSystem::fileExists(fullPathMapHER)) {
68  B2FATAL("The HER quadrupole magnetic field map file '" << m_mapFilenameHER << "' could not be found !");
69  return;
70  }
71  string fullPathMapLER = FileSystem::findFile("/data/" + m_mapFilenameLER);
72  if (!FileSystem::fileExists(fullPathMapLER)) {
73  B2FATAL("The LER quadrupole magnetic field map file '" << m_mapFilenameLER << "' could not be found !");
74  return;
75  }
76  string fullPathMapHERleak = FileSystem::findFile("/data/" + m_mapFilenameHERleak);
77  if (!FileSystem::fileExists(fullPathMapHERleak)) {
78  B2FATAL("The HERleak quadrupole magnetic field map file '" << m_mapFilenameHERleak << "' could not be found !");
79  return;
80  }
81  string fullPathApertHER = FileSystem::findFile("/data/" + m_apertFilenameHER);
82  if (!FileSystem::fileExists(fullPathApertHER)) {
83  B2FATAL("The HER aperture file '" << m_apertFilenameHER << "' could not be found !");
84  return;
85  }
86  string fullPathApertLER = FileSystem::findFile("/data/" + m_apertFilenameLER);
87  if (!FileSystem::fileExists(fullPathApertLER)) {
88  B2FATAL("The LER aperture file '" << m_apertFilenameLER << "' could not be found !");
89  return;
90  }
91 
92  //--------------------------------------------------------------
93  // Load the field map files
94  //--------------------------------------------------------------
95 
97  struct ParamPoint {
98  double s{0};
99  double L{0};
100  double K0{0};
101  double K1{0};
102  double SK0{0};
103  double SK1{0};
104  double ROTATE{0};
105  double DX{0};
106  double DY{0};
107  /* Note that K parameters used in SAD is multiplied by the element length.
108  * Popular definitions are: K0,SK0[1/m] and K1,SK1[1/m^2]
109  */
110  };
111 
112  io::filtering_istream fieldMapFileHER, fieldMapFileLER, fieldMapFileHERleak;
113  fieldMapFileHER.push(io::file_source(fullPathMapHER));
114  fieldMapFileLER.push(io::file_source(fullPathMapLER));
115  fieldMapFileHERleak.push(io::file_source(fullPathMapHERleak));
116 
117  //Create the parameter map and read the data from the file
118  auto readLenseParameters = [](istream & IN) -> vector<ParamPoint> {
119  vector<ParamPoint> r;
120  string name;
121  ParamPoint t;
122  while (IN >> name >> t.s >> t.L >> t.K0 >> t.K1 >> t.SK0 >> t.SK1 >> t.ROTATE >> t.DX >> t.DY)
123  {
124  /* Convert parameters in basf2 default unit [cm].*/
125  t.s *= 100;
126  t.L *= 100;
127  t.DX *= 100;
128  t.DY *= 100;
129  t.K1 /= 100;
130  t.SK1 /= 100;
131  r.push_back(t);
132  }
133  return r;
134  };
135 
136  std::vector<ParamPoint> params_her, params_ler, params_herl;
137  params_her = readLenseParameters(fieldMapFileHER);
138  params_ler = readLenseParameters(fieldMapFileLER);
139  params_herl = readLenseParameters(fieldMapFileHERleak);
140 
141  //--------------------------------------------------------------
142  // Load the aperture map files
143  //--------------------------------------------------------------
144  auto readAperturePoints = [this](istream & IN) -> vector<ApertPoint> {
145  vector<ApertPoint> r;
146  ApertPoint t;
147  while (IN >> t.s >> t.r)
148  {
149  /* s and r are in [mm] in Apert?ER.dat. */
150  /* Transform parameters in basf2 default unit [cm].*/
151  t.s /= 10; t.r /= 10;
152  r.push_back(t);
153  m_maxr2 = max(m_maxr2, t.r);
154  }
155  r.push_back({numeric_limits<double>::infinity(), m_maxr2});
156  return r;
157  };
158 
159  io::filtering_istream apertFileHER, apertFileLER;
160  apertFileHER.push(io::file_source(fullPathApertHER));
161  apertFileLER.push(io::file_source(fullPathApertLER));
162 
163  m_ah = readAperturePoints(apertFileHER);
164  m_al = readAperturePoints(apertFileLER);
165 
166  m_maxr2 *= m_maxr2;
167 
174  auto proc3 = [](const vector<ParamPoint>& in, double p0) -> vector<ParamPoint3> {
175  vector<ParamPoint3> out;
176  out.resize(in.size());
177  auto it = out.begin();
178  for (auto b = in.begin(); b != in.end(); ++b, ++it)
179  {
180  ParamPoint3& t = *it;
181  t.s = b->s;
182  t.L = b->L;
183 
184  double K0 = b->K0;
185  double K1 = b->K1;
186  double SK0 = b->SK0;
187  double SK1 = b->SK1;
188  double DX = b->DX;
189  double DY = b->DY;
190  double k = p0 / t.L;
191  K0 *= k;
192  K1 *= k;
193  SK0 *= k;
194  SK1 *= k;
195 
196 #define ROTATE_DIRECTION 1 // 1: default, 0: rotate-off, -1: inversely rotate
197 #if ROTATE_DIRECTION==0
198  double sphi = 0, cphi = 1;
199 #else
200  double sphi, cphi;
201  sincos(-b->ROTATE * (M_PI / 180), &sphi, &cphi);
202 #if ROTATE_DIRECTION==-1
203  sphi = -sphi;
204 #endif
205 #endif
206  double s2phi = 2 * cphi * sphi;
207  double c2phi = cphi * cphi - sphi * sphi;
208  double tp = DX * SK1 + DY * K1;
209  double tm = DY * SK1 - DX * K1;
210 
211  t.mxx = K1 * s2phi + SK1 * c2phi;
212  t.mxy = -SK1 * s2phi + K1 * c2phi;
213  t.mx0 = tm * s2phi - tp * c2phi + SK0 * cphi + K0 * sphi;
214 
215  t.myx = -SK1 * s2phi + K1 * c2phi;
216  t.myy = -K1 * s2phi - SK1 * c2phi;
217  t.my0 = tp * s2phi + tm * c2phi + K0 * cphi - SK0 * sphi;
218  }
219  return out;
220  };
221 
222  const double c = Const::speedOfLight / (Unit::m / Unit::s) / 100;
223  const double p0_HER = 7.0e+9 / c, p0_LER = 4.0e+9 / c;
224 
225  m_h3 = proc3(params_her, p0_HER);
226  vector<ParamPoint3> hleak3 = proc3(params_herl, p0_HER);
227  m_l3 = proc3(params_ler, p0_LER);
228 
238  auto merge = [](vector<ParamPoint3>& v, const vector<ParamPoint3>& a) {
239  for (const auto& t : a) {
240  auto i = upper_bound(v.begin(), v.end(), t.s, [](double s, const ParamPoint3 & b) {return s < b.s;});
241  if (i == v.end()) continue;
242  ParamPoint3& p = *(i - 1);
243  if (p.s == t.s && p.L == t.L)
244  p += t;
245  else
246  v.insert(i, t);
247  }
248  };
249  merge(m_h3, hleak3);
250 
257  auto getranges = [](const vector<ParamPoint3>& v) {
258  ranges_t r;
259  double s0 = v[0].s, smax = v.back().s + v.back().L;
260  for (int i = 0, N = v.size(); i < N - 1; i++) {
261  const ParamPoint3& t0 = v[i], t1 = v[i + 1];
262  double sn = t0.s + t0.L;
263  if (abs(sn - t1.s) > 1e-10) {
264  r.push_back({s0, sn});
265  s0 = t1.s;
266  }
267  }
268  r.push_back({s0, smax});
269  return r;
270  };
271 
272  m_ranges_her = getranges(m_h3);
273  m_ranges_ler = getranges(m_l3);
274 
275  const double inf = numeric_limits<double>::infinity();
276  // add sentinels
277  m_ranges_her.insert(m_ranges_her.begin(), { -inf, -inf});
278  m_ranges_her.insert(m_ranges_her.end(), {inf, inf});
279  m_ranges_ler.insert(m_ranges_ler.begin(), { -inf, -inf});
280  m_ranges_ler.insert(m_ranges_ler.end(), {inf, inf});
281 
288  auto associate_aperture = [](const vector<ApertPoint>& ap, const ranges_t& v) {
289  auto less = [](double s, const ApertPoint & b) {return s < b.s;};
290  vector<std::vector<ApertPoint>::const_iterator> res;
291  for (auto r : v) {
292  auto i0 = upper_bound(ap.begin(), ap.end(), r.r0, less);
293  if (i0 == ap.begin() || i0 == ap.end()) continue;
294  res.push_back(i0 - 1);
295  }
296  return res;
297  };
298  m_offset_ap_her = associate_aperture(m_ah, m_ranges_her);
299  m_offset_ap_ler = associate_aperture(m_al, m_ranges_ler);
300 
307  auto associate_lenses = [](const vector<ParamPoint3>& ap, const ranges_t& v) {
308  vector<std::vector<ParamPoint3>::const_iterator> res;
309  for (auto r : v) {
310  auto i0 = find_if(ap.begin(), ap.end(), [r](const ParamPoint3 & b) {return abs(b.s - r.r0) < 1e-10;});
311  if (i0 == ap.end()) continue;
312  res.push_back(i0);
313  }
314  return res;
315  };
316  m_offset_pp_her = associate_lenses(m_h3, m_ranges_her);
317  m_offset_pp_ler = associate_lenses(m_l3, m_ranges_ler);
318 }
319 
320 double BFieldComponentQuad::getApertureHER(double s) const
321 {
322  int i = getRange(s, m_ranges_her);
323  if (i < 0) return 0;
324  return getAperture(s, m_offset_ap_her[i]);
325 }
326 
327 double BFieldComponentQuad::getApertureLER(double s) const
328 {
329  int i = getRange(s, m_ranges_ler);
330  if (i < 0) return 0;
331  return getAperture(s, m_offset_ap_ler[i]);
332 }
333 
334 int BFieldComponentQuad::getRange(double s, const ranges_t& r) const
335 {
336  auto it0 = r.begin() + 1;
337  auto it = linear_sentinel(it0, s, [](double s_, const range_t& r_) {return s_ <= r_.r0;});
338  if (s > (--it)->r1) return -1;
339  return it - it0;
340 }
341 
342 double BFieldComponentQuad::getAperture(double s, std::vector<ApertPoint>::const_iterator jt0) const
343 {
344  auto jt = linear_sentinel(jt0, s, [](double s_, const ApertPoint & r) {return s_ <= r.s;});
345  const ApertPoint& p1 = *(jt - 1), &p2 = *jt;
346  return p1.r + (p2.r - p1.r) / (p2.s - p1.s) * (s - p1.s);
347 }
348 
349 B2Vector3D BFieldComponentQuad::calculate(const B2Vector3D& point) const
350 {
351  const double sa = sin(0.0415), ca = cos(0.0415);
352  //assume point is given in [cm]
353  B2Vector3D B(0, 0, 0);
354 
355  const B2Vector3D& v{point};
356  double xc = v.x() * ca, zs = v.z() * sa, zc = v.z() * ca, xs = v.x() * sa;
357  B2Vector3D vh{(xc - zs), -v.y(), -(zc + xs)}; // to the HER beamline frame
358  B2Vector3D vl{(xc + zs), -v.y(), -(zc - xs)}; // to the LER beamline frame
359 
360  double r2h = vh.Perp2(), r2l = vl.Perp2();
361 
362  if (r2h < r2l) { /* the point is closer to HER*/
363  if (r2h < m_maxr2) { /* within max radius */
364  double s = vh.z();
365  int i = getRange(s, m_ranges_her);
366  if (i < 0) return B;
367  double r = getAperture(s, m_offset_ap_her[i]);
368  if (r2h < r * r) {
369  auto kt = m_offset_pp_her[i] + static_cast<unsigned int>(s - m_ranges_her[i + 1].r0);
370  double Bx = kt->getBx(vh.x(), vh.y());
371  double By = kt->getBy(vh.x(), vh.y());
372  B.SetXYZ(Bx * ca, -By, -Bx * sa); // to the detector frame
373  }
374  }
375  } else { /* the point is closer to LER*/
376  if (r2l < m_maxr2) { /* within max radius */
377  double s = vl.z();
378  int i = getRange(s, m_ranges_ler);
379  if (i < 0) return B;
380  double r = getAperture(s, m_offset_ap_ler[i]);
381  if (r2l < r * r) {
382  auto kt = m_offset_pp_ler[i] + static_cast<unsigned int>(s - m_ranges_ler[i + 1].r0);
383  double Bx = kt->getBx(vl.x(), vl.y());
384  double By = kt->getBy(vl.x(), vl.y());
385  B.SetXYZ(Bx * ca, -By, Bx * sa); // to the detector frame
386  }
387  }
388  }
389  return B;
390 }
Belle2::BFieldComponentQuad::ParamPoint3
Quadrupole lense data structure.
Definition: BFieldComponentQuad.h:64
Belle2::BFieldComponentQuad::ranges_t
std::vector< range_t > ranges_t
vector of Range data structure.
Definition: BFieldComponentQuad.h:54
Belle2::B2Vector3< double >
Belle2::merge
std::vector< std::vector< double > > merge(std::vector< std::vector< std::vector< double >>> toMerge)
merge { vector<double> a, vector<double> b} into {a, b}
Definition: tools.h:44
Belle2::BFieldComponentQuad::range_t::r0
double r0
min of the range
Definition: BFieldComponentQuad.h:50
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::BFieldComponentQuad::range_t
Range data structure.
Definition: BFieldComponentQuad.h:49
Belle2::BFieldComponentQuad::ApertPoint
Aperture data structure.
Definition: BFieldComponentQuad.h:57