ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
BFieldOptions.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file BFieldOptions.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2019 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 
11 #include <boost/program_options.hpp>
12 #include <iostream>
13 #include <tuple>
14 #include <utility>
15 
22 #include "Acts/Utilities/Units.hpp"
23 
24 namespace po = boost::program_options;
25 
29 
33 
38 
39 namespace FW {
40 
41 namespace Options {
42 
43 // common bfield options, with a bf prefix
44 void addBFieldOptions(boost::program_options::options_description& opt) {
45  opt.add_options()("bf-map", po::value<std::string>()->default_value(""),
46  "Set this string to point to the bfield source file."
47  "That can either be a '.txt', a '.csv' or a '.root' file. "
48  "Omit for a constant magnetic field.")(
49  "bf-name", po::value<std::string>()->default_value("bField"),
50  "In case your field map file is given in root format, please specify "
51  "the "
52  "name of the TTree.")(
53  "bf-gridpoints", po::value<size_t>()->default_value(100000),
54  "Estimate of number of grid points, "
55  "needed for allocation, only for txt and csv files.")(
56  "bf-lscalor", po::value<double>()->default_value(1.),
57  "The default unit for the grid "
58  "points is mm. In case the grid points of your field map has another "
59  "unit, please set the scalor to mm.")(
60  "bf-bscalor", po::value<double>()->default_value(1.),
61  "The default unit for the magnetic field values is Tesla. In case the "
62  "grid points of your field map has another unit, please set the "
63  "scalor "
64  "to [T].")(
65  "bf-rz", po::value<bool>()->default_value(false),
66  "Please set this flag to true, if your grid points and your "
67  "magnetic field values are given in 'rz'. The default is 'xyz'.")(
68  "bf-foctant", po::value<bool>()->default_value(false),
69  "Please set this flag to true, if your field map is only given for the "
70  "first octant/quadrant and should be symmetrically created for all "
71  "other "
72  "octants/quadrants.")(
73  "bf-values",
74  po::value<read_range>()->multitoken()->default_value({0., 0., 0.}),
75  "In case no magnetic field map is handed over. A constant magnetic "
76  "field will be created automatically. The values can be set with this "
77  "options. Please hand over the coordinates in cartesian coordinates: "
78  "{Bx,By,Bz} in Tesla.")(
79  "bf-context-scalable", po::value<bool>()->default_value(false),
80  "This is for testing the event dependent magnetic field scaling.");
81 }
82 
83 // create the bfield maps
84 BFieldVariant readBField(const boost::program_options::variables_map& vm) {
85  std::string bfieldmap = "constfield";
86 
87  enum BFieldMapType { constant = 0, root = 1, text = 2 };
88 
89  std::shared_ptr<InterpolatedBFieldMap2D> map2D = nullptr;
90  std::shared_ptr<InterpolatedBFieldMap3D> map3D = nullptr;
91  std::shared_ptr<Acts::ConstantBField> mapConst = nullptr;
92  std::shared_ptr<FW::BField::ScalableBField> mapScale = nullptr;
93 
94  int bfieldmaptype = constant;
95  if (vm.count("bf-map") && vm["bf-map"].template as<std::string>() != "") {
96  bfieldmap = vm["bf-map"].template as<std::string>();
97  std::cout << "- read in magnetic field map: "
98  << vm["bf-map"].template as<std::string>() << std::endl;
99  if (bfieldmap.find(".root") != std::string::npos) {
100  std::cout << "- root format for magnetic field detected" << std::endl;
101  bfieldmaptype = root;
102  } else if (bfieldmap.find(".txt") != std::string::npos ||
103  bfieldmap.find(".csv") != std::string::npos) {
104  std::cout << "- txt format for magnetic field detected" << std::endl;
105  bfieldmaptype = text;
106  } else {
107  std::cout << "- magnetic field format could not be detected";
108  std::cout << " use '.root', '.txt', or '.csv'." << std::endl;
109  throw std::runtime_error("Invalid BField options");
110  }
111  }
112  if (bfieldmaptype == text && vm.count("bf-gridpoints")) {
113  std::cout << "- number of points set to: "
114  << vm["bf-gridpoints"].template as<size_t>() << std::endl;
115  }
116  double lscalor = 1.;
117  if (bfieldmaptype != constant && vm.count("bf-lscalor")) {
118  lscalor = vm["bf-lscalor"].template as<double>();
119  std::cout << "- length scalor to mm set to: " << lscalor << std::endl;
120  }
121  double bscalor = 1.;
122  if (vm.count("bf-bscalor")) {
123  bscalor = vm["bf-bscalor"].template as<double>();
124  std::cout << "- BField (scalor to/in) Tesla set to: " << bscalor
125  << std::endl;
126  }
127  if (bfieldmaptype != constant && vm["bf-rz"].template as<bool>())
128  std::cout << "- BField map is given in 'rz' coordiantes." << std::endl;
129  else if (bfieldmaptype != constant)
130  std::cout << "- BField map is given in 'xyz' coordiantes." << std::endl;
131 
132  if (bfieldmaptype != constant && vm["bf-foctant"].template as<bool>()) {
133  std::cout
134  << "- Only the first octant/quadrant is given, bField map will be "
135  "symmetrically created for all other octants/quadrants"
136  << std::endl;
137  }
138 
139  // Declare the mapper
140  double lengthUnit = lscalor * Acts::units::_mm;
141  double BFieldUnit = bscalor * Acts::units::_T;
142 
143  // set the mapper - foort
144  if (bfieldmaptype == root) {
145  if (vm["bf-rz"].template as<bool>()) {
146  auto mapper2D = FW::BField::root::fieldMapperRZ(
147  [](std::array<size_t, 2> binsRZ, std::array<size_t, 2> nBinsRZ) {
148  return (binsRZ.at(1) * nBinsRZ.at(0) + binsRZ.at(0));
149  },
150  vm["bf-map"].template as<std::string>(),
151  vm["bf-name"].template as<std::string>(), lengthUnit, BFieldUnit,
152  vm["bf-foctant"].template as<bool>());
153 
154  // create field mapping
155  InterpolatedBFieldMap2D::Config config2D(std::move(mapper2D));
156  config2D.scale = bscalor;
157  // create BField service
158  return std::make_shared<InterpolatedBFieldMap2D>(std::move(config2D));
159 
160  } else {
161  auto mapper3D = FW::BField::root::fieldMapperXYZ(
162  [](std::array<size_t, 3> binsXYZ, std::array<size_t, 3> nBinsXYZ) {
163  return (binsXYZ.at(0) * (nBinsXYZ.at(1) * nBinsXYZ.at(2)) +
164  binsXYZ.at(1) * nBinsXYZ.at(2) + binsXYZ.at(2));
165  },
166  vm["bf-map"].template as<std::string>(),
167  vm["bf-name"].template as<std::string>(), lengthUnit, BFieldUnit,
168  vm["bf-foctant"].template as<bool>());
169 
170  // create field mapping
171  InterpolatedBFieldMap3D::Config config3D(std::move(mapper3D));
172  config3D.scale = bscalor;
173  // create BField service
174  return std::make_shared<InterpolatedBFieldMap3D>(std::move(config3D));
175  }
176  } else if (bfieldmaptype == text) {
177  if (vm["bf-rz"].template as<bool>()) {
178  auto mapper2D = FW::BField::txt::fieldMapperRZ(
179  [](std::array<size_t, 2> binsRZ, std::array<size_t, 2> nBinsRZ) {
180  return (binsRZ.at(1) * nBinsRZ.at(0) + binsRZ.at(0));
181  },
182  vm["bf-map"].template as<std::string>(), lengthUnit, BFieldUnit,
183  vm["bf-gridpoints"].template as<size_t>(),
184  vm["bf-foctant"].template as<bool>());
185 
186  // create field mapping
187  InterpolatedBFieldMap2D::Config config2D(std::move(mapper2D));
188  config2D.scale = bscalor;
189  // create BField service
190  return std::make_shared<InterpolatedBFieldMap2D>(std::move(config2D));
191 
192  } else {
193  auto mapper3D = FW::BField::txt::fieldMapperXYZ(
194  [](std::array<size_t, 3> binsXYZ, std::array<size_t, 3> nBinsXYZ) {
195  return (binsXYZ.at(0) * (nBinsXYZ.at(1) * nBinsXYZ.at(2)) +
196  binsXYZ.at(1) * nBinsXYZ.at(2) + binsXYZ.at(2));
197  },
198  vm["bf-map"].template as<std::string>(), lengthUnit, BFieldUnit,
199  vm["bf-gridpoints"].template as<size_t>(),
200  vm["bf-foctant"].template as<bool>());
201 
202  // create field mapping
203  InterpolatedBFieldMap3D::Config config3D(std::move(mapper3D));
204  config3D.scale = bscalor;
205  // create BField service
206  return std::make_shared<InterpolatedBFieldMap3D>(std::move(config3D));
207  }
208  } else { // constant
209  // No bfield map is handed over
210  // get the constant bField values
211  auto bFieldValues = vm["bf-values"].template as<read_range>();
212  if (bFieldValues.size() != 3) {
213  throw std::invalid_argument(
214  "- The values handed over for the constant magnetic field "
215  "have wrong dimension. Needs to have 3 dimension. Please "
216  "hand over the coordinates in cartesian coordinates: "
217  "{Bx,By,Bz} in Tesla.");
218  }
219  if (vm["bf-context-scalable"].template as<bool>()) {
220  // Create the scalable magnetic field
221  return std::make_shared<FW::BField::ScalableBField>(
222  bFieldValues.at(0) * Acts::units::_T,
223  bFieldValues.at(1) * Acts::units::_T,
224  bFieldValues.at(2) * Acts::units::_T);
225  } else {
226  // Create the constant magnetic field
227  return std::make_shared<Acts::ConstantBField>(
228  bFieldValues.at(0) * Acts::units::_T,
229  bFieldValues.at(1) * Acts::units::_T,
230  bFieldValues.at(2) * Acts::units::_T);
231  }
232  }
233 }
234 } // namespace Options
235 } // namespace FW