EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
BFieldMapUtils.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file BFieldMapUtils.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2017-2018 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
10 
15 
16 #include <iostream>
17 
20 
24 Acts::fieldMapperRZ(const std::function<size_t(std::array<size_t, 2> binsRZ,
25  std::array<size_t, 2> nBinsRZ)>&
26  localToGlobalBin,
27  std::vector<double> rPos, std::vector<double> zPos,
28  std::vector<Acts::Vector2D> bField, double lengthUnit,
29  double BFieldUnit, bool firstQuadrant) {
30  // [1] Create Grid
31  // sort the values
32  std::sort(rPos.begin(), rPos.end());
33  std::sort(zPos.begin(), zPos.end());
34  // Get unique values
35  rPos.erase(std::unique(rPos.begin(), rPos.end()), rPos.end());
36  zPos.erase(std::unique(zPos.begin(), zPos.end()), zPos.end());
37  rPos.shrink_to_fit();
38  zPos.shrink_to_fit();
39  // get the number of bins
40  size_t nBinsR = rPos.size();
41  size_t nBinsZ = zPos.size();
42 
43  // get the minimum and maximum
44  auto minMaxR = std::minmax_element(rPos.begin(), rPos.end());
45  auto minMaxZ = std::minmax_element(zPos.begin(), zPos.end());
46  double rMin = *minMaxR.first;
47  double zMin = *minMaxZ.first;
48  double rMax = *minMaxR.second;
49  double zMax = *minMaxZ.second;
50  // calculate maxima (add one last bin, because bin value always corresponds to
51  // left boundary)
52  double stepZ = std::fabs(zMax - zMin) / (nBinsZ - 1);
53  double stepR = std::fabs(rMax - rMin) / (nBinsR - 1);
54  rMax += stepR;
55  zMax += stepZ;
56  if (firstQuadrant) {
57  zMin = -(*minMaxZ.second);
58  nBinsZ = 2. * nBinsZ - 1;
59  }
60 
61  // Create the axis for the grid
62  Acts::detail::EquidistantAxis rAxis(rMin * lengthUnit, rMax * lengthUnit,
63  nBinsR);
64  Acts::detail::EquidistantAxis zAxis(zMin * lengthUnit, zMax * lengthUnit,
65  nBinsZ);
66 
67  // Create the grid
68  using Grid_t =
70  Acts::detail::EquidistantAxis>;
71  Grid_t grid(std::make_tuple(std::move(rAxis), std::move(zAxis)));
72 
73  // [2] Set the bField values
74  for (size_t i = 1; i <= nBinsR; ++i) {
75  for (size_t j = 1; j <= nBinsZ; ++j) {
76  std::array<size_t, 2> nIndices = {{rPos.size(), zPos.size()}};
77  Grid_t::index_t indices = {{i, j}};
78  if (firstQuadrant) {
79  // std::vectors begin with 0 and we do not want the user needing to
80  // take underflow or overflow bins in account this is why we need to
81  // subtract by one
82  size_t n = std::abs(int(j) - int(zPos.size()));
83  Grid_t::index_t indicesFirstQuadrant = {{i - 1, n}};
84 
85  grid.atLocalBins(indices) =
86  bField.at(localToGlobalBin(indicesFirstQuadrant, nIndices)) *
87  BFieldUnit;
88  } else {
89  // std::vectors begin with 0 and we do not want the user needing to
90  // take underflow or overflow bins in account this is why we need to
91  // subtract by one
92  grid.atLocalBins(indices) =
93  bField.at(localToGlobalBin({{i - 1, j - 1}}, nIndices)) *
94  BFieldUnit;
95  }
96  }
97  }
98  grid.setExteriorBins(Acts::Vector2D::Zero());
99 
100  // [3] Create the transformation for the position
101  // map (x,y,z) -> (r,z)
102  auto transformPos = [](const Acts::Vector3D& pos) {
103  return Acts::Vector2D(perp(pos), pos.z());
104  };
105 
106  // [4] Create the transformation for the bfield
107  // map (Br,Bz) -> (Bx,By,Bz)
108  auto transformBField = [](const Acts::Vector2D& field,
109  const Acts::Vector3D& pos) {
110  double r_sin_theta_2 = pos.x() * pos.x() + pos.y() * pos.y();
111  double cos_phi, sin_phi;
112  if (r_sin_theta_2 > std::numeric_limits<double>::min()) {
113  double inv_r_sin_theta = 1. / sqrt(r_sin_theta_2);
114  cos_phi = pos.x() * inv_r_sin_theta;
115  sin_phi = pos.y() * inv_r_sin_theta;
116  } else {
117  cos_phi = 1.;
118  sin_phi = 0.;
119  }
120  return Acts::Vector3D(field.x() * cos_phi, field.x() * sin_phi, field.y());
121  };
122 
123  // [5] Create the mapper & BField Service
124  // create field mapping
125  return Acts::InterpolatedBFieldMapper<Grid_t>(transformPos, transformBField,
126  std::move(grid));
127 }
128 
131  Acts::detail::EquidistantAxis, Acts::detail::EquidistantAxis>>
133  const std::function<size_t(std::array<size_t, 3> binsXYZ,
134  std::array<size_t, 3> nBinsXYZ)>&
135  localToGlobalBin,
136  std::vector<double> xPos, std::vector<double> yPos,
137  std::vector<double> zPos, std::vector<Acts::Vector3D> bField,
138  double lengthUnit, double BFieldUnit, bool firstOctant) {
139  // [1] Create Grid
140  // Sort the values
141  std::sort(xPos.begin(), xPos.end());
142  std::sort(yPos.begin(), yPos.end());
143  std::sort(zPos.begin(), zPos.end());
144  // Get unique values
145  xPos.erase(std::unique(xPos.begin(), xPos.end()), xPos.end());
146  yPos.erase(std::unique(yPos.begin(), yPos.end()), yPos.end());
147  zPos.erase(std::unique(zPos.begin(), zPos.end()), zPos.end());
148  xPos.shrink_to_fit();
149  yPos.shrink_to_fit();
150  zPos.shrink_to_fit();
151  // get the number of bins
152  size_t nBinsX = xPos.size();
153  size_t nBinsY = yPos.size();
154  size_t nBinsZ = zPos.size();
155 
156  // get the minimum and maximum
157  auto minMaxX = std::minmax_element(xPos.begin(), xPos.end());
158  auto minMaxY = std::minmax_element(yPos.begin(), yPos.end());
159  auto minMaxZ = std::minmax_element(zPos.begin(), zPos.end());
160  // Create the axis for the grid
161  // get minima
162  double xMin = *minMaxX.first;
163  double yMin = *minMaxY.first;
164  double zMin = *minMaxZ.first;
165  // get maxima
166  double xMax = *minMaxX.second;
167  double yMax = *minMaxY.second;
168  double zMax = *minMaxZ.second;
169  // calculate maxima (add one last bin, because bin value always corresponds to
170  // left boundary)
171  double stepZ = std::fabs(zMax - zMin) / (nBinsZ - 1);
172  double stepY = std::fabs(yMax - yMin) / (nBinsY - 1);
173  double stepX = std::fabs(xMax - xMin) / (nBinsX - 1);
174  xMax += stepX;
175  yMax += stepY;
176  zMax += stepZ;
177 
178  // If only the first octant is given
179  if (firstOctant) {
180  xMin = -*minMaxX.second;
181  yMin = -*minMaxY.second;
182  zMin = -*minMaxZ.second;
183  nBinsX = 2 * nBinsX - 1;
184  nBinsY = 2 * nBinsY - 1;
185  nBinsZ = 2 * nBinsZ - 1;
186  }
187  Acts::detail::EquidistantAxis xAxis(xMin * lengthUnit, xMax * lengthUnit,
188  nBinsX);
189  Acts::detail::EquidistantAxis yAxis(yMin * lengthUnit, yMax * lengthUnit,
190  nBinsY);
191  Acts::detail::EquidistantAxis zAxis(zMin * lengthUnit, zMax * lengthUnit,
192  nBinsZ);
193  // Create the grid
194  using Grid_t =
197  Acts::detail::EquidistantAxis>;
198  Grid_t grid(
199  std::make_tuple(std::move(xAxis), std::move(yAxis), std::move(zAxis)));
200 
201  // [2] Set the bField values
202  for (size_t i = 1; i <= nBinsX; ++i) {
203  for (size_t j = 1; j <= nBinsY; ++j) {
204  for (size_t k = 1; k <= nBinsZ; ++k) {
205  Grid_t::index_t indices = {{i, j, k}};
206  std::array<size_t, 3> nIndices = {
207  {xPos.size(), yPos.size(), zPos.size()}};
208  if (firstOctant) {
209  // std::vectors begin with 0 and we do not want the user needing to
210  // take underflow or overflow bins in account this is why we need to
211  // subtract by one
212  size_t m = std::abs(int(i) - (int(xPos.size())));
213  size_t n = std::abs(int(j) - (int(yPos.size())));
214  size_t l = std::abs(int(k) - (int(zPos.size())));
215  Grid_t::index_t indicesFirstOctant = {{m, n, l}};
216 
217  grid.atLocalBins(indices) =
218  bField.at(localToGlobalBin(indicesFirstOctant, nIndices)) *
219  BFieldUnit;
220 
221  } else {
222  // std::vectors begin with 0 and we do not want the user needing to
223  // take underflow or overflow bins in account this is why we need to
224  // subtract by one
225  grid.atLocalBins(indices) =
226  bField.at(localToGlobalBin({{i - 1, j - 1, k - 1}}, nIndices)) *
227  BFieldUnit;
228  }
229  }
230  }
231  }
232  grid.setExteriorBins(Acts::Vector3D::Zero());
233 
234  // [3] Create the transformation for the position
235  // map (x,y,z) -> (r,z)
236  auto transformPos = [](const Acts::Vector3D& pos) { return pos; };
237 
238  // [4] Create the transformation for the bfield
239  // map (Bx,By,Bz) -> (Bx,By,Bz)
240  auto transformBField = [](const Acts::Vector3D& field,
241  const Acts::Vector3D& /*pos*/) { return field; };
242 
243  // [5] Create the mapper & BField Service
244  // create field mapping
245  return Acts::InterpolatedBFieldMapper<Grid_t>(transformPos, transformBField,
246  std::move(grid));
247 }
248 
251  Acts::detail::EquidistantAxis>>
252 Acts::solenoidFieldMapper(std::pair<double, double> rlim,
253  std::pair<double, double> zlim,
254  std::pair<size_t, size_t> nbins,
255  const SolenoidBField& field) {
256  double rMin, rMax, zMin, zMax;
257  std::tie(rMin, rMax) = rlim;
258  std::tie(zMin, zMax) = zlim;
259 
260  size_t nBinsR, nBinsZ;
261  std::tie(nBinsR, nBinsZ) = nbins;
262 
263  double stepZ = std::abs(zMax - zMin) / (nBinsZ - 1);
264  double stepR = std::abs(rMax - rMin) / (nBinsR - 1);
265 
266  rMax += stepR;
267  zMax += stepZ;
268 
269  // Create the axis for the grid
270  Acts::detail::EquidistantAxis rAxis(rMin, rMax, nBinsR);
271  Acts::detail::EquidistantAxis zAxis(zMin, zMax, nBinsZ);
272 
273  // Create the grid
274  using Grid_t =
276  Acts::detail::EquidistantAxis>;
277  Grid_t grid(std::make_tuple(std::move(rAxis), std::move(zAxis)));
278 
279  // Create the transformation for the position
280  // map (x,y,z) -> (r,z)
281  auto transformPos = [](const Acts::Vector3D& pos) {
282  return Acts::Vector2D(perp(pos), pos.z());
283  };
284 
285  // Create the transformation for the bfield
286  // map (Br,Bz) -> (Bx,By,Bz)
287  auto transformBField = [](const Acts::Vector2D& bfield,
288  const Acts::Vector3D& pos) {
289  double r_sin_theta_2 = pos.x() * pos.x() + pos.y() * pos.y();
290  double cos_phi, sin_phi;
291  if (r_sin_theta_2 > std::numeric_limits<double>::min()) {
292  double inv_r_sin_theta = 1. / sqrt(r_sin_theta_2);
293  cos_phi = pos.x() * inv_r_sin_theta;
294  sin_phi = pos.y() * inv_r_sin_theta;
295  } else {
296  cos_phi = 1.;
297  sin_phi = 0.;
298  }
299  return Acts::Vector3D(bfield.x() * cos_phi, bfield.x() * sin_phi,
300  bfield.y());
301  };
302 
303  // iterate over all bins, set their value to the solenoid value
304  // at their lower left position
305  for (size_t i = 0; i <= nBinsR + 1; i++) {
306  for (size_t j = 0; j <= nBinsZ + 1; j++) {
307  Grid_t::index_t index({i, j});
308  if (i == 0 || j == 0 || i == nBinsR + 1 || j == nBinsZ + 1) {
309  // under or overflow bin, set zero
310  grid.atLocalBins(index) = Grid_t::value_type(0, 0);
311  } else {
312  // regular bin, get lower left boundary
313  Grid_t::point_t lowerLeft = grid.lowerLeftBinEdge(index);
314  // do lookup
315  Vector2D B = field.getField(Vector2D(lowerLeft[0], lowerLeft[1]));
316  grid.atLocalBins(index) = B;
317  }
318  }
319  }
320 
321  // Create the mapper & BField Service
322  // create field mapping
323  Acts::InterpolatedBFieldMapper<Grid_t> mapper(transformPos, transformBField,
324  std::move(grid));
325  return mapper;
326 }