static DD4hep::Geometry::Ref_t createCaloDiscs(DD4hep::Geometry::LCDD& aLcdd, DD4hep::XML::Handle_t aXmlElement, DD4hep::Geometry::SensitiveDetector aSensDet) { ServiceHandle<IMessageSvc> msgSvc("MessageSvc", "CalDiscsConstruction"); MsgStream lLog(&(*msgSvc), "CalDiscsConstruction"); DD4hep::XML::DetElement xmlDetElem = aXmlElement; std::string nameDet = xmlDetElem.nameStr(); int idDet = xmlDetElem.id(); DD4hep::XML::Dimension dim(xmlDetElem.dimensions()); DD4hep::Geometry::DetElement caloDetElem(nameDet, idDet); // Create air envelope for the whole endcap DD4hep::Geometry::Cone envelopePositive(dim.dz(), dim.rmin1(), dim.rmax(), dim.rmin2(), dim.rmax()); DD4hep::Geometry::Cone envelopeNegative(dim.dz(), dim.rmin2(), dim.rmax(), dim.rmin1(), dim.rmax()); DD4hep::Geometry::UnionSolid envelopeShape(envelopePositive, envelopeNegative, DD4hep::Geometry::Position(0, 0, -2 * dim.z_offset())); DD4hep::Geometry::Volume envelopeVol(nameDet + "_vol", envelopeShape, aLcdd.material("Air")); DD4hep::Geometry::Volume envelopePositiveVol(nameDet + "_positive_vol", envelopePositive, aLcdd.material("Air")); DD4hep::Geometry::Volume envelopeNegativeVol(nameDet + "_negative_vol", envelopeNegative, aLcdd.material("Air")); lLog << MSG::DEBUG << "Placing dector on the positive side: (cm) " << dim.z_offset() << endmsg; buildOneSide(lLog, aLcdd, aSensDet, envelopePositiveVol, aXmlElement, 1); lLog << MSG::DEBUG << "Placing dector on the negative side: (cm) " << -dim.z_offset() << endmsg; buildOneSide(lLog, aLcdd, aSensDet, envelopeNegativeVol, aXmlElement, -1); // Place the envelope DD4hep::Geometry::PlacedVolume envelopePositivePhysVol = envelopeVol.placeVolume(envelopePositiveVol); envelopePositivePhysVol.addPhysVolID("subsystem", 0); DD4hep::Geometry::DetElement caloPositiveDetElem(caloDetElem, "positive", 0); caloPositiveDetElem.setPlacement(envelopePositivePhysVol); DD4hep::Geometry::PlacedVolume envelopeNegativePhysVol = envelopeVol.placeVolume(envelopeNegativeVol, DD4hep::Geometry::Position(0, 0, -2 * dim.z_offset())); envelopeNegativePhysVol.addPhysVolID("subsystem", 1); DD4hep::Geometry::DetElement caloNegativeDetElem(caloDetElem, "negative", 0); caloNegativeDetElem.setPlacement(envelopeNegativePhysVol); DD4hep::Geometry::Volume motherVol = aLcdd.pickMotherVolume(caloDetElem); DD4hep::Geometry::PlacedVolume envelopePhysVol = motherVol.placeVolume(envelopeVol, DD4hep::Geometry::Position(0., 0., dim.z_offset())); caloDetElem.setPlacement(envelopePhysVol); envelopePhysVol.addPhysVolID("system", idDet); return caloDetElem; }
static DD4hep::Geometry::Ref_t createHCal ( DD4hep::Geometry::LCDD& lcdd, xml_h xmlElement, DD4hep::Geometry::SensitiveDetector sensDet ) { // Get the Gaudi message service and message stream: ServiceHandle<IMessageSvc> msgSvc("MessageSvc", "HCalConstruction"); MsgStream lLog(&(*msgSvc), "HCalConstruction"); xml_det_t xmlDet = xmlElement; std::string detName = xmlDet.nameStr(); //Make DetElement DetElement hCal(detName, xmlDet.id()); // Get status for the RecoGeometry what is status? // xml_comp_t xmlStatus = xmlDet.child(_U(status)); // int status = xmlStatus.id(); // add Extension to Detlement for the RecoGeometry // Let's skip this for now... // Det::DetCylinderVolume* detVolume = new Det::DetCylinderVolume(status); // hCal.addExtension<Det::IDetExtension>(detVolume); // Make volume that envelopes the whole barrel; set material to air Dimension dimensions(xmlDet.dimensions()); DD4hep::Geometry::Tube envelopeShape(dimensions.rmin(), dimensions.rmax(), dimensions.dz()); Volume envelopeVolume(detName, envelopeShape, lcdd.air()); // Invisibility seems to be broken in visualisation tags, have to hardcode that // envelopeVolume.setVisAttributes(lcdd, dimensions.visStr()); envelopeVolume.setVisAttributes(lcdd.invisible()); // set the sensitive detector type to the DD4hep calorimeter sensDet.setType("SimpleCalorimeterSD"); // Add structural support made of steel inside of HCal xml_comp_t xFacePlate = xmlElement.child("face_plate"); double dRhoFacePlate = xFacePlate.thickness(); double sensitiveBarrelRmin = dimensions.rmin() + dRhoFacePlate; DetElement facePlate("facePlate", 0); DD4hep::Geometry::Tube facePlateShape(dimensions.rmin(), sensitiveBarrelRmin, dimensions.dz()); Volume facePlateVol("facePlate", facePlateShape, lcdd.material(xFacePlate.materialStr())); facePlateVol.setVisAttributes(lcdd, xFacePlate.visStr()); PlacedVolume placedFacePlate = envelopeVolume.placeVolume(facePlateVol); placedFacePlate.addPhysVolID("facePlate", facePlate.id()); facePlate.setPlacement(placedFacePlate); // Add structural support made of steel at both ends of HCal xml_comp_t xEndPlate = xmlElement.child("end_plate"); double dZEndPlate = xEndPlate.thickness(); DD4hep::Geometry::Tube endPlateShape(dimensions.rmin(), dimensions.rmax(), dZEndPlate); Volume endPlateVol("endPlate", endPlateShape, lcdd.material(xEndPlate.materialStr())); endPlateVol.setVisAttributes(lcdd, xEndPlate.visStr()); DetElement endPlatePos("endPlate", 0); DD4hep::Geometry::Position posOffset(0, 0, dimensions.dz() - dZEndPlate); PlacedVolume placedEndPlatePos = envelopeVolume.placeVolume(endPlateVol, posOffset); placedEndPlatePos.addPhysVolID("endPlatePos", endPlatePos.id()); endPlatePos.setPlacement(placedEndPlatePos); DetElement endPlateNeg("endPlate", 1); DD4hep::Geometry::Position negOffset(0, 0, -dimensions.dz() + dZEndPlate); PlacedVolume placedEndPlateNeg = envelopeVolume.placeVolume(endPlateVol, negOffset); placedEndPlateNeg.addPhysVolID("endPlateNeg", endPlateNeg.id()); endPlateNeg.setPlacement(placedEndPlateNeg); // Hard-coded assumption that we have two different sequences for the modules std::vector<xml_comp_t> sequences = {xmlElement.child("sequence_a"), xmlElement.child("sequence_b")}; // NOTE: This assumes that both have the same dimensions! Dimension moduleDimensions(sequences[0].dimensions()); double dzModule = moduleDimensions.dz(); // calculate the number of modules fitting in phi, Z and Rho unsigned int numModulesPhi = moduleDimensions.phiBins(); unsigned int numModulesZ = static_cast<unsigned>(dimensions.dz() / dzModule); unsigned int numModulesR = static_cast<unsigned>((dimensions.rmax() - sensitiveBarrelRmin) / moduleDimensions.dr()); lLog << MSG::DEBUG << "constructing " << numModulesPhi << " modules per ring in phi, " << numModulesZ << " rings in Z, " << numModulesR << " rings (layers) in Rho" << numModulesR*numModulesZ*numModulesPhi << " modules" << endmsg; // Calculate correction along z based on the module size (can only have natural number of modules) double dzDetector = numModulesZ * dzModule + dZEndPlate; lLog << MSG::INFO << "correction of dz:" << dimensions.dz() - dzDetector << endmsg; // calculate the dimensions of one module: double dphi = 2 * dd4hep::pi / static_cast<double>(numModulesPhi); double tn = tan(dphi / 2.); double spacing = moduleDimensions.x(); double dy0 = moduleDimensions.dz(); double dz0 = moduleDimensions.dr() / 2.; double drWedge = cos(dphi / 2.) * (dimensions.rmax() - sensitiveBarrelRmin) * 0.5; double dxWedge1 = tn * sensitiveBarrelRmin - spacing; double dxWedge2 = tn * cos(dphi / 2.) * dimensions.rmax() - spacing; // First we construct one wedge with width of one module: Volume subWedgeVolume("subWedge", DD4hep::Geometry::Trapezoid( dxWedge1, dxWedge2, dzModule, dzModule, drWedge ), lcdd.material("Air") ); for (unsigned int idxLayer = 0; idxLayer < numModulesR; ++idxLayer) { auto layerName = std::string("wedge") + DD4hep::XML::_toString(idxLayer, "layer%d"); unsigned int sequenceIdx = idxLayer % 2; double rminLayer = idxLayer * moduleDimensions.dr(); double rmaxLayer = (idxLayer + 1) * cos(dphi / 2.) * moduleDimensions.dr(); double dx1 = tn * (rminLayer + sensitiveBarrelRmin) - spacing; double dx2 = tn * cos(dphi / 2.) * (rmaxLayer + sensitiveBarrelRmin) - spacing; // -drWedge to place it in the middle of the wedge-volume double rMiddle = rminLayer + 0.5 * moduleDimensions.dr() - drWedge; Volume moduleVolume(layerName, DD4hep::Geometry::Trapezoid( dx1, dx2, dy0, dy0, dz0 ), lcdd.material("Air") ); moduleVolume.setVisAttributes(lcdd.invisible()); unsigned int idxSubMod = 0; // DetElement moduleDet(wedgeDet, layerName, idxLayer); double modCompZOffset = -moduleDimensions.dz(); for (xml_coll_t xCompColl(sequences[sequenceIdx], _U(module_component)); xCompColl; ++xCompColl, ++idxSubMod) { xml_comp_t xComp = xCompColl; std::string subModuleName = layerName+DD4hep::XML::_toString(idxSubMod, "module_component%d"); double dyComp = xComp.thickness(); Volume modCompVol(subModuleName, DD4hep::Geometry::Trapezoid( dx1, dx2, dyComp, dyComp, dz0 ), lcdd.material(xComp.materialStr()) ); if (xComp.isSensitive()) { modCompVol.setSensitiveDetector(sensDet); } modCompVol.setVisAttributes(lcdd, xComp.visStr()); // modCompVol.setVisAttributes(lcdd.invisible()); // DetElement modCompDet(wedgeDet, subModuleName, idxSubMod); DD4hep::Geometry::Position offset(0, modCompZOffset + dyComp + xComp.y_offset()*2, 0); PlacedVolume placedModCompVol = moduleVolume.placeVolume(modCompVol, offset); placedModCompVol.addPhysVolID("sub_module", idxSubMod); // modCompDet.setPlacement(placedModCompVol); modCompZOffset += xComp.thickness()*2 + xComp.y_offset()*2; } DD4hep::Geometry::Position modOffset(0, 0, rMiddle); PlacedVolume placedModuleVol = subWedgeVolume.placeVolume(moduleVolume, modOffset); placedModuleVol.addPhysVolID("layer", idxLayer); // moduleDet.setPlacement(placedModuleVol); } // Now we place the components along z within the wedge Volume wedgeVolume("wedge", DD4hep::Geometry::Trapezoid( dxWedge1, dxWedge2, dzDetector, dzDetector, drWedge ), lcdd.material("Air") ); wedgeVolume.setVisAttributes(lcdd.invisible()); for (unsigned int idxZRow = 0; idxZRow < numModulesZ; ++idxZRow) { double zOffset = -dzDetector + dZEndPlate * 2 + (2*idxZRow + 1) * dzModule; auto wedgeRowName = DD4hep::XML::_toString(idxZRow, "row%d"); DD4hep::Geometry::Position wedgeOffset(0, zOffset, 0); PlacedVolume placedRowVolume = wedgeVolume.placeVolume(subWedgeVolume, wedgeOffset); placedRowVolume.addPhysVolID("row", idxZRow); // wedgeDet.setPlacement(placedWedgeVol); } // Finally we place all the wedges around phi for (unsigned int idxPhi = 0; idxPhi < numModulesPhi; ++idxPhi) { auto modName = DD4hep::XML::_toString(idxPhi, "mod%d"); // Volume and DetElement for one row in Z DetElement wedgeDet(hCal, modName, idxPhi); // moduleVolume.setVisAttributes(lcdd, sequences[sequenceIdx].visStr()); // moduleVolume.setVisAttributes(lcdd.invisible()); // calculate position and rotation of this wedge; // first rotation due to default rotation of trapezoid double phi = 0.5 * dphi - idxPhi * dphi; // 0.5*dphi for middle of module double yPosModule = (sensitiveBarrelRmin + drWedge) * cos(phi); double xPosModule = (sensitiveBarrelRmin + drWedge) * sin(phi); DD4hep::Geometry::Position moduleOffset(xPosModule, yPosModule, 0); DD4hep::Geometry::Transform3D trans( DD4hep::Geometry::RotationX(-0.5*dd4hep::pi)* DD4hep::Geometry::RotationY(phi), moduleOffset ); PlacedVolume placedWedgeVol = envelopeVolume.placeVolume(wedgeVolume, trans); placedWedgeVol.addPhysVolID("wedge", idxPhi); wedgeDet.setPlacement(placedWedgeVol); } //Place envelope (or barrel) volume Volume motherVol = lcdd.pickMotherVolume(hCal); PlacedVolume placedHCal = motherVol.placeVolume(envelopeVolume); placedHCal.addPhysVolID("system", hCal.id()); hCal.setPlacement(placedHCal); return hCal; }