12 #include <pxd/geometry/GeoPXDCreator.h>
13 #include <vxd/geometry/GeoCache.h>
14 #include <pxd/geometry/SensorInfo.h>
15 #include <pxd/simulation/SensitiveDetector.h>
17 #include <simulation/background/BkgSensitiveDetector.h>
19 #include <geometry/Materials.h>
20 #include <geometry/CreatorFactory.h>
21 #include <geometry/utilities.h>
22 #include <framework/gearbox/GearDir.h>
23 #include <framework/gearbox/Unit.h>
24 #include <framework/logging/Logger.h>
27 #include <boost/format.hpp>
29 #include <G4LogicalVolume.hh>
30 #include <G4PVPlacement.hh>
35 #include <G4Polycone.hh>
36 #include <G4SubtractionSolid.hh>
37 #include <G4Region.hh>
40 using namespace boost;
47 using namespace geometry;
52 geometry::CreatorFactory<GeoPXDCreator>
GeoPXDFactory(
"PXDCreator");
54 GeoPXDCreator::~GeoPXDCreator()
56 for (
SensorInfo* sensorInfo : m_SensorInfo)
delete sensorInfo;
75 info->setDEPFETParams(
90 info->setIntegrationWindow(
95 m_SensorInfo.push_back(info);
103 sensor.getLength(
"width"),
104 sensor.getLength(
"length"),
105 sensor.getLength(
"height"),
106 sensor.getInt(
"pixelsU"),
107 sensor.getInt(
"pixelsV[1]"),
108 sensor.getLength(
"splitLength", 0),
109 sensor.getInt(
"pixelsV[2]", 0)
112 info->setDEPFETParams(
113 sensor.getDouble(
"BulkDoping"),
114 sensor.getWithUnit(
"BackVoltage"),
115 sensor.getWithUnit(
"TopVoltage"),
116 sensor.getLength(
"SourceBorderSmallPixel"),
117 sensor.getLength(
"ClearBorderSmallPixel"),
118 sensor.getLength(
"DrainBorderSmallPixel"),
119 sensor.getLength(
"SourceBorderLargePixel"),
120 sensor.getLength(
"ClearBorderLargePixel"),
121 sensor.getLength(
"DrainBorderLargePixel"),
122 sensor.getLength(
"GateDepth"),
123 sensor.getBool(
"DoublePixel"),
124 sensor.getDouble(
"ChargeThreshold"),
125 sensor.getDouble(
"NoiseFraction")
127 info->setIntegrationWindow(
128 sensor.getTime(
"IntegrationStart"),
129 sensor.getTime(
"IntegrationEnd")
144 VXDGlobalPar globals((
float)content.getDouble(
"ElectronTolerance", 100),
145 (
float)content.getDouble(
"MinimumElectrons", 10),
146 content.getLength(
"ActiveStepSize", 0.005),
147 content.getBool(
"ActiveChips",
false),
148 content.getBool(
"SeeNeutrons",
false),
149 content.getBool(
"OnlyPrimaryTrueHits",
false),
150 content.getBool(
"OnlyActiveMaterial",
false),
151 (
float)content.getLength(
"DistanceTolerance", 0.005),
152 content.getString(
"DefaultMaterial",
"Air")
157 GearDir envelopeParams(content,
"Envelope/");
159 envelopeParams.
getString(
"Material",
"Air"),
161 envelopeParams.
getAngle(
"minPhi", 0),
162 envelopeParams.
getAngle(
"maxPhi", 2 * M_PI),
163 (envelopeParams.
getNodes(
"InnerPoints/point").size() > 0)
166 for (
const GearDir point : envelopeParams.
getNodes(
"InnerPoints/point")) {
167 pair<double, double> ZXPoint(point.getLength(
"z"), point.getLength(
"x"));
170 for (
const GearDir point : envelopeParams.
getNodes(
"OuterPoints/point")) {
171 pair<double, double> ZXPoint(point.getLength(
"z"), point.getLength(
"x"));
177 string pathAlign = (boost::format(
"Align[@component='%1%']/") % m_prefix).str();
180 B2WARNING(
"Could not find alignment parameters for component " << m_prefix);
181 return pxdGeometryPar;
192 GearDir components(content,
"Components/");
193 for (
const GearDir& paramsSensor : components.getNodes(
"Sensor")) {
194 string sensorTypeID = paramsSensor.getString(
"@type");
197 paramsSensor.getString(
"Color",
""),
198 paramsSensor.getLength(
"width"),
199 paramsSensor.getLength(
"width2", 0),
200 paramsSensor.getLength(
"length"),
201 paramsSensor.getLength(
"height"),
202 paramsSensor.getAngle(
"angle", 0),
203 paramsSensor.getBool(
"@slanted",
false)
206 paramsSensor.getString(
"Material"),
207 paramsSensor.getString(
"Active/Color",
"#f00"),
208 paramsSensor.getLength(
"Active/width"),
209 paramsSensor.getLength(
"Active/width2", 0),
210 paramsSensor.getLength(
"Active/length"),
211 paramsSensor.getLength(
"Active/height")
214 paramsSensor.getLength(
"Active/u"),
215 paramsSensor.getLength(
"Active/v"),
216 paramsSensor.getString(
"Active/w",
"center"),
217 paramsSensor.getLength(
"Active/woffset", 0)
221 sensor.setSensorInfo(pxdInfo);
222 sensor.setComponents(getSubComponents(paramsSensor));
228 GearDir support(content,
"Support/");
229 readHalfShellSupport(support, pxdGeometryPar);
231 for (
const GearDir& shell : content.getNodes(
"HalfShell")) {
233 string shellName = m_prefix +
"." + shell.getString(
"@name");
234 string pathShell = (boost::format(
"Align[@component='%1%']/") % shellName).str();
237 B2WARNING(
"Could not find alignment parameters for component " << shellName);
238 return pxdGeometryPar;
248 VXDHalfShellPar halfShell(shell.getString(
"@name") , shell.getAngle(
"shellAngle", 0));
250 for (
const GearDir& layer : shell.getNodes(
"Layer")) {
251 int layerID = layer.getInt(
"@id");
253 readLadder(layerID, components, pxdGeometryPar);
256 for (
const GearDir& ladder : layer.getNodes(
"Ladder")) {
257 int ladderID = ladder.getInt(
"@id");
258 double phi = ladder.getAngle(
"phi", 0);
259 readLadderComponents(layerID, ladderID, content, pxdGeometryPar);
260 halfShell.
addLadder(layerID, ladderID, phi);
267 GearDir radiationDir(content,
"RadiationSensors");
271 radiationDir.
getBool(
"insideEnvelope"),
281 position.getLength(
"radius"),
282 position.getAngle(
"theta")
286 for (
GearDir& sensor : position.getNodes(
"phi")) {
288 diamonds.
addSensor(sensor.getInt(
"@id"), sensor.getAngle());
295 return pxdGeometryPar;
302 endflange.getString(
"@name"),
303 endflange.getString(
"Material",
"Air"),
304 endflange.getAngle(
"minPhi", 0),
305 endflange.getAngle(
"maxPhi", 2 * M_PI),
306 (endflange.getNodes(
"Cutout").size() > 0),
307 endflange.getLength(
"Cutout/width", 0.),
308 endflange.getLength(
"Cutout/height", 0.),
309 endflange.getLength(
"Cutout/depth", 0.)
312 for (
const GearDir& plane : endflange.getNodes(
"Plane")) {
314 plane.getLength(
"posZ"),
315 plane.getLength(
"innerRadius"),
316 plane.getLength(
"outerRadius")
318 endflangePar.
getPlanes().push_back(planePar);
349 m_activeStepSize = parameters.getGlobalParams().getActiveStepSize() / Unit::mm;
350 m_activeChips = parameters.getGlobalParams().getActiveChips();
351 m_seeNeutrons = parameters.getGlobalParams().getSeeNeutrons();
352 m_onlyPrimaryTrueHits = parameters.getGlobalParams().getOnlyPrimaryTrueHits();
353 m_distanceTolerance = parameters.getGlobalParams().getDistanceTolerance();
354 m_electronTolerance = parameters.getGlobalParams().getElectronTolerance();
355 m_minimumElectrons = parameters.getGlobalParams().getMinimumElectrons();
356 m_onlyActiveMaterial = parameters.getGlobalParams().getOnlyActiveMaterial();
357 m_defaultMaterial = parameters.getGlobalParams().getDefaultMaterial();
359 G4Material* material = Materials::get(m_defaultMaterial);
360 if (!material) B2FATAL(
"Default Material of VXD, '" << m_defaultMaterial <<
"', could not be found");
364 G4LogicalVolume* envelope(0);
365 G4VPhysicalVolume* physEnvelope{
nullptr};
366 if (!parameters.getEnvelope().getExists()) {
367 B2INFO(
"Could not find definition for " + m_prefix +
" Envelope, placing directly in top volume");
368 envelope = &topVolume;
370 double minZ(0), maxZ(0);
371 G4Polycone* envelopeCone = geometry::createRotationSolid(
"Envelope",
372 parameters.getEnvelope().getInnerPoints(),
373 parameters.getEnvelope().getOuterPoints(),
374 parameters.getEnvelope().getMinPhi(),
375 parameters.getEnvelope().getMaxPhi(),
378 envelope =
new G4LogicalVolume(envelopeCone, material, m_prefix +
".Envelope");
380 physEnvelope =
new G4PVPlacement(getAlignment(parameters.getAlignment(m_prefix)), envelope, m_prefix +
".Envelope",
381 &topVolume,
false, 1);
384 G4Region* aRegion =
new G4Region(
"PXDEnvelope");
385 envelope->SetRegion(aRegion);
386 aRegion->AddRootLogicalVolume(envelope);
390 for (
const pair<const string, VXDGeoSensorPar>& typeAndSensor : parameters.getSensorMap()) {
391 const string& sensorTypeID = typeAndSensor.first;
416 sensor.setSensorInfo(createSensorInfo(paramsSensor));
418 vector<VXDGeoPlacement> subcomponents;
420 subcomponents.reserve(components.size());
421 std::transform(components.begin(), components.end(), std::back_inserter(subcomponents),
422 [](
auto const & component) {
423 return VXDGeoPlacement(component.getName(),
424 component.getU() / Unit::mm,
425 component.getV() / Unit::mm,
427 component.getWOffset() / Unit::mm
430 sensor.setComponents(subcomponents);
431 m_sensorMap[sensorTypeID] = sensor;
435 for (
const string& name : parameters.getComponentInsertOder()) {
436 if (m_componentCache.find(name) != m_componentCache.end()) {
441 B2WARNING(
"Component " << name <<
" already created from previous subcomponents, should not be here");
448 paramsComponent.
getWidth() / Unit::mm,
453 double angle = paramsComponent.
getAngle();
456 if (c.getWidth() <= 0 || c.getLength() <= 0 || c.getHeight() <= 0) {
457 B2DEBUG(100,
"One dimension empty, using auto resize for component");
459 G4VSolid* solid = createTrapezoidal(m_prefix +
"." + name, c.getWidth(), c.getWidth2(), c.getLength(), c.getHeight(), angle);
460 c.setVolume(
new G4LogicalVolume(solid, Materials::get(c.getMaterial()), m_prefix +
"." + name));
463 vector<VXDGeoPlacement> subComponents;
465 subComponents.reserve(paramsSubComponents.size());
466 std::transform(paramsSubComponents.begin(), paramsSubComponents.end(), std::back_inserter(subComponents),
467 [](
auto const & paramsSubComponent) {
468 return VXDGeoPlacement(paramsSubComponent.getName(),
469 paramsSubComponent.getU() / Unit::mm,
470 paramsSubComponent.getV() / Unit::mm,
471 paramsSubComponent.getW(),
472 paramsSubComponent.getWOffset() / Unit::mm
475 createSubComponents(m_prefix +
"." + name, c, subComponents);
476 if (m_activeChips && parameters.getSensitiveChipID(name) >= 0) {
477 int chipID = parameters.getSensitiveChipID(name);
478 B2DEBUG(50,
"Creating BkgSensitiveDetector for component " << name <<
" with chipID " << chipID);
480 c.getVolume()->SetSensitiveDetector(sensitive);
481 m_sensitive.push_back(sensitive);
484 m_componentCache[name] = c;
492 string shellName = shell.getName();
493 m_currentHalfShell = m_prefix +
"." + shellName;
494 G4Transform3D shellAlignment = getAlignment(parameters.getAlignment(m_currentHalfShell));
497 VXD::GeoCache::getInstance().addHalfShellPlacement(m_halfShellVxdIDs[m_currentHalfShell], shellAlignment);
500 double shellAngle = shell.getShellAngle();
501 if (!m_onlyActiveMaterial) shellSupport.
place(envelope, shellAlignment * G4RotateZ3D(shellAngle));
504 for (
const std::pair<
const int, std::vector<std::pair<int, double>> >& layer : shell.getLayers()) {
505 int layerID = layer.first;
506 const std::vector<std::pair<int, double>>& Ladders = layer.second;
509 setCurrentLayer(layerID, parameters);
513 if (!m_onlyActiveMaterial) layerSupport.
place(envelope, shellAlignment * G4RotateZ3D(shellAngle));
517 for (
const std::pair<int, double>& ladder : Ladders) {
518 int ladderID = ladder.first;
519 double phi = ladder.second;
521 G4Transform3D ladderPlacement = placeLadder(ladderID, phi, envelope, shellAlignment, parameters);
522 if (!m_onlyActiveMaterial) ladderSupport.
place(envelope, ladderPlacement);
530 VXD::GeoCache::getInstance().findVolumes(physEnvelope);
533 G4PVPlacement topPlacement(
nullptr, G4ThreeVector(0, 0, 0), &topVolume,
534 "temp_Top",
nullptr,
false, 1,
false);
536 VXD::GeoCache::getInstance().findVolumes(&topPlacement);
541 if (parameters.getRadiationSensors().getSubDetector() ==
"") {
542 B2DEBUG(10,
"Apparently no radiation sensors defined, skipping");
544 createDiamonds(parameters.getRadiationSensors(), topVolume, *envelope);
553 sensorInfo->
setID(sensorID);
567 if (!parameters.getBuildSupport())
return supportAssembly;
571 const std::vector<VXDPolyConePar> Endflanges = parameters.getEndflanges();
574 double minZ(0), maxZ(0);
575 string name = endflange.getName();
578 double minPhi = endflange.getMinPhi();
579 double dPhi = endflange.getMaxPhi() - minPhi;
580 int nPlanes = endflange.getPlanes().size();
582 B2ERROR(
"Polycone needs at least two planes");
583 return supportAssembly;
585 std::vector<double> z(nPlanes, 0);
586 std::vector<double> rMin(nPlanes, 0);
587 std::vector<double> rMax(nPlanes, 0);
589 minZ = numeric_limits<double>::infinity();
590 maxZ = -numeric_limits<double>::infinity();
592 const std::vector<VXDPolyConePlanePar> Planes = endflange.getPlanes();
594 z[index] = plane.getPosZ() / Unit::mm;
595 minZ = min(minZ, z[index]);
596 maxZ = max(maxZ, z[index]);
597 rMin[index] = plane.getInnerRadius() / Unit::mm;
598 rMax[index] = plane.getOuterRadius() / Unit::mm;
602 G4VSolid* supportCone =
new G4Polycone(name, minPhi, dPhi, nPlanes, z.data(), rMin.data(), rMax.data());
610 minZ -= 1. / Unit::mm;
611 maxZ += 1. / Unit::mm;
615 int nCutouts = parameters.getNCutOuts();
616 double sizeX = parameters.getCutOutWidth() / Unit::mm / 2.;
617 double sizeY = parameters.getCutOutHeight() / Unit::mm / 2.;
618 double sizeZ = (maxZ - minZ) / 2.;
619 G4ThreeVector origin(
620 parameters.getCutOutShift() / Unit::mm,
621 parameters.getCutOutRPhi() / Unit::mm,
625 double phi0 = parameters.getCutOutStartPhi();
626 double dphi = parameters.getCutOutDeltaPhi();
627 for (
int i = 0; i < nCutouts; ++i) {
628 G4Box* box =
new G4Box(
"Cutout", sizeX, sizeY, sizeZ);
629 G4Transform3D placement = G4RotateZ3D(phi0 + i * dphi) * G4Translate3D(origin);
630 supportCone =
new G4SubtractionSolid(
"PXD Support endflange", supportCone, box, placement);
634 string materialName = endflange.getMaterial();
635 G4Material* material = geometry::Materials::get(materialName);
636 if (!material) B2FATAL(
"Material '" << materialName <<
"', required by PXD component " << name <<
", could not be found");
638 G4LogicalVolume* volume =
new G4LogicalVolume(supportCone, material, name);
639 geometry::setColor(*volume,
"#ccc4");
640 supportAssembly.
add(volume);
647 int nTubes = parameters.getNTubes();
648 double minZ = parameters.getTubesMinZ() / Unit::mm;
649 double maxZ = parameters.getTubesMaxZ() / Unit::mm;
650 double minR = parameters.getTubesMinR() / Unit::mm;
651 double maxR = parameters.getTubesMaxR() / Unit::mm;
652 double sizeZ = (maxZ - minZ) / 2.;
653 double shiftX = parameters.getTubesRPhi() / Unit::mm;
655 double shiftZ = minZ + sizeZ;
656 double phi0 = parameters.getTubesStartPhi();
657 double dphi = parameters.getTubesDeltaPhi();
658 string material = parameters.getTubesMaterial();
660 G4Tubs* tube =
new G4Tubs(
"CarbonTube", minR, maxR, sizeZ, 0, 2 * M_PI);
661 G4LogicalVolume* tubeVol =
new G4LogicalVolume(tube, geometry::Materials::get(material),
"CarbonTube");
662 geometry::setColor(*tubeVol,
"#000");
663 for (
int i = 0; i < nTubes; ++i) {
664 G4Transform3D placement = G4RotateZ3D(phi0 + i * dphi) * G4Translate3D(shiftX, shiftY, shiftZ);
665 supportAssembly.
add(tubeVol, placement);
669 return supportAssembly;