EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
BFieldAccessExample.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file BFieldAccessExample.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2017 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 
13 #include "Acts/Utilities/Units.hpp"
18 
19 #include <random>
20 #include <string>
21 
22 #include <boost/program_options.hpp>
23 #include <boost/progress.hpp>
24 
31 
32 namespace po = boost::program_options;
33 
34 using UniformDist = std::uniform_real_distribution<double>;
35 using RandomEngine = std::mt19937;
36 
37 template <typename field_t, typename field_context_t>
38 void accessStepWise(field_t& bField, field_context_t& bFieldContext,
39  size_t events, size_t theta_steps, double theta_0,
40  double theta_step, size_t phi_steps, double phi_0,
41  double phi_step, size_t access_steps, double access_step) {
42  std::cout << "[>>>] Start: step-wise access pattern ... " << std::endl;
43  size_t mismatched = 0;
44  // initialize the field cache
45  typename field_t::Cache bCache(bFieldContext);
46  // boost display
47  size_t totalSteps = events * theta_steps * phi_steps * access_steps;
48  boost::progress_display show_progress(totalSteps);
49  // the event loop
50  // loop over the events - @todo move to parallel for
51  for (size_t ievt = 0; ievt < events; ++ievt) {
52  for (size_t itheta = 0; itheta < theta_steps; ++itheta) {
53  double theta = theta_0 + itheta * theta_step;
54  for (size_t iphi = 0; iphi < phi_steps; ++iphi) {
55  double phi = phi_0 + iphi * phi_step;
56  // make a direction
57  Acts::Vector3D dir(cos(phi) * sin(theta), sin(phi) * sin(theta),
58  cos(theta));
59  // check for the current step
60  double currentStep = 0.;
61  // now step through the magnetic field
62  for (size_t istep = 0; istep < access_steps; ++istep) {
63  Acts::Vector3D position = currentStep * dir;
64  // access the field directly
65  auto field_direct = bField.getField(position);
66  // access the field with the cell
67  auto field_from_cache = bField.getField(position, bCache);
68  // check
69  if (!field_direct.isApprox(field_from_cache)) {
70  ++mismatched;
71  }
72  // increase the step
73  currentStep += access_step;
74  // show the progress bar
75  ++show_progress;
76  }
77  }
78  }
79  std::cout << "[<<<] End result : " << mismatched << "/" << totalSteps
80  << " mismatches" << std::endl;
81  }
82 }
83 
84 template <typename field_t, typename field_context_t>
85 void accessRandom(field_t& bField, field_context_t& bFieldContext,
86  size_t totalSteps, double radius) {
87  std::cout << "[>>>] Start: random access pattern ... " << std::endl;
88  size_t mismatched = 0;
89  RandomEngine rng;
90  UniformDist xDist(-radius, radius);
91  UniformDist yDist(-radius, radius);
92  UniformDist zDist(-radius, radius);
93 
94  // initialize the field cache
95  typename field_t::Cache bCache(bFieldContext);
96  boost::progress_display show_progress(totalSteps);
97 
98  // the event loop
99  // loop over the events - @todo move to parallel for
100  for (size_t istep = 0; istep < totalSteps; ++istep) {
101  Acts::Vector3D position(xDist(rng), yDist(rng), zDist(rng));
102  // access the field directly
103  auto field_direct = bField.getField(position);
104  // access the field with the cell
105  auto field_from_cache = bField.getField(position, bCache);
106  // check
107  if (!field_direct.isApprox(field_from_cache)) {
108  ++mismatched;
109  }
110  // show the progress bar
111  ++show_progress;
112  }
113  std::cout << "[<<<] End result : " << mismatched << "/" << totalSteps
114  << " mismatches" << std::endl;
115 }
116 
121 int main(int argc, char* argv[]) {
122  // Declare the supported program options.
126  desc.add_options()("bf-phi-range",
127  po::value<read_range>()->default_value({-M_PI, M_PI}),
128  "range in which the phi parameter is generated.")(
129  "bf-theta-range", po::value<read_range>()->default_value({0., M_PI}),
130  "range in which the eta parameter is generated.")(
131  "bf-phisteps", po::value<size_t>()->default_value(1000),
132  "number of steps for the phi parameter.")(
133  "bf-thetasteps", po::value<size_t>()->default_value(100),
134  "number of steps for the eta parameter.")(
135  "bf-accesssteps", po::value<size_t>()->default_value(100),
136  "number of steps for magnetic field access.")(
137  "bf-tracklength", po::value<double>()->default_value(100.),
138  "track length in [mm] magnetic field access.");
139  auto vm = ActsExamples::Options::parse(desc, argc, argv);
140  if (vm.empty()) {
141  return EXIT_FAILURE;
142  }
143 
144  // A test magnetic field context
146 
147  // TODO
148  // Why does this need number-of-events? If it really does emulate
149  // per-event access patterns this should be switched to a proper
150  // Sequencer-based tool. Otherwise it should be removed.
152  auto bFieldVar = ActsExamples::Options::readBField(vm);
153 
154  // Get the phi and eta range
155  auto phir = vm["bf-phi-range"].as<read_range>();
156  auto thetar = vm["bf-theta-range"].as<read_range>();
157  // Get the granularity
158  size_t phi_steps = vm["bf-phisteps"].as<size_t>();
159  size_t theta_steps = vm["bf-thetasteps"].as<size_t>();
160  // The defaults
161  size_t access_steps = vm["bf-accesssteps"].as<size_t>();
162  double track_length =
163  vm["bf-tracklength"].as<double>() * Acts::UnitConstants::mm;
164  // sort the ranges - and prepare the access grid
165  std::sort(phir.begin(), phir.end());
166  std::sort(thetar.begin(), thetar.end());
167  double phi_span = std::abs(phir[1] - phir[0]);
168  double phi_step = phi_span / phi_steps;
169  double theta_span = std::abs(thetar[1] - thetar[0]);
170  double theta_step = theta_span / theta_steps;
171  double access_step = track_length / access_steps;
172 
173  return std::visit(
174  [&](auto& bField) -> int {
175  using field_type =
176  typename std::decay_t<decltype(bField)>::element_type;
177  if constexpr (!std::is_same_v<field_type, InterpolatedBFieldMap2D> &&
178  !std::is_same_v<field_type, InterpolatedBFieldMap3D>) {
179  std::cout << "Bfield map could not be read. Exiting." << std::endl;
180  return EXIT_FAILURE;
181  } else {
182  // Step-wise access pattern
183  accessStepWise(*bField, magFieldContext, nEvents, theta_steps,
184  thetar[0], theta_step, phi_steps, phir[0], phi_step,
185  access_steps, access_step);
186  // Random access pattern
187  accessRandom(*bField, magFieldContext,
188  nEvents * theta_steps * phi_steps * access_steps,
189  track_length);
190  return EXIT_SUCCESS;
191  }
192  },
193  bFieldVar);
194 }