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