Belle II Software development
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
43using namespace std;
44
45namespace 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 = 0;
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 if (not shape) shape = new G4Box("radiationSensorDiamond", width / 2 * CLHEP::cm, length / 2 * CLHEP::cm, height / 2 * CLHEP::cm);
243 G4LogicalVolume* volume = new G4LogicalVolume(shape, material, name);
244 //add a sensitive detector implementation
245 BkgSensitiveDetector* sensitive = new BkgSensitiveDetector(params.getSubDetector().c_str(), id);
246 volume->SetSensitiveDetector(sensitive);
247 //and place it at the correct position
248 G4Transform3D transform = G4RotateZ3D(phi - M_PI / 2) * G4Translate3D(0, r * CLHEP::cm,
249 z * CLHEP::cm) * G4RotateX3D(-M_PI / 2 - theta);
250 new G4PVPlacement(transform, volume, name, top, false, 1);
251 }
252 }
253 }
254
255 G4VSolid* GeoVXDCreator::createTrapezoidal(const string& name, double width, double width2, double length, double& height,
256 double angle)
257 {
258 double offset(0);
259 if (angle > 0) {
260 const double tana = tan(angle);
261 height = min(tana * length, min(tana * width, height));
262 offset = height / tana;
263 }
264 const double hwidth = width / 2.0;
265 const double hwidth2 = width2 / 2.0;
266 const double hlength = length / 2.0;
267 const double hheight = height / 2.0;
268
269 if (width2 <= 0 || width == width2) {
270 if (angle <= 0) {
271 return new G4Box(name, hwidth, hlength, hheight);
272 } else {
273 return new G4Trd(name, hwidth, hwidth - offset, hlength, hlength - offset, hheight);
274 }
275 }
276 //FIXME: offset not working, g4 complains about nonplanarity of face -X. But we do not need that shape at the moment
277 //so lets ignore it for now
278 return new G4Trap(name, hheight, 0, 0, hlength, hwidth, hwidth2, 0, hlength - offset, hwidth - offset, hwidth2 - offset, 0);
279 }
280
281 G4Transform3D GeoVXDCreator::placeLadder(int ladderID, double phi, G4LogicalVolume* volume,
282 const G4Transform3D& placement,
283 const VXDGeometryPar& parameters)
284 {
285 VxdID ladder(m_ladder.getLayerID(), ladderID, 0);
286
287 G4Translate3D ladderPos(m_ladder.getRadius(), m_ladder.getShift(), 0);
288 G4Transform3D ladderPlacement = placement * G4RotateZ3D(phi) * ladderPos * getAlignment(parameters.getAlignment(ladder));
289 // The actuall coordinate system of ladder (w still points to Z, there is only phi rotation + move to correct radius + shift)
291
292
293 vector<G4Point3D> lastSensorEdge;
294 for (const VXDGeoSensorPlacement& p : m_ladder.getSensors()) {
295 VxdID sensorID(ladder);
296 sensorID.setSensorNumber(p.getSensorID());
297
298
299 std::map<string, VXDGeoSensor>::iterator it = m_sensorMap.find(p.getSensorTypeID());
300 if (it == m_sensorMap.end()) {
301 B2FATAL("Invalid SensorTypeID " << p.getSensorTypeID() << ", please check the definition of " << sensorID);
302 }
303 VXDGeoSensor& s = it->second;
304 string name = m_prefix + "." + (string)sensorID;
305
306 //Calculate the reflection transformation needed. Since we want the
307 //active area to be non reflected we apply this transformation on the
308 //sensor and on the active area
309 G4Transform3D reflection;
310 if (p.getFlipU()) reflection = reflection * G4ReflectX3D();
311 if (p.getFlipV()) reflection = reflection * G4ReflectY3D();
312 if (p.getFlipW()) reflection = reflection * G4ReflectZ3D();
313
314 G4VSolid* sensorShape = createTrapezoidal(name, s.getWidth(), s.getWidth2(), s.getLength(),
315 s.getHeight());
316 G4Material* sensorMaterial = Materials::get(s.getMaterial());
318 s.setVolume(new G4LogicalVolume(sensorShape, Materials::get(m_defaultMaterial), name));
319 } else {
320 s.setVolume(new G4LogicalVolume(sensorShape, sensorMaterial, name));
321 }
322
323 // Create sensitive Area: this Part is created separately since we want full control over the coordinate system:
324 // local x (called u) should point in RPhi direction
325 // local y (called v) should point in global z
326 // local z (called w) should away from the origin
327 G4VSolid* activeShape = createTrapezoidal(name + ".Active", s.getActiveArea().getWidth(), s.getActiveArea().getWidth2(),
328 s.getActiveArea().getLength(), s.getActiveArea().getHeight());
329
330 //Create appropriate sensitive detector instance
331 SensitiveDetectorBase* sensitive = createSensitiveDetector(sensorID, s, p);
332
335 m_sensitive.push_back(sensitive);
336 G4LogicalVolume* active = new G4LogicalVolume(activeShape, sensorMaterial, name + ".Active",
337 0, sensitive);
338 m_UserLimits.push_back(new G4UserLimits(m_activeStepSize));
339 active->SetUserLimits(m_UserLimits.back());
340
341 setColor(*active, s.getActiveArea().getColor());
342
343 //The coordinates of the active region are given as the distance between the corners, not to the center
344 //Place the active area
345 G4Transform3D activePosition = G4Translate3D(s.getActiveArea().getWidth() / 2.0, s.getActiveArea().getLength() / 2.0, 0) *
346 getPosition(s, s.getActiveArea(), s.getActivePlacement(), false);
347
348 G4ReflectionFactory::Instance()->Place(activePosition * reflection, name + ".Active", active, s.getVolume(),
349 false, (int)sensorID, false);
350
351 //Now create all the other components and place the Sensor
352 GeoVXDAssembly assembly;
353 if (!m_onlyActiveMaterial) assembly = createSubComponents(name, s, s.getComponents(), false, true);
354
355 G4RotationMatrix rotation(0, -M_PI / 2.0, -M_PI / 2.0);
356 G4Transform3D sensorAlign = getAlignment(parameters.getAlignment(sensorID));
357 G4Transform3D sensorPlacement = G4Rotate3D(rotation) * sensorAlign * reflection;
358
359 if (s.getSlanted()) {
360 sensorPlacement = G4TranslateX3D(m_ladder.getSlantedRadius() - m_ladder.getRadius()) * G4RotateY3D(
361 -m_ladder.getSlantedAngle()) * sensorPlacement;
362 }
363 sensorPlacement = G4Translate3D(0.0, 0.0, p.getZ()) * sensorPlacement;
364 // Remember the placement of sensor into ladder
365 VXD::GeoCache::getInstance().addSensorPlacement(ladder, sensorID, sensorPlacement * activePosition * reflection);
366 sensorPlacement = ladderPlacement * sensorPlacement;
367
368 assembly.add(s.getVolume());
369 assembly.place(volume, sensorPlacement);
370
371 //See if we want to glue the modules together
372 if (!m_ladder.getGlueMaterial().empty() && !m_onlyActiveMaterial) {
373 double u = s.getWidth() / 2.0 + m_ladder.getGlueSize();
374 double v = s.getLength() / 2.0;
375 double w = s.getHeight() / 2.0 + m_ladder.getGlueSize();
376 std::vector<G4Point3D> curSensorEdge(4);
377 //Lets get the forward corners of the sensor by applying the unreflected placement matrix
378 curSensorEdge[0] = sensorPlacement * reflection * G4Point3D(u, v, + w);
379 curSensorEdge[1] = sensorPlacement * reflection * G4Point3D(u, v, - w);
380 curSensorEdge[2] = sensorPlacement * reflection * G4Point3D(-u, v, - w);
381 curSensorEdge[3] = sensorPlacement * reflection * G4Point3D(-u, v, + w);
382 //If we already have backward edges this is not the first module so we can apply the glue
383 if (lastSensorEdge.size()) {
384 //Check that the modules don't overlap in z
385 bool glueOK = true;
386 for (int i = 0; i < 4; ++i) glueOK &= curSensorEdge[i].z() <= lastSensorEdge[i].z();
387 if (!glueOK) {
388 B2WARNING("Cannot place Glue at sensor " + (string)sensorID +
389 " since it overlaps with the last module in z");
390 } else {
391 //Create Glue which spans from last sensor to this sensor
392 G4TessellatedSolid* solidTarget = new G4TessellatedSolid(m_prefix + ".Glue." + (string)sensorID);
393
394 //Face at end of last Sensor
395 solidTarget->AddFacet(new G4QuadrangularFacet(
396 curSensorEdge[3], curSensorEdge[2], curSensorEdge[1], curSensorEdge[0], ABSOLUTE));
397 //Face at begin of current Sensor
398 solidTarget->AddFacet(new G4QuadrangularFacet(
399 lastSensorEdge[0], lastSensorEdge[1], lastSensorEdge[2], lastSensorEdge[3], ABSOLUTE));
400
401 //Top faces
402 solidTarget->AddFacet(new G4TriangularFacet(
403 curSensorEdge[3], curSensorEdge[0], lastSensorEdge[0], ABSOLUTE));
404 solidTarget->AddFacet(new G4TriangularFacet(
405 lastSensorEdge[0], lastSensorEdge[3], curSensorEdge[3], ABSOLUTE));
406 //Bottom faces
407 solidTarget->AddFacet(new G4TriangularFacet(
408 curSensorEdge[1], curSensorEdge[2], lastSensorEdge[2], ABSOLUTE));
409 solidTarget->AddFacet(new G4TriangularFacet(
410 lastSensorEdge[2], lastSensorEdge[1], curSensorEdge[1], ABSOLUTE));
411 //Right faces
412 solidTarget->AddFacet(new G4TriangularFacet(
413 curSensorEdge[0], curSensorEdge[1], lastSensorEdge[1], ABSOLUTE));
414 solidTarget->AddFacet(new G4TriangularFacet(
415 lastSensorEdge[1], lastSensorEdge[0], curSensorEdge[0], ABSOLUTE));
416 //Left faces
417 solidTarget->AddFacet(new G4TriangularFacet(
418 curSensorEdge[2], curSensorEdge[3], lastSensorEdge[3], ABSOLUTE));
419 solidTarget->AddFacet(new G4TriangularFacet(
420 lastSensorEdge[3], lastSensorEdge[2], curSensorEdge[2], ABSOLUTE));
421
422 solidTarget->SetSolidClosed(true);
423
424 G4LogicalVolume* glue = new G4LogicalVolume(solidTarget, Materials::get(m_ladder.getGlueMaterial()),
425 m_prefix + ".Glue." + (string)sensorID);
426 setColor(*glue, "#097");
427 new G4PVPlacement(G4Transform3D(), glue, m_prefix + ".Glue." + (string)sensorID, volume, false, 1);
428 }
429 }
430 //Remember the backward edge of this sensor to be glued to.
431 lastSensorEdge.resize(4);
432 lastSensorEdge[0] = sensorPlacement * reflection * G4Point3D(u, -v, + w);
433 lastSensorEdge[1] = sensorPlacement * reflection * G4Point3D(u, -v, - w);
434 lastSensorEdge[2] = sensorPlacement * reflection * G4Point3D(-u, -v, - w);
435 lastSensorEdge[3] = sensorPlacement * reflection * G4Point3D(-u, -v, + w);
436 }
437 }
438
439 return ladderPlacement;
440 }
441
442 void GeoVXDCreator::setCurrentLayer(int layer, const VXDGeometryPar& parameters)
443 {
444 const VXDGeoLadderPar& paramsLadder = parameters.getLadder(layer);
445
447 layer,
448 paramsLadder.getShift() / Unit::mm,
449 paramsLadder.getRadius() / Unit::mm,
450 paramsLadder.getSlantedAngle(),
451 paramsLadder.getSlantedRadius() / Unit::mm,
452 paramsLadder.getGlueSize() / Unit::mm,
453 paramsLadder.getGlueMaterial()
454 );
455
456
457 for (const VXDGeoSensorPlacementPar& sensorInfo : paramsLadder.getSensors()) {
459 sensorInfo.getSensorID(),
460 sensorInfo.getSensorTypeID(),
461 sensorInfo.getZ() / Unit::mm,
462 sensorInfo.getFlipU(),
463 sensorInfo.getFlipV(),
464 sensorInfo.getFlipW()
465 ));
466 }
467 }
468
469
470
471 void GeoVXDCreator::readLadderComponents(int layerID, int ladderID, GearDir content, VXDGeometryPar& vxdGeometryPar)
472 {
473 VxdID ladder(layerID, ladderID, 0);
474
475 // Read alignment for ladder
476 string path = (boost::format("Align[@component='%1%']/") % ladder).str();
477 GearDir params(GearDir(content, "Alignment/"), path);
478 if (!params) {
479 B2WARNING("Could not find alignment parameters for ladder " << ladder);
480 return;
481 }
482 vxdGeometryPar.getAlignmentMap()[ladder] = VXDAlignmentPar(params.getLength("du"),
483 params.getLength("dv"),
484 params.getLength("dw"),
485 params.getAngle("alpha"),
486 params.getAngle("beta"),
487 params.getAngle("gamma")
488 );
489
490
491
492 for (const VXDGeoSensorPlacementPar& p : vxdGeometryPar.getLadderMap()[layerID].getSensors()) {
493 VxdID sensorID(ladder);
494 sensorID.setSensorNumber(p.getSensorID());
495
496 std::map<string, VXDGeoSensorPar>::iterator it = vxdGeometryPar.getSensorMap().find(p.getSensorTypeID());
497 if (it == vxdGeometryPar.getSensorMap().end()) {
498 B2FATAL("Invalid SensorTypeID " << p.getSensorTypeID() << ", please check the definition of " << sensorID);
499 }
500
501 //Now create all the other components and place the Sensor
502 if (!vxdGeometryPar.getGlobalParams().getOnlyActiveMaterial()) {
503 VXDGeoSensorPar& s = it->second;
504 readSubComponents(s.getComponents(), GearDir(content, "Components/"), vxdGeometryPar);
505 }
506 // Read alignment for sensor
507 string pathSensor = (boost::format("Align[@component='%1%']/") % sensorID).str();
508 GearDir paramsSensor(GearDir(content, "Alignment/"), pathSensor);
509 if (!paramsSensor) {
510 B2WARNING("Could not find alignment parameters for sensorID " << sensorID);
511 return;
512 }
513 vxdGeometryPar.getAlignmentMap()[sensorID] = VXDAlignmentPar(paramsSensor.getLength("du"),
514 paramsSensor.getLength("dv"),
515 paramsSensor.getLength("dw"),
516 paramsSensor.getAngle("alpha"),
517 paramsSensor.getAngle("beta"),
518 paramsSensor.getAngle("gamma")
519 );
520 }
521 return;
522 }
523
524 void GeoVXDCreator::readSubComponents(const std::vector<VXDGeoPlacementPar>& placements, const GearDir& componentsDir,
525 VXDGeometryPar& vxdGeometryPar)
526 {
527 for (const VXDGeoPlacementPar& p : placements) {
528 readComponent(p.getName(), componentsDir, vxdGeometryPar);
529 }
530 return;
531 }
532
533 void GeoVXDCreator::readComponent(const std::string& name, GearDir componentsDir, VXDGeometryPar& vxdGeometryPar)
534 {
535
536
537 //Check if component already exists
538 if (vxdGeometryPar.getComponentMap().find(name) != vxdGeometryPar.getComponentMap().end()) {
539 return; // nothing to do
540 }
541
542 //Component does not exist, so lets create a new one
543 string path = (boost::format("descendant::Component[@name='%1%']/") % name).str();
544 GearDir params(componentsDir, path);
545 if (!params) {
546 B2FATAL("Could not find definition for component " << name);
547 return;
548 }
549
551 params.getString("Material", vxdGeometryPar.getGlobalParams().getDefaultMaterial()),
552 params.getString("Color", ""),
553 params.getLength("width", 0),
554 params.getLength("width2", 0),
555 params.getLength("length", 0),
556 params.getLength("height", 0),
557 params.getAngle("angle", 0)
558 );
559
560 if (c.getWidth() <= 0 || c.getLength() <= 0 || c.getHeight() <= 0) {
561 B2DEBUG(100, "One dimension empty, using auto resize for component");
562 }
563
564 c.setSubComponents(getSubComponents(params));
565 readSubComponents(c.getSubComponents(), componentsDir, vxdGeometryPar);
566
567 if (vxdGeometryPar.getGlobalParams().getActiveChips() && params.exists("activeChipID")) {
568 int chipID = params.getInt("activeChipID");
569 vxdGeometryPar.getSensitiveChipIdMap()[name] = chipID;
570 }
571 vxdGeometryPar.getComponentMap()[name] = c;
572 vxdGeometryPar.getComponentInsertOder().push_back(name);
573 }
574
575 void GeoVXDCreator::readLadder(int layer, GearDir components, VXDGeometryPar& geoparameters)
576 {
577 string path = (boost::format("Ladder[@layer=%1%]/") % layer).str();
578 GearDir paramsLadder(components, path);
579 if (!paramsLadder) {
580 B2FATAL("Could not find Ladder definition for layer " << layer);
581 }
582
583 geoparameters.getLadderMap()[layer] = VXDGeoLadderPar(
584 layer,
585 paramsLadder.getLength("shift"),
586 paramsLadder.getLength("radius"),
587 paramsLadder.getAngle("slantedAngle", 0),
588 paramsLadder.getLength("slantedRadius", 0),
589 paramsLadder.getLength("Glue/oversize", 0),
590 paramsLadder.getString("Glue/Material", "")
591 );
592
593 for (const GearDir& sensorInfo : paramsLadder.getNodes("Sensor")) {
594
595 geoparameters.getLadderMap()[layer].addSensor(VXDGeoSensorPlacementPar(
596 sensorInfo.getInt("@id"),
597 sensorInfo.getString("@type"),
598 sensorInfo.getLength("."),
599 sensorInfo.getBool("@flipU", false),
600 sensorInfo.getBool("@flipV", false),
601 sensorInfo.getBool("@flipW", false)
602 ));
603 }
604 }
605
606 std::vector<VXDGeoPlacementPar> GeoVXDCreator::getSubComponents(const GearDir& path)
607 {
608 vector<VXDGeoPlacementPar> result;
609 for (const GearDir& component : path.getNodes("Component")) {
610 string type;
611 if (!component.exists("@type")) {
612 type = component.getString("@name");
613 } else {
614 type = component.getString("@type");
615 }
616 int nPos = max(component.getNumberNodes("u"), component.getNumberNodes("v"));
617 nPos = max(nPos, component.getNumberNodes("w"));
618 nPos = max(nPos, component.getNumberNodes("woffset"));
619 for (int iPos = 1; iPos <= nPos; ++iPos) {
620 string index = (boost::format("[%1%]") % iPos).str();
621 result.push_back(VXDGeoPlacementPar(
622 type,
623 component.getLength("u" + index, 0),
624 component.getLength("v" + index, 0),
625 component.getString("w" + index, "bottom"),
626 component.getLength("woffset" + index, 0)
627 ));
628 }
629 }
630 return result;
631 }
632
633 } // namespace VXD
635} // 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.
double getWidth() const
get the width of the component
double & getHeight()
get the height of the component
double getLength() const
get the length of the component
The Class for VXD Ladder payload.
const std::string & getGlueMaterial() const
get the glue material
double getSlantedAngle() const
get the slant angle for slanted sensors
const std::vector< VXDGeoSensorPlacementPar > & getSensors() const
get list of sensors
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.
const std::vector< VXDGeoSensorPlacement > & getSensors() const
get list of sensors
int getLayerID() const
get the layer id
const std::string & getGlueMaterial() const
get the glue material
double getSlantedAngle() const
get the slant angle for slanted sensors
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
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, VXDGeoComponentPar > & getComponentMap() const
get component maps
const std::map< std::string, VXDGeoSensorPar > & getSensorMap() const
get sensor map
const VXDGlobalPar & getGlobalParams() const
get global parameters
std::map< std::string, VXDAlignmentPar > & getAlignmentMap()
get alignmant map
const std::vector< std::string > & getComponentInsertOder() const
get component insert order
std::map< int, VXDGeoLadderPar > & getLadderMap()
get ladder 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)
GeoVXDCreator(const std::string &prefix)
Constructor of the GeoVXDCreator class.
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
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.
STL namespace.