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