7#include "Acts/Definitions/Algebra.hpp"
8#include "Acts/MagneticField/BFieldMapUtils.hpp"
9#include "Acts/MagneticField/InterpolatedBFieldMap.hpp"
10#include "Acts/MagneticField/MagneticFieldContext.hpp"
11#include "Acts/Utilities/AxisDefinitions.hpp"
12#include "Acts/Utilities/Grid.hpp"
13#include "Framework/Exception/Exception.h"
15static const double DIPOLE_OFFSET = 400.;
17using InterpolatedMagneticField3 = Acts::InterpolatedBFieldMap<
18 Acts::Grid<Acts::Vector3, Acts::Axis<Acts::AxisType::Equidistant>,
19 Acts::Axis<Acts::AxisType::Equidistant>,
20 Acts::Axis<Acts::AxisType::Equidistant>>>;
22using GenericTransformPos = std::function<Acts::Vector3(
const Acts::Vector3&)>;
23using GenericTransformBField =
24 std::function<Acts::Vector3(
const Acts::Vector3&,
const Acts::Vector3&)>;
34Acts::Vector3 defaultTransformPos(
const Acts::Vector3& pos_);
42Acts::Vector3 defaultTransformBField(
const Acts::Vector3& field,
43 const Acts::Vector3& );
45void testField(
const std::shared_ptr<Acts::MagneticFieldProvider> bfield,
46 const Acts::Vector3& eval_pos,
47 const Acts::MagneticFieldContext& bctx);
67 Acts::Vector3
pivot_{-DIPOLE_OFFSET, 0., 0.};
73 return (Acts::AngleAxis3(
rotation_(2), Acts::Vector3::UnitZ()) *
74 Acts::AngleAxis3(
rotation_(1), Acts::Vector3::UnitY()) *
75 Acts::AngleAxis3(
rotation_(0), Acts::Vector3::UnitX()))
94size_t localToGlobalBinXyz(std::array<size_t, 3> bins,
95 std::array<size_t, 3> sizes);
97inline InterpolatedMagneticField3 rotateFieldMapXYZ(
98 const std::function<
size_t(std::array<size_t, 3> binsXYZ,
99 std::array<size_t, 3> nBinsXYZ)>&
101 std::vector<double> xPos, std::vector<double> yPos,
102 std::vector<double> zPos, std::vector<Acts::Vector3> bField,
103 double lengthUnit,
double BFieldUnit,
bool firstOctant,
104 GenericTransformPos transformPosition,
105 GenericTransformBField transformMagneticField) {
108 std::sort(xPos.begin(), xPos.end());
109 std::sort(yPos.begin(), yPos.end());
110 std::sort(zPos.begin(), zPos.end());
113 xPos.erase(std::unique(xPos.begin(), xPos.end()), xPos.end());
114 yPos.erase(std::unique(yPos.begin(), yPos.end()), yPos.end());
115 zPos.erase(std::unique(zPos.begin(), zPos.end()), zPos.end());
116 xPos.shrink_to_fit();
117 yPos.shrink_to_fit();
118 zPos.shrink_to_fit();
121 size_t n_bins_x = xPos.size();
122 size_t n_bins_y = yPos.size();
123 size_t n_bins_z = zPos.size();
126 auto min_max_x = std::minmax_element(xPos.begin(), xPos.end());
127 auto min_max_y = std::minmax_element(yPos.begin(), yPos.end());
128 auto min_max_z = std::minmax_element(zPos.begin(), zPos.end());
131 double x_min = *min_max_x.first;
132 double y_min = *min_max_y.first;
133 double z_min = *min_max_z.first;
135 double x_max = *min_max_x.second;
136 double y_max = *min_max_y.second;
137 double z_max = *min_max_z.second;
140 double step_z = std::fabs(z_max - z_min) / (n_bins_z - 1);
141 double step_y = std::fabs(y_max - y_min) / (n_bins_y - 1);
142 double step_x = std::fabs(x_max - x_min) / (n_bins_x - 1);
149 x_min = -*min_max_x.second;
150 y_min = -*min_max_y.second;
151 z_min = -*min_max_z.second;
152 n_bins_x = 2 * n_bins_x - 1;
153 n_bins_y = 2 * n_bins_y - 1;
154 n_bins_z = 2 * n_bins_z - 1;
156 Acts::Axis<Acts::AxisType::Equidistant> x_axis(x_min * lengthUnit,
157 x_max * lengthUnit, n_bins_x);
158 Acts::Axis<Acts::AxisType::Equidistant> y_axis(y_min * lengthUnit,
159 y_max * lengthUnit, n_bins_y);
160 Acts::Axis<Acts::AxisType::Equidistant> z_axis(z_min * lengthUnit,
161 z_max * lengthUnit, n_bins_z);
164 Acts::Grid<Acts::Vector3, Acts::Axis<Acts::AxisType::Equidistant>,
165 Acts::Axis<Acts::AxisType::Equidistant>,
166 Acts::Axis<Acts::AxisType::Equidistant>>;
168 std::make_tuple(std::move(x_axis), std::move(y_axis), std::move(z_axis)));
171 for (
size_t i = 1; i <= n_bins_x; ++i) {
172 for (
size_t j = 1; j <= n_bins_y; ++j) {
173 for (
size_t k = 1; k <= n_bins_z; ++k) {
174 Grid_t::index_t indices = {{i, j, k}};
175 std::array<size_t, 3> n_indices = {
176 {xPos.size(), yPos.size(), zPos.size()}};
181 size_t m = std::abs(
int(i) - (
int(xPos.size())));
182 size_t n = std::abs(
int(j) - (
int(yPos.size())));
183 size_t l = std::abs(
int(k) - (
int(zPos.size())));
184 Grid_t::index_t indices_first_octant = {{m, n, l}};
186 grid.atLocalBins(indices) =
187 bField.at(localToGlobalBin(indices_first_octant, n_indices)) *
194 grid.atLocalBins(indices) =
195 bField.at(localToGlobalBin({{i - 1, j - 1, k - 1}}, n_indices)) *
201 grid.setExteriorBins(Acts::Vector3::Zero());
237 return Acts::InterpolatedBFieldMap<Grid_t>(
238 {transformPosition, transformMagneticField, std::move(grid)});
246inline InterpolatedMagneticField3 makeMagneticFieldMapXyzFromText(
247 std::function<
size_t(std::array<size_t, 3> binsXYZ,
248 std::array<size_t, 3> nBinsXYZ)>
250 GenericTransformPos transformPosition,
251 GenericTransformBField transformMagneticField,
252 const std::string& fieldMapFile,
double lengthUnit,
double BFieldUnit,
253 bool firstOctant,
bool rotateAxes) {
256 std::vector<double> x_pos;
257 std::vector<double> y_pos;
258 std::vector<double> z_pos;
260 std::vector<Acts::Vector3> b_field;
262 constexpr size_t k_default_size = 1 << 15;
264 x_pos.reserve(k_default_size);
265 y_pos.reserve(k_default_size);
266 z_pos.reserve(k_default_size);
267 b_field.reserve(k_default_size);
269 std::ifstream map_file(fieldMapFile.c_str(), std::ios::in);
270 if (!map_file.is_open()) {
271 EXCEPTION_RAISE(
"BadConf",
"BFieldXYZUtils: cannot open field map file '" +
275 double pos_x = 0., pos_y = 0., pos_z = 0.;
276 double bx = 0., by = 0., bz = 0.;
278 bool header_found =
false;
280 while (std::getline(map_file, line)) {
281 if (line.empty() || line[0] ==
'%' || line[0] ==
'#' || line[0] ==
' ' ||
282 line.find_first_not_of(
' ') == std::string::npos || !header_found) {
283 if (line.find(
"Header") != std::string::npos) header_found =
true;
286 std::istringstream tmp(line);
287 tmp >> pos_x >> pos_y >> pos_z >> bx >> by >> bz;
289 x_pos.push_back(pos_x);
290 y_pos.push_back(pos_y);
291 z_pos.push_back(pos_z);
292 b_field.push_back(Acts::Vector3(bx, by, bz));
297 EXCEPTION_RAISE(
"BadConf",
298 "BFieldXYZUtils: no 'Header' line found in field map "
302 if (b_field.empty()) {
303 EXCEPTION_RAISE(
"BadConf",
"BFieldXYZUtils: no field data read from '" +
307 x_pos.shrink_to_fit();
308 y_pos.shrink_to_fit();
309 z_pos.shrink_to_fit();
310 b_field.shrink_to_fit();
313 return rotateFieldMapXYZ(localToGlobalBin, x_pos, y_pos, z_pos, b_field,
314 lengthUnit, BFieldUnit, firstOctant,
315 transformPosition, transformMagneticField);
317 return Acts::fieldMapXYZ(localToGlobalBin, x_pos, y_pos, z_pos, b_field,
318 lengthUnit, BFieldUnit, firstOctant);
321inline InterpolatedMagneticField3 loadDefaultBField(
322 const std::string& fieldMapFile, GenericTransformPos transformPosition,
323 GenericTransformBField transformMagneticField) {
328 return makeMagneticFieldMapXyzFromText(
329 std::move(localToGlobalBinXyz), transformPosition, transformMagneticField,
331 1. * Acts::UnitConstants::mm,
332 1000. * Acts::UnitConstants::T,
A deliberate mis-placement of the reconstruction magnetic field, used to quantify how well we need to...
double scale_
overall scaling of the field strength
Acts::Vector3 pivot_
centre of rotation [mm], default the field-map origin
Acts::Vector3 rotation_
rotation about x, y, z through pivot [rad]
Acts::RotationMatrix3 rotationMatrix() const
Rz(gamma) * Ry(beta) * Rx(alpha)
Acts::Vector3 translation_
displacement of the magnet [mm]
bool isNominal() const
Exact comparison on purpose: the nominal case reuses the default transforms unchanged,...