Belle II Software  release-08-01-10
GeoVXDCreator.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 #include <vxd/geometry/GeoVXDCreator.h>
10 #include <vxd/geometry/GeoCache.h>
11 #include <vxd/simulation/SensitiveDetector.h>
12 #include <simulation/background/BkgSensitiveDetector.h>
13 
14 #include <geometry/CreatorFactory.h>
15 #include <geometry/Materials.h>
16 #include <geometry/utilities.h>
17 #include <framework/gearbox/GearDir.h>
18 
19 #include <boost/algorithm/string.hpp>
20 #include <boost/format.hpp>
21 
22 #include <G4ReflectionFactory.hh>
23 #include <G4LogicalVolume.hh>
24 #include <G4Trd.hh>
25 #include <G4Trap.hh>
26 #include <G4Box.hh>
27 #include <G4Tubs.hh>
28 #include <G4Polycone.hh>
29 #include <G4PVPlacement.hh>
30 #include <G4AssemblyVolume.hh>
31 #include <G4UserLimits.hh>
32 #include <G4Point3D.hh>
33 
34 #include <G4TessellatedSolid.hh>
35 #include <G4QuadrangularFacet.hh>
36 #include <G4TriangularFacet.hh>
37 
38 #include <CLHEP/Units/PhysicalConstants.h>
39 #include <CLHEP/Units/SystemOfUnits.h>
40 
41 #include <limits>
42 
43 using namespace std;
44 
45 namespace Belle2 {
51  using namespace geometry;
52  namespace VXD {
53 
54  GeoVXDCreator::GeoVXDCreator(const string& prefix) : m_prefix(prefix), m_radiationsensors(prefix)
55  {
56  m_UserLimits.clear();
57  }
58 
60  {
61  //Lets assume that it cannot be that only one part of the vxd gets destroyed
62  // FIXME: This causes problems: VXD::GeoCache::getInstance().clear();
63  //Delete all sensitive detectors
65  delete sensitive;
66  }
67  m_sensitive.clear();
68 
69  for (G4UserLimits* userLimit : m_UserLimits) delete userLimit;
70  m_UserLimits.clear();
71 
72  }
73 
75  vector<VXDGeoPlacement> placements, bool originCenter, bool allowOutside)
76  {
77  GeoVXDAssembly assembly;
78  B2DEBUG(100, "Creating component " << name);
79  vector<VXDGeoComponent> subComponents;
80  subComponents.reserve(placements.size());
81  //Go over all subcomponents and check if they will fit inside.
82  //If component.volume is zero we will create one so sum up needed space
83  bool widthResize = component.getWidth() <= 0;
84  bool lengthResize = component.getLength() <= 0;
85  bool heightResize = component.getHeight() <= 0;
86 
87  for (VXDGeoPlacement& p : placements) {
88  //Test component already exists
89  if (m_componentCache.find(p.getName()) == m_componentCache.end()) {
90  B2FATAL("A component is requested that was not created before!");
91  }
92  VXDGeoComponent sub = m_componentCache[p.getName()];
93 
94  B2DEBUG(100, "SubComponent " << p.getName());
95  B2DEBUG(100, boost::format("Placement: u:%1% cm, v:%2% cm, w:%3% + %4% cm") % p.getU() % p.getV() % p.getW() % p.getWOffset());
96  B2DEBUG(100, boost::format("Dimensions: %1%x%2%x%3% cm") % sub.getWidth() % sub.getLength() % sub.getHeight());
97 
98  if (p.getW() == VXDGeoPlacement::c_above || p.getW() == VXDGeoPlacement::c_below) {
99  //Below placement only valid if we are allowed to create a container around component
100  if (!allowOutside) B2FATAL("Cannot place component " << p.getName() << " outside of component " << name);
101  } else if (sub.getHeight() + p.getWOffset() > component.getHeight()) {
102  //Component will not fit heightwise. If we resize the volume anyway than we don't have problems
103  if (!heightResize) {
104  B2FATAL("Subcomponent " << p.getName() << " does not fit into volume: "
105  << "height " << sub.getHeight() << " > " << component.getHeight());
106  }
107  component.getHeight() = sub.getHeight() + p.getWOffset();
108  }
109 
110  //Check if compoent will fit inside width,length. If we can resize do it if needed, otherwise bail
111  double minWidth = max(abs(p.getU() + sub.getWidth() / 2.0), abs(p.getU() - sub.getWidth() / 2.0));
112  double minLength = max(abs(p.getV() + sub.getLength() / 2.0), abs(p.getV() - sub.getLength() / 2.0));
113  if (minWidth > component.getWidth() + component.getWidth() * numeric_limits<double>::epsilon()) {
114  if (!widthResize) {
115  B2FATAL("Subcomponent " << p.getName() << " does not fit into volume: "
116  << "minWidth " << minWidth << " > " << component.getWidth());
117  }
118  component.setWidth(minWidth * 2.0);
119  }
120  if (minLength > component.getLength() + component.getLength() * numeric_limits<double>::epsilon()) {
121  if (!lengthResize) {
122  B2FATAL("Subcomponent " << p.getName() << " does not fit into volume: "
123  << "minLength " << minLength << " > " << component.getLength());
124  }
125  component.setLength(minLength * 2.0);
126  }
127  subComponents.push_back(sub);
128  }
129 
130  //zero dimensions are fine mathematically but we don't want them in the simulation
131  if (component.getWidth() <= 0 || component.getLength() <= 0 || component.getHeight() <= 0) {
132  B2FATAL("At least one dimension of component " << name << " is zero which does not make sense");
133  }
134 
135  //No volume yet, create a new one automatically assuming air material
136  if (!component.getVolume()) {
137  G4VSolid* componentShape = createTrapezoidal(name, component.getWidth(), component.getWidth2(), component.getLength(),
138  component.getHeight());
139  component.setVolume(new G4LogicalVolume(componentShape, Materials::get(component.getMaterial()), name));
140  }
141 
142  B2DEBUG(100, boost::format("Component %1% dimensions: %2%x%3%x%4% cm") % name % component.getWidth() % component.getLength() %
143  component.getHeight());
144 
145  //Ok, all volumes set up, now add them together
146  for (size_t i = 0; i < placements.size(); ++i) {
147  VXDGeoPlacement& p = placements[i];
148  VXDGeoComponent& s = subComponents[i];
149 
150  G4Transform3D transform = getPosition(component, s, p, originCenter);
151  if (p.getW() == VXDGeoPlacement::c_below || p.getW() == VXDGeoPlacement::c_above) {
152  //Add to selected mother (either component or container around component
153  assembly.add(s.getVolume(), transform);
154  } else {
155  new G4PVPlacement(transform, s.getVolume(), name + "." + p.getName(), component.getVolume(), false, i);
156  }
157  }
158 
159  //Set some visibility options for volume. Done here because all components including sensor go through here
160  if (component.getColor().empty()) {
161  B2DEBUG(200, "Component " << name << " is an Air volume, setting invisible");
162  setVisibility(*component.getVolume(), false);
163  } else {
164  B2DEBUG(200, "Component " << name << " color: " << component.getColor());
165  setColor(*component.getVolume(), component.getColor());
166  }
167  B2DEBUG(100, "--> Created component " << name);
168  //Return the difference in W between the origin of the original component and the including container
169  return assembly;
170  }
171 
172  G4Transform3D GeoVXDCreator::getAlignment(const VXDAlignmentPar& params)
173  {
174  G4RotationMatrix rotation(params.getAlpha(), params.getBeta(), params.getGamma());
175  G4ThreeVector translation(params.getDU() / Unit::mm, params.getDV() / Unit::mm, params.getDW() / Unit::mm);
176  return G4Transform3D(rotation, translation);
177  }
178 
179  G4Transform3D GeoVXDCreator::getPosition(const VXDGeoComponent& mother, const VXDGeoComponent& daughter,
180  const VXDGeoPlacement& placement, bool originCenter)
181  {
182  double u(placement.getU()), v(placement.getV()), w(0);
183  switch (placement.getW()) {
184  case VXDGeoPlacement::c_below: //Place below component
185  w = - mother.getHeight() / 2.0 - daughter.getHeight() / 2.0;
186  break;
187  case VXDGeoPlacement::c_bottom: //Place inside, at bottom of component
188  w = - mother.getHeight() / 2.0 + daughter.getHeight() / 2.0;
189  break;
190  case VXDGeoPlacement::c_center: //Place inside, centered
191  w = 0;
192  break;
193  case VXDGeoPlacement::c_top: //Place inside, at top of mother
194  w = mother.getHeight() / 2.0 - daughter.getHeight() / 2.0;
195  break;
196  case VXDGeoPlacement::c_above: //Place above mother
197  w = mother.getHeight() / 2.0 + daughter.getHeight() / 2.0;
198  break;
199  }
200  if (!originCenter) { //Sensor has coordinate origin in the corner, all submothers at their center
201  u -= mother.getWidth() / 2.0;
202  v -= mother.getLength() / 2.0;
203  }
204  return G4Translate3D(u, v, w + placement.getWOffset());
205  }
206 
207 
208 
209  void GeoVXDCreator::createDiamonds(const VXDGeoRadiationSensorsPar& params, G4LogicalVolume& topVolume,
210  G4LogicalVolume& envelopeVolume)
211  {
212  //Set the correct top volume to either global top or detector envelope
213  G4LogicalVolume* top = &topVolume;
214  if (params.getInsideEnvelope()) {
215  top = &envelopeVolume;
216  }
217 
218  //shape and material are the same for all sensors so create them now
219  const double width = params.getWidth();
220  const double length = params.getLength();
221  const double height = params.getHeight();
222  G4Box* shape = new G4Box("radiationSensorDiamond", width / 2 * CLHEP::cm, length / 2 * CLHEP::cm, height / 2 * CLHEP::cm);
223  G4Material* material = geometry::Materials::get(params.getMaterial());
224 
225  //Now loop over all positions
226  const std::vector<VXDGeoRadiationSensorsPositionPar>& Positions = params.getPositions();
227  for (const VXDGeoRadiationSensorsPositionPar& position : Positions) {
228  //get the radial and z position
229  const double r = position.getRadius();
230  const double z = position.getZ();
231  const double theta = position.getTheta();
232  //and loop over all phi positions
233  const std::map<int, double>& Sensors = position.getSensors();
234  for (const std::pair<const int, double>& sensor : Sensors) {
235  //for (GearDir& sensor : position.getNodes("phi")) {
236  //we need angle and Id
237  const double phi = sensor.second;
238  const int id = sensor.first;
239  //then we create a nice name
240  const std::string name = params.getSubDetector() + ".DiamondSensor." + std::to_string(id);
241  //and create the sensor volume
242  G4LogicalVolume* volume = new G4LogicalVolume(shape, material, name);
243  //add a sensitive detector implementation
244  BkgSensitiveDetector* sensitive = new BkgSensitiveDetector(params.getSubDetector().c_str(), id);
245  volume->SetSensitiveDetector(sensitive);
246  //and place it at the correct position
247  G4Transform3D transform = G4RotateZ3D(phi - M_PI / 2) * G4Translate3D(0, r * CLHEP::cm,
248  z * CLHEP::cm) * G4RotateX3D(-M_PI / 2 - theta);
249  new G4PVPlacement(transform, volume, name, top, false, 1);
250  }
251  }
252  }
253 
254  G4VSolid* GeoVXDCreator::createTrapezoidal(const string& name, double width, double width2, double length, double& height,
255  double angle)
256  {
257  double offset(0);
258  if (angle > 0) {
259  const double tana = tan(angle);
260  height = min(tana * length, min(tana * width, height));
261  offset = height / tana;
262  }
263  const double hwidth = width / 2.0;
264  const double hwidth2 = width2 / 2.0;
265  const double hlength = length / 2.0;
266  const double hheight = height / 2.0;
267 
268  if (width2 <= 0 || width == width2) {
269  if (angle <= 0) {
270  return new G4Box(name, hwidth, hlength, hheight);
271  } else {
272  return new G4Trd(name, hwidth, hwidth - offset, hlength, hlength - offset, hheight);
273  }
274  }
275  //FIXME: offset not working, g4 complains about nonplanarity of face -X. But we do not need that shape at the moment
276  //so lets ignore it for now
277  return new G4Trap(name, hheight, 0, 0, hlength, hwidth, hwidth2, 0, hlength - offset, hwidth - offset, hwidth2 - offset, 0);
278  }
279 
280  G4Transform3D GeoVXDCreator::placeLadder(int ladderID, double phi, G4LogicalVolume* volume,
281  const G4Transform3D& placement,
282  const VXDGeometryPar& parameters)
283  {
284  VxdID ladder(m_ladder.getLayerID(), ladderID, 0);
285 
286  G4Translate3D ladderPos(m_ladder.getRadius(), m_ladder.getShift(), 0);
287  G4Transform3D ladderPlacement = placement * G4RotateZ3D(phi) * ladderPos * getAlignment(parameters.getAlignment(ladder));
288  // The actuall coordinate system of ladder (w still points to Z, there is only phi rotation + move to correct radius + shift)
290 
291 
292  vector<G4Point3D> lastSensorEdge;
293  for (const VXDGeoSensorPlacement& p : m_ladder.getSensors()) {
294  VxdID sensorID(ladder);
295  sensorID.setSensorNumber(p.getSensorID());
296 
297 
298  std::map<string, VXDGeoSensor>::iterator it = m_sensorMap.find(p.getSensorTypeID());
299  if (it == m_sensorMap.end()) {
300  B2FATAL("Invalid SensorTypeID " << p.getSensorTypeID() << ", please check the definition of " << sensorID);
301  }
302  VXDGeoSensor& s = it->second;
303  string name = m_prefix + "." + (string)sensorID;
304 
305  //Calculate the reflection transformation needed. Since we want the
306  //active area to be non reflected we apply this transformation on the
307  //sensor and on the active area
308  G4Transform3D reflection;
309  if (p.getFlipU()) reflection = reflection * G4ReflectX3D();
310  if (p.getFlipV()) reflection = reflection * G4ReflectY3D();
311  if (p.getFlipW()) reflection = reflection * G4ReflectZ3D();
312 
313  G4VSolid* sensorShape = createTrapezoidal(name, s.getWidth(), s.getWidth2(), s.getLength(),
314  s.getHeight());
315  G4Material* sensorMaterial = Materials::get(s.getMaterial());
316  if (m_onlyActiveMaterial) {
317  s.setVolume(new G4LogicalVolume(sensorShape, Materials::get(m_defaultMaterial), name));
318  } else {
319  s.setVolume(new G4LogicalVolume(sensorShape, sensorMaterial, name));
320  }
321 
322  // Create sensitive Area: this Part is created separately since we want full control over the coordinate system:
323  // local x (called u) should point in RPhi direction
324  // local y (called v) should point in global z
325  // local z (called w) should away from the origin
326  G4VSolid* activeShape = createTrapezoidal(name + ".Active", s.getActiveArea().getWidth(), s.getActiveArea().getWidth2(),
327  s.getActiveArea().getLength(), s.getActiveArea().getHeight());
328 
329  //Create appropriate sensitive detector instance
330  SensitiveDetectorBase* sensitive = createSensitiveDetector(sensorID, s, p);
331 
334  m_sensitive.push_back(sensitive);
335  G4LogicalVolume* active = new G4LogicalVolume(activeShape, sensorMaterial, name + ".Active",
336  0, sensitive);
337  m_UserLimits.push_back(new G4UserLimits(m_activeStepSize));
338  active->SetUserLimits(m_UserLimits.back());
339 
340  setColor(*active, s.getActiveArea().getColor());
341 
342  //The coordinates of the active region are given as the distance between the corners, not to the center
343  //Place the active area
344  G4Transform3D activePosition = G4Translate3D(s.getActiveArea().getWidth() / 2.0, s.getActiveArea().getLength() / 2.0, 0) *
345  getPosition(s, s.getActiveArea(), s.getActivePlacement(), false);
346 
347  G4ReflectionFactory::Instance()->Place(activePosition * reflection, name + ".Active", active, s.getVolume(),
348  false, (int)sensorID, false);
349 
350  //Now create all the other components and place the Sensor
351  GeoVXDAssembly assembly;
352  if (!m_onlyActiveMaterial) assembly = createSubComponents(name, s, s.getComponents(), false, true);
353 
354  G4RotationMatrix rotation(0, -M_PI / 2.0, -M_PI / 2.0);
355  G4Transform3D sensorAlign = getAlignment(parameters.getAlignment(sensorID));
356  G4Transform3D sensorPlacement = G4Rotate3D(rotation) * sensorAlign * reflection;
357 
358  if (s.getSlanted()) {
359  sensorPlacement = G4TranslateX3D(m_ladder.getSlantedRadius() - m_ladder.getRadius()) * G4RotateY3D(
360  -m_ladder.getSlantedAngle()) * sensorPlacement;
361  }
362  sensorPlacement = G4Translate3D(0.0, 0.0, p.getZ()) * sensorPlacement;
363  // Remember the placement of sensor into ladder
364  VXD::GeoCache::getInstance().addSensorPlacement(ladder, sensorID, sensorPlacement * activePosition * reflection);
365  sensorPlacement = ladderPlacement * sensorPlacement;
366 
367  assembly.add(s.getVolume());
368  assembly.place(volume, sensorPlacement);
369 
370  //See if we want to glue the modules together
371  if (!m_ladder.getGlueMaterial().empty() && !m_onlyActiveMaterial) {
372  double u = s.getWidth() / 2.0 + m_ladder.getGlueSize();
373  double v = s.getLength() / 2.0;
374  double w = s.getHeight() / 2.0 + m_ladder.getGlueSize();
375  std::vector<G4Point3D> curSensorEdge(4);
376  //Lets get the forward corners of the sensor by applying the unreflected placement matrix
377  curSensorEdge[0] = sensorPlacement * reflection * G4Point3D(u, v, + w);
378  curSensorEdge[1] = sensorPlacement * reflection * G4Point3D(u, v, - w);
379  curSensorEdge[2] = sensorPlacement * reflection * G4Point3D(-u, v, - w);
380  curSensorEdge[3] = sensorPlacement * reflection * G4Point3D(-u, v, + w);
381  //If we already have backward edges this is not the first module so we can apply the glue
382  if (lastSensorEdge.size()) {
383  //Check that the modules don't overlap in z
384  bool glueOK = true;
385  for (int i = 0; i < 4; ++i) glueOK &= curSensorEdge[i].z() <= lastSensorEdge[i].z();
386  if (!glueOK) {
387  B2WARNING("Cannot place Glue at sensor " + (string)sensorID +
388  " since it overlaps with the last module in z");
389  } else {
390  //Create Glue which spans from last sensor to this sensor
391  G4TessellatedSolid* solidTarget = new G4TessellatedSolid(m_prefix + ".Glue." + (string)sensorID);
392 
393  //Face at end of last Sensor
394  solidTarget->AddFacet(new G4QuadrangularFacet(
395  curSensorEdge[3], curSensorEdge[2], curSensorEdge[1], curSensorEdge[0], ABSOLUTE));
396  //Face at begin of current Sensor
397  solidTarget->AddFacet(new G4QuadrangularFacet(
398  lastSensorEdge[0], lastSensorEdge[1], lastSensorEdge[2], lastSensorEdge[3], ABSOLUTE));
399 
400  //Top faces
401  solidTarget->AddFacet(new G4TriangularFacet(
402  curSensorEdge[3], curSensorEdge[0], lastSensorEdge[0], ABSOLUTE));
403  solidTarget->AddFacet(new G4TriangularFacet(
404  lastSensorEdge[0], lastSensorEdge[3], curSensorEdge[3], ABSOLUTE));
405  //Bottom faces
406  solidTarget->AddFacet(new G4TriangularFacet(
407  curSensorEdge[1], curSensorEdge[2], lastSensorEdge[2], ABSOLUTE));
408  solidTarget->AddFacet(new G4TriangularFacet(
409  lastSensorEdge[2], lastSensorEdge[1], curSensorEdge[1], ABSOLUTE));
410  //Right faces
411  solidTarget->AddFacet(new G4TriangularFacet(
412  curSensorEdge[0], curSensorEdge[1], lastSensorEdge[1], ABSOLUTE));
413  solidTarget->AddFacet(new G4TriangularFacet(
414  lastSensorEdge[1], lastSensorEdge[0], curSensorEdge[0], ABSOLUTE));
415  //Left faces
416  solidTarget->AddFacet(new G4TriangularFacet(
417  curSensorEdge[2], curSensorEdge[3], lastSensorEdge[3], ABSOLUTE));
418  solidTarget->AddFacet(new G4TriangularFacet(
419  lastSensorEdge[3], lastSensorEdge[2], curSensorEdge[2], ABSOLUTE));
420 
421  solidTarget->SetSolidClosed(true);
422 
423  G4LogicalVolume* glue = new G4LogicalVolume(solidTarget, Materials::get(m_ladder.getGlueMaterial()),
424  m_prefix + ".Glue." + (string)sensorID);
425  setColor(*glue, "#097");
426  new G4PVPlacement(G4Transform3D(), glue, m_prefix + ".Glue." + (string)sensorID, volume, false, 1);
427  }
428  }
429  //Remember the backward edge of this sensor to be glued to.
430  lastSensorEdge.resize(4);
431  lastSensorEdge[0] = sensorPlacement * reflection * G4Point3D(u, -v, + w);
432  lastSensorEdge[1] = sensorPlacement * reflection * G4Point3D(u, -v, - w);
433  lastSensorEdge[2] = sensorPlacement * reflection * G4Point3D(-u, -v, - w);
434  lastSensorEdge[3] = sensorPlacement * reflection * G4Point3D(-u, -v, + w);
435  }
436  }
437 
438  return ladderPlacement;
439  }
440 
441  void GeoVXDCreator::setCurrentLayer(int layer, const VXDGeometryPar& parameters)
442  {
443  const VXDGeoLadderPar& paramsLadder = parameters.getLadder(layer);
444 
446  layer,
447  paramsLadder.getShift() / Unit::mm,
448  paramsLadder.getRadius() / Unit::mm,
449  paramsLadder.getSlantedAngle(),
450  paramsLadder.getSlantedRadius() / Unit::mm,
451  paramsLadder.getGlueSize() / Unit::mm,
452  paramsLadder.getGlueMaterial()
453  );
454 
455 
456  for (const VXDGeoSensorPlacementPar& sensorInfo : paramsLadder.getSensors()) {
458  sensorInfo.getSensorID(),
459  sensorInfo.getSensorTypeID(),
460  sensorInfo.getZ() / Unit::mm,
461  sensorInfo.getFlipU(),
462  sensorInfo.getFlipV(),
463  sensorInfo.getFlipW()
464  ));
465  }
466  }
467 
468 
469 
470  void GeoVXDCreator::readLadderComponents(int layerID, int ladderID, GearDir content, VXDGeometryPar& vxdGeometryPar)
471  {
472  VxdID ladder(layerID, ladderID, 0);
473 
474  // Read alignment for ladder
475  string path = (boost::format("Align[@component='%1%']/") % ladder).str();
476  GearDir params(GearDir(content, "Alignment/"), path);
477  if (!params) {
478  B2WARNING("Could not find alignment parameters for ladder " << ladder);
479  return;
480  }
481  vxdGeometryPar.getAlignmentMap()[ladder] = VXDAlignmentPar(params.getLength("du"),
482  params.getLength("dv"),
483  params.getLength("dw"),
484  params.getAngle("alpha"),
485  params.getAngle("beta"),
486  params.getAngle("gamma")
487  );
488 
489 
490 
491  for (const VXDGeoSensorPlacementPar& p : vxdGeometryPar.getLadderMap()[layerID].getSensors()) {
492  VxdID sensorID(ladder);
493  sensorID.setSensorNumber(p.getSensorID());
494 
495  std::map<string, VXDGeoSensorPar>::iterator it = vxdGeometryPar.getSensorMap().find(p.getSensorTypeID());
496  if (it == vxdGeometryPar.getSensorMap().end()) {
497  B2FATAL("Invalid SensorTypeID " << p.getSensorTypeID() << ", please check the definition of " << sensorID);
498  }
499 
500  //Now create all the other components and place the Sensor
501  if (!vxdGeometryPar.getGlobalParams().getOnlyActiveMaterial()) {
502  VXDGeoSensorPar& s = it->second;
503  readSubComponents(s.getComponents(), GearDir(content, "Components/"), vxdGeometryPar);
504  }
505  // Read alignment for sensor
506  string pathSensor = (boost::format("Align[@component='%1%']/") % sensorID).str();
507  GearDir paramsSensor(GearDir(content, "Alignment/"), pathSensor);
508  if (!paramsSensor) {
509  B2WARNING("Could not find alignment parameters for sensorID " << sensorID);
510  return;
511  }
512  vxdGeometryPar.getAlignmentMap()[sensorID] = VXDAlignmentPar(paramsSensor.getLength("du"),
513  paramsSensor.getLength("dv"),
514  paramsSensor.getLength("dw"),
515  paramsSensor.getAngle("alpha"),
516  paramsSensor.getAngle("beta"),
517  paramsSensor.getAngle("gamma")
518  );
519  }
520  return;
521  }
522 
523  void GeoVXDCreator::readSubComponents(const std::vector<VXDGeoPlacementPar>& placements, const GearDir& componentsDir,
524  VXDGeometryPar& vxdGeometryPar)
525  {
526  for (const VXDGeoPlacementPar& p : placements) {
527  readComponent(p.getName(), componentsDir, vxdGeometryPar);
528  }
529  return;
530  }
531 
532  void GeoVXDCreator::readComponent(const std::string& name, GearDir componentsDir, VXDGeometryPar& vxdGeometryPar)
533  {
534 
535 
536  //Check if component already exists
537  if (vxdGeometryPar.getComponentMap().find(name) != vxdGeometryPar.getComponentMap().end()) {
538  return; // nothing to do
539  }
540 
541  //Component does not exist, so lets create a new one
542  string path = (boost::format("descendant::Component[@name='%1%']/") % name).str();
543  GearDir params(componentsDir, path);
544  if (!params) {
545  B2FATAL("Could not find definition for component " << name);
546  return;
547  }
548 
550  params.getString("Material", vxdGeometryPar.getGlobalParams().getDefaultMaterial()),
551  params.getString("Color", ""),
552  params.getLength("width", 0),
553  params.getLength("width2", 0),
554  params.getLength("length", 0),
555  params.getLength("height", 0),
556  params.getAngle("angle", 0)
557  );
558 
559  if (c.getWidth() <= 0 || c.getLength() <= 0 || c.getHeight() <= 0) {
560  B2DEBUG(100, "One dimension empty, using auto resize for component");
561  }
562 
563  c.setSubComponents(getSubComponents(params));
564  readSubComponents(c.getSubComponents(), componentsDir, vxdGeometryPar);
565 
566  if (vxdGeometryPar.getGlobalParams().getActiveChips() && params.exists("activeChipID")) {
567  int chipID = params.getInt("activeChipID");
568  vxdGeometryPar.getSensitiveChipIdMap()[name] = chipID;
569  }
570  vxdGeometryPar.getComponentMap()[name] = c;
571  vxdGeometryPar.getComponentInsertOder().push_back(name);
572  }
573 
574  void GeoVXDCreator::readLadder(int layer, GearDir components, VXDGeometryPar& geoparameters)
575  {
576  string path = (boost::format("Ladder[@layer=%1%]/") % layer).str();
577  GearDir paramsLadder(components, path);
578  if (!paramsLadder) {
579  B2FATAL("Could not find Ladder definition for layer " << layer);
580  }
581 
582  geoparameters.getLadderMap()[layer] = VXDGeoLadderPar(
583  layer,
584  paramsLadder.getLength("shift"),
585  paramsLadder.getLength("radius"),
586  paramsLadder.getAngle("slantedAngle", 0),
587  paramsLadder.getLength("slantedRadius", 0),
588  paramsLadder.getLength("Glue/oversize", 0),
589  paramsLadder.getString("Glue/Material", "")
590  );
591 
592  for (const GearDir& sensorInfo : paramsLadder.getNodes("Sensor")) {
593 
594  geoparameters.getLadderMap()[layer].addSensor(VXDGeoSensorPlacementPar(
595  sensorInfo.getInt("@id"),
596  sensorInfo.getString("@type"),
597  sensorInfo.getLength("."),
598  sensorInfo.getBool("@flipU", false),
599  sensorInfo.getBool("@flipV", false),
600  sensorInfo.getBool("@flipW", false)
601  ));
602  }
603  }
604 
605  std::vector<VXDGeoPlacementPar> GeoVXDCreator::getSubComponents(const GearDir& path)
606  {
607  vector<VXDGeoPlacementPar> result;
608  for (const GearDir& component : path.getNodes("Component")) {
609  string type;
610  if (!component.exists("@type")) {
611  type = component.getString("@name");
612  } else {
613  type = component.getString("@type");
614  }
615  int nPos = max(component.getNumberNodes("u"), component.getNumberNodes("v"));
616  nPos = max(nPos, component.getNumberNodes("w"));
617  nPos = max(nPos, component.getNumberNodes("woffset"));
618  for (int iPos = 1; iPos <= nPos; ++iPos) {
619  string index = (boost::format("[%1%]") % iPos).str();
620  result.push_back(VXDGeoPlacementPar(
621  type,
622  component.getLength("u" + index, 0),
623  component.getLength("v" + index, 0),
624  component.getString("w" + index, "bottom"),
625  component.getLength("woffset" + index, 0)
626  ));
627  }
628  }
629  return result;
630  }
631 
632  } // namespace VXD
634 } // namespace Belle2
The Class for BeamBackground Sensitive Detector.
GearDir is the basic class used for accessing the parameter store.
Definition: GearDir.h:31
virtual std::string getString(const std::string &path="") const noexcept(false) override
Get the parameter path as a string.
Definition: GearDir.h:69
Base class for all Sensitive Detectors to create hits during simulation.
static const double mm
[millimeters]
Definition: Unit.h:70
The Class for VXD Alignment payload.
The Class for VXD geometry component.
Class holding all parameters for an VXD geometry component.
The Class for VXD Ladder payload.
double getSlantedAngle() const
get the slant angle for slanted sensors
const std::vector< VXDGeoSensorPlacementPar > & getSensors() const
get list of sensors
const std::string & getGlueMaterial() const
get the glue material
double getRadius() const
get the radius of all sensors except slanted ones
double getShift() const
get the shift along the u coordinate for all sensors in the ladder
double getSlantedRadius() const
get the radius for slanted sensors
double getGlueSize() const
get the additional glue size, e.g.
Struct containing all parameters of one ladder.
int getLayerID() const
get the layer id
double getSlantedAngle() const
get the slant angle for slanted sensors
const std::string & getGlueMaterial() const
get the glue material
double getRadius() const
get the radius of all sensors except slanted ones
const std::vector< VXDGeoSensorPlacement > & getSensors() const
get list of sensors
double getShift() const
get the shift along the u coordinate for all sensors in the ladder
void addSensor(const VXDGeoSensorPlacement &sensor)
add a sensor to the list of sensors in the ladder
double getSlantedRadius() const
get the radius for slanted sensors
double getGlueSize() const
get the additional glue size, e.g.
The Class for VXD placement payload.
Class holding all parameters to place a VXD geometry subcomponent.
double getU() const
get local u coordinate where to place the component
double getV() const
get local v coordinate where to place the component
EPosW getW() const
get local w position where to place the component
@ c_bottom
Place the component at the bottom of the mother.
@ c_above
Place the component above the mother.
@ c_center
Place the component at the center of the mother.
@ c_top
Place the component at the top of the mother.
@ c_below
Place the component below the mother.
double getWOffset() const
get offset to local w position where to place the component
The Class for VXD Radiation Sensor parameters.
The Class for VXD Radiation Sensor Position parameters.
The Class for VXD Sensor payload.
The Class for VXD Sensor Placement payload.
Struct holding the information where a sensor should be placed inside the ladder.
Struct holding all parameters for a completeVXD Sensor.
The Class for VXD geometry.
const std::map< std::string, VXDGeoSensorPar > & getSensorMap() const
get sensor map
const std::vector< std::string > & getComponentInsertOder() const
get component insert order
const VXDGlobalPar & getGlobalParams() const
get global parameters
std::map< int, VXDGeoLadderPar > & getLadderMap()
get ladder map
const std::map< std::string, VXDGeoComponentPar > & getComponentMap() const
get component maps
std::map< std::string, VXDAlignmentPar > & getAlignmentMap()
get alignmant map
std::map< std::string, int > & getSensitiveChipIdMap()
get sensitive chip id map
bool getOnlyActiveMaterial() const
Get whether only active materials will be placed for tracking studies.
Definition: VXDGlobalPar.h:55
bool getActiveChips() const
Get whether chips are sensitive
Definition: VXDGlobalPar.h:48
std::string getDefaultMaterial() const
Get default material.
Definition: VXDGlobalPar.h:59
void addSensorPlacement(VxdID ladder, VxdID sensor, const G4Transform3D &placement)
Remember how sensor is placed into ladder.
Definition: GeoCache.cc:220
static GeoCache & getInstance()
Return a reference to the singleton instance.
Definition: GeoCache.cc:214
void addLadderPlacement(VxdID halfShell, VxdID ladder, const G4Transform3D &placement)
Remember how ladder is placed into half-shell.
Definition: GeoCache.cc:225
Class to group some Geant4 volumes and place them all at once with a given transformation matrix.
void place(G4LogicalVolume *mother, const G4Transform3D &transform)
Place all the volumes already added to the assembly in the given mother.
void add(G4LogicalVolume *volume, const G4Transform3D &transform=G4Transform3D())
Add a volume to the assembly.
std::map< std::string, VXDGeoSensor > m_sensorMap
Map containing Information about all defined sensor types.
float m_minimumElectrons
minimum number of electrons to be deposited by a particle to be saved
G4VSolid * createTrapezoidal(const std::string &name, double width, double width2, double length, double &height, double angle=0)
Create a trapezoidal solid.
virtual void readLadderComponents(int layerID, int ladderID, GearDir content, VXDGeometryPar &vxdGeometryPar)
Read parameters for ladder components and their alignment corresponding to the given ladder id.
void createDiamonds(const VXDGeoRadiationSensorsPar &params, G4LogicalVolume &topVolume, G4LogicalVolume &envelopeVolume)
Create diamond radiation sensors.
std::vector< Simulation::SensitiveDetectorBase * > m_sensitive
List to all created sensitive detector instances.
std::string m_prefix
Prefix to prepend to all volume names.
bool m_onlyActiveMaterial
If this is true, only active Materials will be placed for tracking studies.
double m_activeStepSize
Stepsize to be used inside active volumes.
float m_distanceTolerance
tolerance for Geant4 steps to be merged to a single step
virtual void readLadder(int layer, GearDir components, VXDGeometryPar &geoparameters)
Read parameters for a ladder in layer with given ID from gearbox and layer store them in payload.
VXDGeoLadder m_ladder
Parameters of the currently active ladder.
std::map< std::string, Belle2::VxdID > m_halfShellVxdIDs
Used for translation of half-shell name into a VxdID to consitently handle it in hierarchy.
bool m_onlyPrimaryTrueHits
If true only create TrueHits from primary particles and ignore secondaries.
G4Transform3D getPosition(const VXDGeoComponent &mother, const VXDGeoComponent &daughter, const VXDGeoPlacement &placement, bool originCenter)
Return the position where a daughter component is to be placed.
float m_electronTolerance
tolerance for the energy deposition in electrons to be merged in a single step
std::vector< G4UserLimits * > m_UserLimits
Vector of G4UserLimit pointers.
G4Transform3D getAlignment(const VXDAlignmentPar &params)
Get Alignment from paylead object.
void readComponent(const std::string &name, GearDir components, VXDGeometryPar &vxdGeometryPar)
Read parameters for component name from Gearbox into geometry payload.
virtual ~GeoVXDCreator()
The destructor of the GeoVXDCreator class.
GeoVXDAssembly createSubComponents(const std::string &name, VXDGeoComponent &component, std::vector< VXDGeoPlacement > placements, bool originCenter=true, bool allowOutside=false)
Place a list of subcomponents into an component.
void readSubComponents(const std::vector< VXDGeoPlacementPar > &placements, const GearDir &componentsDir, VXDGeometryPar &vxdGeometryPar)
Read parameters for all components in placement container from Gearbox into payload.
std::map< std::string, VXDGeoComponent > m_componentCache
Cache of all previously created components.
G4Transform3D placeLadder(int ladderID, double phi, G4LogicalVolume *volume, const G4Transform3D &placement, const VXDGeometryPar &parameters)
Place ladder corresponding to the given ladder id into volume setLayer has to be called first to set ...
virtual void setCurrentLayer(int layer, const VXDGeometryPar &parameters)
Read parameters for given layer and store in m_ladder.
std::vector< VXDGeoPlacementPar > getSubComponents(const GearDir &path)
Return vector of VXDGeoPlacements with all the components defined inside a given path.
virtual SensitiveDetectorBase * createSensitiveDetector(VxdID sensorID, const VXDGeoSensor &sensor, const VXDGeoSensorPlacement &placement)=0
Return a SensitiveDetector implementation for a given sensor.
bool m_seeNeutrons
Make sensitive detectors also see neutrons.
std::string m_defaultMaterial
Name of the Material to be used for Air.
std::string m_currentHalfShell
Current half-shell being processed (need to know ladder parent for hierarchy)
Base class for Sensitive Detector implementation of PXD and SVD.
void setOptions(bool seeNeutrons, bool onlyPrimaryTrueHits, float distanceTolerance, float electronTolerance, float minimumElectrons)
Set all common options.
Class to uniquely identify a any structure of the PXD and SVD.
Definition: VxdID.h:33
void setSensorNumber(baseType sensor)
Set the sensor id.
Definition: VxdID.h:111
double getAngle(const std::string &path="") const noexcept(false)
Get the parameter path as a double converted to the standard angle unit.
Definition: Interface.h:299
double getLength(const std::string &path="") const noexcept(false)
Get the parameter path as a double converted to the standard length unit.
Definition: Interface.h:259
std::vector< GearDir > getNodes(const std::string &path="") const
Get vector of GearDirs which point to all the nodes the given path evaluates to.
Definition: Interface.cc:21
static G4Material * get(const std::string &name)
Find given material.
Definition: Materials.h:63
double tan(double a)
tan for double
Definition: beamHelpers.h:31
void setVisibility(G4LogicalVolume &volume, bool visible)
Helper function to quickly set the visibility of a given volume.
Definition: utilities.cc:108
void setColor(G4LogicalVolume &volume, const std::string &color)
Set the color of a logical volume.
Definition: utilities.cc:100
Abstract base class for different kinds of events.