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); } } }
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); } }
/// Compute the survey to-world transformation from the detector element placement with respect to the survey constants void DD4hep::Alignments::AlignmentTools::computeSurvey(Alignment alignment) { Alignment::Object* a = alignment.ptr(); DetElement parent = a->detector.parent(); MaskManipulator mask(a->flag); if ( parent.isValid() ) { DetectorTools::PlacementPath path; DetectorTools::placementPath(parent, a->detector, path); // TODO: need to take survey corrections into account! for (size_t i = 0, n=path.size(); n>0 && i < n-1; ++i) { const PlacedVolume& p = path[i]; a->detectorTrafo.MultiplyLeft(p->GetMatrix()); } a->worldTrafo = parent.survey()->worldTrafo; a->worldTrafo.MultiplyLeft(&a->detectorTrafo); a->trToWorld = Geometry::_transform(&a->worldTrafo); a->placement = a->detector.placement(); } mask.set(AlignmentData::SURVEY); //mask.clear(AlignmentData::INVALID|AlignmentData::DIRTY); //mask.set(AlignmentData::VALID|AlignmentData::IDEAL); }
/// Find a detector element by it's system ID DetElement LCDDHelper::detectorByID(int id) const { const LCDD::HandleMap& dets = ptr()->detectors(); for(LCDD::HandleMap::const_iterator i=dets.begin(); i!=dets.end(); ++i) { DetElement de = (*i).second; if ( de.id() == id ) return de; } return DetElement(0); }
/* * Returns the closest detector element in the hierarchy for a given global position */ DetElement IDDecoder::detectorElement(const Position& pos) const { DetElement world = Geometry::LCDD::getInstance().world(); DetElement det = getClosestDaughter(world, pos); if (not det.isValid()) { throw invalid_position("DD4hep::DDRec::IDDecoder::detectorElement", pos); } std::cout << det.name() << std::endl; return det; }
static long cache(DetElement de) { const DetElement::Children& c = de.children(); de.worldTransformation(); de.parentTransformation(); de.placementPath(); de.path(); for (DetElement::Children::const_iterator i = c.begin(); i != c.end(); ++i) cache((*i).second); 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; }
/// Access mother volume by detector element Volume LCDDImp::pickMotherVolume(const DetElement& de) const { if ( de.isValid() ) { string de_name = de.name(); HandleMap::const_iterator i = m_motherVolumes.find(de_name); if (i == m_motherVolumes.end()) { return m_worldVol; } return (*i).second; } throw runtime_error("LCDD: Attempt access mother volume of invalid detector [Invalid-handle]"); }
/** * Returns the cell ID from the local position in the given volume ID. */ CellID IDDecoder::cellIDFromLocal(const Position& local, const VolumeID volID) const { double l[3]; double g[3]; local.GetCoordinates(l); // FIXME: direct lookup of transformations seems to be broken //const TGeoMatrix& localToGlobal = _volumeManager.worldTransformation(volID); DetElement det = this->detectorElement(volID); const TGeoMatrix& localToGlobal = det.worldTransformation(); localToGlobal.LocalToMaster(l, g); Position global(g[0], g[1], g[2]); return this->findReadout(det).segmentation().cellID(local, global, volID); }
/** * Returns the global position from a given cell ID */ Position IDDecoder::position(const CellID& cell) const { double l[3]; double g[3]; DetElement det = this->detectorElement(cell); Position local = this->findReadout(det).segmentation().position(cell); local.GetCoordinates(l); // FIXME: direct lookup of transformations seems to be broken //const TGeoMatrix& localToGlobal = _volumeManager.worldTransformation(cell); const TGeoMatrix& localToGlobal = det.worldTransformation(); localToGlobal.LocalToMaster(l, g); return Position(g[0], g[1], g[2]); }
/// 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; }
/// Access optical surface data by its identifier OpticalSurface OpticalSurfaceManager::opticalSurface(DetElement de, const string& nam) const { if ( de.isValid() ) { Object* o = access(); string n = de.path() + '#' + nam; TGeoOpticalSurface* surf = o->detector.manager().GetOpticalSurface(n.c_str()); if ( surf ) return surf; auto i = o->opticalSurfaces.find(n); if ( i != o->opticalSurfaces.end() ) return (*i).second; return 0; } except("OpticalSurface", "++ Cannot access OpticalSurface %s without valid detector element!",nam.c_str()); return OpticalSurface(); }
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; }
/// Register the temporary surface objects with the TGeoManager void OpticalSurfaceManager::registerSurfaces(DetElement subdetector) { Object* o = access(); unique_ptr<Object> extension(new Object(o->detector)); for(auto& s : o->opticalSurfaces) { //string n = s.first.first.path() + '#' + s.first.second; //s.second->SetName(n.c_str()); o->detector.manager().AddOpticalSurface(s.second.ptr()); extension->opticalSurfaces.insert(s); } o->opticalSurfaces.clear(); for(auto& s : o->skinSurfaces) { string n = s.first.first.path() + '#' + s.first.second; s.second->SetName(n.c_str()); o->detector.manager().AddSkinSurface(s.second.ptr()); extension->skinSurfaces.insert(s); } o->skinSurfaces.clear(); for(auto& s : o->borderSurfaces) { string n = s.first.first.path() + '#' + s.first.second; s.second->SetName(n.c_str()); o->detector.manager().AddBorderSurface(s.second.ptr()); extension->borderSurfaces.insert(s); } o->borderSurfaces.clear(); if ( extension->opticalSurfaces.empty() && extension->borderSurfaces.empty() && extension->skinSurfaces.empty() ) { return; } subdetector.addExtension(new detail::DeleteExtension<Object,Object>(extension.release())); }
/// Callback to process a single detector element int ConditionsDependencyCreator::operator()(DetElement de, int) const { ConditionKey key(de,"derived_data"); ConditionKey target1(de,"derived_data/derived_1"); ConditionKey target2(de,"derived_data/derived_2"); ConditionKey target3(de,"derived_data/derived_3"); DependencyBuilder build_1(de, target1.item_key(), call1); DependencyBuilder build_2(de, target2.item_key(), call2); DependencyBuilder build_3(de, target3.item_key(), call3); //DependencyBuilder build_1(de, "derived_data/derived_1", call1); //DependencyBuilder build_2(de, "derived_data/derived_2", call2); //DependencyBuilder build_3(de, "derived_data/derived_3", call3); // Compute the derived stuff build_1.add(key); build_2.add(key); build_2.add(target1); build_3.add(key); build_3.add(target1); build_3.add(target2); content.addDependency(build_1.release()); content.addDependency(build_2.release()); content.addDependency(build_3.release()); printout(printLevel,"Example","++ Added derived conditions dependencies for %s",de.path().c_str()); return 1; }
template<typename T> Condition ConditionsCreator::make_condition(DetElement de, const string& name, T val) const { Condition cond(de.path()+"#"+name, name); T& value = cond.bind<T>(); value = val; cond->hash = ConditionKey::hashCode(de,name); return cond; }
template <> void AlignmentActor<DDAlign_standard_operations::node_align>::operator()(Nodes::value_type& n) const { Entry& e = *n.second.second; bool check = e.checkOverlap(); bool overlap = e.overlapDefined(); bool has_matrix = e.hasMatrix(); DetElement det = e.detector; bool valid = det->global_alignment.isValid(); string det_placement = det.placementPath(); if ( !valid && !has_matrix ) { cout << "++++ SKIP ALIGNMENT: ++++ " << e.path << " DE:" << det_placement << " Valid:" << yes_no(valid) << " Matrix:" << yes_no(has_matrix) << endl; /* */ return; } cout << "++++ " << e.path << " DE:" << det_placement << " Valid:" << yes_no(valid) << " Matrix:" << yes_no(has_matrix) << endl; /* */ // Need to care about optional arguments 'check_overlaps' and 'overlap' DetectorAlignment ad(det); Alignment alignment; bool is_not_volume = e.path == det_placement; if ( check && overlap ) { alignment = is_not_volume ? ad.align(e.transform, e.overlapValue(), e.overlap) : ad.align(e.path, e.transform, e.overlapValue(), e.overlap); } else if ( check ) { alignment = is_not_volume ? ad.align(e.transform, e.overlapValue()) : ad.align(e.path, e.transform, e.overlapValue()); } else { alignment = is_not_volume ? ad.align(e.transform) : ad.align(e.path, e.transform); } if ( alignment.isValid() ) { insert(alignment); return; } throw runtime_error("Failed to apply alignment for "+e.path); }
void local_to_world(const char* com,const DetElement de, const Position& pos,const Position& loc) { Position glob; printf("Local to World: Transformation '%s'(%7.3f, %7.3f, %7.3f)->world (Should be: (%7.3f, %7.3f, %7.3f) :\n", com, loc.x(),loc.y(),loc.z(), loc.x()+pos.x(),loc.y()+pos.y(),loc.z()+pos.z() ); de.localToWorld(loc,glob); printCoord(glob,loc); }
void world_to_local(const char* com,const DetElement de, const Position& pos,const Position& glob) { Position loc; printf("World to Local: Transformation '%s'(%7.3f, %7.3f, %7.3f)->world (Should be: (%7.3f, %7.3f, %7.3f) :\n", com, glob.x(),glob.y(),glob.z(), glob.x()-pos.x(),glob.y()-pos.y(),glob.z()-pos.z() ); de.worldToLocal(glob,loc); printCoord(glob,loc); }
// helper method to get the closest daughter DetElement to the position starting from the given DetElement DetElement IDDecoder::getClosestDaughter(const DetElement& det, const Position& position) { DetElement result; // check if we have a shape and see if we are inside if (det.volume().isValid() and det.volume().solid().isValid()) { double globalPosition[3] = { position.x(), position.y(), position.z() }; double localPosition[3] = { 0., 0., 0. }; det.worldTransformation().MasterToLocal(globalPosition, localPosition); if (det.volume().solid()->Contains(localPosition)) { result = det; } else { // assuming that any daughter shape would be inside this shape return DetElement(); } } const DetElement::Children& children = det.children(); DetElement::Children::const_iterator it = children.begin(); while (it != children.end()) { DetElement daughterDet = getClosestDaughter(it->second, position); if (daughterDet.isValid()) { result = daughterDet; break; } ++it; } return result; }
static void* create_printer(Detector& description, int argc,char** argv) { PrintLevel print_level = INFO; string prefix = "", name = ""; int flags = 0, have_pool = 0, arg_error = false; for(int i=0; i<argc && argv[i]; ++i) { if ( 0 == ::strncmp("-prefix",argv[i],4) ) prefix = argv[++i]; else if ( 0 == ::strncmp("-name",argv[i],5) ) name = argv[++i]; else if ( 0 == ::strncmp("-flags",argv[i],5) ) flags = ::atol(argv[++i]); else if ( 0 == ::strncmp("-pool",argv[i],5) ) have_pool = 1; else if ( 0 == ::strncmp("-print",argv[i],5) ) print_level = dd4hep::printLevel(argv[++i]); else arg_error = true; } if ( arg_error ) { /// Help printout describing the basic command line interface cout << "Usage: -plugin <name> -arg [-arg] \n" " name: factory name(s) DD4hep_ConditionsPrinter, \n" " dd4hep_AlignmentsPrinter \n" " dd4hep_AlignedVolumePrinter \n" " -prefix <string> Printout prefix for user customized output. \n" " -flags <number> Printout processing flags. \n" " -pool Attach conditions user pool from \n" " PluginTester's slice instance attached. \n\n" " -print <value> Printout level for the printer object. \n" "\tArguments given: " << arguments(argc,argv) << endl << flush; ::exit(EINVAL); } DetElement world = description.world(); printout(INFO,"Printer","World=%s [%p]",world.path().c_str(),world.ptr()); ConditionsSlice* slice = 0; if ( have_pool ) { PluginTester* test = description.extension<PluginTester>(); slice = test->extension<ConditionsSlice>("ConditionsTestSlice"); } PRINTER* p = (flags) ? new PRINTER(slice, prefix, flags) : new PRINTER(slice, prefix); p->printLevel = print_level; if ( !name.empty() ) p->name = name; return (void*)dynamic_cast<WRAPPER*>(createProcessorWrapper(p)); }
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; }
/// Compute the ideal/nominal to-world transformation from the detector element placement void DD4hep::Alignments::AlignmentTools::computeIdeal(Alignment alignment) { Alignment::Object* a = alignment.ptr(); MaskManipulator mask(a->flag); DetElement parent = a->detector.parent(); if ( parent.isValid() ) { DetectorTools::PlacementPath path; DetectorTools::placementPath(parent, a->detector, path); for (size_t i = 0, n=path.size(); n>0 && i < n-1; ++i) { const PlacedVolume& p = path[i]; a->detectorTrafo.MultiplyLeft(p->GetMatrix()); a->nodes.push_back(p); } a->worldTrafo = parent.nominal()->worldTrafo; a->worldTrafo.MultiplyLeft(&a->detectorTrafo); a->trToWorld = Geometry::_transform(&a->worldTrafo); a->placement = a->detector.placement(); mask.clear(); mask.set(AlignmentData::HAVE_PARENT_TRAFO); mask.set(AlignmentData::HAVE_WORLD_TRAFO); mask.set(AlignmentData::IDEAL); } }
/// Callback to process a single detector element int ConditionsCreator::operator()(DetElement de, int) const { Condition temperature = make_condition<double>(de,"temperature",1.222); Condition pressure = make_condition<double>(de,"pressure",888.88); Condition derived = make_condition<int> (de,"derived_data",100); Condition dbl_table = make_condition<vector<double> >(de,"double_table",{1.,2.,3.,4.,5.,6.,7.,8.,9.}); Condition int_table = make_condition<vector<int> > (de,"int_table",{10,20,30,40,50,60,70,80,90}); slice.manager.registerUnlocked(pool, temperature); slice.manager.registerUnlocked(pool, pressure); slice.manager.registerUnlocked(pool, derived); slice.manager.registerUnlocked(pool, dbl_table); slice.manager.registerUnlocked(pool, int_table); printout(printLevel,"Creator","++ Adding manually conditions for %s",de.path().c_str()); return 5; }
int DeltaCollector<T>::operator()(DetElement de, int level) const { if ( de.isValid() ) { int count = 0; vector<Condition> conditions; cond::conditionsCollector(mapping,conditions)(de,level); for( auto cond : conditions ) { if ( cond->testFlag(Condition::ALIGNMENT_DELTA) ) { insert_item(deltas, de, cond.get<Delta>()); ++count; } } return count; } except("Alignments","Cannot process alignments of an invalid detector element"); return 0; }
/// 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, 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; }
/* * Returns the volume ID of a given global position */ VolumeID IDDecoder::volumeID(const Position& pos) const { DetElement det = this->detectorElement(pos); return det.volumeID(); }
/// Dump method. virtual int operator()(DetElement de, int) { return de.hasConditions() ? processor->processElement(de) : 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; }