CMS 3D CMS Logo

DD4hep_MagGeoBuilder.cc
Go to the documentation of this file.
1 /*
2  * See header file for a description of this class.
3  *
4  */
5 
6 #include "DD4hep_MagGeoBuilder.h"
7 #include "bLayer.h"
8 #include "eSector.h"
9 #include "InterpolatorBuilder.h"
10 
13 
15 
17 
20 
23 
25 
29 
30 #include <iomanip>
31 #include <string>
32 #include <vector>
33 #include <sstream>
34 #include <algorithm>
35 #include <iterator>
36 #include <map>
37 #include <set>
38 #include <boost/algorithm/string/replace.hpp>
39 
40 using namespace std;
41 using namespace magneticfield;
42 using namespace edm;
43 using namespace angle_units::operators;
44 
45 MagGeoBuilder::MagGeoBuilder(string tableSet, int geometryVersion, bool debug, bool mergeFile)
46  : tableSet_(tableSet),
47  geometryVersion_(geometryVersion),
48  theGridFiles_(nullptr),
49  debug_(debug),
50  useMergeFileIfAvailable_(mergeFile) {
51  LogTrace("MagGeoBuilder") << "Constructing a MagGeoBuilder";
52 }
53 
55  for (auto i : bVolumes_) {
56  delete i;
57  }
58  for (auto i : eVolumes_) {
59  delete i;
60  }
61 }
62 
64  // The final countdown.
65  int ivolumes = volumes.size(); // number of volumes
66  int isurfaces = ivolumes * 6; // number of individual surfaces
67  int iassigned = 0; // How many have been assigned
68  int iunique = 0; // number of unique surfaces
69  int iref_ass = 0;
70  int iref_nass = 0;
71 
72  set<const void*> ptrs;
73 
74  for (auto i : volumes) {
75  DDSolidShape theShape = i->shape();
76  if (theShape == DDSolidShape::ddbox || theShape == DDSolidShape::ddcons || theShape == DDSolidShape::ddtrap ||
77  theShape == DDSolidShape::ddtubs) {
78  for (int side = 0; side < 6; ++side) {
79  int references = i->references(side);
80  if (i->isPlaneMatched(side)) {
81  ++iassigned;
82  bool firstOcc = (ptrs.insert(&(i->surface(side)))).second;
83  if (firstOcc)
84  iref_ass += references;
85  if (references < 2) {
86  LogTrace("MagGeoBuilder") << "*** Only 1 ref, vol: " << i->volumeno << " # " << i->copyno
87  << " side: " << side;
88  }
89  } else {
90  iref_nass += references;
91  if (references > 1) {
92  LogTrace("MagGeoBuilder") << "*** Ref_nass >1 ";
93  }
94  }
95  }
96  } // end if theShape
97  } // end for
98  iunique = ptrs.size();
99 
100  LogTrace("MagGeoBuilder") << " volumes " << ivolumes << newln << " surfaces " << isurfaces << newln
101  << " assigned " << iassigned << newln << " unique " << iunique << newln
102  << " iref_ass " << iref_ass << newln << " iref_nass " << iref_nass;
103 }
104 
106  cms::Volume top = det->worldVolume();
107  cms::DDFilteredView fv(det, top);
108  if (fv.next(0) == false) {
109  LogError("MagGeoBuilder") << "Filtered view is empty. Cannot build.";
110  return;
111  }
112 
113  // The actual field interpolators
114  map<string, MagProviderInterpol*> bInterpolators;
115  map<string, MagProviderInterpol*> eInterpolators;
116 
117  // Counter of different volumes
118  int bVolCount = 0;
119  int eVolCount = 0;
120 
121  const string magfStr{"MAGF"};
122  const string magfStr2{"cmsMagneticField:MAGF"};
123  if (fv.name() != magfStr && fv.name() != magfStr2) {
124  std::string topNodeName(fv.name());
125  LogTrace("MagGeoBuilder") << "Filtered view top node name is " << topNodeName << ".";
126 
127  //see if one of the children is MAGF
128  bool doSubDets = fv.next(0);
129 
130  bool go = true;
131  while (go && doSubDets) {
132  LogTrace("MagGeoBuilder") << "Next node name is " << fv.name() << ".";
133  if (fv.name() == magfStr)
134  break;
135  else
136  go = fv.next(0);
137  }
138  if (!go) {
139  throw cms::Exception("NoMAGF")
140  << " Neither the top node, nor any child node of the filtered view is \"MAGF\" but the top node is instead \""
141  << topNodeName << "\"";
142  }
143  }
144 
145  // Loop over MAGF volumes and create volumeHandles.
146  bool doSubDets = fv.next(0);
147  if (doSubDets == false) {
148  LogError("MagGeoBuilder") << "Filtered view has no node. Cannot build.";
149  return;
150  }
152  while (doSubDets) {
153  string name = fv.volume().volume().name();
154  LogTrace("MagGeoBuilder") << "Name: " << name;
155 
156  bool expand = false;
157  volumeHandle* v = new volumeHandle(fv, expand, debug_);
158 
159  if (theGridFiles_ != nullptr) {
160  int key = (v->volumeno) * 100 + v->copyno;
161  TableFileMap::const_iterator itable = theGridFiles_->find(key);
162  if (itable == theGridFiles_->end()) {
163  key = (v->volumeno) * 100;
164  itable = theGridFiles_->find(key);
165  }
166 
167  if (itable != theGridFiles_->end()) {
168  string magFile = (*itable).second.first;
169  stringstream conv;
170  string svol, ssec;
171  conv << setfill('0') << setw(3) << v->volumeno << " " << setw(2)
172  << v->copyno; // volume assumed to have 0s padding to 3 digits; sector assumed to have 0s padding to 2 digits
173  conv >> svol >> ssec;
174  boost::replace_all(magFile, "[v]", svol);
175  boost::replace_all(magFile, "[s]", ssec);
176  int masterSector = (*itable).second.second;
177  if (masterSector == 0)
178  masterSector = v->copyno;
179  v->magFile = magFile;
180  v->masterSector = masterSector;
181  } else {
182  edm::LogError("MagGeoBuilderbuild") << "ERROR: no table spec found for V " << v->volumeno << ":" << v->copyno;
183  }
184  }
185 
186  // Select volumes, build volume handles.
187  float Z = v->center().z();
188  float R = v->center().perp();
189  LogTrace("MagGeoBuilder") << " Vol R and Z values determine barrel or endcap. R = " << R << ", Z = " << Z;
190 
191  // v 85l: Barrel is everything up to |Z| = 661.0, excluding
192  // volume #7, centered at 6477.5
193  // v 1103l: same numbers work fine. #16 instead of #7, same coords;
194  // see comment below for V6,7
195  //ASSUMPTION: no misalignment is applied to mag volumes.
196  //FIXME: implement barrel/endcap flags as DDD SpecPars.
197  if ((fabs(Z) < 647. || (R > 350. && fabs(Z) < 662.)) &&
198  !(fabs(Z) > 480 && R < 172) // in 1103l we place V_6 and V_7 in the
199  // endcaps to preserve nice layer structure
200  // in the barrel. This does not hurt in v85l
201  // where there is a single V1
202  ) { // Barrel
203  LogTrace("MagGeoBuilder") << " (Barrel)";
204  bVolumes_.push_back(v);
205 
206  // Build the interpolator of the "master" volume (the one which is
207  // not replicated in phi)
208  // ASSUMPTION: copyno == sector.
209  if (v->copyno == v->masterSector) {
210  auto i = buildInterpolator(v, interpolatorBuilder);
211  if (i) {
212  bInterpolators[v->magFile] = i;
213  }
214  ++bVolCount;
215  }
216  } else { // Endcaps
217  LogTrace("MagGeoBuilder") << " (Endcaps)";
218  eVolumes_.push_back(v);
219  if (v->copyno == v->masterSector) {
220  auto i = buildInterpolator(v, interpolatorBuilder);
221  if (i) {
222  eInterpolators[v->magFile] = i;
223  }
224  ++eVolCount;
225  }
226  }
227  doSubDets = fv.next(0); // end of loop over MAGF
228  }
229 
230  LogTrace("MagGeoBuilder") << "Number of volumes (barrel): " << bVolumes_.size() << newln
231  << "Number of volumes (endcap): " << eVolumes_.size();
232  LogTrace("MagGeoBuilder") << "**********************************************************";
233 
234  // Now all volumeHandles are there, and parameters for each of the planes
235  // are calculated.
236 
237  //----------------------------------------------------------------------
238  // Print summary information
239 
240  if (debug_) {
241  LogTrace("MagGeoBuilder") << "-----------------------";
242  LogTrace("MagGeoBuilder") << "SUMMARY: Barrel ";
244 
245  LogTrace("MagGeoBuilder") << "SUMMARY: Endcaps ";
247  LogTrace("MagGeoBuilder") << "-----------------------";
248  }
249 
250  //----------------------------------------------------------------------
251  // Find barrel layers.
252 
253  if (bVolumes_.empty()) {
254  LogError("MagGeoBuilder") << "Error: Barrel volumes are missing. Terminating build.";
255  return;
256  }
257  vector<bLayer> layers; // the barrel layers
259 
260  // Find the layers (in R)
261  const float resolution = 1.; // cm
262  float rmin = bVolumes_.front()->RN() - resolution;
263  float rmax = bVolumes_.back()->RN() + resolution;
264  ClusterizingHistogram hisR(int((rmax - rmin) / resolution) + 1, rmin, rmax);
265 
266  LogTrace("MagGeoBuilder") << " R layers: " << rmin << " " << rmax;
267 
268  handles::const_iterator first = bVolumes_.begin();
269  handles::const_iterator last = bVolumes_.end();
270 
271  for (auto i : bVolumes_) {
272  hisR.fill(i->RN());
273  }
274  vector<float> rClust = hisR.clusterize(resolution);
275 
276  handles::const_iterator ringStart = first;
277  handles::const_iterator separ = first;
278 
279  for (unsigned int i = 0; i < rClust.size() - 1; ++i) {
280  if (debug_)
281  LogTrace("MagGeoBuilder") << " Layer at RN = " << rClust[i];
282  float rSepar = (rClust[i] + rClust[i + 1]) / 2.f;
283  while ((*separ)->RN() < rSepar)
284  ++separ;
285 
286  bLayer thislayer(ringStart, separ, debug_);
287  layers.push_back(thislayer);
288  ringStart = separ;
289  }
290  {
291  if (debug_)
292  LogTrace("MagGeoBuilder") << " Layer at RN = " << rClust.back();
293  bLayer thislayer(separ, last, debug_);
294  layers.push_back(thislayer);
295  }
296 
297  LogTrace("MagGeoBuilder") << "Barrel: Found " << rClust.size() << " clusters in R, " << layers.size() << " layers ";
298 
299  //----------------------------------------------------------------------
300  // Find endcap sectors
301  vector<eSector> sectors; // the endcap sectors
302 
303  // Find the number of sectors (should be 12 or 24 depending on the geometry model)
304  constexpr float phireso = 0.05; // rad
305  constexpr int twoPiOverPhiReso = static_cast<int>(2._pi / phireso) + 1;
306  ClusterizingHistogram hisPhi(twoPiOverPhiReso, -1._pi, 1._pi);
307 
308  for (auto i : eVolumes_) {
309  hisPhi.fill(i->minPhi());
310  }
311  vector<float> phiClust = hisPhi.clusterize(phireso);
312  int nESectors = phiClust.size();
313  if (nESectors <= 0) {
314  LogError("MagGeoBuilder") << "ERROR: Endcap sectors are missing. Terminating build.";
315  return;
316  }
317  if (debug_ && (nESectors % 12) != 0) {
318  LogTrace("MagGeoBuilder") << "ERROR: unexpected # of endcap sectors: " << nESectors;
319  }
320 
321  //Sort in phi
323 
324  // Handle the -pi/pi boundary: volumes crossing it could be half at the begin and half at end of the sorted list.
325  // So, check if any of the volumes that should belong to the first bin (at -phi) are at the end of the list:
326  float lastBinPhi = phiClust.back();
327  handles::reverse_iterator ri = eVolumes_.rbegin();
328  while ((*ri)->center().phi() > lastBinPhi) {
329  ++ri;
330  }
331  if (ri != eVolumes_.rbegin()) {
332  // ri points to the first element that is within the last bin.
333  // We need to move the following element (ie ri.base()) to the beginning of the list,
334  handles::iterator newbeg = ri.base();
335  rotate(eVolumes_.begin(), newbeg, eVolumes_.end());
336  }
337 
338  //Group volumes in sectors
339  int offset = eVolumes_.size() / nESectors;
340  for (int i = 0; i < nESectors; ++i) {
341  if (debug_) {
342  LogTrace("MagGeoBuilder") << " Sector at phi = " << (*(eVolumes_.begin() + ((i)*offset)))->center().phi();
343  // Additional x-check: sectors are expected to be made by volumes with the same copyno
344  int secCopyNo = -1;
345  for (handles::const_iterator iv = eVolumes_.begin() + ((i)*offset); iv != eVolumes_.begin() + ((i + 1) * offset);
346  ++iv) {
347  if (secCopyNo >= 0 && (*iv)->copyno != secCopyNo)
348  LogTrace("MagGeoBuilder") << "ERROR: volume copyno " << (*iv)->name << ":" << (*iv)->copyno
349  << " differs from others in same sectors with copyno = " << secCopyNo;
350  secCopyNo = (*iv)->copyno;
351  }
352  }
353 
354  sectors.push_back(eSector(eVolumes_.begin() + ((i)*offset), eVolumes_.begin() + ((i + 1) * offset), debug_));
355  }
356 
357  LogTrace("MagGeoBuilder") << "Endcap: Found " << sectors.size() << " sectors ";
358 
359  //----------------------------------------------------------------------
360  // Build MagVolumes and the MagGeometry hierarchy.
361 
362  //--- Barrel
363 
364  // Build MagVolumes and associate interpolators to them
365  buildMagVolumes(bVolumes_, bInterpolators);
366 
367  // Build MagBLayers
368  for (const auto& ilay : layers) {
369  mBLayers_.push_back(ilay.buildMagBLayer());
370  }
371  LogTrace("MagGeoBuilder") << "*** BARREL ********************************************" << newln
372  << "Number of different volumes = " << bVolCount << newln
373  << "Number of interpolators built = " << bInterpolators.size() << newln
374  << "Number of MagBLayers built = " << mBLayers_.size();
375  if (debug_) {
376  testInside(bVolumes_); // FIXME: all volumes should be checked in one go.
377  }
378  //--- Endcap
379  // Build MagVolumes and associate interpolators to them
380  buildMagVolumes(eVolumes_, eInterpolators);
381 
382  // Build the MagESectors
383  for (const auto& isec : sectors) {
384  mESectors_.push_back(isec.buildMagESector());
385  }
386  LogTrace("MagGeoBuilder") << "*** ENDCAP ********************************************" << newln
387  << "Number of different volumes = " << eVolCount << newln
388  << "Number of interpolators built = " << eInterpolators.size() << newln
389  << "Number of MagESector built = " << mESectors_.size();
390  if (debug_) {
391  testInside(eVolumes_); // FIXME: all volumes should be checked in one go.
392  }
393 }
394 
396  const map<string, MagProviderInterpol*>& interpolators) const {
397  // Build all MagVolumes setting the MagProviderInterpol
398  for (auto vol : volumes) {
399  const MagProviderInterpol* mp = nullptr;
400  auto found = interpolators.find(vol->magFile);
401  if (found != interpolators.end()) {
402  mp = found->second;
403  } else {
404  edm::LogError("MagGeoBuilder") << "No interpolator found for file " << vol->magFile << " vol: " << vol->volumeno
405  << "\n"
406  << interpolators.size();
407  }
408 
409  // Search for [volume,sector] in the list of scaling factors; sector = 0 handled as wildcard
410  // ASSUMPTION: copyno == sector.
411  int key = (vol->volumeno) * 100 + vol->copyno;
412  map<int, double>::const_iterator isf = theScalingFactors_.find(key);
413  if (isf == theScalingFactors_.end()) {
414  key = (vol->volumeno) * 100;
415  isf = theScalingFactors_.find(key);
416  }
417 
418  double sf = 1.;
419  if (isf != theScalingFactors_.end()) {
420  sf = (*isf).second;
421 
422  LogTrace("MagGeoBuilder") << "Applying scaling factor " << sf << " to " << vol->volumeno << "[" << vol->copyno
423  << "] (key:" << key << ")";
424  }
425 
426  const GloballyPositioned<float>* gpos = vol->placement();
427  vol->magVolume = new MagVolume6Faces(gpos->position(), gpos->rotation(), vol->sides(), mp, sf);
428 
429  if (vol->copyno == vol->masterSector) {
430  vol->magVolume->ownsFieldProvider(true);
431  }
432 
433  vol->magVolume->setIsIron(vol->isIron());
434 
435  // The name and sector of the volume are saved for debug purposes only. They may be removed at some point...
436  vol->magVolume->volumeNo = vol->volumeno;
437  vol->magVolume->copyno = vol->copyno;
438  }
439 }
440 
442  MagProviderInterpol* retValue = nullptr;
443  LogTrace("MagGeoBuilder") << "Building interpolator from " << vol->volumeno << " copyno " << vol->copyno << " at "
444  << vol->center() << " phi: " << static_cast<double>(vol->center().phi()) / 1._pi
445  << " pi, file: " << vol->magFile << " master: " << vol->masterSector;
446  if (debug_) {
447  // Phi of the master sector
448  double masterSectorPhi = (vol->masterSector - 1) * 1._pi / 6.;
449  double delta = std::abs(vol->center().phi() - masterSectorPhi);
450  if (delta > (1._pi / 9.)) {
451  LogTrace("MagGeoBuilder") << "***WARNING wrong sector? Vol delta from master sector is " << delta / 1._pi
452  << " pi";
453  }
454  }
455 
456  try {
457  retValue = builder.build(vol).release();
458  } catch (edm::Exception& exc) {
459  cerr << "MagGeoBuilder: exception in reading table; " << exc.what() << endl;
460  if (!debug_)
461  throw;
462  return nullptr;
463  } catch (MagException const& exc) {
464  LogTrace("MagGeoBuilder") << exc.what();
465  if (!debug_)
466  throw;
467  return nullptr;
468  }
469 
470  if (debug_) {
471  // Check that all grid points of the interpolator are inside the volume.
472  const MagVolume6Faces tempVolume(
473  vol->placement()->position(), vol->placement()->rotation(), vol->sides(), retValue);
474 
475  const MFGrid* grid = dynamic_cast<const MFGrid*>(retValue);
476  if (grid != nullptr) {
477  Dimensions sizes = grid->dimensions();
478  LogTrace("MagGeoBuilder") << "Grid has 3 dimensions "
479  << " number of nodes is " << sizes.w << " " << sizes.h << " " << sizes.d;
480 
481  const double tolerance = 0.03;
482 
483  size_t dumpCount = 0;
484  for (int j = 0; j < sizes.h; j++) {
485  for (int k = 0; k < sizes.d; k++) {
486  for (int i = 0; i < sizes.w; i++) {
487  MFGrid::LocalPoint lp = grid->nodePosition(i, j, k);
488  if (!tempVolume.inside(lp, tolerance)) {
489  if (++dumpCount < 2) {
490  MFGrid::GlobalPoint gp = tempVolume.toGlobal(lp);
491  LogTrace("MagGeoBuilder") << "GRID ERROR: " << i << " " << j << " " << k << " local: " << lp
492  << " global: " << gp << " R= " << gp.perp() << " phi=" << gp.phi();
493  }
494  }
495  }
496  }
497  }
498 
499  LogTrace("MagGeoBuilder") << "Volume:" << vol->volumeno
500  << " : Number of grid points outside the MagVolume: " << dumpCount << "/"
501  << sizes.w * sizes.h * sizes.d;
502  }
503  }
504  return retValue;
505 }
506 
508  // test inside() for all volumes.
509  LogTrace("MagGeoBuilder") << "--------------------------------------------------";
510  LogTrace("MagGeoBuilder") << " inside(center) test";
511  for (auto vol : volumes) {
512  for (auto i : volumes) {
513  if (i == vol)
514  continue;
515  //if (i->magVolume == 0) continue;
516  if (i->magVolume->inside(vol->center())) {
517  LogTrace("MagGeoBuilder") << "*** ERROR: center of V " << vol->volumeno << ":" << vol->copyno << " is inside V "
518  << i->volumeno << ":" << i->copyno;
519  }
520  }
521 
522  if (vol->magVolume->inside(vol->center())) {
523  LogTrace("MagGeoBuilder") << "V " << vol->volumeno << ":" << vol->copyno << " OK ";
524  } else {
525  LogTrace("MagGeoBuilder") << "*** ERROR: center of volume is not inside it, " << vol->volumeno << ":"
526  << vol->copyno;
527  }
528  }
529  LogTrace("MagGeoBuilder") << "--------------------------------------------------";
530 }
531 
532 vector<MagBLayer*> MagGeoBuilder::barrelLayers() const { return mBLayers_; }
533 
534 vector<MagESector*> MagGeoBuilder::endcapSectors() const { return mESectors_; }
535 
536 vector<MagVolume6Faces*> MagGeoBuilder::barrelVolumes() const {
537  vector<MagVolume6Faces*> v;
538  v.reserve(bVolumes_.size());
539  for (auto i : bVolumes_) {
540  v.push_back(i->magVolume);
541  }
542  return v;
543 }
544 
545 vector<MagVolume6Faces*> MagGeoBuilder::endcapVolumes() const {
546  vector<MagVolume6Faces*> v;
547  v.reserve(eVolumes_.size());
548  for (auto i : eVolumes_) {
549  v.push_back(i->magVolume);
550  }
551  return v;
552 }
553 
554 float MagGeoBuilder::maxR() const {
555  //FIXME: should get it from the actual geometry
556  return 900.;
557 }
558 
559 float MagGeoBuilder::maxZ() const {
560  //FIXME: should get it from the actual geometry
561  if (geometryVersion_ >= 160812)
562  return 2400.;
563  else if (geometryVersion_ >= 120812)
564  return 2000.;
565  else
566  return 1600.;
567 }
568 
569 void MagGeoBuilder::setScaling(const std::vector<int>& keys, const std::vector<double>& values) {
570  if (keys.size() != values.size()) {
571  throw cms::Exception("InvalidParameter")
572  << "Invalid field scaling parameters 'scalingVolumes' and 'scalingFactors' ";
573  }
574  for (unsigned int i = 0; i < keys.size(); ++i) {
576  }
577 }
578 
MagGeoBuilderFromDDD::volumeHandle volumeHandle
void buildMagVolumes(const handles &volumes, const std::map< std::string, MagProviderInterpol *> &interpolators) const
std::vector< MagBLayer * > barrelLayers() const
Get barrel layers.
int32_t *__restrict__ iv
const double tolerance
Geom::Phi< T > phi() const
Definition: PV3DBase.h:66
void summary(handles &volumes) const
GloballyPositioned< float >::LocalPoint LocalPoint
Definition: MFGrid.h:31
std::vector< MagESector * > mESectors_
Log< level::Error, false > LogError
const GlobalPoint & center() const
Return the center of the volume.
unsigned short volumeno
volume number
const char *const newln
#define LogTrace(id)
int w
Definition: MFGrid.h:16
unsigned short copyno
copy number
U second(std::pair< T, U > const &p)
std::string_view name() const
std::unique_ptr< MagProviderInterpol > build(volumeHandle const *)
std::vector< MagBLayer * > mBLayers_
std::vector< float > clusterize(float resolution)
std::vector< BaseVolumeHandle * > handles
MagProviderInterpol * buildInterpolator(const volumeHandle *vol, InterpolatorBuilder &) const
const char * what() const override
Definition: MagExceptions.cc:5
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
int masterSector
The sector for which an interpolator for this class of volumes should be built.
double f[11][100]
bool next(int)
set current node to the next node in the filtered tree
dd4hep::Volume Volume
const TableFileMap * theGridFiles_
void setGridFiles(const TableFileMap &gridFiles)
#define debug
Definition: HDRShower.cc:19
void precomputed_value_sort(RandomAccessIterator begin, RandomAccessIterator end, const Extractor &extr, const Compare &comp)
const PositionType & position() const
GloballyPositioned< float >::GlobalPoint GlobalPoint
Definition: MFGrid.h:29
dd4hep::Volume worldVolume() const
Handle to the world volume containing everything.
Definition: DDDetector.cc:67
void testInside(handles &volumes) const
DDSolidShape
Definition: DDSolidShapes.h:6
std::vector< MagESector * > endcapSectors() const
Get endcap layers.
Definition: MFGrid.h:27
int d
Definition: MFGrid.h:18
int h
Definition: MFGrid.h:17
EPOS::IO_EPOS conv
std::map< int, double > theScalingFactors_
std::vector< MagVolume6Faces * > barrelVolumes() const
HLT enums.
void build(const cms::DDDetector *det)
const PlacedVolume volume() const
The physical volume of the current node.
std::vector< VolumeSide > sides() const override
The surfaces and they orientation, as required to build a MagVolume.
void setScaling(const std::vector< int > &keys, const std::vector< double > &values)
const RotationType & rotation() const
char const * what() const noexcept override
Definition: Exception.cc:107
std::map< int, std::pair< std::string, int > > TableFileMap
const GloballyPositioned< float > * placement() const
Position and rotation.
def rotate(angle, cx=0, cy=0)
Definition: svgfig.py:705
std::vector< MagVolume6Faces * > endcapVolumes() const
std::string magFile
Name of magnetic field table file.
void ownsFieldProvider(bool o)
Definition: MagVolume.h:47