/// Access the placement of a node in the chain of placements for this branch PlacedVolume GlobalAlignment::nodePlacement(int level) const { CheckHandle verify_handle(*this); PlacedVolume pv = PlacedVolume(ptr()->GetNode(level)); if ( pv.isValid() ) return pv; throw runtime_error("DD4hep: The object chain of "+string(placement().name())+ " is too short. [Invalid index]"); }
static void placeStaves(DetElement& parent, DetElement& stave, double rmin, int numsides, double total_thickness, Volume envelopeVolume, double innerAngle, Volume sectVolume) { double innerRotation = innerAngle; double offsetRotation = -innerRotation / 2; double sectCenterRadius = rmin + total_thickness / 2; double rotX = M_PI / 2; double rotY = -offsetRotation; double posX = -sectCenterRadius * std::sin(rotY); double posY = sectCenterRadius * std::cos(rotY); for (int module = 1; module <= numsides; ++module) { DetElement det = module>1 ? stave.clone(_toString(module,"stave%d")) : stave; PlacedVolume pv = envelopeVolume.placeVolume(sectVolume,Transform3D(RotationZYX(0,rotY,rotX), Translation3D(-posX,-posY,0))); // Not a valid volID: pv.addPhysVolID("stave", 0); pv.addPhysVolID("module",module); det.setPlacement(pv); parent.add(det); rotY -= innerRotation; posX = -sectCenterRadius * std::sin(rotY); posY = sectCenterRadius * std::cos(rotY); } }
static long dump(DetElement de,int level, bool sensitive_only) { const DetElement::Children& c = de.children(); if ( !sensitive_only || 0 != de.volumeID() ) { PlacedVolume place = de.placement(); const TGeoNode* node = place.ptr(); char sens = place.volume().isSensitive() ? 'S' : ' '; int value = flag; char fmt[128]; switch(value) { case 0: ::snprintf(fmt,sizeof(fmt),"%03d %%-%ds %%s #Dau:%%d VolID:%%08X Place:%%p %%c",level+1,2*level+1); printout(INFO,"DetectorDump",fmt,"",de.path().c_str(),int(c.size()), (unsigned long)de.volumeID(), (void*)node, sens); break; case 1: ::snprintf(fmt,sizeof(fmt),"%03d %%-%ds Detector: %%s #Dau:%%d VolID:%%p",level+1,2*level+1); printout(INFO,"DetectorDump", fmt, "", de.path().c_str(), int(c.size()), (void*)de.volumeID()); ::snprintf(fmt,sizeof(fmt),"%03d %%-%ds Placement: %%s %%c",level+1,2*level+3); printout(INFO,"DetectorDump",fmt,"", de.placementPath().c_str(), sens); break; default: break; } } for (DetElement::Children::const_iterator i = c.begin(); i != c.end(); ++i) dump((*i).second,level+1,sensitive_only); return 1; }
static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector sens) { xml_det_t x_det = e; xml_dim_t dim = x_det.dimensions(); Material air = description.air(); string det_name = x_det.nameStr(); DetElement sdet (det_name,x_det.id()); double z = dim.outer_z(); double rmin = dim.inner_r(); double r = rmin; int n = 0; Tube envelope(rmin,2*rmin,2*z); Volume envelopeVol(det_name+"_envelope",envelope,air); for(xml_coll_t c(x_det,_U(layer)); c; ++c) { xml_comp_t x_layer = c; for(int i=0, im=0, repeat=x_layer.repeat(); i<repeat; ++i, im=0) { string layer_name = det_name + _toString(n,"_layer%d"); double rlayer = r; Tube layer_tub(rmin,rlayer,2*z); Volume layer_vol(layer_name,layer_tub,air); for(xml_coll_t l(x_layer,_U(slice)); l; ++l, ++im) { xml_comp_t x_slice = l; double router = r + x_slice.thickness(); Material slice_mat = description.material(x_slice.materialStr()); string slice_name = layer_name + _toString(im,"slice%d"); Tube slice_tube(r,router,z*2); Volume slice_vol (slice_name,slice_tube,slice_mat); if ( x_slice.isSensitive() ) { sens.setType("calorimeter"); slice_vol.setSensitiveDetector(sens); } r = router; slice_vol.setAttributes(description,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr()); // Instantiate physical volume layer_vol.placeVolume(slice_vol); } layer_vol.setVisAttributes(description,x_layer.visStr()); layer_tub.setDimensions(rlayer,r,z*2,0,2*M_PI); PlacedVolume layer_physvol = envelopeVol.placeVolume(layer_vol); layer_physvol.addPhysVolID("layer",n); ++n; } } envelope.setDimensions(rmin,r,2*z); // Set region of slice envelopeVol.setAttributes(description,x_det.regionStr(),x_det.limitsStr(),x_det.visStr()); PlacedVolume physvol = description.pickMotherVolume(sdet).placeVolume(envelopeVol); physvol.addPhysVolID("system",sdet.id()).addPhysVolID(_U(barrel),0); sdet.setPlacement(physvol); return sdet; }
/// Callback to output PlacedVolume information of an single Placement int VisMaterialProcessor::operator()(PlacedVolume pv, int /* level */) { Volume vol = pv.volume(); double frac_active = 0.0; VisAttr attr; for ( Atom atom : activeElements ) { frac_active += vol.material().fraction(atom); } //if ( frac_active >= fraction ) printout(DEBUG,name, "++ Volume:%s [%s] active:%s fraction:%.3f active-vis:%s inactive-vis:%s", pv.name(), vol.name(), yes_no(frac_active >= fraction), frac_active, yes_no(activeVis.isValid()), yes_no(inactiveVis.isValid())); if ( activeVis.isValid() ) { if ( frac_active >= fraction ) { attr = activeVis; ++numActive; } if ( !attr.isValid() ) { for ( Material mat : activeMaterials ) { if ( mat.ptr() == vol.material().ptr() ) { attr = activeVis; ++numActive; break; } } } } // If we get here, the material is definitely inactive if ( inactiveVis.isValid() ) { if ( !attr.isValid() && setAllInactive ) { attr = inactiveVis; ++numInactive; } else if ( frac_active<fraction ) { attr = inactiveVis; ++numInactive; } if ( !attr.isValid() && inactiveVis.isValid() ) { for ( Material imat : inactiveMaterials ) { if ( imat.ptr() == vol.material().ptr() ) { attr = inactiveVis; ++numInactive; break; } } } } if ( attr.isValid() ) { set_attr(vol,attr); } return 1; }
/// Dump method. virtual int operator()(DetElement de,int level) const { const DetElement::Children& children = de.children(); PlacedVolume place = de.placement(); char sens = place.volume().isSensitive() ? 'S' : ' '; char fmt[128], tmp[32]; ::snprintf(tmp,sizeof(tmp),"%03d/",level+1); ::snprintf(fmt,sizeof(fmt),"%03d %%-%ds %%s #Dau:%%d VolID:%%08X %%c",level+1,2*level+1); printout(INFO,"DetectorDump",fmt,"",de.path().c_str(),int(children.size()), (unsigned long)de.volumeID(), sens); printer.prefix = string(tmp)+de.name(); (printer)(de, level); return 1; }
void Installer<UserData>::install(DetElement component, PlacedVolume pv) { Volume comp_vol = pv.volume(); if ( comp_vol.isSensitive() ) { Volume mod_vol = parentVolume(component); DD4hep::Geometry::PolyhedraRegular comp_shape(comp_vol.solid()), mod_shape(mod_vol.solid()); if ( !comp_shape.isValid() || !mod_shape.isValid() ) { invalidInstaller("Components and/or modules are not Trapezoid -- invalid shapes"); } else if ( !handleUsingCache(component,comp_vol) ) { DetElement par = component.parent(); const TGeoHMatrix& m = par.worldTransformation(); double dz = m.GetTranslation()[2]; const double* trans = placementTranslation(component); double half_mod_thickness = (mod_shape->GetZ(1)-mod_shape->GetZ(0))/2.0; double half_comp_thickness = (comp_shape->GetZ(1)-comp_shape->GetZ(0))/2.0; double si_position = trans[2]+half_mod_thickness; double outer_thickness = half_mod_thickness - si_position; double inner_thickness = half_mod_thickness + si_position; Vector3D u(1.,0.,0.), v(0.,1.,0.), n(0.,0.,1.), o(100.,100.,0.); std::cout << " Module: " << mod_shape.toString() << std::endl; std::cout << " Component: " << comp_shape.toString() << std::endl; std::cout << "dz:" << dz << " Si-pos:" << si_position << " Mod-thickness:" << half_mod_thickness << " Comp-thickness:" << half_comp_thickness << std::endl; VolPlane surf(comp_vol,Type(Type::Sensitive,Type::Measurement1D), inner_thickness, outer_thickness, u, v, n, o); addSurface(component,surf); } } }
/// Given a detector element, access it's sensitive detector (if the sub-detector is sensitive!) SensitiveDetector LCDDHelper::sensitiveDetector(DetElement detector) const { for(DetElement par = detector; par.isValid(); par = par.parent()) { if ( par.ptr() != ptr()->world().ptr() ) { PlacedVolume pv = par.placement(); if ( pv.isValid() ) { const PlacedVolume::VolIDs& ids = pv.volIDs(); for(PlacedVolume::VolIDs::const_iterator i=ids.begin(); i!=ids.end();++i) { if ( (*i).first == "system" ) { return sensitiveDetector(par.name()); } } } } } return SensitiveDetector(0); }
static Ref_t create_detector(LCDD& lcdd, xml_h e, Ref_t) { xml_det_t x_det = e; string name = x_det.nameStr(); DetElement sdet (name,x_det.id()); Material mat (lcdd.material(x_det.materialStr())); // multiplication factor for ellipse major radius double c0 = 3.5; double rmin = 0.0, rmax = 0.0, z = 0.0; for(xml_coll_t c(x_det,_U(zplane)); c; ++c) { xml_comp_t dim(c); rmin = dim.rmin(); rmax = dim.rmax(); z = dim.z(); } double ra = rmax * c0; // elipse long radius double rb = rmax; // elipse short radius double thick = rmax - rmin; // pipe wall thickness EllipticalTube bpElTubeOut(ra+thick, rb+thick, z); EllipticalTube bpElTubeInn(ra, rb, z+thick); SubtractionSolid bpElTube(bpElTubeOut,bpElTubeInn); Tube bpTube1(rb, rb+thick, z+thick, 3*M_PI/2, M_PI/2); UnionSolid beamTube1(bpElTube,bpTube1); Tube bpTube2(rb+thick, ra+thick, z+thick, 3*M_PI/2, M_PI/2); SubtractionSolid beamTube(beamTube1,bpTube2); Volume volume(name, beamTube, mat); double z_offset = x_det.hasAttr(_U(z_offset)) ? x_det.z_offset() : 0.0; volume.setVisAttributes(lcdd, x_det.visStr()); PlacedVolume pv = lcdd.pickMotherVolume(sdet).placeVolume(volume,Position(0,0,z_offset)); sdet.setPlacement(pv); if ( x_det.hasAttr(_U(id)) ) { int det_id = x_det.id(); pv.addPhysVolID("system",det_id); } return sdet; }
/// Callback to output PlacedVolume information of an single Placement int VisDensityProcessor::operator()(PlacedVolume pv, int /* level */) { Volume vol = pv.volume(); Material mat = vol.material(); if ( vol.visAttributes().ptr() != minVis.ptr() ) { if ( mat.density() <= minDensity ) { vol.setVisAttributes(minVis); } ++numInactive; } return 1; }
/// Accessfully decoded volume fields by placement path void Geant4VolumeManager::volumeDescriptor(const vector<const G4VPhysicalVolume*>& path, VolIDDescriptor& vol_desc) const { vol_desc.second.clear(); vol_desc.first = NonExisting; if (!path.empty() && checkValidity()) { const auto& m = ptr()->g4Paths; auto i = m.find(path); if (i != m.end()) { VolumeID vid = (*i).second; G4LogicalVolume* lvol = path[0]->GetLogicalVolume(); if (lvol->GetSensitiveDetector()) { const G4VPhysicalVolume* node = path[0]; const PlacementMap& pm = ptr()->g4Placements; for (PlacementMap::const_iterator ipm = pm.begin(); ipm != pm.end(); ++ipm) { if ((*ipm).second == node) { PlacedVolume pv = (*ipm).first; SensitiveDetector sd = pv.volume().sensitiveDetector(); IDDescriptor dsc = sd.readout().idSpec(); vol_desc.first = vid; dsc.decodeFields(vid, vol_desc.second); return; } } } vol_desc.first = Insensitive; return; } if (!path[0]) vol_desc.first = InvalidPath; else if (!path[0]->GetLogicalVolume()->GetSensitiveDetector()) vol_desc.first = Insensitive; else vol_desc.first = NonExisting; } }
static Ref_t create_element(LCDD& lcdd, xml_h e, SensitiveDetector sens) { xml_det_t x_det = e; string det_name = x_det.nameStr(); Material air = lcdd.air(); //Detector envelope of SubDetector DetElement tracker(det_name, x_det.id()); //add Extension to Detlement for the RecoGeometry Det::DetExtension* ex = new Det::DetExtension(); tracker.addExtension<Det::IDetExtension> (ex); //Create the Volume of the Detector envelope DD4hep::XML::Dimension x_det_dim(x_det.dimensions()); double z = x_det_dim.z(); Tube tracker_shape(x_det_dim.rmin(),x_det_dim.rmax(),z); Volume tracker_vol(x_det.nameStr()+"_envelope",tracker_shape, air); //Vizualization tracker_vol.setVisAttributes(lcdd.invisible()); //Set sensitive type tracker sens.setType("tracker"); int layer_num = 0; //Go through layers for (xml_coll_t j(e,_U(layer)); j; ++j ) { xml_comp_t x_layer = j; double rmin = x_layer.inner_r(); double rmax = x_layer.outer_r(); double radius = (rmax+rmin)*0.5; double layer_z = x_layer.z(); //Create Volume and DetElement for Layer string layer_name = det_name + _toString(layer_num,"layer%d"); Volume layer_vol(layer_name,Tube(rmin,rmax,layer_z), lcdd.material(x_layer.materialStr())); DetElement lay_det (tracker,layer_name,layer_num); //Visualization layer_vol.setVisAttributes(lcdd.invisible()); //module in phi // later also loop through modules for different modules xml_comp_t x_module = x_layer.child(_U(module)); int repeat = x_module.repeat(); double deltaphi = 2.*M_PI/repeat; //slices in z xml_comp_t x_slice = x_layer.child(_U(slice)); int zrepeat = x_slice.repeat(); double dz = x_slice.z(); //add Extension to Detlement for the RecoGeometry Det::DetCylinderLayer* detcylinderlayer = new Det::DetCylinderLayer(); lay_det.addExtension<Det::IDetExtension>(detcylinderlayer); int module_num = 0; //Place the Modules in z for (int k = -zrepeat; k<=zrepeat; k++) { string zname = _toString(k,"z%d"); //Place the Modules in phi for (int i = 0; i < repeat; ++i) { //Create Module Volume Volume mod_vol("module", Box(x_module.length(), x_module.width(),x_module.thickness()), air); //Vizualization mod_vol.setVisAttributes(lcdd.invisible()); double phi = deltaphi/dd4hep::rad * i; string module_name = zname + _toString(i,"module%d"); Position trans(radius * cos(phi), radius * sin(phi), k*dz); //Create module Detelement DetElement mod_det(lay_det,module_name,module_num); //add Extension to Detlement for the RecoGeometry Det::DetModule* detmod = new Det::DetModule(); mod_det.addExtension<Det::IDetExtension> (detmod); int comp_num = 0; //go through module components for (xml_coll_t n(x_module,_U(module_component)); n; ++n) { xml_comp_t x_comp = n; Volume comp_vol("component " + x_comp.materialStr(), Box(x_comp.length(),x_comp.width(), x_comp.thickness()),lcdd.material(x_comp.materialStr())); // comp_vol.setVisAttributes(lcdd, x_comp.visStr()); //Set Sensitive Volmes sensitive if (x_comp.isSensitive()) { comp_vol.setSensitiveDetector(sens); } //Create DetElement DetElement comp_det(mod_det, "component, " + x_comp.materialStr(),comp_num); //add Extension comp_det.addExtension<Det::IDetExtension> (ex); //place component in Module xml_comp_t x_pos = x_comp.position(false); Position transComp (x_pos.x(),x_pos.y(),x_pos.z()); PlacedVolume placedcomp = mod_vol.placeVolume(comp_vol,transComp); //assign the placed Volume to the DetElement comp_det.setPlacement(placedcomp); placedcomp.addPhysVolID("component",comp_num); ++comp_num; } //Place Box Volumes in layer PlacedVolume placedmodule = layer_vol.placeVolume(mod_vol, Transform3D(RotationX(0.5*M_PI)*RotationZ(0.5*M_PI)*RotationX(phi-0.6*M_PI),trans)); placedmodule.addPhysVolID("module", module_num); // assign module DetElement to the placed Module volume mod_det.setPlacement(placedmodule); ++module_num; } ++module_num; } //Place Layervolume PlacedVolume placedLayer = tracker_vol.placeVolume(layer_vol); placedLayer.addPhysVolID("layer",layer_num); placedLayer.addPhysVolID("system",x_det.id()); //Assign Layer DetElement to LayerVolume lay_det.setPlacement(placedLayer); ++layer_num; } Volume mother_vol = lcdd.pickMotherVolume(tracker); //Place envelopevolume in mothervolume PlacedVolume placed_env = mother_vol.placeVolume(tracker_vol); //assign tracker DetElement to tracker volume tracker.setPlacement(placed_env); //fuer envelope moeglich return tracker; }
static DD4hep::Geometry::Ref_t createTkLayoutTrackerBarrel(DD4hep::Geometry::LCDD& lcdd, DD4hep::XML::Handle_t xmlElement, DD4hep::Geometry::SensitiveDetector sensDet) { // shorthands DD4hep::XML::DetElement xmlDet = static_cast<DD4hep::XML::DetElement>(xmlElement); Dimension dimensions(xmlDet.dimensions()); // get sensitive detector type from xml DD4hep::XML::Dimension sdTyp = xmlElement.child(_Unicode(sensitive)); // sensitive detector used for all sensitive parts of this detector sensDet.setType(sdTyp.typeStr()); // definition of top volume // has min/max dimensions of tracker for visualization etc. std::string detectorName = xmlDet.nameStr(); DetElement topDetElement(detectorName, xmlDet.id()); Acts::ActsExtension::Config barrelConfig; barrelConfig.isBarrel = true; // detElement owns extension Acts::ActsExtension* detWorldExt = new Acts::ActsExtension(barrelConfig); topDetElement.addExtension<Acts::IActsExtension>(detWorldExt); DD4hep::Geometry::Tube topVolumeShape( dimensions.rmin(), dimensions.rmax(), (dimensions.zmax() - dimensions.zmin()) * 0.5); Volume topVolume(detectorName, topVolumeShape, lcdd.air()); topVolume.setVisAttributes(lcdd.invisible()); // counts all layers - incremented in the inner loop over repeat - tags unsigned int layerCounter = 0; double integratedModuleComponentThickness = 0; double phi = 0; // loop over 'layer' nodes in xml DD4hep::XML::Component xLayers = xmlElement.child(_Unicode(layers)); for (DD4hep::XML::Collection_t xLayerColl(xLayers, _U(layer)); nullptr != xLayerColl; ++xLayerColl) { DD4hep::XML::Component xLayer = static_cast<DD4hep::XML::Component>(xLayerColl); DD4hep::XML::Component xRods = xLayer.child("rods"); DD4hep::XML::Component xRodEven = xRods.child("rodOdd"); DD4hep::XML::Component xRodOdd = xRods.child("rodEven"); DD4hep::XML::Component xModulesEven = xRodEven.child("modules"); DD4hep::XML::Component xModulePropertiesOdd = xRodOdd.child("moduleProperties"); DD4hep::XML::Component xModulesOdd = xRodOdd.child("modules"); DD4hep::Geometry::Tube layerShape(xLayer.rmin(), xLayer.rmax(), dimensions.zmax()); Volume layerVolume("layer", layerShape, lcdd.material("Air")); layerVolume.setVisAttributes(lcdd.invisible()); PlacedVolume placedLayerVolume = topVolume.placeVolume(layerVolume); placedLayerVolume.addPhysVolID("layer", layerCounter); DetElement lay_det(topDetElement, "layer" + std::to_string(layerCounter), layerCounter); Acts::ActsExtension::Config layConfig; layConfig.isLayer = true; // the local coordinate systems of modules in dd4hep and acts differ // see http://acts.web.cern.ch/ACTS/latest/doc/group__DD4hepPlugins.html layConfig.axes = "XzY"; // correct translation of local x axis in dd4hep to local x axis in acts // detElement owns extension Acts::ActsExtension* layerExtension = new Acts::ActsExtension(layConfig); lay_det.addExtension<Acts::IActsExtension>(layerExtension); lay_det.setPlacement(placedLayerVolume); DD4hep::XML::Component xModuleComponentsOdd = xModulePropertiesOdd.child("components"); integratedModuleComponentThickness = 0; int moduleCounter = 0; Volume moduleVolume; for (DD4hep::XML::Collection_t xModuleComponentOddColl(xModuleComponentsOdd, _U(component)); nullptr != xModuleComponentOddColl; ++xModuleComponentOddColl) { DD4hep::XML::Component xModuleComponentOdd = static_cast<DD4hep::XML::Component>(xModuleComponentOddColl); moduleVolume = Volume("module", DD4hep::Geometry::Box(0.5 * xModulePropertiesOdd.attr<double>("modWidth"), 0.5 * xModuleComponentOdd.thickness(), 0.5 * xModulePropertiesOdd.attr<double>("modLength")), lcdd.material(xModuleComponentOdd.materialStr())); unsigned int nPhi = xRods.repeat(); DD4hep::XML::Handle_t currentComp; for (unsigned int phiIndex = 0; phiIndex < nPhi; ++phiIndex) { double lX = 0; double lY = 0; double lZ = 0; if (0 == phiIndex % 2) { phi = 2 * M_PI * static_cast<double>(phiIndex) / static_cast<double>(nPhi); currentComp = xModulesEven; } else { currentComp = xModulesOdd; } for (DD4hep::XML::Collection_t xModuleColl(currentComp, _U(module)); nullptr != xModuleColl; ++xModuleColl) { DD4hep::XML::Component xModule = static_cast<DD4hep::XML::Component>(xModuleColl); double currentPhi = atan2(xModule.Y(), xModule.X()); double componentOffset = integratedModuleComponentThickness - 0.5 * xModulePropertiesOdd.attr<double>("modThickness") + 0.5 * xModuleComponentOdd.thickness(); lX = xModule.X() + cos(currentPhi) * componentOffset; lY = xModule.Y() + sin(currentPhi) * componentOffset; lZ = xModule.Z(); DD4hep::Geometry::Translation3D moduleOffset(lX, lY, lZ); DD4hep::Geometry::Transform3D lTrafo(DD4hep::Geometry::RotationZ(atan2(lY, lX) + 0.5 * M_PI), moduleOffset); DD4hep::Geometry::RotationZ lRotation(phi); PlacedVolume placedModuleVolume = layerVolume.placeVolume(moduleVolume, lRotation * lTrafo); if (xModuleComponentOdd.isSensitive()) { placedModuleVolume.addPhysVolID("module", moduleCounter); moduleVolume.setSensitiveDetector(sensDet); DetElement mod_det(lay_det, "module" + std::to_string(moduleCounter), moduleCounter); mod_det.setPlacement(placedModuleVolume); ++moduleCounter; } } } integratedModuleComponentThickness += xModuleComponentOdd.thickness(); } ++layerCounter; } Volume motherVol = lcdd.pickMotherVolume(topDetElement); PlacedVolume placedGenericTrackerBarrel = motherVol.placeVolume(topVolume); placedGenericTrackerBarrel.addPhysVolID("system", topDetElement.id()); topDetElement.setPlacement(placedGenericTrackerBarrel); return topDetElement; }
static Ref_t create_detector(Detector& theDetector, xml_h e, SensitiveDetector sens) { typedef vector<PlacedVolume> Placements; xml_det_t x_det = e; Material vacuum = theDetector.vacuum(); int det_id = x_det.id(); string det_name = x_det.nameStr(); bool reflect = x_det.reflect(false); DetElement sdet (det_name,det_id); int m_id=0, c_id=0, n_sensor=0; map<string, Volume> modules; map<string, Placements> sensitives; PlacedVolume pv; // --- create an envelope volume and position it into the world --------------------- Volume envelope = dd4hep::xml::createPlacedEnvelope(theDetector, e, sdet); dd4hep::xml::setDetectorTypeFlag(e, sdet); if( theDetector.buildType() == BUILD_ENVELOPE ) return sdet; //----------------------------------------------------------------------------------- envelope.setVisAttributes(theDetector.invisible()); sens.setType("tracker"); // Build the sensor units // Loop over 'modules' as defined in the XML for(xml_coll_t mi(x_det,_U(module)); mi; ++mi, ++m_id) { xml_comp_t x_mod = mi; string m_nam = x_mod.nameStr(); xml_comp_t trd = x_mod.trd(); double posY; double x1 = trd.x1(); double x2 = trd.x2(); double z = trd.z(); double y1, y2, total_thickness=0.; xml_coll_t ci(x_mod, _U(module_component)); for(ci.reset(), total_thickness=0.0; ci; ++ci) total_thickness += xml_comp_t(ci).thickness(); y1 = y2 = total_thickness / 2; Volume m_volume(m_nam, Trapezoid(x1, x2, y1, y2, z), vacuum); m_volume.setVisAttributes(theDetector.visAttributes(x_mod.visStr())); std::cout << m_nam << ", thickness=" << total_thickness << std::endl; // Loop over the module_components ('slices') in the 'module' // The first component (top in the XML) is placed at the 'bottom' for(ci.reset(), n_sensor=1, c_id=0, posY=-y1; ci; ++ci, ++c_id) { xml_comp_t c = ci; double c_thick = c.thickness(); Material c_mat = theDetector.material(c.materialStr()); string c_name = _toString(c_id, "component%d"); Volume c_vol(c_name, Trapezoid(x1,x2,c_thick/2e0,c_thick/2e0,z), c_mat); std::cout << " + sensor " << n_sensor << " " << c_name; c_vol.setVisAttributes(theDetector.visAttributes(c.visStr())); pv = m_volume.placeVolume(c_vol, Position(0, posY + c_thick/2, 0)); if ( c.isSensitive() ) { sdet.check(n_sensor > 2, "SiTrackerEndcap::fromCompact: " + c_name + " Max of 2 modules allowed!"); pv.addPhysVolID("sensor", n_sensor); c_vol.setSensitiveDetector(sens); sensitives[m_nam].push_back(pv); std::cout << " (" << n_sensor << " is sensitive) "; ++n_sensor; } std::cout << std::endl; posY += c_thick; } modules[m_nam] = m_volume; } // done building the 2 modules, of 12 layers each int mod_count[12] = {0}; // Build now the detector itself // Loop over layers as defined in the XML for(xml_coll_t li(x_det, _U(layer)); li; ++li) { xml_comp_t x_layer(li); int l_id = x_layer.id(); int ring_num = 0; std::cout << "Layer " << l_id << ":" << std::endl; // Loop over rings, as defined in the XML for(xml_coll_t ri(x_layer, _U(ring)); ri; ++ri) { xml_comp_t x_ring = ri; double r = x_ring.r(); double phi0 = x_ring.phi0(0); double zstart = x_ring.zstart(); double dz = x_ring.dz(0); int nmodules = x_ring.nmodules(); string m_nam = x_ring.moduleStr(); Volume m_vol = modules[m_nam]; double iphi = 2*M_PI/nmodules; double phi = phi0; Placements& sensVols = sensitives[m_nam]; // This driver version encodes the rings as layers and the // petals as modules, such that 'layer' 1 contains all innermost rings // and last 'layer' contains the outermost rings in the tracker // farthest away on z from the IP (unintuititive, but works) std::cout << " Ring " << ring_num << ":" << std::endl; // Loop over modules in each ring, modules are either type 1 or 2 for(int k=0; k < nmodules; ++k) { double x = -r*std::cos(phi); double y = -r*std::sin(phi); for(int s=1-2*int(reflect); s<2; s+=1+int(reflect)){ string e_name = _toString(s, "side%d") + _toString(l_id, "_layer%d") + _toString(ring_num, "_ring%d") + _toString(k, "_sensor%d"); DetElement module(sdet, e_name, det_id); pv = envelope.placeVolume(m_vol, Transform3D(RotationZYX(0,-M_PI/2-phi,-M_PI/2), Position(x, y, s*(zstart+dz) ))); pv.addPhysVolID("side", s).addPhysVolID("layer", ring_num).addPhysVolID("module", mod_count[ring_num] + k); module.setPlacement(pv); for(size_t ic=0; ic<sensVols.size(); ++ic) { PlacedVolume sens_pv = sensVols[ic]; DetElement comp_elt(module, sens_pv.volume().name(), det_id); comp_elt.setPlacement(sens_pv); std::cout << "Name: " << e_name << "_" << sens_pv.volume().name() << std::endl; std::cout << " ID: side " << s << ", layer " << ring_num << ", module " << mod_count[ring_num] + k << ", sensor" << ic+1 << std::endl; } } dz = -dz; phi += iphi; } mod_count[ring_num] += nmodules; ++ring_num; } } std::cout << "Number of modules per 'layer':" << std::endl; for(int ii=0; ii<12; ii++){ std::cout << " mod_count[" << ii << "] = " << mod_count[ii] << std::endl; } return sdet; }
static Ref_t create_detector(LCDD& lcdd, xml_h e, SensitiveDetector sens) { //XML detector object: DDCore/XML/XMLDetector.h xml_dim_t x_det = e; //Create the DetElement for DD4hep DetElement d_det(x_det.nameStr(),x_det.id()); //XML dimension object: DDCore/XML/XMLDimension.h xml_dim_t x_det_dim(x_det.dimensions()); //double inner_r = x_det_dim.rmin(); //double outer_r = x_det_dim.rmax(); Assembly calo_vol(x_det.nameStr()+"_envelope"); PlacedVolume pv; //Set envelope volume attributes calo_vol.setAttributes(lcdd,x_det.regionStr(),x_det.limitsStr(),x_det.visStr()); #if 0 //Declare this sensitive detector as a calorimeter Tube tub(inner_r,outer_r,x_det_dim.z()/2.0,0.0,2*M_PI); //Volume tub_vol(x_det.nameStr()+"_tube",tub,lcdd.material("PyrexGlass")); Volume tub_vol(x_det.nameStr()+"_tube",tub,lcdd.material("Iron")); calo_vol.placeVolume(tub_vol); sens.setType("calorimeter"); tub_vol.setSensitiveDetector(sens); d_det.setAttributes(lcdd,tub_vol,x_det.regionStr(),x_det.limitsStr(),x_det.visStr()); #endif #if 1 int layer_num = 0; float layer_pos_z = 0; double tile_phi = 2*M_PI/x_det_dim.phiBins(); float r = x_det_dim.rmin(); bool debug = true; Assembly stave_vol(x_det.nameStr()+"_stave_0"); //Repeat layers until we reach the rmax while(r<x_det_dim.rmax()) { //Loop over layers of type: XML Collection_t object: DDCore/XML/XMLElements.h for(DD4hep::XML::Collection_t layerIt(x_det,_U(layer)); layerIt; ++layerIt, ++layer_num) { //Build a layer volume xml_comp_t x_det_layer = layerIt; float dr = x_det_layer.dr(); string layer_name = x_det.nameStr()+_toString(layer_num,"_layer%d"); float x1 = r * tan(tile_phi/2.); float x2 = (r+dr) * tan(tile_phi/2.); float y1 = x_det_dim.z(); float y2 = x_det_dim.z(); float z = x_det_layer.dr(); if(debug) { cout << " r:" << r << " dr:" << dr << " x1:" << x1 << " x2:" << x2 << " y1:" << y1 << " y2:" << y2 << " z:" << z << endl; } //Shape a Trapezoid (tile): DDCore/DD4hep/Shapes.h Trapezoid layer_shape(x1,x2,y1,y2,z); //Create a volume with trapezoid shape Volume layer_vol(layer_name, layer_shape, lcdd.air()); layer_vol.setAttributes(lcdd,x_det.regionStr(),x_det.limitsStr(),x_det_layer.visStr()); //DetElement layer(layer_name,_toString(layer_num,"layer%d"),x_det.id()); //Fill the volume with tiles vector<Volume> tiles; //Assembly tile_seq(layer_name+"_seq"); Trapezoid tile_seq_shape(x1,x2,x_det_layer.dz(),x_det_layer.dz(),x_det_layer.dr()); Volume tile_seq(layer_name + "_seq",tile_seq_shape,lcdd.air()); double total_thickness = 0; //Repeat slices until we reach the end of the calorimeter int slice_num = 0, tile_number = 0; tile_seq.setVisAttributes(lcdd.visAttributes("VisibleGreen")); for(xml_coll_t k(x_det_layer,_U(slice)); k; ++k, ++slice_num) { xml_comp_t tile_xml = k; string tile_name = layer_name + _toString(tile_number,"_slice%d"); Material tile_material = lcdd.material(tile_xml.materialStr()); float tile_thickness = tile_xml.dz(); float tile_y1 = tile_thickness; float tile_y2 = tile_thickness; float tile_z = x_det_layer.dr(); Trapezoid tile_shape(x1,x2,tile_y1,tile_y2,tile_z); Volume tile_vol(tile_name,tile_shape,tile_material); pv = tile_seq.placeVolume(tile_vol,Position(0,total_thickness,0)); pv.addPhysVolID("slice",slice_num); total_thickness += tile_thickness; if ( tile_xml.isSensitive() ) { cout << "Set volume " << tile_name << " sensitive...." << endl; tile_vol.setSensitiveDetector(sens); } // Set region, limitset, and visibility settings tile_vol.setAttributes(lcdd,tile_xml.regionStr(),tile_xml.limitsStr(),tile_xml.visStr()); tiles.push_back(tile_vol); tile_number++; } // Place the same volumes inside the envelope float tile_pos_z = -x_det_dim.z()/2.; int tile_num = 0; while(tile_pos_z<x_det_dim.z()/2.) { pv = layer_vol.placeVolume(tile_seq,Position(0,tile_pos_z,0)); pv.addPhysVolID("tile",tile_num); tile_pos_z += total_thickness; tile_num++; } // Place the same layer around the beam axis phiBins times Transform3D tr(RotationZYX(M_PI*0.5,M_PI*0.5,0),Translation3D(r,0,layer_pos_z)); pv = stave_vol.placeVolume(layer_vol,tr); pv.addPhysVolID("layer",layer_num); r += dr; cout << "+++ R=" << r << endl; } } //double mod_x_off = outer_r - (outer_r-inner_r)/2.0; //double mod_y_off = 0; int nphi_bins = x_det_dim.phiBins(); for(int i=0; i<nphi_bins; i++) { if(debug) cout << "Layer:" << i << " phi:" << tile_phi << " rotz:" << (tile_phi*i) << endl; double phi = tile_phi*i; //double pos_x = mod_x_off * cos(phi) - mod_y_off * sin(phi); //double pos_y = mod_x_off * sin(phi) + mod_y_off * cos(phi); Transform3D tr(RotationZYX(phi,0,0),Translation3D(0,0,0)); pv = calo_vol.placeVolume(stave_vol,tr); pv.addPhysVolID("stave",i+1); } cout << "Number of layers: " << layer_num << endl; #endif //Place the calo inside the world PlacedVolume calo_plv = lcdd.pickMotherVolume(d_det).placeVolume(calo_vol); calo_plv.addPhysVolID("system",x_det.id()); calo_plv.addPhysVolID("barrel",0); d_det.setPlacement(calo_plv); return d_det; }
static Ref_t create_detector(LCDD& lcdd, xml_h e, SensitiveDetector sens) { //XML detector object: DDCore/XML/XMLDetector.h DD4hep::XML::DetElement x_det = e; //Create the DetElement for DD4hep DetElement d_det(x_det.nameStr(),x_det.id()); //Pick the mothervolume Volume det_vol = lcdd.pickMotherVolume(d_det); //XML dimension object: DDCore/XML/XMLDimension.h DD4hep::XML::Dimension x_det_dim(x_det.dimensions()); //Tube: DDCore/DD4hep/Shapes.h Tube calo_shape(x_det_dim.rmin(),x_det_dim.rmax(),x_det_dim.z()); //Create the detector mother volume Volume calo_vol(x_det.nameStr()+"_envelope",calo_shape,lcdd.air()); //Set envelope volume attributes calo_vol.setAttributes(lcdd,x_det.regionStr(),x_det.limitsStr(),x_det.visStr()); //Place inside the mother volume PlacedVolume calo_plv = det_vol.placeVolume(calo_vol); calo_plv.addPhysVolID("system",x_det.id()); calo_plv.addPhysVolID("barrel",0); d_det.setPlacement(calo_plv); //Declare this sensitive detector as a calorimeter sens.setType("calorimeter"); int layer_num = 0; float layer_pos_z = 0; double tile_phi = 2*M_PI/x_det_dim.phiBins(); float r = x_det_dim.rmin(); bool debug = false; //Repeat layers until we reach the rmax while(r<x_det_dim.rmax()){ //Loop over layers of type: XML Collection_t object: DDCore/XML/XMLElements.h for(DD4hep::XML::Collection_t layerIt(x_det,_U(layer));layerIt; ++layerIt){ //Build a layer volume DD4hep::XML::Component x_det_layer = layerIt; float dr = x_det_layer.dr(); string layer_name = x_det.nameStr()+_toString(layer_num,"_layer%d"); float x1 = r * tan(tile_phi/2.); float x2 = (r+dr) * tan(tile_phi/2.); float y1 = x_det_dim.z(); float y2 = x_det_dim.z(); float z = x_det_layer.dr(); if(debug){ cout << " r:" << r << " dr:" << dr << " x1:" << x1 << " x2:" << x2 << " y1:" << y1 << " y2:" << y2 << " z:" << z << endl; } //Shape a Trapezoid (tile): DDCore/DD4hep/Shapes.h Trapezoid layer_shape(x1,x2,y1,y2,z); //Create a volume with trapezoid shape Volume layer_vol(layer_name, layer_shape, lcdd.air()); layer_vol.setAttributes(lcdd,x_det.regionStr(),x_det.limitsStr(),x_det_layer.visStr()); //DetElement layer(layer_name,_toString(layer_num,"layer%d"),x_det.id()); //Fill the volume with tiles int tile_number = 0; vector<Volume> tiles; //Repeat slices until we reach the end of the calorimeter for(xml_coll_t k(x_det_layer,_U(slice)); k; ++k) { DD4hep::XML::Component tile_xml = k; string tile_name = layer_name + _toString(tile_number,"_slice%d"); Material tile_material = lcdd.material(tile_xml.materialStr()); float tile_thickness = tile_xml.dz(); float tile_y1 = tile_thickness; float tile_y2 = tile_thickness; float tile_z = x_det_layer.dr(); //Shape a Trapezoid (tile): DDCore/DD4hep/Shapes.h Trapezoid tile_shape(x1,x2,tile_y1,tile_y2,tile_z); //Create a volume with trapezoid shape Volume tile_vol(tile_name,tile_shape,tile_material); if ( tile_xml.isSensitive() ) { tile_vol.setSensitiveDetector(sens); } //Set region, limitset, and visibility settings tile_vol.setAttributes(lcdd,tile_xml.regionStr(),tile_xml.limitsStr(),tile_xml.visStr()); tiles.push_back(tile_vol); tile_number++; } //Place the same volumes inside the envelope float tile_pos_z = -x_det_dim.z()/2.; int slice_num = 0; while(tile_pos_z<x_det_dim.z()/2.){ tile_number=0; for(xml_coll_t k(x_det_layer,_U(slice)); k; ++k) { DD4hep::XML::Component tile_xml = k; float tile_thickness = tile_xml.dz(); //Place the tile inside the layer PlacedVolume tile_plv = layer_vol.placeVolume(tiles.at(tile_number),Position(0,tile_pos_z,0)); tile_plv.addPhysVolID("layer",layer_num); tile_plv.addPhysVolID("slice",slice_num); //Increment the z pos of the tile tile_pos_z += tile_thickness; tile_number++; slice_num++; } } //Place the same layer around the beam axis phiBins times double mod_x_off = r; double mod_y_off = 0; for(int i=0;i<x_det_dim.phiBins();i++){ if(debug) cout << "Layer:" << i << " phi:" << tile_phi << " rotz:" << (tile_phi*i) << endl; double layer_pos_x = mod_x_off * cos(tile_phi*i) - mod_y_off * sin(tile_phi*i); double layer_pos_y = mod_x_off * sin(tile_phi*i) + mod_y_off * cos(tile_phi*i); Transform3D tr(RotationZYX(M_PI*0.5,M_PI*0.5,0)*RotationZYX(0,tile_phi*i,0), Translation3D(layer_pos_x,layer_pos_y,layer_pos_z)); PlacedVolume pv = calo_vol.placeVolume(layer_vol,tr); pv.addPhysVolID("system",x_det.id()); pv.addPhysVolID("barrel",0); pv.addPhysVolID("layer",layer_num); pv.addPhysVolID("module",i+1); //DetElement sd = i==0 ? stave_det : stave_det.clone(_toString(i,"stave%d")); } r += dr; layer_num += 1; } } //Place the calo inside the world return d_det; }
static DD4hep::Geometry::Ref_t createTkLayoutTrackerEndcap(DD4hep::Geometry::LCDD& lcdd, DD4hep::XML::Handle_t xmlElement, DD4hep::Geometry::SensitiveDetector sensDet) { // shorthands DD4hep::XML::DetElement xmlDet = static_cast<DD4hep::XML::DetElement>(xmlElement); Dimension dimensions(xmlDet.dimensions()); // get sensitive detector type from xml DD4hep::XML::Dimension sdTyp = xmlElement.child("sensitive"); // retrieve the type sensDet.setType(sdTyp.typeStr()); // set for the whole detector // definition of top volume std::string detName = xmlDet.nameStr(); DetElement GenericTrackerEndcapWorld(detName, xmlDet.id()); // envelope volume with the max dimensions of tracker for visualization etc. // contains both endcaps, in forward and in backwards direction // the part between -z1 and z1 is subtracted from the envelope DD4hep::Geometry::Tube posnegEnvelopeShape_add(dimensions.rmin(), dimensions.rmax(), dimensions.zmax()); // make the negative shape slighly larger in the radial direction // to be sure that everything is subtracted between -z1 and z1 DD4hep::Geometry::Box posnegEnvelopeShape_subtract( dimensions.rmax() * 1.001, dimensions.rmax() * 1.001, dimensions.zmin()); DD4hep::Geometry::SubtractionSolid posnegEnvelopeShape(posnegEnvelopeShape_add, posnegEnvelopeShape_subtract); Volume posnegEnvelopeVolume(detName, posnegEnvelopeShape, lcdd.air()); posnegEnvelopeVolume.setVisAttributes(lcdd.invisible()); // envelope volume for one of the endcaps, either forward or backward DD4hep::Geometry::Tube envelopeShape( dimensions.rmin(), dimensions.rmax(), 0.5 * (dimensions.zmax() - dimensions.zmin())); Volume envelopeVolume(detName, envelopeShape, lcdd.air()); envelopeVolume.setVisAttributes(lcdd.invisible()); Component xDiscs = xmlElement.child("discs"); Component xFirstDisc = xDiscs.child("discZPls"); Component xFirstDiscRings = xFirstDisc.child("rings"); // create disc volume double discThickness = (xFirstDisc.zmax() - xFirstDisc.zmin()); DD4hep::Geometry::Tube discShape(dimensions.rmin(), dimensions.rmax(), 0.5 * discThickness); Volume discVolume("disc", discShape, lcdd.air()); discVolume.setVisAttributes(lcdd.invisible()); // generate rings and place in discs int moduleCounter = 0; for (DD4hep::XML::Collection_t xRingColl(xFirstDiscRings, _U(ring)); nullptr != xRingColl; ++xRingColl) { Component xRing = static_cast<Component>(xRingColl); Component xRingModules = xRing.child("modules"); Component xModuleOdd = xRingModules.child("moduleOdd"); Component xModuleEven = xRingModules.child("moduleEven"); Component xModuleProperties = xRing.child("moduleProperties"); Component xModulePropertiesComp = xModuleProperties.child("components"); Component xSensorProperties = xRing.child("sensorProperties"); Volume moduleVolume("module", DD4hep::Geometry::Trapezoid(0.5 * xModuleProperties.attr<double>("modWidthMin"), 0.5 * xModuleProperties.attr<double>("modWidthMax"), 0.5 * xModuleProperties.attr<double>("modThickness"), 0.5 * xModuleProperties.attr<double>("modThickness"), 0.5 * xSensorProperties.attr<double>("sensorLength")), lcdd.material("Air")); // place components in module double integratedCompThickness = 0; int componentCounter = 0; for (DD4hep::XML::Collection_t xCompColl(xModulePropertiesComp, _U(component)); nullptr != xCompColl; ++xCompColl) { Component xComp = static_cast<Component>(xCompColl); Volume componentVolume("component", DD4hep::Geometry::Trapezoid(0.5 * xModuleProperties.attr<double>("modWidthMin"), 0.5 * xModuleProperties.attr<double>("modWidthMax"), 0.5 * xComp.thickness(), 0.5 * xComp.thickness(), 0.5 * xSensorProperties.attr<double>("sensorLength")), lcdd.material(xComp.materialStr())); PlacedVolume placedComponentVolume = moduleVolume.placeVolume( componentVolume, DD4hep::Geometry::Position( 0, integratedCompThickness - 0.5 * xModuleProperties.attr<double>("modThickness"), 0)); placedComponentVolume.addPhysVolID("component", componentCounter); componentVolume.setSensitiveDetector(sensDet); integratedCompThickness += xComp.thickness(); ++componentCounter; } unsigned int nPhi = xRing.attr<int>("nModules"); double lX, lY, lZ; double phi = 0; double phiTilt, thetaTilt; for (unsigned int phiIndex = 0; phiIndex < nPhi; ++phiIndex) { if (0 == phiIndex % 2) { // the rotation for the odd module is already taken care // of by the position in tklayout xml phi = 2 * dd4hep::pi * static_cast<double>(phiIndex) / static_cast<double>(nPhi); lX = xModuleEven.X(); lY = xModuleEven.Y(); lZ = xModuleEven.Z() - dimensions.zmin() - discThickness * 0.5; phiTilt = xModuleEven.attr<double>("phiTilt"); thetaTilt = xModuleEven.attr<double>("thetaTilt"); } else { lX = xModuleOdd.X(); lY = xModuleOdd.Y(); lZ = xModuleOdd.Z() - dimensions.zmin() - discThickness * 0.5; phiTilt = xModuleOdd.attr<double>("phiTilt"); thetaTilt = xModuleOdd.attr<double>("thetaTilt"); } // position module in the x-y plane, smaller end inward // and incorporate phi tilt if any DD4hep::Geometry::RotationY lRotation1(M_PI * 0.5); DD4hep::Geometry::RotationX lRotation2(M_PI * 0.5 + phiTilt); // align radially DD4hep::Geometry::RotationZ lRotation3(atan(lY / lX)); // theta tilt, if any -- note the different convention between // tklayout and here, thus the subtraction of pi / 2 DD4hep::Geometry::RotationY lRotation4(thetaTilt - M_PI * 0.5); DD4hep::Geometry::RotationZ lRotation_PhiPos(phi); // position in disk DD4hep::Geometry::Translation3D lTranslation(lX, lY, lZ); DD4hep::Geometry::Transform3D myTrafo(lRotation4 * lRotation3 * lRotation2 * lRotation1, lTranslation); PlacedVolume placedModuleVolume = discVolume.placeVolume(moduleVolume, lRotation_PhiPos * myTrafo); placedModuleVolume.addPhysVolID("module", moduleCounter); ++moduleCounter; } } unsigned int discCounter = 0; double currentZ; for (DD4hep::XML::Collection_t xDiscColl(xDiscs, "discZPls"); nullptr != xDiscColl; ++xDiscColl) { Component xDisc = static_cast<Component>(xDiscColl); currentZ = xDisc.z() - dimensions.zmin() - 0.5 * (dimensions.zmax() - dimensions.zmin()); PlacedVolume placedDiscVolume = envelopeVolume.placeVolume(discVolume, DD4hep::Geometry::Position(0, 0, currentZ)); placedDiscVolume.addPhysVolID("disc", discCounter); ++discCounter; } // top of the hierarchy Volume motherVol = lcdd.pickMotherVolume(GenericTrackerEndcapWorld); PlacedVolume placedEnvelopeVolume = motherVol.placeVolume(posnegEnvelopeVolume); placedEnvelopeVolume.addPhysVolID("system", xmlDet.id()); // place everything twice -- forward / backward DD4hep::Geometry::Translation3D lTranslation_posEnvelope( 0, 0, -dimensions.zmin() - 0.5 * (dimensions.zmax() - dimensions.zmin())); PlacedVolume placedGenericTrackerEndcap_pos = posnegEnvelopeVolume.placeVolume( envelopeVolume, DD4hep::Geometry::Position(0, 0, dimensions.zmin() + 0.5 * (dimensions.zmax() - dimensions.zmin()))); PlacedVolume placedGenericTrackerEndcap_neg = posnegEnvelopeVolume.placeVolume( envelopeVolume, lTranslation_posEnvelope * DD4hep::Geometry::RotationX(dd4hep::pi)); placedGenericTrackerEndcap_pos.addPhysVolID("posneg", 0); placedGenericTrackerEndcap_neg.addPhysVolID("posneg", 1); GenericTrackerEndcapWorld.setPlacement(placedEnvelopeVolume); return GenericTrackerEndcapWorld; }
/** Factory for a configurable, generic tracker endcap. @author: Valentin Volkl */ static DD4hep::Geometry::Ref_t createGenericTrackerEndcap(DD4hep::Geometry::LCDD& lcdd, DD4hep::XML::Handle_t xmlElement, DD4hep::Geometry::SensitiveDetector sensDet) { // shorthands DD4hep::XML::DetElement xmlDet = static_cast<DD4hep::XML::DetElement>(xmlElement); Dimension dimensions(xmlDet.dimensions()); // get sensitive detector type from xml DD4hep::XML::Dimension sdTyp = xmlElement.child("sensitive"); // retrieve the type if (xmlDet.isSensitive()) { sensDet.setType(sdTyp.typeStr()); // set for the whole detector } // definition of top volume std::string detName = xmlDet.nameStr(); DetElement GenericTrackerEndcapWorld(detName, xmlDet.id()); // envelope volume with the max dimensions of tracker for visualization etc. // contains both endcaps, in forward and in backwards direction // the part between -z1 and z1 is subtracted from the envelope DD4hep::Geometry::Tube posnegEnvelopeShape_add(dimensions.rmin(), dimensions.rmax(), (dimensions.z2())); // make the negative shape slighly larger in the radial direction // to be sure that everything is subtracted between -z1 and z1 DD4hep::Geometry::Box posnegEnvelopeShape_subtract( dimensions.rmax() * 1.001, dimensions.rmax() * 1.001, dimensions.z1()); DD4hep::Geometry::SubtractionSolid posnegEnvelopeShape(posnegEnvelopeShape_add, posnegEnvelopeShape_subtract); Volume posnegEnvelopeVolume(detName, posnegEnvelopeShape, lcdd.air()); posnegEnvelopeVolume.setVisAttributes(lcdd.invisible()); // envelope volume for one of the endcaps, either forward or backward DD4hep::Geometry::Tube envelopeShape(dimensions.rmin(), dimensions.rmax(), 0.5 * (dimensions.z2() - dimensions.z1())); Volume envelopeVolume(detName, envelopeShape, lcdd.air()); envelopeVolume.setVisAttributes(lcdd.invisible()); // loop over 'layer' nodes in xml unsigned int layerCounter = 0; for (DD4hep::XML::Collection_t xLayerColl(xmlElement, _U(layers)); nullptr != xLayerColl; ++xLayerColl) { DD4hep::XML::Component xLayer = static_cast<DD4hep::XML::Component>(xLayerColl); // create petals unsigned int nPhi = static_cast<unsigned int>(getAttrValueWithFallback(xLayer, "nPhi", 16)); const double lModuleTwistAngle = getAttrValueWithFallback(xLayer, "module_twist_angle", 0.05 * M_PI); double dr = xLayer.rmax() - xLayer.rmin(); double dphi = 2 * dd4hep::pi / static_cast<double>(nPhi); double tn = tan(dphi); Volume petalVolume( "petal", DD4hep::Geometry::Trapezoid( 0.5 * xLayer.rmin() * tn, 0.5 * xLayer.rmax() * tn, xLayer.thickness(), xLayer.thickness(), 0.5 * dr), lcdd.material("Silicon")); petalVolume.setVisAttributes(lcdd, xLayer.visStr()); petalVolume.setSensitiveDetector(sensDet); // handle repeat attribute in xml double layerThickness; unsigned int numLayers; double current_z; // "repeat" layers equidistant between rmin and rmax numLayers = xLayer.repeat(); layerThickness = (xLayer.z2() - xLayer.z1()) / numLayers; // create layers. for (unsigned int repeatIndex = 0; repeatIndex < numLayers; ++repeatIndex) { DD4hep::Geometry::Tube layerShape(xLayer.rmin(), xLayer.rmax(), 0.5 * layerThickness); Volume layerVolume("layer" + std::to_string(layerCounter), layerShape, lcdd.air()); layerVolume.setVisAttributes(lcdd.invisible()); ++layerCounter; // place layers not at center, but at z1 value of containing envelope // subtract half of the envelope length current_z = (repeatIndex + 0.5) * layerThickness + xLayer.z1() - dimensions.z1(); PlacedVolume placedLayerVolume = envelopeVolume.placeVolume( layerVolume, DD4hep::Geometry::Position(0, 0, current_z - 0.5 * (dimensions.z2() - dimensions.z1()))); placedLayerVolume.addPhysVolID("layer", layerCounter); double phi; double r = xLayer.rmin(); for (unsigned int phiIndex = 0; phiIndex < nPhi; ++phiIndex) { phi = 2 * dd4hep::pi * static_cast<double>(phiIndex) / static_cast<double>(nPhi); // oriented along z at first DD4hep::Geometry::Translation3D lTranslation_ringPhiPos(0, 0, r + 0.5 * dr); DD4hep::Geometry::RotationY lRotation_ringPhiPos(phi); DD4hep::Geometry::RotationX lRotation_orientRing(0.5 * dd4hep::pi); // twist petals slightly so they can overlap DD4hep::Geometry::RotationZ lRotation_twist(lModuleTwistAngle); PlacedVolume placedPetalVolume = layerVolume.placeVolume( petalVolume, lRotation_orientRing * lRotation_ringPhiPos * lTranslation_ringPhiPos * lRotation_twist); placedPetalVolume.addPhysVolID("petal", phiIndex); } } } // top of the hierarchy Volume motherVol = lcdd.pickMotherVolume(GenericTrackerEndcapWorld); PlacedVolume placedEnvelopeVolume = motherVol.placeVolume(posnegEnvelopeVolume); placedEnvelopeVolume.addPhysVolID("system", xmlDet.id()); // place everything twice -- forward / backward DD4hep::Geometry::Translation3D lTranslation_posEnvelope( 0, 0, -dimensions.z1() - 0.5 * (dimensions.z2() - dimensions.z1())); PlacedVolume placedGenericTrackerEndcap_pos = posnegEnvelopeVolume.placeVolume( envelopeVolume, DD4hep::Geometry::Position(0, 0, dimensions.z1() + 0.5 * (dimensions.z2() - dimensions.z1()))); PlacedVolume placedGenericTrackerEndcap_neg = posnegEnvelopeVolume.placeVolume( envelopeVolume, lTranslation_posEnvelope * DD4hep::Geometry::RotationX(dd4hep::pi)); placedGenericTrackerEndcap_pos.addPhysVolID("posneg", 0); placedGenericTrackerEndcap_neg.addPhysVolID("posneg", 1); GenericTrackerEndcapWorld.setPlacement(placedEnvelopeVolume); return GenericTrackerEndcapWorld; }
static Ref_t create_element(Detector& theDetector, xml_h element, SensitiveDetector sens) { xml_det_t x_det = element; std::string name = x_det.nameStr(); DetElement sdet( name, x_det.id() ) ; PlacedVolume pv; // --- create an envelope volume and position it into the world --------------------- Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector, element , sdet ) ; if( theDetector.buildType() == BUILD_ENVELOPE ) return sdet ; //----------------------------------------------------------------------------------- // ----- read xml ---------------------- xml_dim_t dim = x_det.dimensions(); double inner_r = dim.rmin() ; double outer_r = dim.rmax() ; double z0 = dim.z0() ; double z1 = dim.z1() ; // double phi0 = dim.phi0() ; unsigned nsides = dim.nsides(); double thick = z1 - z0 ; double zpos = z0 + thick/2. ; Material mat = envelope.material() ; //-------------------------------------- sens.setType("tracker"); // base vectors for surfaces: Vector3D u(0,1,0) ; Vector3D v(1,0,0) ; Vector3D n(0,0,1) ; PolyhedraRegular phSolid ( nsides, inner_r, outer_r , 0.5*thick ) ; //============================================================================== DetElement fwdDE( sdet, name + std::string( "_fwd" ) , x_det.id() ); Volume phVol( name + std::string("_vol") , phSolid , mat ) ; phVol.setSensitiveDetector(sens); //fixme: the drawing of endcap surfaces in a polyhedral shape does not work right now // -> set surface to be invisible for now VolPlane surf( phVol,SurfaceType(SurfaceType::Sensitive, SurfaceType::Invisible), thick/4., thick/4., u,v,n ) ; volSurfaceList( fwdDE )->push_back( surf ) ; pv = envelope.placeVolume( phVol , Position( 0., 0., zpos ) ) ; pv.addPhysVolID("layer", 0 ).addPhysVolID( "side" , +1 ) ; fwdDE.setPlacement( pv ) ; //============================================================================== DetElement bwdDE( sdet, name + std::string( "_bwd" ) , x_det.id() ); // Volume phVol( name + std::string("_bwd") , phSolid , mat ) ; phVol.setSensitiveDetector(sens); volSurfaceList( bwdDE )->push_back( surf ) ; pv = envelope.placeVolume( phVol , Position( 0., 0., -zpos ) ) ; pv.addPhysVolID("layer", 0 ).addPhysVolID( "side" , -1 ) ; bwdDE.setPlacement( pv ) ; //-------------------------------------- return sdet ; }
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; }
static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDetector sens) { static double tolerance = 0e0; xml_det_t x_det = element; string det_name = x_det.nameStr(); Layering layering (element); Material air = theDetector.air(); //unused: Material vacuum = theDetector.vacuum(); int det_id = x_det.id(); xml_comp_t x_staves = x_det.staves(); DetElement sdet (det_name,det_id); xml_comp_t x_dim = x_det.dimensions(); int nsides = x_dim.numsides(); double dphi = (2*M_PI/nsides); double hphi = dphi/2; // --- create an envelope volume and position it into the world --------------------- Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector, element , sdet ) ; dd4hep::xml::setDetectorTypeFlag( element, sdet ) ; if( theDetector.buildType() == BUILD_ENVELOPE ) return sdet ; //----------------------------------------------------------------------------------- sens.setType("calorimeter"); Material stave_material = theDetector.material(x_staves.materialStr()); DetElement stave_det("module0stave0",det_id); Readout readout = sens.readout(); Segmentation seg = readout.segmentation(); // check if we have a WaferGridXY segmentation : WaferGridXY* waferSeg = dynamic_cast< WaferGridXY*>( seg.segmentation() ) ; std::vector<double> cellSizeVector = seg.segmentation()->cellDimensions(0); //Assume uniform cell sizes, provide dummy cellID double cell_sizeX = cellSizeVector[0]; double cell_sizeY = cellSizeVector[1]; //==================================================================== // // Read all the constant from ILD_o1_v05.xml // Use them to build HcalBarrel // //==================================================================== int N_FIBERS_W_STRUCTURE = 2; int N_FIBERS_ALVOULUS = 3; // read parametere from compact.xml file double Ecal_Alveolus_Air_Gap = theDetector.constant<double>("Ecal_Alveolus_Air_Gap"); double Ecal_Slab_shielding = theDetector.constant<double>("Ecal_Slab_shielding"); double Ecal_Slab_copper_thickness = theDetector.constant<double>("Ecal_Slab_copper_thickness"); double Ecal_Slab_PCB_thickness = theDetector.constant<double>("Ecal_Slab_PCB_thickness"); double Ecal_Slab_glue_gap = theDetector.constant<double>("Ecal_Slab_glue_gap"); double Ecal_Slab_ground_thickness = theDetector.constant<double>("Ecal_Slab_ground_thickness"); double Ecal_fiber_thickness = theDetector.constant<double>("Ecal_fiber_thickness"); double Ecal_Si_thickness = theDetector.constant<double>("Ecal_Si_thickness"); double Ecal_inner_radius = theDetector.constant<double>("TPC_outer_radius") +theDetector.constant<double>("Ecal_Tpc_gap"); double Ecal_radiator_thickness1 = theDetector.constant<double>("Ecal_radiator_layers_set1_thickness"); double Ecal_radiator_thickness2 = theDetector.constant<double>("Ecal_radiator_layers_set2_thickness"); double Ecal_radiator_thickness3 = theDetector.constant<double>("Ecal_radiator_layers_set3_thickness"); double Ecal_Barrel_halfZ = theDetector.constant<double>("Ecal_Barrel_halfZ"); double Ecal_support_thickness = theDetector.constant<double>("Ecal_support_thickness"); double Ecal_front_face_thickness = theDetector.constant<double>("Ecal_front_face_thickness"); double Ecal_lateral_face_thickness = theDetector.constant<double>("Ecal_lateral_face_thickness"); double Ecal_Slab_H_fiber_thickness = theDetector.constant<double>("Ecal_Slab_H_fiber_thickness"); double Ecal_Slab_Sc_PCB_thickness = theDetector.constant<double>("Ecal_Slab_Sc_PCB_thickness"); double Ecal_Sc_thickness = theDetector.constant<double>("Ecal_Sc_thickness"); double Ecal_Sc_reflector_thickness = theDetector.constant<double>("Ecal_Sc_reflector_thickness"); int Ecal_nlayers1 = theDetector.constant<int>("Ecal_nlayers1"); int Ecal_nlayers2 = theDetector.constant<int>("Ecal_nlayers2"); int Ecal_nlayers3 = theDetector.constant<int>("Ecal_nlayers3"); int Ecal_barrel_number_of_towers = theDetector.constant<int>("Ecal_barrel_number_of_towers"); //double Ecal_cells_size = theDetector.constant<double>("Ecal_cells_size"); double Ecal_guard_ring_size = theDetector.constant<double>("Ecal_guard_ring_size"); //==================================================================== // // general calculated parameters // //==================================================================== double Ecal_total_SiSlab_thickness = Ecal_Slab_shielding + Ecal_Slab_copper_thickness + Ecal_Slab_PCB_thickness + Ecal_Slab_glue_gap + Ecal_Si_thickness + Ecal_Slab_ground_thickness + Ecal_Alveolus_Air_Gap / 2; #ifdef VERBOSE std::cout << " Ecal_total_SiSlab_thickness = " << Ecal_total_SiSlab_thickness << std::endl; #endif double Ecal_total_ScSlab_thickness = Ecal_Slab_shielding + Ecal_Slab_copper_thickness + Ecal_Slab_Sc_PCB_thickness + Ecal_Sc_thickness + Ecal_Sc_reflector_thickness * 2 + Ecal_Alveolus_Air_Gap / 2; #ifdef VERBOSE std::cout << " Ecal_total_ScSlab_thickness = " << Ecal_total_ScSlab_thickness << std::endl; #endif int Number_of_Si_Layers_in_Barrel = 0; int Number_of_Sc_Layers_in_Barrel = 0; #ifdef VERBOSE std::cout << " Ecal total number of Silicon layers = " << Number_of_Si_Layers_in_Barrel << std::endl; std::cout << " Ecal total number of Scintillator layers = " << Number_of_Sc_Layers_in_Barrel << std::endl; #endif // In this release the number of modules is fixed to 5 double Ecal_Barrel_module_dim_z = 2 * Ecal_Barrel_halfZ / 5. ; #ifdef VERBOSE std::cout << "Ecal_Barrel_module_dim_z = " << Ecal_Barrel_module_dim_z << std::endl; #endif // The alveolus size takes in account the module Z size // but also 4 fiber layers for the alveoulus wall, the all // divided by the number of towers double alveolus_dim_z = (Ecal_Barrel_module_dim_z - 2. * Ecal_lateral_face_thickness) / Ecal_barrel_number_of_towers - 2 * N_FIBERS_ALVOULUS * Ecal_fiber_thickness - 2 * Ecal_Slab_H_fiber_thickness - 2 * Ecal_Slab_shielding; #ifdef VERBOSE std::cout << "alveolus_dim_z = " << alveolus_dim_z << std::endl; #endif int n_total_layers = Ecal_nlayers1 + Ecal_nlayers2 + Ecal_nlayers3; Number_of_Si_Layers_in_Barrel = n_total_layers+1; double module_thickness = Ecal_nlayers1 * Ecal_radiator_thickness1 + Ecal_nlayers2 * Ecal_radiator_thickness2 + Ecal_nlayers3 * Ecal_radiator_thickness3 + int(n_total_layers/2) * // fiber around W struct layers (N_FIBERS_W_STRUCTURE * 2 * Ecal_fiber_thickness) + Number_of_Si_Layers_in_Barrel * // Silicon slabs plus fiber around and inside (Ecal_total_SiSlab_thickness + (N_FIBERS_ALVOULUS + 1 ) * Ecal_fiber_thickness) + Number_of_Sc_Layers_in_Barrel * // Scintillator slabs plus fiber around and inside (Ecal_total_ScSlab_thickness + (N_FIBERS_ALVOULUS + 1 ) * Ecal_fiber_thickness) + Ecal_support_thickness + Ecal_front_face_thickness; #ifdef VERBOSE std::cout << "For information : module_thickness = " << module_thickness << std::endl; #endif // module barrel key parameters double bottom_dim_x = 2. * tan(M_PI/8.) * Ecal_inner_radius + module_thickness/sin(M_PI/4.); double top_dim_x = bottom_dim_x - 2 * module_thickness; //------------------------------------------------------------------------------------ LayeredCalorimeterData::Layer caloLayer ; caloLayer.cellSize0 = cell_sizeX; caloLayer.cellSize1 = cell_sizeY; //== For Wafer === double cell_dim_x = caloLayer.cellSize0; double total_Si_dim_z = alveolus_dim_z; double util_SI_wafer_dim_z = total_Si_dim_z/2 - 2 * Ecal_guard_ring_size; double cell_dim_z = util_SI_wafer_dim_z/ floor(util_SI_wafer_dim_z/ cell_dim_x); int N_cells_in_Z = int(util_SI_wafer_dim_z/cell_dim_z); int N_cells_in_X = N_cells_in_Z; cell_dim_x = cell_dim_z; #ifdef VERBOSE std::cout << " bottom_dim_x = " << bottom_dim_x << std::endl; std::cout << " top_dim_x = " << top_dim_x << std::endl; std::cout << " Ecal total number of Silicon layers = " << Number_of_Si_Layers_in_Barrel << std::endl; std::cout << " Ecal total number of Scintillator layers = " << Number_of_Sc_Layers_in_Barrel << std::endl; #endif // ========= Create Ecal Barrel stave ==================================== // It will be the volume for palcing the Ecal Barrel alveolus(i.e. Layers). // And the structure W plate. // Itself will be placed into the world volume. // ========================================================================== // The TOP_X and BOTTOM_X is different in Mokka and DD4hep Trapezoid trd(top_dim_x / 2, bottom_dim_x / 2, Ecal_Barrel_module_dim_z / 2, Ecal_Barrel_module_dim_z / 2, module_thickness/2); // Volume mod_vol(det_name+"_module",trd,theDetector.material("g10")); Volume mod_vol(det_name+"_module",trd,theDetector.material("CarbonFiber")); // DJeans 5-sep-2016 // We count the layers starting from IP and from 1, // so odd layers should be inside slabs and // even ones on the structure. // The structure W layers are here big plans, as the // gap between each W plate is too small to create problems // The even W layers are part of H structure placed inside // the alveolus. // ############################ // Dimension of radiator wLog // slice provide the thickness // ############################ double y_floor = Ecal_front_face_thickness + N_FIBERS_ALVOULUS * Ecal_fiber_thickness; // ############################ // Dimension of alveolus // slice provide the thickness // ############################ // ===== build Si Slab and put into the Layer volume ===== // ===== place the layer into the module 5 time for one full layer into the trd module ==== // ===== build and place barrel structure into trd module ==== // Parameters for computing the layer X dimension: double stave_z =(Ecal_Barrel_module_dim_z - 2. * Ecal_lateral_face_thickness) / Ecal_barrel_number_of_towers/2.; double l_dim_x = bottom_dim_x/2.; // Starting X dimension for the layer. double l_pos_z = module_thickness/2; l_dim_x -= y_floor; l_pos_z -= y_floor; // ------------- create extension objects for reconstruction ----------------- //========== fill data for reconstruction ============================ LayeredCalorimeterData* caloData = new LayeredCalorimeterData ; caloData->layoutType = LayeredCalorimeterData::BarrelLayout ; caloData->inner_symmetry = nsides ; //added by Thorben Quast caloData->outer_symmetry = nsides ; caloData->phi0 = 0 ; // hardcoded /// extent of the calorimeter in the r-z-plane [ rmin, rmax, zmin, zmax ] in mm. caloData->extent[0] = Ecal_inner_radius ; //line fixed by Thorben Quast since actual conversion is made during the drawing caloData->extent[1] = ( Ecal_inner_radius + module_thickness ); //caloData->extent[1] = ( Ecal_inner_radius + module_thickness ) / cos( M_PI/8. ) ; caloData->extent[2] = 0. ; caloData->extent[3] = Ecal_Barrel_halfZ ; // // base vectors for surfaces: // dd4hep::rec::Vector3D u(1,0,0) ; // dd4hep::rec::Vector3D v(0,1,0) ; // dd4hep::rec::Vector3D n(0,0,1) ; //-------------------- start loop over ECAL layers ---------------------- // Loop over the sets of layer elements in the detector. double nRadiationLengths = 0. ; double nInteractionLengths = 0. ; double thickness_sum = 0. ; nRadiationLengths = Ecal_radiator_thickness1/(stave_material.radLength()) + y_floor/air.radLength(); nInteractionLengths = Ecal_radiator_thickness1/(stave_material.intLength()) + y_floor/air.intLength(); thickness_sum = Ecal_radiator_thickness1 + y_floor; int l_num = 1; bool isFirstSens = true; int myLayerNum = 0 ; for(xml_coll_t li(x_det,_U(layer)); li; ++li) { xml_comp_t x_layer = li; int repeat = x_layer.repeat(); // Loop over number of repeats for this layer. for (int j=0; j<repeat; j++) { string l_name = _toString(l_num,"layer%d"); double l_thickness = layering.layer(l_num-1)->thickness(); // Layer's thickness. double xcut = (l_thickness); // X dimension for this layer. l_dim_x -= xcut; Box l_box(l_dim_x-tolerance,stave_z-tolerance,l_thickness/2.0-tolerance); Volume l_vol(det_name+"_"+l_name,l_box,air); l_vol.setVisAttributes(theDetector.visAttributes(x_layer.visStr())); //fg: need vector of DetElements for towers ! // DetElement layer(stave_det, l_name, det_id); std::vector< DetElement > layers( Ecal_barrel_number_of_towers ) ; // place layer 5 times in module. at same layer position (towers !) double l_pos_y = Ecal_Barrel_module_dim_z / 2. - ( Ecal_lateral_face_thickness + Ecal_fiber_thickness * N_FIBERS_ALVOULUS + Ecal_Slab_shielding + Ecal_Slab_H_fiber_thickness + alveolus_dim_z /2.); for (int i=0; i<Ecal_barrel_number_of_towers; i++){ // need four clone layers[i] = DetElement( stave_det, l_name+_toString(i,"tower%02d") , det_id ) ; Position l_pos(0,l_pos_y,l_pos_z-l_thickness/2.); // Position of the layer. PlacedVolume layer_phv = mod_vol.placeVolume(l_vol,l_pos); // layer_phv.addPhysVolID("layer", l_num); layer_phv.addPhysVolID("tower", i); layers[i].setPlacement(layer_phv); l_pos_y -= (alveolus_dim_z + 2. * Ecal_fiber_thickness * N_FIBERS_ALVOULUS + 2. * Ecal_Slab_H_fiber_thickness + 2. * Ecal_Slab_shielding); } // Loop over the sublayers or slices for this layer. int s_num = 1; double s_pos_z = l_thickness / 2.; //-------------------------------------------------------------------------------- // BuildBarrelAlveolus: BuildSiliconSlab: //-------------------------------------------------------------------------------- double radiator_dim_y = Ecal_radiator_thickness1; //to be updated with slice radiator thickness for(xml_coll_t si(x_layer,_U(slice)); si; ++si) { xml_comp_t x_slice = si; string s_name = _toString(s_num,"slice%d"); double s_thick = x_slice.thickness(); Material slice_material = theDetector.material(x_slice.materialStr()); #ifdef VERBOSE std::cout<<"Ecal_barrel_number_of_towers: "<< Ecal_barrel_number_of_towers <<std::endl; #endif double slab_dim_x = l_dim_x-tolerance; double slab_dim_y = s_thick/2.; double slab_dim_z = stave_z-tolerance; Box s_box(slab_dim_x,slab_dim_z,slab_dim_y); Volume s_vol(det_name+"_"+l_name+"_"+s_name,s_box,slice_material); //fg: not needed DetElement slice(layer,s_name,det_id); s_vol.setVisAttributes(theDetector.visAttributes(x_slice.visStr())); #ifdef VERBOSE std::cout<<"x_slice.materialStr(): "<< x_slice.materialStr() <<std::endl; #endif if (x_slice.materialStr().compare(x_staves.materialStr()) == 0){ radiator_dim_y = s_thick; // W StructureLayer has the same thickness as W radiator layer in the Alveolus layer #if DD4HEP_VERSION_GE( 0, 15 ) caloLayer.outer_nRadiationLengths = nRadiationLengths; caloLayer.outer_nInteractionLengths = nInteractionLengths; caloLayer.outer_thickness = thickness_sum; if (!isFirstSens){ caloData->layers.push_back( caloLayer ) ; #ifdef VERBOSE std::cout<<" caloLayer.distance: "<< caloLayer.distance <<std::endl; std::cout<<" caloLayer.inner_nRadiationLengths: "<< caloLayer.inner_nRadiationLengths <<std::endl; std::cout<<" caloLayer.inner_nInteractionLengths: "<< caloLayer.inner_nInteractionLengths <<std::endl; std::cout<<" caloLayer.inner_thickness: "<< caloLayer.inner_thickness <<std::endl; std::cout<<" caloLayer.sensitive_thickness: "<< caloLayer.sensitive_thickness <<std::endl; std::cout<<" caloLayer.outer_nRadiationLengths: "<< caloLayer.outer_nRadiationLengths <<std::endl; std::cout<<" caloLayer.outer_nInteractionLengths: "<< caloLayer.outer_nInteractionLengths <<std::endl; std::cout<<" caloLayer.outer_thickness: "<< caloLayer.outer_thickness <<std::endl; std::cout<<" EcalBarrel[1]==>caloLayer.inner_thickness + caloLayer.outer_thickness: " << caloLayer.inner_thickness + caloLayer.outer_thickness <<std::endl; #endif } #endif // Init for inner nRadiationLengths = 0. ; nInteractionLengths = 0. ; thickness_sum = 0. ; isFirstSens = false; } nRadiationLengths += s_thick/(2.*slice_material.radLength()); nInteractionLengths += s_thick/(2.*slice_material.intLength()); thickness_sum += s_thick/2.; if ( x_slice.isSensitive() ) { //s_vol.setSensitiveDetector(sens); // Normal squared wafers double wafer_dim_x = N_cells_in_X * cell_dim_x; double wafer_dim_z = N_cells_in_Z * cell_dim_z; Box WaferSiSolid( wafer_dim_x/2,wafer_dim_z/2,slab_dim_y); //Volume WaferSiLog(det_name+"_"+l_name+"_"+s_name+"Wafer",WaferSiSolid,slice_material); //WaferSiLog.setSensitiveDetector(sens); double real_wafer_size_x = wafer_dim_x + 2 * Ecal_guard_ring_size; int n_wafers_x = int(floor(slab_dim_x*2 / real_wafer_size_x)); double wafer_pos_x = -slab_dim_x + Ecal_guard_ring_size + wafer_dim_x /2 ; int n_wafer_x; int wafer_num = 0; for (n_wafer_x = 1; n_wafer_x < n_wafers_x + 1; n_wafer_x++) { double wafer_pos_z = -alveolus_dim_z/2.0 + Ecal_guard_ring_size + wafer_dim_z /2; for (int n_wafer_z = 1; n_wafer_z < 3; n_wafer_z++) { wafer_num++; string Wafer_name = _toString(wafer_num,"wafer%d"); Volume WaferSiLog(det_name+"_"+l_name+"_"+s_name+"_"+Wafer_name,WaferSiSolid,slice_material); WaferSiLog.setSensitiveDetector(sens); //WaferSiLog.setVisAttributes(theDetector.visAttributes(x_slice.visStr())); PlacedVolume wafer_phv = s_vol.placeVolume(WaferSiLog,Position(wafer_pos_x, wafer_pos_z, 0)); wafer_phv.addPhysVolID("wafer", wafer_num); // Normal squared wafers, this waferOffsetX is 0.0 waferSeg->setWaferOffsetX(myLayerNum, wafer_num, 0.0); wafer_pos_z += wafer_dim_z + 2 * Ecal_guard_ring_size; } wafer_pos_x += wafer_dim_x + 2 * Ecal_guard_ring_size; } // Magic wafers to complete the slab... // (wafers with variable number of cells just // to complete the slab. in reality we think that // we'll have just a few models of special wafers // for that. double resting_dim_x = slab_dim_x*2 - (wafer_dim_x + 2 * Ecal_guard_ring_size) * n_wafers_x; if(resting_dim_x > (cell_dim_x + 2 * Ecal_guard_ring_size)) { int N_cells_x_remaining = int(floor((resting_dim_x - 2 * Ecal_guard_ring_size) /cell_dim_x)); wafer_dim_x = N_cells_x_remaining * cell_dim_x; Box MagicWaferSiSolid( wafer_dim_x/2,wafer_dim_z/2,slab_dim_y); //Volume MagicWaferSiLog(det_name+"_"+l_name+"_"+s_name+"MagicWafer",MagicWaferSiSolid,slice_material); // Magic wafers, this waferOffsetX has to be taken care, 0.0 or half cell size in X. double thisWaferOffsetX = 0.0; if ( N_cells_x_remaining%2 ) thisWaferOffsetX = cell_dim_x/2.0; wafer_pos_x = -slab_dim_x + n_wafers_x * real_wafer_size_x + (wafer_dim_x + 2 * Ecal_guard_ring_size)/2; real_wafer_size_x = wafer_dim_x + 2 * Ecal_guard_ring_size; double wafer_pos_z = -alveolus_dim_z/2.0 + Ecal_guard_ring_size + wafer_dim_z /2; //int MagicWafer_num = 0; for (int n_wafer_z = 1; n_wafer_z < 3; n_wafer_z++) { wafer_num++; string MagicWafer_name = _toString(wafer_num,"MagicWafer%d"); Volume MagicWaferSiLog(det_name+"_"+l_name+"_"+s_name+"_"+MagicWafer_name,MagicWaferSiSolid,slice_material); MagicWaferSiLog.setSensitiveDetector(sens); //MagicWaferSiLog.setVisAttributes(theDetector.visAttributes(x_slice.visStr())); PlacedVolume wafer_phv = s_vol.placeVolume(MagicWaferSiLog,Position(wafer_pos_x, wafer_pos_z, 0)); wafer_phv.addPhysVolID("wafer", wafer_num); // Magic wafers, set the waferOffsetX for this layer this wafer. waferSeg->setWaferOffsetX(myLayerNum, wafer_num, thisWaferOffsetX); wafer_pos_z += wafer_dim_z + 2 * Ecal_guard_ring_size; } } #if DD4HEP_VERSION_GE( 0, 15 ) //Store "inner" quantities caloLayer.inner_nRadiationLengths = nRadiationLengths ; caloLayer.inner_nInteractionLengths = nInteractionLengths ; caloLayer.inner_thickness = thickness_sum ; //Store sensitive slice thickness caloLayer.sensitive_thickness = s_thick ; #ifdef VERBOSE std::cout<<" l_num: "<<l_num <<std::endl; std::cout<<" s_num: "<<s_num <<std::endl; std::cout<<" Ecal_inner_radius: "<< Ecal_inner_radius <<std::endl; std::cout<<" module_thickness: "<< module_thickness <<std::endl; std::cout<<" l_pos_z: "<< l_pos_z <<std::endl; std::cout<<" l_thickness: "<< l_thickness <<std::endl; std::cout<<" s_pos_z: "<< s_pos_z <<std::endl; std::cout<<" s_thick: "<< s_thick <<std::endl; std::cout<<" radiator_dim_y: "<< radiator_dim_y <<std::endl; #endif //----------------------------------------------------------------------------------------- caloLayer.distance = Ecal_inner_radius + module_thickness/2.0 - l_pos_z + l_thickness/2. + (s_pos_z+s_thick/2.) - caloLayer.inner_thickness; caloLayer.absorberThickness = radiator_dim_y ; //----------------------------------------------------------------------------------------- #endif // Init for outer nRadiationLengths = 0. ; nInteractionLengths = 0. ; thickness_sum = 0. ; } nRadiationLengths += s_thick/(2.*slice_material.radLength()); nInteractionLengths += s_thick/(2.*slice_material.intLength()); thickness_sum += s_thick/2; // Slice placement. PlacedVolume slice_phv = l_vol.placeVolume(s_vol,Position(0,0,s_pos_z-s_thick/2)); if ( x_slice.isSensitive() ) { slice_phv.addPhysVolID("layer", myLayerNum++ ); // slice_phv.addPhysVolID("slice",s_num); } //fg: not needed slice.setPlacement(slice_phv); // Increment Z position of slice. s_pos_z -= s_thick; // Increment slice number. ++s_num; } #if DD4HEP_VERSION_GE( 0, 15 ) caloLayer.outer_nRadiationLengths = nRadiationLengths + (Ecal_fiber_thickness * (N_FIBERS_ALVOULUS + N_FIBERS_W_STRUCTURE))/air.radLength(); caloLayer.outer_nInteractionLengths = nInteractionLengths + (Ecal_fiber_thickness * (N_FIBERS_ALVOULUS + N_FIBERS_W_STRUCTURE))/air.intLength(); caloLayer.outer_thickness = thickness_sum + (Ecal_fiber_thickness * (N_FIBERS_ALVOULUS + N_FIBERS_W_STRUCTURE)); if (!isFirstSens) caloData->layers.push_back( caloLayer ) ; #ifdef VERBOSE std::cout<<" caloLayer.distance: "<< caloLayer.distance <<std::endl; std::cout<<" caloLayer.inner_nRadiationLengths: "<< caloLayer.inner_nRadiationLengths <<std::endl; std::cout<<" caloLayer.inner_nInteractionLengths: "<< caloLayer.inner_nInteractionLengths <<std::endl; std::cout<<" caloLayer.inner_thickness: "<< caloLayer.inner_thickness <<std::endl; std::cout<<" caloLayer.sensitive_thickness: "<< caloLayer.sensitive_thickness <<std::endl; std::cout<<" caloLayer.outer_nRadiationLengths: "<< caloLayer.outer_nRadiationLengths <<std::endl; std::cout<<" caloLayer.outer_nInteractionLengths: "<< caloLayer.outer_nInteractionLengths <<std::endl; std::cout<<" caloLayer.outer_thickness: "<< caloLayer.outer_thickness <<std::endl; std::cout<<" EcalBarrel[2]==>caloLayer.inner_thickness + caloLayer.outer_thickness: " << caloLayer.inner_thickness + caloLayer.outer_thickness <<std::endl; #endif #endif // Init for next double layer nRadiationLengths = radiator_dim_y/(stave_material.radLength()) + (Ecal_fiber_thickness * (N_FIBERS_ALVOULUS + N_FIBERS_W_STRUCTURE))/air.radLength(); nInteractionLengths = radiator_dim_y/(stave_material.intLength()) + (Ecal_fiber_thickness * (N_FIBERS_ALVOULUS + N_FIBERS_W_STRUCTURE))/air.intLength(); thickness_sum = radiator_dim_y + (Ecal_fiber_thickness * (N_FIBERS_ALVOULUS + N_FIBERS_W_STRUCTURE)); if(radiator_dim_y <= 0) { stringstream err; err << " \n ERROR: The subdetector " << x_det.nameStr() << " geometry parameter -- radiator_dim_y = " << radiator_dim_y ; err << " \n Please check the radiator material name in the subdetector xml file"; throw runtime_error(err.str()); } // ######################### // BuildBarrelStructureLayer // ######################### l_dim_x -= (radiator_dim_y + Ecal_fiber_thickness * (N_FIBERS_ALVOULUS + N_FIBERS_W_STRUCTURE)); double radiator_dim_x = l_dim_x*2.; #ifdef VERBOSE std::cout << "radiator_dim_x = " << radiator_dim_x << std::endl; #endif double radiator_dim_z = Ecal_Barrel_module_dim_z - 2 * Ecal_lateral_face_thickness - 2 * N_FIBERS_W_STRUCTURE * Ecal_fiber_thickness; string bs_name="bs"; Box barrelStructureLayer_box(radiator_dim_x/2.,radiator_dim_z/2.,radiator_dim_y/2.); Volume barrelStructureLayer_vol(det_name+"_"+l_name+"_"+bs_name,barrelStructureLayer_box,stave_material); barrelStructureLayer_vol.setVisAttributes(theDetector.visAttributes(x_layer.visStr())); // Increment to next layer Z position. l_pos_z -= l_thickness; // Without last W StructureLayer, the last part is Si SD even layer. // the last number of Ecal_nlayers1, Ecal_nlayers2 and Ecal_nlayers3 is odd. int even_layer = l_num*2; if(even_layer > Ecal_nlayers1 + Ecal_nlayers2 + Ecal_nlayers3) continue; //if ( Number_of_Si_Layers_in_Barrel > n_total_layers ) continue; double bsl_pos_z = l_pos_z - (radiator_dim_y/2. + Ecal_fiber_thickness * (N_FIBERS_ALVOULUS + N_FIBERS_W_STRUCTURE)); l_pos_z -= (Ecal_fiber_thickness * (N_FIBERS_ALVOULUS + N_FIBERS_W_STRUCTURE)); Position bsl_pos(0,0,bsl_pos_z); // Position of the layer. // PlacedVolume barrelStructureLayer_phv = mod_vol.placeVolume(barrelStructureLayer_vol,bsl_pos); l_dim_x -= (Ecal_fiber_thickness * (N_FIBERS_ALVOULUS + N_FIBERS_W_STRUCTURE)); l_pos_z -= (radiator_dim_y + Ecal_fiber_thickness * (N_FIBERS_ALVOULUS + N_FIBERS_W_STRUCTURE)); ++l_num; } } // Set stave visualization. if (x_staves) { mod_vol.setVisAttributes(theDetector.visAttributes(x_staves.visStr())); } //==================================================================== // Place ECAL Barrel stave module into the envelope volume //==================================================================== double X,Y; X = module_thickness * sin(M_PI/4.); Y = Ecal_inner_radius + module_thickness / 2.; for (int stave_id = 1; stave_id <= nsides ; stave_id++) for (int module_id = 1; module_id < 6; module_id++) { double phirot = (stave_id-1) * dphi - hphi*3.0; double module_z_offset = (2 * module_id-6) * Ecal_Barrel_module_dim_z/2.; // And the rotation in Mokka is right hand rule, and the rotation in DD4hep is clockwise rule // So there is a negitive sign when port Mokka into DD4hep Transform3D tr(RotationZYX(0,phirot,M_PI*0.5),Translation3D(X*cos(phirot)-Y*sin(phirot), X*sin(phirot)+Y*cos(phirot), module_z_offset)); PlacedVolume pv = envelope.placeVolume(mod_vol,tr); pv.addPhysVolID("module",module_id); pv.addPhysVolID("stave",stave_id); DetElement sd = (module_id==0&&stave_id==0) ? stave_det : stave_det.clone(_toString(module_id,"module%d")+_toString(stave_id,"stave%d")); sd.setPlacement(pv); sdet.add(sd); } // Set envelope volume attributes. envelope.setAttributes(theDetector,x_det.regionStr(),x_det.limitsStr(),x_det.visStr()); sdet.addExtension< LayeredCalorimeterData >( caloData ) ; return sdet; }
static DD4hep::Geometry::Ref_t createGenericTrackerBarrel(DD4hep::Geometry::LCDD& lcdd, DD4hep::XML::Handle_t xmlElement, DD4hep::Geometry::SensitiveDetector sensDet) { // shorthands DD4hep::XML::DetElement xmlDet = static_cast<DD4hep::XML::DetElement>(xmlElement); Dimension dimensions(xmlDet.dimensions()); // get sensitive detector type from xml DD4hep::XML::Dimension sdTyp = xmlElement.child("sensitive"); if (xmlDet.isSensitive()) { // sensitive detector used for all sensitive parts of this detector sensDet.setType(sdTyp.typeStr()); } // definition of top volume // has min/max dimensions of tracker for visualization etc. std::string detectorName = xmlDet.nameStr(); DetElement topDetElement(detectorName, xmlDet.id()); DD4hep::Geometry::Tube topVolumeShape(dimensions.rmin(), dimensions.rmax(), dimensions.dz()); Volume topVolume(detectorName, topVolumeShape, lcdd.air()); topVolume.setVisAttributes(lcdd.invisible()); // counts all layers - incremented in the inner loop over repeat - tags unsigned int layerCounter = 0; // loop over 'layer' nodes in xml for (DD4hep::XML::Collection_t xLayerColl(xmlElement, _U(layers)); nullptr != xLayerColl; ++xLayerColl) { DD4hep::XML::Component xLayer = static_cast<DD4hep::XML::Component>(xLayerColl); DD4hep::XML::Component xModuleComponents = xmlElement.child("module_components"); DD4hep::XML::Component xModule = utils::getNodeByStrAttr(xmlElement, "module", "name", xLayer.attr<std::string>("module")); // optional parameters double stereo_offset = utils::getAttrValueWithFallback(xLayer, "stereo_offset", 0.0); double module_twist_angle = utils::getAttrValueWithFallback(xLayer, "module_twist_angle", 0.1 * M_PI); double stereo_module_overlap = utils::getAttrValueWithFallback(xLayer, "stereo_module_overlap", 0.0); // get total thickness of module unsigned int idxSubMod = 0; double totalModuleComponentThickness = 0; for (DD4hep::XML::Collection_t xCompColl(xModuleComponents, _U(module_component)); nullptr != xCompColl; ++xCompColl, ++idxSubMod) { DD4hep::XML::Component xComp = static_cast<DD4hep::XML::Component>(xCompColl); totalModuleComponentThickness += xComp.thickness(); } // now that thickness is known: define module components volumes idxSubMod = 0; double integratedModuleComponentThickness = 0; std::vector<Volume> moduleComponentVector; for (DD4hep::XML::Collection_t xCompColl(xModuleComponents, _U(module_component)); nullptr != xCompColl; ++xCompColl, ++idxSubMod) { DD4hep::XML::Component xComp = static_cast<DD4hep::XML::Component>(xCompColl); std::string moduleComponentName = "layer" + std::to_string(layerCounter) + "_rod_module_component" + std::to_string(idxSubMod) + "_" + xComp.materialStr(); Volume moduleComponentVolume(moduleComponentName, DD4hep::Geometry::Box(xModule.width(), xComp.thickness(), xModule.length()), lcdd.material(xComp.materialStr())); moduleComponentVolume.setVisAttributes(lcdd, xComp.visStr()); if (xComp.isSensitive()) { moduleComponentVolume.setSensitiveDetector(sensDet); } moduleComponentVector.push_back(moduleComponentVolume); } // definition of module volume (smallest independent subdetector) // define the module whose name was given in the "layer" xml Element Volume moduleVolume("module", DD4hep::Geometry::Box(xModule.width(), xModule.thickness(), xModule.length()), lcdd.material("Air")); moduleVolume.setVisAttributes(lcdd, xModule.visStr()); // definition of rod volume (longitudinal arrangement of modules) Volume rodVolume("GenericTrackerBarrel_layer" + std::to_string(layerCounter) + "_rod", DD4hep::Geometry::Box(xModule.width(), xModule.thickness(), xLayer.dz()), lcdd.material("Air")); rodVolume.setVisAttributes(lcdd.invisible()); /// @todo: allow for more than one type of module components // analogous to module // place module substructure in module std::string moduleComponentName = "moduleComponent"; idxSubMod = 0; for (DD4hep::XML::Collection_t xCompColl(xModuleComponents, _U(module_component)); nullptr != xCompColl; ++xCompColl, ++idxSubMod) { DD4hep::XML::Component xComp = static_cast<DD4hep::XML::Component>(xCompColl); DD4hep::Geometry::Position offset(0, -0.5 * totalModuleComponentThickness + integratedModuleComponentThickness, 0); integratedModuleComponentThickness += xComp.thickness(); PlacedVolume placedModuleComponentVolume = moduleVolume.placeVolume(moduleComponentVector[idxSubMod], offset); placedModuleComponentVolume.addPhysVolID("module_component", idxSubMod); } // handle repeat attribute in xml // "repeat" layers equidistant between rmin and rmax double numRepeat = xLayer.repeat(); double layerThickness = (xLayer.rmax() - xLayer.rmin()) / numRepeat; double layer_rmin = xLayer.rmin(); unsigned int nPhi = 0; double r = 0; double phi = 0; // loop over repeated layers defined by one layer tag for (unsigned int repeatIndex = 0; repeatIndex < numRepeat; ++repeatIndex) { ++layerCounter; // let r be the middle between two equidistant layer boundaries r = layer_rmin + (0.5 + repeatIndex) * layerThickness; // definition of layer volumes DD4hep::Geometry::Tube layerShape(r - 0.5*layerThickness, r + 0.5*layerThickness, xLayer.dz()); std::string layerName = "layer" + std::to_string(layerCounter); Volume layerVolume(layerName, layerShape, lcdd.material("Silicon")); layerVolume.setVisAttributes(lcdd.invisible()); PlacedVolume placedLayerVolume = topVolume.placeVolume(layerVolume); placedLayerVolume.addPhysVolID("layer", layerCounter); // approximation of tklayout values double phiOverlapFactor = utils::getAttrValueWithFallback(xLayer, "phi_overlap_factor", 1.15); nPhi = static_cast<unsigned int>( phiOverlapFactor * 2 * M_PI * r / (2 * xModule.width())); for (unsigned int phiIndex = 0; phiIndex < nPhi; ++phiIndex) { phi = 2 * M_PI * static_cast<double>(phiIndex) / static_cast<double>(nPhi); DD4hep::Geometry::Translation3D lTranslation(r * cos(phi), r * sin(phi), 0); DD4hep::Geometry::RotationZ lRotation(phi + module_twist_angle + 0.5 * M_PI); PlacedVolume placedRodVolume = layerVolume.placeVolume(rodVolume, lTranslation * lRotation); placedRodVolume.addPhysVolID("rod", phiIndex); } } // placement of modules within rods unsigned int zRepeat = static_cast<int>(xLayer.dz() / (xModule.length() - stereo_module_overlap)); // stereo overlap for (unsigned int zIndex = 0; zIndex < zRepeat; ++zIndex) { stereo_offset *= -1.; DD4hep::Geometry::Position moduleOffset(0, stereo_offset, zIndex * 2 * (xModule.length() - stereo_module_overlap) - xLayer.dz() + xModule.length() - stereo_module_overlap); PlacedVolume placedModuleVolume = rodVolume.placeVolume(moduleVolume, moduleOffset); placedModuleVolume.addPhysVolID("module", zIndex); } } Volume motherVol = lcdd.pickMotherVolume(topDetElement); PlacedVolume placedGenericTrackerBarrel = motherVol.placeVolume(topVolume); placedGenericTrackerBarrel.addPhysVolID("system", topDetElement.id()); topDetElement.setPlacement(placedGenericTrackerBarrel); return topDetElement; }
/** Basic entry point to print out the volume hierarchy * * @author M.Frank * @version 1.0 * @date 01/04/2014 */ static long dump_volume_tree(LCDD& lcdd, int argc, char** argv) { struct Actor { typedef PlacedVolume::VolID VID; typedef PlacedVolume::VolIDs VIDs; bool m_printVolIDs; bool m_printPositions; bool m_printSensitivesOnly; Actor(int ac, char** av) : m_printVolIDs(false), m_printPositions(false), m_printSensitivesOnly(false) { for(int i=0; i<ac; ++i) { char c = ::tolower(av[i][0]); if ( c == 'v' ) m_printVolIDs = true; else if ( c == 'p' ) m_printPositions = true; else if ( c == 's' ) m_printSensitivesOnly = true; } } long dump(TGeoNode* ideal, TGeoNode* aligned,int level, VIDs volids) const { char fmt[128]; string opt_info; PlacedVolume pv(ideal); bool sensitive = false; if ( m_printPositions || m_printVolIDs ) { stringstream log; if ( m_printPositions ) { const double* trans = ideal->GetMatrix()->GetTranslation(); ::snprintf(fmt, sizeof(fmt), "Pos: (%f,%f,%f) ",trans[0],trans[1],trans[2]); log << fmt; } // Top level volume! have no volume ids if ( m_printVolIDs && ideal && ideal->GetMotherVolume() ) { VIDs vid = pv.volIDs(); if ( !vid.empty() ) { sensitive = true; log << " VolID: "; volids.std::vector<VID>::insert(volids.end(),vid.begin(),vid.end()); for(VIDs::const_iterator i=volids.begin(); i!=volids.end(); ++i) { ::snprintf(fmt, sizeof(fmt), "%s:%2d ",(*i).first.c_str(), (*i).second); log << fmt; } } } opt_info = log.str(); } TGeoVolume* volume = ideal->GetVolume(); if ( !m_printSensitivesOnly || (m_printSensitivesOnly && sensitive) ) { char sens = pv.volume().isSensitive() ? 'S' : ' '; if ( ideal == aligned ) { ::snprintf(fmt,sizeof(fmt),"%03d %%-%ds %%s (%%s: %%s) \t[%p] %c %%s", level+1,2*level+1,(void*)ideal, sens); } else { ::snprintf(fmt,sizeof(fmt),"%03d %%-%ds %%s (%%s: %%s) Ideal:%p Aligned:%p %c %%s", level+1,2*level+1,(void*)ideal,(void*)aligned, sens); } printout(INFO,"+++",fmt,"", aligned->GetName(), volume->GetTitle(), volume->GetShape()->IsA()->GetName(), opt_info.c_str()); } for (Int_t idau = 0, ndau = aligned->GetNdaughters(); idau < ndau; ++idau) { TGeoNode* ideal_daughter = ideal->GetDaughter(idau); const char* daughter_name = ideal_daughter->GetName(); TGeoNode* aligned_daughter = volume->GetNode(daughter_name); dump(ideal_daughter, aligned_daughter, level+1, volids); } return 1; } }; string place = lcdd.world().placementPath(); DetectorTools::PlacementPath path; DetectorTools::placementPath(lcdd.world(), path); PlacedVolume pv = DetectorTools::findNode(lcdd.world().placement(),place); Actor actor(argc,argv); return actor.dump(lcdd.world().placement().ptr(),pv.ptr(),0,PlacedVolume::VolIDs()); }
static Ref_t create_detector(LCDD& lcdd, xml_h e, SensitiveDetector sens) { typedef vector<PlacedVolume> Placements; xml_det_t x_det = e; Material vacuum = lcdd.vacuum(); int det_id = x_det.id(); string det_name = x_det.nameStr(); bool reflect = x_det.reflect(false); DetElement sdet (det_name,det_id); Assembly assembly (det_name); //Volume assembly (det_name,Box(10000,10000,10000),vacuum); Volume motherVol = lcdd.pickMotherVolume(sdet); int m_id=0, c_id=0, n_sensor=0; map<string,Volume> modules; map<string, Placements> sensitives; PlacedVolume pv; assembly.setVisAttributes(lcdd.invisible()); sens.setType("tracker"); for(xml_coll_t mi(x_det,_U(module)); mi; ++mi, ++m_id) { xml_comp_t x_mod = mi; string m_nam = x_mod.nameStr(); xml_comp_t trd = x_mod.trd(); double posY; double x1 = trd.x1(); double x2 = trd.x2(); double z = trd.z(); double y1, y2, total_thickness=0.; xml_coll_t ci(x_mod,_U(module_component)); for(ci.reset(), total_thickness=0.0; ci; ++ci) total_thickness += xml_comp_t(ci).thickness(); y1 = y2 = total_thickness / 2; Volume m_volume(m_nam, Trapezoid(x1, x2, y1, y2, z), vacuum); m_volume.setVisAttributes(lcdd.visAttributes(x_mod.visStr())); for(ci.reset(), n_sensor=1, c_id=0, posY=-y1; ci; ++ci, ++c_id) { xml_comp_t c = ci; double c_thick = c.thickness(); Material c_mat = lcdd.material(c.materialStr()); string c_name = _toString(c_id,"component%d"); Volume c_vol(c_name, Trapezoid(x1,x2,c_thick/2e0,c_thick/2e0,z), c_mat); c_vol.setVisAttributes(lcdd.visAttributes(c.visStr())); pv = m_volume.placeVolume(c_vol,Position(0,posY+c_thick/2,0)); if ( c.isSensitive() ) { sdet.check(n_sensor > 2,"SiTrackerEndcap2::fromCompact: "+c_name+" Max of 2 modules allowed!"); pv.addPhysVolID("sensor",n_sensor); c_vol.setSensitiveDetector(sens); sensitives[m_nam].push_back(pv); ++n_sensor; } posY += c_thick; } modules[m_nam] = m_volume; } for(xml_coll_t li(x_det,_U(layer)); li; ++li) { xml_comp_t x_layer(li); int l_id = x_layer.id(); int mod_num = 1; for(xml_coll_t ri(x_layer,_U(ring)); ri; ++ri) { xml_comp_t x_ring = ri; double r = x_ring.r(); double phi0 = x_ring.phi0(0); double zstart = x_ring.zstart(); double dz = x_ring.dz(0); int nmodules = x_ring.nmodules(); string m_nam = x_ring.moduleStr(); Volume m_vol = modules[m_nam]; double iphi = 2*M_PI/nmodules; double phi = phi0; Placements& sensVols = sensitives[m_nam]; for(int k=0; k<nmodules; ++k) { string m_base = _toString(l_id,"layer%d") + _toString(mod_num,"_module%d"); double x = -r*std::cos(phi); double y = -r*std::sin(phi); DetElement module(sdet,m_base+"_pos",det_id); pv = assembly.placeVolume(m_vol,Transform3D(RotationZYX(0,-M_PI/2-phi,-M_PI/2),Position(x,y,zstart+dz))); pv.addPhysVolID("side",1).addPhysVolID("layer", l_id).addPhysVolID("module",mod_num); module.setPlacement(pv); for(size_t ic=0; ic<sensVols.size(); ++ic) { PlacedVolume sens_pv = sensVols[ic]; DetElement comp_elt(module,sens_pv.volume().name(),mod_num); comp_elt.setPlacement(sens_pv); } if ( reflect ) { pv = assembly.placeVolume(m_vol,Transform3D(RotationZYX(M_PI,-M_PI/2-phi,-M_PI/2),Position(x,y,-zstart-dz))); pv.addPhysVolID("side",-1).addPhysVolID("layer",l_id).addPhysVolID("module",mod_num); DetElement r_module(sdet,m_base+"_neg",det_id); r_module.setPlacement(pv); for(size_t ic=0; ic<sensVols.size(); ++ic) { PlacedVolume sens_pv = sensVols[ic]; DetElement comp_elt(r_module,sens_pv.volume().name(),mod_num); comp_elt.setPlacement(sens_pv); } } dz = -dz; phi += iphi; ++mod_num; } } } pv = motherVol.placeVolume(assembly); pv.addPhysVolID("system",det_id); sdet.setPlacement(pv); return sdet; }
static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector sens) { xml_det_t x_det = e; Material air = description.air(); string det_name = x_det.nameStr(); bool reflect = x_det.reflect(); DetElement sdet(det_name,x_det.id()); Assembly assembly(det_name); PlacedVolume pv; int l_num = 0; for(xml_coll_t i(x_det,_U(layer)); i; ++i, ++l_num) { xml_comp_t x_layer = i; string l_nam = det_name+_toString(l_num,"_layer%d"); double zmin = x_layer.inner_z(); double rmin = x_layer.inner_r(); double rmax = x_layer.outer_r(); double z = zmin, layerWidth = 0.; int s_num = 0; for(xml_coll_t j(x_layer,_U(slice)); j; ++j) { double thickness = xml_comp_t(j).thickness(); layerWidth += thickness; } Tube l_tub(rmin,rmax,layerWidth,2*M_PI); Volume l_vol(l_nam,l_tub,air); l_vol.setVisAttributes(description,x_layer.visStr()); for(xml_coll_t j(x_layer,_U(slice)); j; ++j, ++s_num) { xml_comp_t x_slice = j; double thick = x_slice.thickness(); Material mat = description.material(x_slice.materialStr()); string s_nam = l_nam+_toString(s_num,"_slice%d"); Volume s_vol(s_nam, Tube(rmin,rmax,thick), mat); if ( x_slice.isSensitive() ) { sens.setType("tracker"); s_vol.setSensitiveDetector(sens); } s_vol.setAttributes(description,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr()); pv = l_vol.placeVolume(s_vol,Position(0,0,z-zmin-layerWidth/2+thick/2)); pv.addPhysVolID("slice",s_num); } DetElement layer(sdet,l_nam+"_pos",l_num); pv = assembly.placeVolume(l_vol,Position(0,0,zmin+layerWidth/2.)); pv.addPhysVolID("layer",l_num); pv.addPhysVolID("barrel",1); layer.setPlacement(pv); if ( reflect ) { pv = assembly.placeVolume(l_vol,Transform3D(RotationY(M_PI),Position(0,0,-zmin-layerWidth/2))); pv.addPhysVolID("layer",l_num); pv.addPhysVolID("barrel",2); DetElement layerR = layer.clone(l_nam+"_neg"); sdet.add(layerR.setPlacement(pv)); } } if ( x_det.hasAttr(_U(combineHits)) ) { sdet.setCombineHits(x_det.attr<bool>(_U(combineHits)),sens); } pv = description.pickMotherVolume(sdet).placeVolume(assembly); pv.addPhysVolID("system", x_det.id()); // Set the subdetector system ID. sdet.setPlacement(pv); return sdet; }
int BoxTrafos() { string xml = "file:"; xml += gSystem->Getenv("DD4hepINSTALL"); xml += "/examples/ClientTests/compact/BoxTrafos.xml"; const char* argv[] = {xml.c_str(), "BUILD_DEFAULT", 0}; gSystem->Load("libDDCore"); LCDD& lcdd = LCDD::getInstance(); lcdd.apply("DD4hepCompactLoader",2,(char**)argv); lcdd.apply("DD4hepGeometryDisplay",0,0); DetElement de = lcdd.detector("B3"); PlacedVolume pv = de.placement(); Volume vol = pv.volume(); Solid solid = vol.solid(); TGeoBBox* box = (TGeoBBox*)(solid.ptr()); Position glob,loc, pos(-10,30,10); printf("\n++++ local->world:\n\n"); loc = Position(-pos.x(),-pos.y(),-pos.z()); local_to_world("origine",de,pos,loc); loc = Position(); local_to_world("center",de,pos,loc); loc = Position(box->GetDX(),box->GetDY(),box->GetDZ()); local_to_world("top edge",de,pos,loc); loc = Position(box->GetDX(),box->GetDY(),-box->GetDZ()); local_to_world("top edge",de,pos,loc); loc = Position(-box->GetDX(),box->GetDY(),box->GetDZ()); local_to_world("top edge",de,pos,loc); loc = Position(-box->GetDX(),box->GetDY(),-box->GetDZ()); local_to_world("top edge",de,pos,loc); loc = Position(box->GetDX(),-box->GetDY(),box->GetDZ()); local_to_world("bottom edge",de,pos,loc); loc = Position(box->GetDX(),-box->GetDY(),-box->GetDZ()); local_to_world("bottom edge",de,pos,loc); loc = Position(-box->GetDX(),-box->GetDY(),box->GetDZ()); local_to_world("bottom edge",de,pos,loc); loc = Position(-box->GetDX(),-box->GetDY(),-box->GetDZ()); local_to_world("bottom edge",de,pos,loc); printf("\n++++ world->local:\n\n"); glob = Position(0,0,0); world_to_local("world center",de,pos,glob); glob = Position(pos.x(),pos.y(),pos.z()); world_to_local("position",de,pos,glob); glob = Position( box->GetDX()+pos.x(), box->GetDY()+pos.y(), box->GetDZ()+pos.z()); world_to_local("top edge",de,pos,glob); glob = Position( box->GetDX()+pos.x(), box->GetDY()+pos.y(), -box->GetDZ()+pos.z()); world_to_local("top edge",de,pos,glob); glob = Position(-box->GetDX()+pos.x(), box->GetDY()+pos.y(), box->GetDZ()+pos.z()); world_to_local("top edge",de,pos,glob); glob = Position(-box->GetDX()+pos.x(), box->GetDY()+pos.y(), -box->GetDZ()+pos.z()); world_to_local("top edge",de,pos,glob); glob = Position( box->GetDX()+pos.x(), -box->GetDY()+pos.y(), box->GetDZ()+pos.z()); world_to_local("bottom edge",de,pos,glob); glob = Position( box->GetDX()+pos.x(), -box->GetDY()+pos.y(), -box->GetDZ()+pos.z()); world_to_local("bottom edge",de,pos,glob); glob = Position(-box->GetDX()+pos.x(), -box->GetDY()+pos.y(), box->GetDZ()+pos.z()); world_to_local("bottom edge",de,pos,glob); glob = Position(-box->GetDX()+pos.x(), -box->GetDY()+pos.y(), -box->GetDZ()+pos.z()); world_to_local("bottom edge",de,pos,glob); return 1; }
static Ref_t create_detector(Detector& theDetector, xml_h e, SensitiveDetector sens) { xml_det_t x_det = e; int det_id = x_det.id(); string det_name = x_det.nameStr(); DetElement sdet (det_name,det_id); // --- create an envelope volume and position it into the world --------------------- Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector, e , sdet ) ; dd4hep::xml::setDetectorTypeFlag( e, sdet ) ; if( theDetector.buildType() == BUILD_ENVELOPE ) return sdet ; //----------------------------------------------------------------------------------- xml_dim_t dim = x_det.dimensions(); Material air = theDetector.air(); int nsides_inner = dim.nsides_inner(); int nsides_outer = dim.nsides_outer(); double rmin = dim.rmin(); double rmax = dim.rmax(); /// FIXME: IS THIS RIGHT? double zmin = dim.zmin(); double rcutout = dim.hasAttr(_U(rmin2)) ? dim.rmin2() : 0.; double zcutout = dim.hasAttr(_U(z2)) ? dim.z2() : 0.; Layering layering(x_det); double totalThickness = layering.totalThickness(); Readout readout = sens.readout(); Segmentation seg = readout.segmentation(); std::vector<double> cellSizeVector = seg.segmentation()->cellDimensions(0); //Assume uniform cell sizes, provide dummy cellID double cell_sizeX = cellSizeVector[0]; double cell_sizeY = cellSizeVector[1]; PolyhedraRegular polyVolume(nsides_outer,rmin,rmax,totalThickness); Volume endcapVol("endcap",polyVolume,air); if(zcutout >0. || rcutout > 0.){ PolyhedraRegular cutoutPolyVolume(nsides_inner,0,rmin+rcutout,zcutout); Position cutoutPos(0,0,(zcutout-totalThickness)/2.0); std::cout<<"Cutout z width will be "<<zcutout<<std::endl; endcapVol=Volume("endcap",SubtractionSolid(polyVolume,cutoutPolyVolume,cutoutPos),air); } DetElement endcapA(sdet,"endcap",det_id); Ref_t(endcapA)->SetName((det_name+"_A").c_str()); int layer_num = 0; int layerType = 0; double layerZ = -totalThickness/2; //Create caloData object to extend driver with data required for reconstruction LayeredCalorimeterData* caloData = new LayeredCalorimeterData ; caloData->layoutType = LayeredCalorimeterData::EndcapLayout ; caloData->inner_symmetry = nsides_inner; caloData->outer_symmetry = nsides_outer; /** NOTE: phi0=0 means lower face flat parallel to experimental floor * This is achieved by rotating the modules with respect to the envelope * which is assumed to be a Polyhedron and has its axes rotated with respect * to the world by 180/nsides. In any other case (e.g. if you want to have * a tip of the calorimeter touching the ground) this value needs to be computed */ caloData->inner_phi0 = 0.; caloData->outer_phi0 = 0.; caloData->gap0 = 0.; //FIXME caloData->gap1 = 0.; //FIXME caloData->gap2 = 0.; //FIXME /// extent of the calorimeter in the r-z-plane [ rmin, rmax, zmin, zmax ] in mm. caloData->extent[0] = rmin ; caloData->extent[1] = rmax ; ///FIXME: CHECK WHAT IS NEEDED (EXSCRIBED?) caloData->extent[2] = zmin ; caloData->extent[3] = zmin + totalThickness; endcapVol.setAttributes(theDetector,x_det.regionStr(),x_det.limitsStr(),x_det.visStr()); for(xml_coll_t c(x_det,_U(layer)); c; ++c) { xml_comp_t x_layer = c; double layer_thick = layering.layer(layer_num)->thickness(); string layer_type_name = _toString(layerType,"layerType%d"); int layer_repeat = x_layer.repeat(); double layer_rcutout = x_layer.hasAttr(_U(gap)) ? x_layer.gap() : 0; std::cout<<"Number of layers in group "<<layerType<<" : "<<layer_repeat<<std::endl; Volume layer_vol(layer_type_name,PolyhedraRegular(nsides_outer,rmin+layer_rcutout,rmax,layer_thick),air); int slice_num = 0; double sliceZ = -layer_thick/2; //Create a caloLayer struct for thiss layer type to store copies of in the parent struct LayeredCalorimeterData::Layer caloLayer ; caloLayer.cellSize0 = cell_sizeX; caloLayer.cellSize1 = cell_sizeY; double nRadiationLengths=0.; double nInteractionLengths=0.; double thickness_sum=0; for(xml_coll_t s(x_layer,_U(slice)); s; ++s) { xml_comp_t x_slice = s; string slice_name = _toString(slice_num,"slice%d"); double slice_thickness = x_slice.thickness(); Material slice_material = theDetector.material(x_slice.materialStr()); Volume slice_vol(slice_name,PolyhedraRegular(nsides_outer,rmin+layer_rcutout,rmax,slice_thickness),slice_material); slice_vol.setVisAttributes(theDetector.visAttributes(x_slice.visStr())); sliceZ += slice_thickness/2; layer_vol.placeVolume(slice_vol,Position(0,0,sliceZ)); nRadiationLengths += slice_thickness/(2.*slice_material.radLength()); nInteractionLengths += slice_thickness/(2.*slice_material.intLength()); thickness_sum += slice_thickness/2; if ( x_slice.isSensitive() ) { sens.setType("calorimeter"); slice_vol.setSensitiveDetector(sens); #if DD4HEP_VERSION_GE( 0, 15 ) //Store "inner" quantities caloLayer.inner_nRadiationLengths = nRadiationLengths; caloLayer.inner_nInteractionLengths = nInteractionLengths; caloLayer.inner_thickness = thickness_sum; //Store scintillator thickness caloLayer.sensitive_thickness = slice_thickness; #endif //Reset counters to measure "outside" quantitites nRadiationLengths=0.; nInteractionLengths=0.; thickness_sum = 0.; } nRadiationLengths += slice_thickness/(2.*slice_material.radLength()); nInteractionLengths += slice_thickness/(2.*slice_material.intLength()); thickness_sum += slice_thickness/2; sliceZ += slice_thickness/2; slice_num++; } #if DD4HEP_VERSION_GE( 0, 15 ) //Store "outer" quantities caloLayer.outer_nRadiationLengths = nRadiationLengths; caloLayer.outer_nInteractionLengths = nInteractionLengths; caloLayer.outer_thickness = thickness_sum; #endif layer_vol.setVisAttributes(theDetector.visAttributes(x_layer.visStr())); if ( layer_repeat <= 0 ) throw std::runtime_error(x_det.nameStr()+"> Invalid repeat value"); for(int j=0; j<layer_repeat; ++j) { string phys_lay = _toString(layer_num,"layer%d"); //The rest of the data is constant; only the distance needs to be updated //Store the position up to the inner face of the layer caloLayer.distance = zmin + totalThickness/2 + layerZ; //Push back a copy to the caloData structure caloData->layers.push_back( caloLayer ); layerZ += layer_thick/2; DetElement layer_elt(endcapA, phys_lay, layer_num); PlacedVolume pv = endcapVol.placeVolume(layer_vol,Position(0,0,layerZ)); pv.addPhysVolID("layer", layer_num); layer_elt.setPlacement(pv); layerZ += layer_thick/2; ++layer_num; } ++layerType; } double z_pos = zmin+totalThickness/2; PlacedVolume pv; // Reflect it. DetElement endcapB = endcapA.clone(det_name+"_B",x_det.id()); //Removed rotations to align with envelope //NOTE: If the envelope is not a polyhedron (eg. if you use a tube) //you may need to rotate so the axes match pv = envelope.placeVolume(endcapVol,Transform3D(RotationZYX(0,0,0), Position(0,0,z_pos))); pv.addPhysVolID("side", 1); endcapA.setPlacement(pv); //Removed rotations pv = envelope.placeVolume(endcapVol,Transform3D(RotationZYX(0,M_PI,0), Position(0,0,-z_pos))); pv.addPhysVolID("side", 2); endcapB.setPlacement(pv); sdet.add(endcapB); sdet.addExtension< LayeredCalorimeterData >( caloData ) ; return sdet; }
static Ref_t create_detector(Detector& theDetector,xml_h e,SensitiveDetector sens){ typedef vector<PlacedVolume>Placements; xml_det_t x_det=e; Material vacuum=theDetector.vacuum(); int det_id= x_det.id(); string det_name=x_det.nameStr(); bool reflect = x_det.reflect(false); DetElement sdet(det_name,det_id); int m_id=0,c_id=0,n_sensor=0; map<string,Volume>modules; map<string,Placements>sensitives; PlacedVolume pv; //encoding that was missing std::string cellIDEncoding=sens.readout().idSpec().fieldDescription(); UTIL::BitField64 encoder(cellIDEncoding); encoder.reset(); encoder[lcio::LCTrackerCellID::subdet()]=det_id; // --- create an envelope volume and position it into the world --------------------- Volume envelope=dd4hep::xml::createPlacedEnvelope(theDetector,e,sdet); dd4hep::xml::setDetectorTypeFlag(e,sdet); if(theDetector.buildType() == BUILD_ENVELOPE)return sdet; //----------------------------------------------------------------------------------- dd4hep::rec::ZDiskPetalsData* zDiskPetalsData=new dd4hep::rec::ZDiskPetalsData; //neighbour surfaces added dd4hep::rec::NeighbourSurfacesData* neighbourSurfacesData=new dd4hep::rec::NeighbourSurfacesData(); // std::map< std::string, double > moduleSensThickness; envelope.setVisAttributes(theDetector.invisible()); sens.setType("tracker"); for(xml_coll_t mi(x_det,_U(module));mi;++mi,++m_id){ xml_comp_t x_mod=mi; string m_nam=x_mod.nameStr(); xml_comp_t trd=x_mod.trd(); double posY; double x1=trd.x1(); double x2=trd.x2(); double z=trd.z(); double y1,y2,total_thickness=0.; xml_coll_t ci(x_mod,_U(module_component)); for(ci.reset(),total_thickness=0.0;ci;++ci) total_thickness += xml_comp_t(ci).thickness(); y1 = y2 = total_thickness / 2; Volume m_volume(m_nam, Trapezoid(x1, x2, y1, y2, z), vacuum); m_volume.setVisAttributes(theDetector.visAttributes(x_mod.visStr())); // Loop over slices // The first slice (top in the xml) is placed at the "bottom" of the module for(ci.reset(), n_sensor=1, c_id=0, posY=-y1; ci; ++ci, ++c_id){ xml_comp_t c=ci; double c_thick=c.thickness(); Material c_mat=theDetector.material(c.materialStr()); string c_name=_toString(c_id,"component%d"); Volume c_vol(c_name, Trapezoid(x1,x2,c_thick/2e0,c_thick/2e0,z), c_mat); c_vol.setVisAttributes(theDetector.visAttributes(c.visStr())); pv = m_volume.placeVolume(c_vol,Position(0,posY+c_thick/2,0)); if (c.isSensitive()){ c_vol.setSensitiveDetector(sens); sensitives[m_nam].push_back(pv); ++n_sensor; } posY += c_thick; } modules[m_nam] = m_volume; } for(xml_coll_t li(x_det,_U(layer));li;++li){ xml_comp_t x_layer(li); int l_id=x_layer.id(); int mod_num=0; int ring_num=0; double sumZ(0.),innerR(1e100),outerR(0.); //loop only to count the number of rings in a disk - it is then needed for looking for neighborous when you are in a "border" cell int nrings = 0; for(xml_coll_t ri(x_layer,_U(ring)); ri; ++ri) { nrings++; } dd4hep::rec::ZDiskPetalsData::LayerLayout thisLayer; for(xml_coll_t ri(x_layer,_U(ring)); ri; ++ri) { xml_comp_t x_ring = ri; double r=x_ring.r(); double phi0=x_ring.phi0(0); double zstart=x_ring.zstart(); double dz=x_ring.dz(0); int nmodules=x_ring.nmodules(); string m_nam=x_ring.moduleStr(); Volume m_vol=modules[m_nam]; double iphi=2*M_PI/nmodules; double phi=phi0; Placements& sensVols=sensitives[m_nam]; Box mod_shape(m_vol.solid()); if(r-mod_shape->GetDZ()<innerR) innerR=r-mod_shape->GetDZ(); if(r+mod_shape->GetDZ()>outerR) outerR=r+mod_shape->GetDZ(); sumZ+=zstart; r=r+mod_shape->GetDY(); for(int k=0;k<nmodules;++k){ string m_base=_toString(l_id,"layer%d")+_toString(mod_num,"_module%d")+_toString(k,"_sensor%d"); double x=-r*std::cos(phi); double y=-r*std::sin(phi); DetElement module(sdet,m_base+"_pos",det_id); pv=envelope.placeVolume(m_vol,Transform3D(RotationZYX(0,-M_PI/2-phi,-M_PI/2),Position(x,y,zstart+dz))); pv.addPhysVolID("side",1).addPhysVolID("layer", l_id).addPhysVolID("module",mod_num).addPhysVolID("sensor",k); module.setPlacement(pv); for(size_t ic=0;ic<sensVols.size();++ic){ PlacedVolume sens_pv=sensVols[ic]; DetElement comp_elt(module,sens_pv.volume().name(),mod_num); comp_elt.setPlacement(sens_pv); } if(reflect){ pv = envelope.placeVolume(m_vol,Transform3D(RotationZYX(M_PI,-M_PI/2-phi,-M_PI/2),Position(x,y,-zstart-dz))); pv.addPhysVolID("side",-1).addPhysVolID("layer",l_id).addPhysVolID("module",mod_num).addPhysVolID("sensor",k); DetElement r_module(sdet,m_base+"_neg",det_id); r_module.setPlacement(pv); for(size_t ic=0;ic<sensVols.size();++ic){ PlacedVolume sens_pv=sensVols[ic]; DetElement comp_elt(r_module,sens_pv.volume().name(),mod_num); comp_elt.setPlacement(sens_pv); } } //modified on comparison with TrackerEndcap_o2_v06_geo.cpp //get cellID and fill map< cellID of surface, vector of cellID of neighbouring surfaces > dd4hep::long64 cellID_reflect; if(reflect){ encoder[lcio::LCTrackerCellID::side()]=lcio::ILDDetID::bwd; encoder[lcio::LCTrackerCellID::layer()]=l_id; encoder[lcio::LCTrackerCellID::module()]=mod_num; encoder[lcio::LCTrackerCellID::sensor()]=k; cellID_reflect=encoder.lowWord(); // 32 bits } encoder[lcio::LCTrackerCellID::side()]=lcio::ILDDetID::fwd; encoder[lcio::LCTrackerCellID::layer()]=l_id; encoder[lcio::LCTrackerCellID::module()]=mod_num; encoder[lcio::LCTrackerCellID::sensor()]=k; dd4hep::long64 cellID = encoder.lowWord(); // 32 bits //compute neighbours int n_neighbours_module = 1; // 1 gives the adjacent modules (i do not think we would like to change this) int n_neighbours_sensor = 1; int newmodule=0,newsensor=0; for(int imodule=-n_neighbours_module; imodule<=n_neighbours_module; imodule++){ // neighbouring modules for(int isensor=-n_neighbours_sensor; isensor<=n_neighbours_sensor; isensor++){ // neighbouring sensors if (imodule==0 && isensor==0) continue; // cellID we started with newmodule = mod_num + imodule; newsensor = k + isensor; //compute special case at the boundary //general computation to allow (if necessary) more then adiacent neighbours (ie: +-2) if (newsensor < 0) newsensor = nmodules + newsensor; if (newsensor >= nmodules) newsensor = newsensor - nmodules; if (newmodule < 0 || newmodule >= nrings)continue; //out of disk //encoding encoder[lcio::LCTrackerCellID::module()] = newmodule; encoder[lcio::LCTrackerCellID::sensor()] = newsensor; neighbourSurfacesData->sameLayer[cellID].push_back(encoder.lowWord()); if (reflect){ encoder[lcio::LCTrackerCellID::side()]=lcio::ILDDetID::bwd; encoder[lcio::LCTrackerCellID::layer()]=l_id; encoder[lcio::LCTrackerCellID::module()]=newmodule; encoder[lcio::LCTrackerCellID::sensor()]=newsensor; neighbourSurfacesData->sameLayer[cellID_reflect].push_back(encoder.lowWord()); } } } dz = -dz; phi += iphi; } ++mod_num; ++ring_num; } // Only filling what is needed for CED/DDMarlinPandora thisLayer.zPosition=sumZ/ring_num; // average z thisLayer.distanceSensitive=innerR; thisLayer.lengthSensitive=outerR - innerR; thisLayer.petalNumber=ring_num; // number of rings in petalNumber, needed for tracking zDiskPetalsData->layers.push_back(thisLayer); } sdet.setAttributes(theDetector,envelope,x_det.regionStr(),x_det.limitsStr(),x_det.visStr()); sdet.addExtension<dd4hep::rec::ZDiskPetalsData>(zDiskPetalsData); //added extension sdet.addExtension<dd4hep::rec::NeighbourSurfacesData>(neighbourSurfacesData); std::cout<<"XXX Tracker endcap layers:"<<zDiskPetalsData->layers.size()<<std::endl; return sdet; }
static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDetector sens) { std::cout << __PRETTY_FUNCTION__ << std::endl; std::cout << "Here is my LumiCal" << std::endl; std::cout << " and this is the sensitive detector: " << &sens << std::endl; sens.setType("calorimeter"); //Materials Material air = theDetector.air(); //Access to the XML File xml_det_t xmlLumiCal = element; const std::string detName = xmlLumiCal.nameStr(); DetElement sdet ( detName, xmlLumiCal.id() ); // --- create an envelope volume and position it into the world --------------------- Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector, element , sdet ) ; DetElement lumiCalDE_1(sdet,"Calorimeter1",1); DetElement lumiCalDE_2(sdet,"Calorimeter2",2); sdet.setTypeFlag( DetType::CALORIMETER | DetType::ENDCAP | DetType::ELECTROMAGNETIC | DetType::FORWARD ) ; if( theDetector.buildType() == BUILD_ENVELOPE ) return sdet ; //----------------------------------------------------------------------------------- dd4hep::xml::Dimension dimensions = xmlLumiCal.dimensions(); //LumiCal Dimensions const double lcalInnerR = dimensions.inner_r(); const double lcalOuterR = dimensions.outer_r(); const double lcalInnerZ = dimensions.inner_z(); const double lcalThickness = Layering(xmlLumiCal).totalThickness(); const double lcalCentreZ = lcalInnerZ+lcalThickness*0.5; double LumiCal_cell_size = theDetector.constant<double>("LumiCal_cell_size"); //========== fill data for reconstruction ============================ LayeredCalorimeterData* caloData = new LayeredCalorimeterData ; caloData->layoutType = LayeredCalorimeterData::EndcapLayout ; caloData->inner_symmetry = 0 ; // hardcoded tube caloData->outer_symmetry = 0 ; caloData->phi0 = 0 ; /// extent of the calorimeter in the r-z-plane [ rmin, rmax, zmin, zmax ] in mm. caloData->extent[0] = lcalInnerR ; caloData->extent[1] = lcalOuterR ; caloData->extent[2] = lcalInnerZ ; caloData->extent[3] = lcalInnerZ + lcalThickness ; // counter for the current layer to be placed int thisLayerId = 0; //Parameters we have to know about dd4hep::xml::Component xmlParameter = xmlLumiCal.child(_Unicode(parameter)); const double fullCrossingAngle = xmlParameter.attr< double >(_Unicode(crossingangle)); std::cout << " The crossing angle is: " << fullCrossingAngle << " radian" << std::endl; //Envelope to place the layers in Tube envelopeTube (lcalInnerR, lcalOuterR, lcalThickness*0.5 ); Volume envelopeVol(detName+"_module",envelopeTube,air); envelopeVol.setVisAttributes(theDetector,xmlLumiCal.visStr()); //////////////////////////////////////////////////////////////////////////////// // Create all the layers //////////////////////////////////////////////////////////////////////////////// //Loop over all the layer (repeat=NN) sections //This is the starting point to place all layers, we need this when we have more than one layer block double referencePosition = -lcalThickness*0.5; for(dd4hep::xml::Collection_t coll(xmlLumiCal,_U(layer)); coll; ++coll) { dd4hep::xml::Component xmlLayer(coll); //we know this thing is a layer //This just calculates the total size of a single layer //Why no convenience function for this? double layerThickness = 0; for(dd4hep::xml::Collection_t l(xmlLayer,_U(slice)); l; ++l) layerThickness += xml_comp_t(l).thickness(); std::cout << "Total Length " << lcalThickness/dd4hep::cm << " cm" << std::endl; std::cout << "Layer Thickness " << layerThickness/dd4hep::cm << " cm" << std::endl; //Loop for repeat=NN for(int i=0, repeat=xmlLayer.repeat(); i<repeat; ++i) { std::string layer_name = detName + dd4hep::xml::_toString(thisLayerId,"_layer%d"); Tube layer_base(lcalInnerR,lcalOuterR,layerThickness*0.5); Volume layer_vol(layer_name,layer_base,air); int sliceID=0; double inThisLayerPosition = -layerThickness*0.5; double nRadiationLengths=0.; double nInteractionLengths=0.; double thickness_sum=0; LayeredCalorimeterData::Layer caloLayer ; for(dd4hep::xml::Collection_t collSlice(xmlLayer,_U(slice)); collSlice; ++collSlice) { dd4hep::xml::Component compSlice = collSlice; const double slice_thickness = compSlice.thickness(); const std::string sliceName = layer_name + dd4hep::xml::_toString(sliceID,"slice%d"); Material slice_material = theDetector.material(compSlice.materialStr()); Tube sliceBase(lcalInnerR,lcalOuterR,slice_thickness/2); Volume slice_vol (sliceName,sliceBase,slice_material); nRadiationLengths += slice_thickness/(2.*slice_material.radLength()); nInteractionLengths += slice_thickness/(2.*slice_material.intLength()); thickness_sum += slice_thickness/2; if ( compSlice.isSensitive() ) { #if DD4HEP_VERSION_GE( 0, 15 ) //Store "inner" quantities caloLayer.inner_nRadiationLengths = nRadiationLengths; caloLayer.inner_nInteractionLengths = nInteractionLengths; caloLayer.inner_thickness = thickness_sum; //Store scintillator thickness caloLayer.sensitive_thickness = slice_thickness; #endif //Reset counters to measure "outside" quantitites nRadiationLengths=0.; nInteractionLengths=0.; thickness_sum = 0.; slice_vol.setSensitiveDetector(sens); } nRadiationLengths += slice_thickness/(2.*slice_material.radLength()); nInteractionLengths += slice_thickness/(2.*slice_material.intLength()); thickness_sum += slice_thickness/2; slice_vol.setAttributes(theDetector,compSlice.regionStr(),compSlice.limitsStr(),compSlice.visStr()); layer_vol.placeVolume(slice_vol,Position(0,0,inThisLayerPosition+slice_thickness*0.5)); inThisLayerPosition += slice_thickness; ++sliceID; }//For all slices in this layer //----------------------------------------------------------------------------------------- ///Needs to be innermost face distance caloLayer.distance = lcalCentreZ + referencePosition; #if DD4HEP_VERSION_GE( 0, 15 ) caloLayer.outer_nRadiationLengths = nRadiationLengths; caloLayer.outer_nInteractionLengths = nInteractionLengths; caloLayer.outer_thickness = thickness_sum; #endif caloLayer.cellSize0 = LumiCal_cell_size ; caloLayer.cellSize1 = LumiCal_cell_size ; caloData->layers.push_back( caloLayer ) ; //----------------------------------------------------------------------------------------- //Why are we doing this for each layer, this just needs to be done once and then placed multiple times //Do we need unique IDs for each piece? layer_vol.setVisAttributes(theDetector,xmlLayer.visStr()); Position layer_pos(0,0,referencePosition+0.5*layerThickness); referencePosition += layerThickness; PlacedVolume pv = envelopeVol.placeVolume(layer_vol,layer_pos); pv.addPhysVolID("layer",thisLayerId); ++thisLayerId; }//for all layers }// for all layer collections const Position bcForwardPos (std::tan(0.5*fullCrossingAngle)*lcalCentreZ,0.0, lcalCentreZ); const Position bcBackwardPos(std::tan(0.5*fullCrossingAngle)*lcalCentreZ,0.0,-lcalCentreZ); const Rotation3D bcForwardRot ( RotationY(fullCrossingAngle*0.5 ) ); const Rotation3D bcBackwardRot( RotationZYX ( (M_PI), (M_PI-fullCrossingAngle*0.5), (0.0))); PlacedVolume pv = envelope.placeVolume(envelopeVol, Transform3D( bcForwardRot, bcForwardPos ) ); pv.addPhysVolID("barrel", 1); lumiCalDE_1.setPlacement(pv); PlacedVolume pv2 = envelope.placeVolume(envelopeVol, Transform3D( bcBackwardRot, bcBackwardPos ) ); pv2.addPhysVolID("barrel", 2); lumiCalDE_2.setPlacement(pv2); sdet.addExtension< LayeredCalorimeterData >( caloData ) ; return sdet; }
static Ref_t create_detector(Detector& theDetector, xml_h e, SensitiveDetector sens) { typedef vector<PlacedVolume> Placements; xml_det_t x_det = e; Material air = theDetector.air(); int det_id = x_det.id(); string det_name = x_det.nameStr(); DetElement sdet (det_name,det_id); // Assembly assembly (det_name); map<string, Volume> volumes; map<string, Placements> sensitives; PlacedVolume pv; // for encoding std::string cellIDEncoding = sens.readout().idSpec().fieldDescription(); UTIL::BitField64 encoder( cellIDEncoding ); encoder.reset(); encoder[lcio::LCTrackerCellID::subdet()] = det_id; encoder[lcio::LCTrackerCellID::side()] = lcio::ILDDetID::barrel; // --- create an envelope volume and position it into the world --------------------- Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector, e , sdet ) ; dd4hep::xml::setDetectorTypeFlag( e, sdet ) ; if( theDetector.buildType() == BUILD_ENVELOPE ) return sdet ; //----------------------------------------------------------------------------------- ZPlanarData* zPlanarData = new ZPlanarData() ; NeighbourSurfacesData* neighbourSurfacesData = new NeighbourSurfacesData() ; sens.setType("tracker"); //NOTE modules are what is defined in compact. Later we call a "module" as a "sensor". for(xml_coll_t mi(x_det,_U(module)); mi; ++mi) { xml_comp_t x_mod = mi; xml_comp_t m_env = x_mod.child(_U(module_envelope)); string m_nam = x_mod.nameStr(); if ( volumes.find(m_nam) != volumes.end() ) { printout(ERROR,"TrackerBarrel","Logics error in building modules."); throw runtime_error("Logic error in building modules."); } double module_thickness = 0; for(xml_coll_t incl(x_mod,_U(include)); incl; ++incl) { dd4hep::xml::DocumentHolder doc(dd4hep::xml::DocumentHandler().load(incl, incl.attr_value(_U(ref)))); xml_h includes = doc.root(); xml_det_t incl_stack = includes; for (xml_coll_t ci(incl_stack, _U(module_component)); ci; ++ci) { xml_comp_t x_comp = ci; module_thickness = module_thickness + x_comp.thickness(); } } Volume m_vol(m_nam,Box(m_env.width()/2.,m_env.length()/2.,module_thickness/2.),air); volumes[m_nam] = m_vol; m_vol.setVisAttributes(theDetector.visAttributes(x_mod.visStr())); int ncomponents = 0; //First component on top of the list is the innermost one. double position_z= -module_thickness/2.; for(xml_coll_t incl(x_mod,_U(include)); incl; ++incl) { dd4hep::xml::DocumentHolder doc(dd4hep::xml::DocumentHandler().load(incl, incl.attr_value(_U(ref)))); xml_h includes = doc.root(); xml_det_t incl_stack = includes; for (xml_coll_t ci(incl_stack, _U(module_component)); ci; ++ci, ++ncomponents) { xml_comp_t x_comp = ci; string c_nam = _toString(ncomponents, "component%d"); Box c_box(m_env.width() / 2.0, m_env.length() / 2.0, x_comp.thickness() / 2.0); Volume c_vol(c_nam, c_box, theDetector.material(x_comp.materialStr())); pv = m_vol.placeVolume(c_vol, Position(0, 0, position_z + x_comp.thickness() / 2.0)); c_vol.setRegion(theDetector, x_comp.regionStr()); c_vol.setLimitSet(theDetector, x_comp.limitsStr()); c_vol.setVisAttributes(theDetector, x_comp.visStr()); if (x_comp.isSensitive()) { // pv.addPhysVolID("wafer",wafer_number++); c_vol.setSensitiveDetector(sens); sensitives[m_nam].push_back(pv); } position_z += x_comp.thickness(); } } } for(xml_coll_t li(x_det,_U(layer)); li; ++li) { xml_comp_t x_layer = li; xml_comp_t x_layout = x_layer.child(_U(rphi_layout)); xml_comp_t z_layout = x_layer.child(_U(z_layout)); // Get the <z_layout> element. int lay_id = x_layer.id(); // int type = x_layer.type(); string m_nam = x_layer.moduleStr(); string lay_nam = _toString(x_layer.id(),"layer%d"); Assembly lay_vol (lay_nam); // Create the layer envelope volume. double phi0 = x_layout.phi0(); // Starting phi of first sensor. double phi_tilt = x_layout.phi_tilt(); // Phi tilt of a sensor. double rc = x_layout.rc(); // Radius of the sensor center. int nphi = x_layout.nphi(); // Number of sensors in phi. double rphi_dr = x_layout.dr(); // The delta radius of every other sensor. double phi_incr = (M_PI * 2) / nphi; // Phi increment for one sensor. double phic = phi0; // Phi of the sensor center. double z0 = z_layout.z0(); // Z position of first sensor in phi. double nz = z_layout.nz(); // Number of sensors to place in z. double z_dr = z_layout.dr(); // Radial displacement parameter, of every other sensor. Volume m_env = volumes[m_nam]; DetElement lay_elt(sdet,_toString(x_layer.id(),"layer%d"),lay_id); Placements& waferVols = sensitives[m_nam]; // Z increment for sensor placement along Z axis. // Adjust for z0 at center of sensor rather than // the end of cylindrical envelope. double z_incr = nz > 1 ? (2.0 * z0) / (nz - 1) : 0.0; // Starting z for sensor placement along Z axis. double sensor_z = -z0; int module_idx =0; ZPlanarData::LayerLayout thisLayer ; // Loop over the number of sensors in phi. for (int ii = 0; ii < nphi; ii++) { double dx = z_dr * std::cos(phic + phi_tilt); // Delta x of sensor position. double dy = z_dr * std::sin(phic + phi_tilt); // Delta y of sensor position. double x = rc * std::cos(phic); // Basic x sensor position. double y = rc * std::sin(phic); // Basic y sensor position. // Loop over the number of sensors in z. //Create stave FIXME disable for now string module_name = _toString(module_idx,"module%d"); // DetElement module_elt(lay_elt,module_name,module_idx); int sensor_idx = 0; for (int j = 0; j < nz; j++) { string sensor_name = _toString(sensor_idx,"sensor%d"); /////////////////// //get cellID and fill map< cellID of surface, vector of cellID of neighbouring surfaces > //encoding encoder[lcio::LCTrackerCellID::layer()] = lay_id; encoder[lcio::LCTrackerCellID::module()] = module_idx; encoder[lcio::LCTrackerCellID::sensor()] = sensor_idx; dd4hep::long64 cellID = encoder.lowWord(); // 32 bits //compute neighbours int n_neighbours_module = 1; // 1 gives the adjacent modules (i do not think we would like to change this) int n_neighbours_sensor = 1; int newmodule=0, newsensor=0; for(int imodule=-n_neighbours_module; imodule<=n_neighbours_module; imodule++){ // neighbouring modules for(int isensor=-n_neighbours_sensor; isensor<=n_neighbours_sensor; isensor++){ // neighbouring sensors if (imodule==0 && isensor==0) continue; // cellID we started with newmodule = module_idx + imodule; newsensor = sensor_idx + isensor; //compute special case at the boundary //general computation to allow (if necessary) more then adjacent neighbours (ie: +-2) if (newmodule < 0) newmodule = nphi + newmodule; if (newmodule >= nphi) newmodule = newmodule - nphi; if (newsensor < 0 || newsensor >= nz) continue; //out of the stave //encoding encoder[lcio::LCTrackerCellID::module()] = newmodule; encoder[lcio::LCTrackerCellID::sensor()] = newsensor; neighbourSurfacesData->sameLayer[cellID].push_back(encoder.lowWord()); } } /////////////////// //FIXME sensor_name = module_name + sensor_name; DetElement sens_elt(lay_elt,sensor_name,sensor_idx); // Module PhysicalVolume. Transform3D tr(RotationZYX(0,((M_PI/2)-phic-phi_tilt),-M_PI/2),Position(x,y,sensor_z)); //FIXME pv = lay_vol.placeVolume(m_env,tr); pv.addPhysVolID(_U(module), module_idx); pv.addPhysVolID(_U(sensor), sensor_idx); sens_elt.setPlacement(pv); for(size_t ic=0; ic<waferVols.size(); ++ic) { // std::cout<<"Layer: "<<lay_id<<" phiIdx: "<<ii<<" zidx: "<<j<<" wafer idx: "<<ic<<std::endl; PlacedVolume wafer_pv = waferVols[ic]; DetElement comp_elt(sens_elt,wafer_pv.volume().name(),sensor_idx); comp_elt.setPlacement(wafer_pv); ///GET GEAR INFORMATION FROM FIRST "MODULE" IN Z AND phi ///NOTE WORKS ONLY FOR ONE WAFER if (ii==0 && j==0 && ic==0){ Box mod_shape(m_env.solid()), comp_shape(wafer_pv.volume().solid()); const double* trans = comp_elt.placement()->GetMatrix()->GetTranslation(); double half_module_thickness = mod_shape->GetDZ(); double half_silicon_thickness = comp_shape->GetDZ(); double sensitive_z_position = trans[2]; double inner_thickness = half_module_thickness - sensitive_z_position; thisLayer.distanceSupport = rc ; thisLayer.offsetSupport = 0; thisLayer.thicknessSupport = inner_thickness- half_silicon_thickness; thisLayer.zHalfSupport = z0 + mod_shape->GetDY(); thisLayer.widthSupport = 2*mod_shape->GetDX(); thisLayer.distanceSensitive = rc+sensitive_z_position; thisLayer.offsetSensitive = 0. ; thisLayer.thicknessSensitive = 2*half_silicon_thickness;//Assembled along Z //Changed by Thorben Quast (same applies to zHalfSupport) //z0 = center of most right sensor, comp_shape-GetDY() = half length of one sensitive are of the module thisLayer.zHalfSensitive = z0 + comp_shape->GetDY(); thisLayer.widthSensitive = 2*comp_shape->GetDX(); thisLayer.ladderNumber = (int) nphi ; thisLayer.phi0 = phic; } } /// Increase counters etc. sensor_idx++; // Adjust the x and y coordinates of the sensor. x += dx; y += dy; // Flip sign of x and y adjustments. dx *= -1; dy *= -1; // Add z increment to get next z placement pos. sensor_z += z_incr; } module_idx++; phic += phi_incr; // Increment the phi placement of sensor. rc += rphi_dr; // Increment the center radius according to dr parameter. rphi_dr *= -1; // Flip sign of dr parameter. sensor_z = -z0; // Reset the Z placement parameter for sensor. } // Create the PhysicalVolume for the layer. pv = envelope.placeVolume(lay_vol); // Place layer in mother pv.addPhysVolID("layer", lay_id); // Set the layer ID. lay_elt.setAttributes(theDetector,lay_vol,x_layer.regionStr(),x_layer.limitsStr(),x_layer.visStr()); lay_elt.setPlacement(pv); zPlanarData->layers.push_back( thisLayer ) ; } sdet.setAttributes(theDetector,envelope,x_det.regionStr(),x_det.limitsStr(),x_det.visStr()); sdet.addExtension< ZPlanarData >( zPlanarData ) ; sdet.addExtension< NeighbourSurfacesData >( neighbourSurfacesData ) ; //envelope.setVisAttributes(theDetector.invisible()); /*pv = theDetector.pickMotherVolume(sdet).placeVolume(assembly); pv.addPhysVolID("system", det_id); // Set the subdetector system ID. pv.addPhysVolID("barrel", 0); // Flag this as a barrel subdetector. sdet.setPlacement(pv);*/ return sdet; }