EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
RootBFieldWriter.hpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file RootBFieldWriter.hpp
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 #pragma once
10 
18 #include <Acts/Utilities/Units.hpp>
19 
20 #include <array>
21 #include <ios>
22 #include <mutex>
23 #include <sstream>
24 #include <stdexcept>
25 
26 #include <TFile.h>
27 #include <TTree.h>
28 #include <boost/optional.hpp>
29 
30 namespace ActsExamples {
31 
36 template <typename bfield_t>
38  public:
40  enum class GridType { rz = 0, xyz = 1 };
41 
42  struct Config {
44  std::string treeName = "TTree";
46  std::string fileName = "TFile.root";
48  std::string fileMode = "recreate";
50  std::shared_ptr<const bfield_t> bField = nullptr;
52  GridType gridType = GridType::xyz;
57  boost::optional<std::array<double, 2>> rBounds;
61  boost::optional<std::array<double, 2>> zBounds;
65  size_t rBins = 200;
67  // @note setting this parameter is optional, in case no bin numbers are
69  size_t zBins = 300;
71  // @note setting this parameter is optional, in case no bin numbers are
73  size_t phiBins = 100;
74  };
75 
77  static void run(const Config& cfg,
78  std::unique_ptr<const Acts::Logger> p_logger =
79  Acts::getDefaultLogger("RootBFieldWriter",
81  // Set up (local) logging
82  // @todo Remove dangerous using declaration once the logger macro
83  // tolerates it
84  using namespace Acts;
85  ACTS_LOCAL_LOGGER(std::move(p_logger))
86 
87  // Check basic configuration
88  if (cfg.treeName.empty()) {
89  throw std::invalid_argument("Missing tree name");
90  } else if (cfg.fileName.empty()) {
91  throw std::invalid_argument("Missing file name");
92  } else if (!cfg.bField) {
93  throw std::invalid_argument("Missing interpolated magnetic field");
94  }
95 
96  // Setup ROOT I/O
97  ACTS_INFO("Registering new ROOT output File : " << cfg.fileName);
98  TFile* outputFile = TFile::Open(cfg.fileName.c_str(), cfg.fileMode.c_str());
99  if (!outputFile) {
100  throw std::ios_base::failure("Could not open '" + cfg.fileName);
101  }
102  outputFile->cd();
103  TTree* outputTree = new TTree(cfg.treeName.c_str(), cfg.treeName.c_str());
104  if (!outputTree)
105  throw std::bad_alloc();
106 
107  // The position values
108  double z;
109  outputTree->Branch("z", &z);
110 
111  // The BField values
112  double Bz;
113  outputTree->Branch("Bz", &Bz);
114 
115  // Get the underlying mapper of the InterpolatedBFieldMap
116  auto mapper = cfg.bField->getMapper();
117 
118  // Access the minima and maxima of all axes
119  auto minima = mapper.getMin();
120  auto maxima = mapper.getMax();
121  auto nBins = mapper.getNBins();
122 
123  if (cfg.gridType == GridType::xyz) {
124  ACTS_INFO("Map will be written out in cartesian coordinates (x,y,z).");
125 
126  // Write out the interpolated magnetic field map
127  double stepX = 0., stepY = 0., stepZ = 0.;
128  double minX = 0., minY = 0., minZ = 0.;
129  double maxX = 0., maxY = 0., maxZ = 0.;
130  size_t nBinsX = 0, nBinsY = 0, nBinsZ = 0;
131 
132  // The position values in xy
133  double x;
134  outputTree->Branch("x", &x);
135  double y;
136  outputTree->Branch("y", &y);
137  // The BField values in xy
138  double Bx;
139  outputTree->Branch("Bx", &Bx);
140  double By;
141  outputTree->Branch("By", &By);
142 
143  // check if range is user defined
144  if (cfg.rBounds && cfg.zBounds) {
145  ACTS_INFO("User defined ranges handed over.");
146 
147  // print out map in user defined range
148  minX = cfg.rBounds->at(0);
149  minY = cfg.rBounds->at(0);
150  minZ = cfg.zBounds->at(0);
151 
152  maxX = cfg.rBounds->at(1);
153  maxY = cfg.rBounds->at(1);
154  maxZ = cfg.zBounds->at(1);
155 
156  nBinsX = cfg.rBins;
157  nBinsY = cfg.rBins;
158  nBinsZ = cfg.zBins;
159 
160  } else {
161  ACTS_INFO(
162  "No user defined ranges handed over - printing out whole map.");
163  // print out whole map
164  // check dimension of Bfieldmap
165  if (minima.size() == 3 && maxima.size() == 3) {
166  minX = minima.at(0);
167  minY = minima.at(1);
168  minZ = minima.at(2);
169 
170  maxX = maxima.at(0);
171  maxY = maxima.at(1);
172  maxZ = maxima.at(2);
173 
174  nBinsX = nBins.at(0);
175  nBinsY = nBins.at(1);
176  nBinsZ = nBins.at(2);
177 
178  } else if (minima.size() == 2 && maxima.size() == 2) {
179  minX = -maxima.at(0);
180  minY = -maxima.at(0);
181  minZ = minima.at(1);
182 
183  maxX = maxima.at(0);
184  maxY = maxima.at(0);
185  maxZ = maxima.at(1);
186 
187  nBinsX = nBins.at(0);
188  nBinsY = nBins.at(0);
189  nBinsZ = nBins.at(1);
190  } else {
191  std::ostringstream errorMsg;
192  errorMsg
193  << "BField has wrong dimension. The dimension needs to be "
194  "either 2 (r,z,Br,Bz) or 3(x,y,z,Bx,By,Bz) in order to be "
195  "written out by this writer.";
196  throw std::invalid_argument(errorMsg.str());
197  }
198  }
199 
200  stepX = fabs(minX - maxX) / nBinsX;
201  stepY = fabs(minY - maxY) / nBinsY;
202  stepZ = fabs(minZ - maxZ) / nBinsZ;
203 
204  for (size_t i = 0; i <= nBinsX; i++) {
205  double raw_x = minX + i * stepX;
206  for (size_t j = 0; j <= nBinsY; j++) {
207  double raw_y = minY + j * stepY;
208  for (size_t k = 0; k <= nBinsZ; k++) {
209  double raw_z = minZ + k * stepZ;
210  Acts::Vector3D position(raw_x, raw_y, raw_z);
211  if (cfg.bField->isInside(position)) {
212  auto bField = cfg.bField->getField(position);
213 
214  x = raw_x / Acts::UnitConstants::mm;
215  y = raw_y / Acts::UnitConstants::mm;
216  z = raw_z / Acts::UnitConstants::mm;
217  Bx = bField.x() / Acts::UnitConstants::T;
218  By = bField.y() / Acts::UnitConstants::T;
220  outputTree->Fill();
221  }
222  } // for z
223  } // for y
224  } // for x
225  } else {
226  ACTS_INFO("Map will be written out in cylinder coordinates (r,z).");
227  // The position value in r
228  double r;
229  outputTree->Branch("r", &r);
230  // The BField value in r
231  double Br;
232  outputTree->Branch("Br", &Br);
233 
234  double minR = 0, maxR = 0;
235  double minZ = 0, maxZ = 0;
236  size_t nBinsR = 0, nBinsZ = 0, nBinsPhi = 0;
237  double stepR = 0, stepZ = 0;
238 
239  if (cfg.rBounds && cfg.zBounds) {
240  ACTS_INFO("User defined ranges handed over.");
241 
242  minR = cfg.rBounds->at(0);
243  minZ = cfg.zBounds->at(0);
244 
245  maxR = cfg.rBounds->at(1);
246  maxZ = cfg.zBounds->at(1);
247 
248  nBinsR = cfg.rBins;
249  nBinsZ = cfg.zBins;
250  nBinsPhi = cfg.phiBins;
251  } else {
252  ACTS_INFO(
253  "No user defined ranges handed over - printing out whole map.");
254 
255  if (minima.size() == 3 && maxima.size() == 3) {
256  minR = 0.;
257  minZ = minima.at(2);
258 
259  maxR = maxima.at(0);
260  maxZ = maxima.at(2);
261 
262  nBinsR = nBins.at(0);
263  nBinsZ = nBins.at(2);
264  nBinsPhi = 100.;
265 
266  } else if (minima.size() == 2 || maxima.size() == 2) {
267  minR = minima.at(0);
268  minZ = minima.at(1);
269 
270  maxR = maxima.at(0);
271  maxZ = maxima.at(1);
272 
273  nBinsR = nBins.at(0);
274  nBinsZ = nBins.at(1);
275  nBinsPhi = 100.;
276 
277  } else {
278  std::ostringstream errorMsg;
279  errorMsg
280  << "BField has wrong dimension. The dimension needs to be "
281  "either 2 (r,z,Br,Bz) or 3(x,y,z,Bx,By,Bz) in order to be "
282  "written out by this writer.";
283  throw std::invalid_argument(errorMsg.str());
284  }
285  }
286  double minPhi = -M_PI;
287  stepR = fabs(minR - maxR) / nBinsR;
288  stepZ = fabs(minZ - maxZ) / nBinsZ;
289  double stepPhi = (2 * M_PI) / nBinsPhi;
290 
291  for (size_t i = 0; i < nBinsPhi; i++) {
292  double phi = minPhi + i * stepPhi;
293  for (size_t k = 0; k < nBinsZ; k++) {
294  double raw_z = minZ + k * stepZ;
295  for (size_t j = 0; j < nBinsR; j++) {
296  double raw_r = minR + j * stepR;
297  Acts::Vector3D position(raw_r * cos(phi), raw_r * sin(phi), raw_z);
298  if (cfg.bField->isInside(position)) {
299  auto bField = cfg.bField->getField(position);
300  z = raw_z / Acts::UnitConstants::mm;
301  r = raw_r / Acts::UnitConstants::mm;
304  outputTree->Fill();
305  }
306  }
307  }
308  } // for
309  }
310 
311  // Tear down ROOT I/O
312  ACTS_INFO("Closing and Writing ROOT output File : " << cfg.fileName);
313  outputFile->cd();
314  outputTree->Write();
315  outputFile->Close();
316  }
317 };
318 
319 } // namespace ActsExamples