11 #include <vxd/geometry/GeoVXDCreator.h>
12 #include <vxd/geometry/GeoCache.h>
13 #include <vxd/simulation/SensitiveDetector.h>
14 #include <simulation/background/BkgSensitiveDetector.h>
16 #include <geometry/CreatorFactory.h>
17 #include <geometry/Materials.h>
18 #include <geometry/utilities.h>
19 #include <framework/gearbox/GearDir.h>
21 #include <boost/algorithm/string.hpp>
22 #include <boost/format.hpp>
24 #include <G4ReflectionFactory.hh>
25 #include <G4LogicalVolume.hh>
30 #include <G4Polycone.hh>
31 #include <G4PVPlacement.hh>
32 #include <G4AssemblyVolume.hh>
33 #include <G4UserLimits.hh>
34 #include <G4Point3D.hh>
36 #include <G4TessellatedSolid.hh>
37 #include <G4QuadrangularFacet.hh>
38 #include <G4TriangularFacet.hh>
40 #include <CLHEP/Units/PhysicalConstants.h>
41 #include <CLHEP/Units/SystemOfUnits.h>
53 using namespace geometry;
56 GeoVXDCreator::GeoVXDCreator(
const string& prefix) : m_prefix(prefix), m_radiationsensors(prefix)
71 for (G4UserLimits* userLimit :
m_UserLimits)
delete userLimit;
77 vector<VXDGeoPlacement> placements,
bool originCenter,
bool allowOutside)
80 B2DEBUG(100,
"Creating component " << name);
81 vector<VXDGeoComponent> subComponents;
82 subComponents.reserve(placements.size());
85 bool widthResize = component.getWidth() <= 0;
86 bool lengthResize = component.getLength() <= 0;
87 bool heightResize = component.getHeight() <= 0;
92 B2FATAL(
"A component is requested that was not created before!");
96 B2DEBUG(100,
"SubComponent " << p.getName());
97 B2DEBUG(100, boost::format(
"Placement: u:%1% cm, v:%2% cm, w:%3% + %4% cm") % p.getU() % p.getV() % p.getW() % p.getWOffset());
98 B2DEBUG(100, boost::format(
"Dimensions: %1%x%2%x%3% cm") % sub.getWidth() % sub.getLength() % sub.getHeight());
102 if (!allowOutside) B2FATAL(
"Cannot place component " << p.getName() <<
" outside of component " << name);
103 }
else if (sub.getHeight() + p.getWOffset() > component.getHeight()) {
106 B2FATAL(
"Subcomponent " << p.getName() <<
" does not fit into volume: "
107 <<
"height " << sub.getHeight() <<
" > " << component.getHeight());
109 component.getHeight() = sub.getHeight() + p.getWOffset();
113 double minWidth = max(abs(p.getU() + sub.getWidth() / 2.0), abs(p.getU() - sub.getWidth() / 2.0));
114 double minLength = max(abs(p.getV() + sub.getLength() / 2.0), abs(p.getV() - sub.getLength() / 2.0));
115 if (minWidth > component.getWidth() + component.getWidth() * numeric_limits<double>::epsilon()) {
117 B2FATAL(
"Subcomponent " << p.getName() <<
" does not fit into volume: "
118 <<
"minWidth " << minWidth <<
" > " << component.getWidth());
120 component.setWidth(minWidth * 2.0);
122 if (minLength > component.getLength() + component.getLength() * numeric_limits<double>::epsilon()) {
124 B2FATAL(
"Subcomponent " << p.getName() <<
" does not fit into volume: "
125 <<
"minLength " << minLength <<
" > " << component.getLength());
127 component.setLength(minLength * 2.0);
129 subComponents.push_back(sub);
133 if (component.getWidth() <= 0 || component.getLength() <= 0 || component.getHeight() <= 0) {
134 B2FATAL(
"At least one dimension of component " << name <<
" is zero which does not make sense");
138 if (!component.getVolume()) {
139 G4VSolid* componentShape =
createTrapezoidal(name, component.getWidth(), component.getWidth2(), component.getLength(),
140 component.getHeight());
141 component.setVolume(
new G4LogicalVolume(componentShape,
Materials::get(component.getMaterial()), name));
144 B2DEBUG(100, boost::format(
"Component %1% dimensions: %2%x%3%x%4% cm") % name % component.getWidth() % component.getLength() %
145 component.getHeight());
148 for (
size_t i = 0; i < placements.size(); ++i) {
152 G4Transform3D transform =
getPosition(component, s, p, originCenter);
155 assembly.
add(s.getVolume(), transform);
157 new G4PVPlacement(transform, s.getVolume(), name +
"." + p.getName(), component.getVolume(),
false, i);
162 if (component.getColor().empty()) {
163 B2DEBUG(200,
"Component " << name <<
" is an Air volume, setting invisible");
166 B2DEBUG(200,
"Component " << name <<
" color: " << component.getColor());
167 setColor(*component.getVolume(), component.getColor());
169 B2DEBUG(100,
"--> Created component " << name);
176 G4RotationMatrix rotation(params.getAlpha(), params.getBeta(), params.getBeta());
178 return G4Transform3D(rotation, translation);
184 double u(placement.
getU()), v(placement.
getV()), w(0);
185 switch (placement.
getW()) {
187 w = - mother.getHeight() / 2.0 - daughter.getHeight() / 2.0;
190 w = - mother.getHeight() / 2.0 + daughter.getHeight() / 2.0;
196 w = mother.getHeight() / 2.0 - daughter.getHeight() / 2.0;
199 w = mother.getHeight() / 2.0 + daughter.getHeight() / 2.0;
203 u -= mother.getWidth() / 2.0;
204 v -= mother.getLength() / 2.0;
206 return G4Translate3D(u, v, w + placement.
getWOffset());
212 G4LogicalVolume& envelopeVolume)
215 G4LogicalVolume* top = &topVolume;
216 if (params.getInsideEnvelope()) {
217 top = &envelopeVolume;
221 const double width = params.getWidth();
222 const double length = params.getLength();
223 const double height = params.getHeight();
224 G4Box* shape =
new G4Box(
"radiationSensorDiamond", width / 2 * CLHEP::cm, length / 2 * CLHEP::cm, height / 2 * CLHEP::cm);
228 const std::vector<VXDGeoRadiationSensorsPositionPar>& Positions = params.getPositions();
231 const double r = position.getRadius();
232 const double z = position.getZ();
233 const double theta = position.getTheta();
235 const std::map<int, double>&
Sensors = position.getSensors();
236 for (
const std::pair<const int, double>& sensor :
Sensors) {
239 const double phi = sensor.second;
240 const int id = sensor.first;
242 const std::string name = params.getSubDetector() +
".DiamondSensor." + std::to_string(
id);
244 G4LogicalVolume* volume =
new G4LogicalVolume(shape, material, name);
247 volume->SetSensitiveDetector(sensitive);
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);
261 const double tana = tan(angle);
262 height = min(tana * length, min(tana * width, height));
263 offset = height / tana;
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;
270 if (width2 <= 0 || width == width2) {
272 return new G4Box(name, hwidth, hlength, hheight);
274 return new G4Trd(name, hwidth, hwidth - offset, hlength, hlength - offset, hheight);
279 return new G4Trap(name, hheight, 0, 0, hlength, hwidth, hwidth2, 0, hlength - offset, hwidth - offset, hwidth2 - offset, 0);
283 const G4Transform3D& placement,
289 G4Transform3D ladderPlacement = placement * G4RotateZ3D(phi) * ladderPos *
getAlignment(parameters.getAlignment(ladder));
294 vector<G4Point3D> lastSensorEdge;
296 VxdID sensorID(ladder);
300 std::map<string, VXDGeoSensor>::iterator it =
m_sensorMap.find(p.getSensorTypeID());
302 B2FATAL(
"Invalid SensorTypeID " << p.getSensorTypeID() <<
", please check the definition of " << sensorID);
305 string name =
m_prefix +
"." + (string)sensorID;
310 G4Transform3D reflection;
311 if (p.getFlipU()) reflection = reflection * G4ReflectX3D();
312 if (p.getFlipV()) reflection = reflection * G4ReflectY3D();
313 if (p.getFlipW()) reflection = reflection * G4ReflectZ3D();
315 G4VSolid* sensorShape =
createTrapezoidal(name, s.getWidth() , s.getWidth2() , s.getLength() ,
321 s.setVolume(
new G4LogicalVolume(sensorShape, sensorMaterial, name));
328 G4VSolid* activeShape =
createTrapezoidal(name +
".Active", s.getActiveArea().getWidth(), s.getActiveArea().getWidth2(),
329 s.getActiveArea().getLength(), s.getActiveArea().getHeight());
337 G4LogicalVolume* active =
new G4LogicalVolume(activeShape, sensorMaterial, name +
".Active",
342 setColor(*active, s.getActiveArea().getColor());
346 G4Transform3D activePosition = G4Translate3D(s.getActiveArea().getWidth() / 2.0, s.getActiveArea().getLength() / 2.0, 0) *
347 getPosition(s, s.getActiveArea(), s.getActivePlacement(),
false);
349 G4ReflectionFactory::Instance()->Place(activePosition * reflection, name +
".Active", active, s.getVolume(),
350 false, (
int)sensorID,
false);
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;
360 if (s.getSlanted()) {
364 sensorPlacement = G4Translate3D(0.0, 0.0, p.getZ()) * sensorPlacement;
367 sensorPlacement = ladderPlacement * sensorPlacement;
369 assembly.
add(s.getVolume());
370 assembly.
place(volume, sensorPlacement);
375 double v = s.getLength() / 2.0;
377 std::vector<G4Point3D> curSensorEdge(4);
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);
384 if (lastSensorEdge.size()) {
387 for (
int i = 0; i < 4; ++i) glueOK &= curSensorEdge[i].z() <= lastSensorEdge[i].z();
389 B2WARNING(
"Cannot place Glue at sensor " + (
string)sensorID +
390 " since it overlaps with the last module in z");
393 G4TessellatedSolid* solidTarget =
new G4TessellatedSolid(
m_prefix +
".Glue." + (
string)sensorID);
396 solidTarget->AddFacet(
new G4QuadrangularFacet(
397 curSensorEdge[3], curSensorEdge[2], curSensorEdge[1], curSensorEdge[0], ABSOLUTE));
399 solidTarget->AddFacet(
new G4QuadrangularFacet(
400 lastSensorEdge[0], lastSensorEdge[1], lastSensorEdge[2], lastSensorEdge[3], ABSOLUTE));
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));
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));
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));
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));
423 solidTarget->SetSolidClosed(
true);
426 m_prefix +
".Glue." + (
string)sensorID);
428 new G4PVPlacement(G4Transform3D(), glue,
m_prefix +
".Glue." + (
string)sensorID, volume,
false, 1);
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);
440 return ladderPlacement;
460 sensorInfo.getSensorID(),
461 sensorInfo.getSensorTypeID(),
463 sensorInfo.getFlipU(),
464 sensorInfo.getFlipV(),
465 sensorInfo.getFlipW()
474 VxdID ladder(layerID, ladderID, 0);
477 string path = (boost::format(
"Align[@component='%1%']/") % ladder).str();
480 B2WARNING(
"Could not find alignment parameters for ladder " << ladder);
484 params.getLength(
"dv"),
485 params.getLength(
"dw"),
486 params.getAngle(
"alpha"),
487 params.getAngle(
"beta"),
488 params.getAngle(
"gamma")
494 VxdID sensorID(ladder);
497 std::map<string, VXDGeoSensorPar>::iterator it = vxdGeometryPar.
getSensorMap().find(p.getSensorTypeID());
499 B2FATAL(
"Invalid SensorTypeID " << p.getSensorTypeID() <<
", please check the definition of " << sensorID);
508 string pathSensor = (boost::format(
"Align[@component='%1%']/") % sensorID).str();
511 B2WARNING(
"Could not find alignment parameters for sensorID " << sensorID);
544 string path = (boost::format(
"descendant::Component[@name='%1%']/") % name).str();
545 GearDir params(componentsDir, path);
547 B2FATAL(
"Could not find definition for component " << name);
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)
561 if (c.getWidth() <= 0 || c.getLength() <= 0 || c.getHeight() <= 0) {
562 B2DEBUG(100,
"One dimension empty, using auto resize for component");
569 int chipID = params.getInt(
"activeChipID");
578 string path = (boost::format(
"Ladder[@layer=%1%]/") % layer).str();
579 GearDir paramsLadder(components, path);
581 B2FATAL(
"Could not find Ladder definition for layer " << layer);
588 paramsLadder.
getAngle(
"slantedAngle", 0),
589 paramsLadder.
getLength(
"slantedRadius", 0),
590 paramsLadder.
getLength(
"Glue/oversize", 0),
591 paramsLadder.
getString(
"Glue/Material",
"")
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)
609 vector<VXDGeoPlacementPar> result;
610 for (
const GearDir& component : path.getNodes(
"Component")) {
612 if (!component.exists(
"@type")) {
613 type = component.getString(
"@name");
615 type = component.getString(
"@type");
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();
624 component.getLength(
"u" + index, 0),
625 component.getLength(
"v" + index, 0),
626 component.getString(
"w" + index,
"bottom"),
627 component.getLength(
"woffset" + index, 0)