Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-10-02 08:09:52

0001 //==========================================================================
0002 //  AIDA Detector description implementation 
0003 //--------------------------------------------------------------------------
0004 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
0005 // All rights reserved.
0006 //
0007 // For the licensing terms see $DD4hepINSTALL/LICENSE.
0008 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
0009 //
0010 // Author     : M.Frank
0011 //
0012 //==========================================================================
0013 #ifndef DD4HEP_NONE
0014 
0015 // Framework include files
0016 #include <XML/VolumeBuilder.h>
0017 #include <XML/Utilities.h>
0018 #include <DD4hep/Printout.h>
0019 #include <DD4hep/Plugins.h>
0020 #include <DD4hep/Detector.h>
0021 #include <DD4hep/DetFactoryHelper.h>
0022 #include <Math/Polar2D.h>
0023 
0024 #include <TClass.h>
0025 
0026 using dd4hep::xml::tools::VolumeBuilder;
0027 
0028 /// Initializing constructor
0029 VolumeBuilder::VolumeBuilder(Detector& dsc, xml_h x_parent, SensitiveDetector sd)
0030   : description(dsc), x_det(x_parent), sensitive(sd)
0031 {
0032   if ( x_det )   {
0033     name     = x_det.nameStr();
0034     id       = x_det.id();
0035     detector = DetElement(name, id);
0036   }
0037   buildType = description.buildType();
0038 }
0039 
0040 /// Collect a set of materials from the leafs of an xml tag
0041 std::size_t VolumeBuilder::collectMaterials(xml_h element)   {
0042   std::size_t len = materials.size();
0043   for( xml_coll_t c(element,_U(material)); c; ++c )   {
0044     xml_comp_t  x_c = c;
0045     std::string nam = x_c.nameStr();
0046     std::string val = x_c.valueStr();
0047     Material    mat = description.material(val);
0048     materials[nam] = mat;
0049   }
0050   return materials.size()-len;
0051 }
0052 
0053 /// Register shape to map
0054 void VolumeBuilder::registerShape(const std::string& nam, Solid shape)   {
0055   auto is = shapes.find(nam);
0056   if( is == shapes.end() )  {
0057     shapes[nam] = std::make_pair(xml_h(0), shape);
0058     return;
0059   }
0060   except("VolumeBuilder","+++ Shape %s is already known to this builder unit. ",nam.c_str());
0061 }
0062 
0063 /// Register volume to map
0064 void VolumeBuilder::registerVolume(const std::string& nam, Volume volume)   {
0065   auto is = volumes.find(nam);
0066   if( is == volumes.end() )  {
0067     printout(debug ? ALWAYS : DEBUG,"VolumeBuilder",
0068              "+++ Register volume:            %-20s shape:%-24s vis:%s sensitive:%s",
0069              nam.c_str(),
0070              volume.solid()->IsA()->GetName(),
0071              volume.visAttributes().name(),
0072              yes_no(volume.isSensitive()));
0073     volumes[nam] = std::make_pair(xml_h(0), volume);
0074     return;
0075   }
0076   except("VolumeBuilder","+++ Volume %s is already known to this builder unit. ",nam.c_str());
0077 }
0078 
0079 /// Access a registered volume by name
0080 dd4hep::Volume VolumeBuilder::volume(const std::string& nam)  const    {
0081   auto iv = volumes.find(nam);
0082   if( iv == volumes.end() )  {
0083     auto ib = vol_veto.find(nam);
0084     if( ib != vol_veto.end() )  {
0085       // Veto'ed shape. Ignore it.
0086       return Volume();
0087     }
0088     except("VolumeBuilder","+++ Volume %s is not known to this builder unit. ",nam.c_str());
0089   }
0090   Volume vol = (*iv).second.second;
0091   if( !vol.isValid() )   {
0092     except("VolumeBuilder","+++ Failed to access volume %s from the local cache.",nam.c_str());
0093   }
0094   return vol;
0095 }
0096 
0097 /// Access element from transformation cache by name
0098 dd4hep::Transform3D VolumeBuilder::getTransform(const std::string& nam)  const   {
0099   auto it = transformations.find(nam);
0100   if( it == transformations.end() )  {
0101     except("VolumeBuilder","+++ Tranformation %s is not known to this builder unit. ",nam.c_str());
0102   }
0103   return (*it).second.second;
0104 }
0105 
0106 /// Access element from shape cache by name. Invalid returns means 'veto'. Otherwise exception
0107 dd4hep::Solid VolumeBuilder::getShape(const std::string& nam)  const   {
0108   auto is = shapes.find(nam);
0109   if( is == shapes.end() )  {
0110     auto ib = shape_veto.find(nam);
0111     if( ib != shape_veto.end() )  {
0112       // Veto'ed shape. Ignore it.
0113       return Solid();
0114     }
0115     except("VolumeBuilder","+++ Shape %s is not known to this builder unit. ",nam.c_str());
0116   }
0117   Solid solid = (*is).second.second;
0118   if( !solid.isValid() )   {
0119     except("VolumeBuilder","+++ Failed to access shape %s from the local cache.",nam.c_str());
0120   }
0121   return solid;
0122 }
0123 
0124 /// Create a new shape from the information given in the xml handle
0125 dd4hep::Solid VolumeBuilder::makeShape(xml_h handle)   {
0126   xml_comp_t  x = handle;
0127   xml_attr_t  a = handle.attr_nothrow(_U(name));
0128   std::string nam;
0129   if( a )   {
0130     nam = handle.attr<std::string>(a);
0131     auto is = shapes.find(nam);
0132     if( is != shapes.end() )  {
0133       except("VolumeBuilder","+++ The named shape %s is already known to this builder unit. "
0134              "Cannot be overridden.",nam.c_str());
0135     }
0136   }
0137   /// Was it veto'ed before ?
0138   if( !nam.empty() )   {
0139     auto iv = shape_veto.find(nam);
0140     if( iv != shape_veto.end() )  {
0141       return Solid();
0142     }
0143   }
0144   /// Check if this volume is part of the volumes to be built for this description type
0145   a = handle.attr_nothrow(_U(build));
0146   if( a )   {
0147     std::string build = handle.attr<std::string>(a);
0148     if( !buildMatch(build, buildType) )  {
0149       printout(INFO,"VolumeBuilder",
0150                "+++ Shape %s does NOT match build requirements. [Ignored]",nam.c_str());
0151       if( !nam.empty() ) shape_veto.emplace(nam);
0152       return Solid();
0153     }
0154   }
0155   /// Now we create the shape....
0156   std::string type = x.attr<std::string>(_U(type));
0157   Solid solid = xml::createShape(description, type, x);
0158   if( !solid.isValid() )   {
0159     except("VolumeBuilder","+++ Failed to create shape %s of type: %s",
0160            nam.c_str(), type.c_str());
0161   }
0162   /// And register it if it is not anonymous
0163   if( !nam.empty() )   {
0164     solid.setName(nam);
0165     shapes.emplace(nam,std::make_pair(handle,solid));
0166   }
0167   printout(debug ? ALWAYS : DEBUG, "VolumeBuilder",
0168            "+++ Created shape of type: %s name: %s",type.c_str(), nam.c_str());
0169   return solid;
0170 }
0171 
0172 /// Build all <shape/> identifiers in the passed parent xml element
0173 std::size_t VolumeBuilder::buildShapes(xml_h handle)    {
0174   std::size_t len = shapes.size();
0175   for( xml_coll_t c(handle,_U(shape)); c; ++c )   {
0176     xml_elt_t x = c;
0177     std::string nam = x.attr<std::string>(_U(name));
0178     auto is = shapes.find(nam);
0179     if( is == shapes.end() )  {
0180       /// Check if this volume is part of the volumes to be built for this description type
0181       xml_attr_t x_build = c.attr_nothrow(_U(build));
0182       if( x_build )   {
0183         std::string build = c.attr<std::string>(x_build);
0184         if( !buildMatch(build, buildType) )  {
0185           printout(INFO,"VolumeBuilder",
0186                    "+++ Shape %s does NOT match build requirements. [Ignored]",nam.c_str());
0187           shape_veto.emplace(nam);
0188           continue;
0189         }
0190       }
0191       std::string type  = x.attr<std::string>(_U(type));
0192       if( type == "Assembly" )  {
0193         continue;
0194       }
0195       Solid solid = xml::createShape(description, type, c);
0196       if( !solid.isValid() )   {
0197         except("VolumeBuilder","+++ Failed to create shape %s of type: %s",
0198                nam.c_str(), type.c_str());
0199       }
0200       printout(debug ? ALWAYS : DEBUG,"VolumeBuilder",
0201                "+++ Building shape  from XML: %s of type: %s",
0202                nam.c_str(), solid->IsA()->GetName());
0203       shapes.emplace(nam, std::make_pair(c,solid));
0204       continue;
0205     }
0206     except("VolumeBuilder","+++ Shape %s is already known to this builder unit. "
0207            "Cannot be overridden.", nam.c_str());
0208   }
0209   return shapes.size()-len;
0210 }
0211 
0212 /// Build all <volume/> identifiers in the passed parent xml element
0213 std::size_t VolumeBuilder::buildVolumes(xml_h handle)    {
0214   std::size_t len = volumes.size();
0215   xml_elt_t  x_comp(0);
0216   for( xml_coll_t c(handle, _U(volume)); c; ++c )   {
0217     Solid       solid;
0218     xml_comp_t  x = c;
0219     std::string nam = x.attr<std::string>(_U(name));
0220     xml_attr_t attr = c.attr_nothrow(_U(build));
0221     /// Check if this volume is part of the volumes to be built for this description type
0222     if( attr )   {
0223       std::string build = c.attr<std::string>(attr);
0224       if( !buildMatch(build,buildType) )  {
0225         printout(INFO,"VolumeBuilder",
0226                  "+++ Volume %s does NOT match build requirements. [Ignored]",nam.c_str());
0227         continue;
0228       }
0229     }
0230     /// If we have an assembly, the shape is implicitly created in the
0231     /// TGeoAssemblyVolume. We MUST NOT explicitly create it.
0232     bool is_volume_with_shape = x.child(_U(shape),false) != 0 || c.attr_nothrow(_U(shape)) != 0;
0233     if( !is_volume_with_shape )  {
0234       is_volume_with_shape = x.child(_U(solid),false) != 0 || c.attr_nothrow(_U(solid)) != 0;
0235     }
0236     bool is_volume_with_type = c.attr_nothrow(_U(type)) != 0;
0237     bool is_assembly = (x.child(_U(assembly),false) != 0 || c.attr_nothrow(_U(assembly)) != 0);
0238     if ( is_assembly && ( is_volume_with_shape || is_volume_with_type) ) {
0239       printout(ERROR, "VolumeBuilder",
0240                "+++ Shape defined, but ignored for ASSEMBLY volume: %s %s",
0241                nam.c_str(), "[Inconsistent description]" );
0242     }
0243     /// Continue with assembly
0244     if ( is_assembly || (!is_volume_with_shape && !is_volume_with_type) )  {
0245       Assembly  vol(nam);
0246       Solid     sol = vol.solid();
0247       xml_elt_t solid_handle(0);
0248       if( (solid_handle=x.child(_U(shape), false)) )  {
0249         shapes.emplace(nam, std::make_pair(solid_handle,sol));
0250       }
0251       placeDaughters(detector, vol, x);
0252       vol.setAttributes(description,x.regionStr(),x.limitsStr(),x.visStr());
0253       volumes.emplace(nam,std::make_pair(c,vol));
0254       printout(debug ? ALWAYS : DEBUG,"VolumeBuilder",
0255                "+++ Building assembly from XML: %-20s shape:%-24s vis:%s",
0256                nam.c_str(), vol->GetShape()->IsA()->GetName(), x.visStr().c_str());
0257       buildVolumes(c);
0258       continue;
0259     }
0260     //
0261     bool   is_sensitive = c.attr_nothrow(_U(sensitive));
0262     /// Check if the volume is implemented by a factory
0263     if( (attr=c.attr_nothrow(_U(type))) )   {
0264       std::string typ = c.attr<std::string>(attr);
0265       Volume      vol = xml::createVolume(description, typ, c);
0266       vol.setAttributes(description, x.regionStr(), x.limitsStr(), x.visStr());
0267       volumes.emplace(nam,std ::make_pair(c,vol));
0268       /// Check if the volume is sensitive
0269       if( is_sensitive )   {
0270         vol.setSensitiveDetector(sensitive);
0271       }
0272       solid = vol.solid();
0273       printout(debug ? ALWAYS : DEBUG, "VolumeBuilder",
0274                "+++ Building volume   from XML: %-20s shape:%-24s vis:%s sensitive:%s",
0275                nam.c_str(), solid->IsA()->GetName(), x.visStr().c_str(),
0276                yes_no(is_sensitive));
0277       buildVolumes(c);
0278       continue;
0279     }
0280     
0281     /// Check if the volume has a shape attribute --> shape reference
0282     if( (attr=c.attr_nothrow(_U(shape))) )   {
0283       std::string ref = c.attr<std::string>(attr);
0284       if( !(solid=getShape(ref)).isValid() ) continue;
0285     }
0286     /// Check if the volume has a solid attribute --> solid reference
0287     else if( (attr=c.attr_nothrow(_U(solid))) )   {
0288       std::string ref = c.attr<std::string>(attr);
0289       if( !(solid=getShape(ref)).isValid() ) continue;
0290     }
0291     /// Else use anonymous shape element embedded in volume
0292     else if( (x_comp=x.child(_U(shape),false)) )  {
0293       if( !(solid=makeShape(x_comp)).isValid() ) continue;
0294     }
0295     /// Else use anonymous solid element embedded in volume
0296     else if( (x_comp=x.child(_U(solid),false)) )  {
0297       if( !(solid=makeShape(x_comp)).isValid() ) continue;
0298     }
0299 
0300     /// We have a real volume here with a concrete shape:
0301     if( solid.isValid() )   {
0302       Material  mat = description.material(x.attr<std::string>(_U(material)));
0303       Volume    vol(nam, solid, mat);
0304       placeDaughters(detector, vol, x);
0305       vol.setAttributes(description,x.regionStr(),x.limitsStr(),x.visStr());
0306       volumes.emplace(nam,std::make_pair(c,vol));
0307       /// Check if the volume is sensitive
0308       if( is_sensitive )   {
0309         vol.setSensitiveDetector(sensitive);
0310       }
0311       printout(debug ? ALWAYS : DEBUG, "VolumeBuilder",
0312                "+++ Building volume   from XML: %-20s shape:%-24s vis:%s sensitive:%s",
0313                nam.c_str(), solid->IsA()->GetName(), x.visStr().c_str(),
0314                yes_no(is_sensitive));
0315       buildVolumes(c);
0316       continue;
0317     }
0318     except("VolumeBuilder","+++ Failed to create volume %s - "
0319            "It is neither Volume nor assembly....", nam.c_str());
0320   }
0321   return volumes.size()-len;
0322 }
0323 
0324 /// Place single volumes
0325 void VolumeBuilder::_placeSingleVolume(DetElement parent, Volume vol, xml_h c)   {
0326   xml_attr_t attr = c.attr_nothrow(_U(logvol));
0327   if( !attr )   {
0328     attr = c.attr_nothrow(_U(volume));
0329   }
0330   if( !attr )   {
0331     except("VolumeBuilder","+++ The xml volume element has no 'logvol' or 'volume' attribute!");
0332   }
0333   std::string nam = c.attr<std::string>(attr);
0334   if( vol_veto.find(nam) != vol_veto.end() )   {
0335     return;
0336   }
0337   auto iv = volumes.find(nam);
0338   if( iv == volumes.end() )  {
0339     except("VolumeBuilder",
0340            "+++ Failed to locate volume %s [typo somewhere in the XML?]",
0341            nam.c_str());      
0342   }
0343   PlacedVolume pv;
0344   Volume daughter = (*iv).second.second;
0345   attr = c.attr_nothrow(_U(transformation));
0346   if( attr )   {
0347     std::string tr_nam = c.attr<std::string>(attr);
0348     auto it = transformations.find(tr_nam);
0349     if( it == transformations.end() )   {
0350       except("VolumeBuilder",
0351              "+++ Failed to locate name transformation %s [typo in the XML?]",
0352              nam.c_str());      
0353     }
0354     const Transform3D& tr = (*it).second.second;
0355     pv = vol.placeVolume(daughter, tr);
0356   }
0357   else  {
0358     Transform3D tr = xml::createTransformation(c);
0359     pv = vol.placeVolume(daughter, tr);
0360   }
0361   xml_attr_t attr_nam = c.attr_nothrow(_U(name));
0362   if( attr_nam )  {
0363     std::string phys_nam = c.attr<std::string>(attr_nam);
0364     pv->SetName(phys_nam.c_str());
0365   }
0366   attr = c.attr_nothrow(_U(element));
0367   if( attr && !parent.isValid() )  {
0368     except("VolumeBuilder",
0369            "+++ Failed to set DetElement placement for volume %s [Invalid parent]",
0370            nam.c_str());      
0371   }
0372   else if( attr )  {
0373     int    elt_id = parent.id();
0374     std::string elt = c.attr<std::string>(attr);
0375     attr = c.attr_nothrow(_U(id));
0376     if( attr )   {
0377       elt_id = c.attr<int>(attr);
0378       elt += c.attr<std::string>(attr);
0379     }
0380     DetElement de(parent, elt, elt_id);
0381     de.setPlacement(pv);
0382     placeDaughters(de, daughter, c);
0383   }
0384   else  {
0385     placeDaughters(parent, daughter, c);
0386   }
0387 }
0388 
0389 /// Place parametrized volumes
0390 void VolumeBuilder::_placeParamVolumes(DetElement parent, Volume vol, xml_h c)   {
0391   xml_attr_t attr_tr, attr_elt, attr_nam;
0392   xml_h      x_phys = c.child(_U(physvol));
0393   xml_attr_t attr   = x_phys.attr_nothrow(_U(logvol));
0394   if( !attr )   {
0395     attr = x_phys.attr_nothrow(_U(volume));
0396   }
0397   if( !attr )   {
0398     except("VolumeBuilder","+++ The xml volume element has no 'logvol' or 'volume' attribute!");
0399   }
0400   std::string nam = x_phys.attr<std::string>(attr);
0401   if( vol_veto.find(nam) != vol_veto.end() )   {
0402     return;
0403   }
0404   auto iv = volumes.find(nam);
0405   if( iv == volumes.end() )  {
0406     except("VolumeBuilder",
0407            "+++ Failed to locate volume %s [typo somewhere in the XML?]",
0408            nam.c_str());      
0409   }
0410   attr_elt = c.attr_nothrow(_U(element));
0411   if( attr_elt && !parent.isValid() )  {
0412     except("VolumeBuilder",
0413            "+++ Failed to set DetElement placement for volume %s [Invalid parent]",
0414            nam.c_str());      
0415   }
0416   Volume daughter = (*iv).second.second;
0417   attr_tr = c.attr_nothrow(_U(transformation));
0418   Transform3D tr;
0419   if( attr_tr )   {
0420     std::string tr_nam = c.attr<std::string>(attr_tr);
0421     auto it = transformations.find(tr_nam);
0422     if( it == transformations.end() )   {
0423       except("VolumeBuilder",
0424              "+++ Failed to locate name transformation %s "
0425              "[typo somewhere in the XML?]",
0426              nam.c_str());      
0427     }
0428     tr = (*it).second.second;
0429   }
0430   else  {
0431     tr = xml::createTransformation(c);
0432   }
0433   Transform3D transformation(Position(0,0,0));
0434   int elt_id = -1;
0435   std::string elt, phys_nam;
0436   attr_nam = x_phys.attr_nothrow(_U(name));
0437   if( attr_nam )  {
0438     phys_nam = x_phys.attr<std::string>(_U(name))+"_%d";
0439   }
0440   if( attr_elt )  {
0441     elt_id = parent.id();
0442     elt = c.attr<std::string>(attr_elt);
0443   }
0444   int number = c.attr<int>(_U(number));
0445   printout(debug ? ALWAYS : DEBUG,"VolumeBuilder","+++ Mother:%s place volume %s  %d times.",
0446            vol.name(), daughter.name(), number);
0447   for(int i=0; i<number; ++i)    {
0448     PlacedVolume pv = vol.placeVolume(daughter, transformation);
0449     if( attr_nam )  {
0450       //pv->SetName(_toStd::String(i,phys_nam.c_str()).c_str());
0451     }
0452     if( attr_elt )  {
0453       DetElement de(parent,elt,elt_id);
0454       de.setPlacement(pv);
0455       //placeDaughters(de, daughter, c);
0456     }
0457     else  {
0458       //placeDaughters(parent, daughter, c);
0459     }
0460     transformation *= tr;
0461   }
0462 }
0463 
0464 /// Load include tags contained in the passed XML handle
0465 std::size_t VolumeBuilder::load(xml_h element, const std::string& tag)  {
0466   std::size_t count = 0;
0467   for( xml_coll_t c(element,Unicode(tag)); c; ++c )   {
0468     std::string ref = c.attr<std::string>(_U(ref));
0469     std::unique_ptr<xml::DocumentHolder> doc(new xml::DocumentHolder(xml::DocumentHandler().load(element, c.attr_value(_U(ref)))));
0470     xml_h vols = doc->root();
0471     printout(debug ? ALWAYS : DEBUG, "VolumeBuilder",
0472              "++ Processing xml document %s.", doc->uri().c_str());
0473     included_docs[ref] = std::unique_ptr<xml::DocumentHolder>(doc.release());
0474     buildShapes(vols);
0475     buildTransformations(vols);
0476     buildVolumes(vols);
0477     ++count;
0478   }
0479   return count;
0480 }
0481 
0482 /// Build all <physvol/> identifiers as PlaceVolume daughters. Ignores structure
0483 VolumeBuilder& VolumeBuilder::placeDaughters(Volume vol, xml_h handle)   {
0484   DetElement null_de;
0485   return placeDaughters(null_de, vol, handle);
0486 }
0487 
0488 /// Build all <physvol/> identifiers as PlaceVolume daughters. Also handles structure
0489 VolumeBuilder& VolumeBuilder::placeDaughters(DetElement parent, Volume vol, xml_h handle)   {
0490   for( xml_coll_t c(handle,_U(physvol)); c; ++c )
0491     _placeSingleVolume(parent, vol, c);
0492   for( xml_coll_t c(handle,_U(paramphysvol)); c; ++c )
0493     _placeParamVolumes(parent, vol, c);
0494   return *this;
0495 }
0496 
0497 /// Build all <transformation/> identifiers in the passed parent xml element
0498 std::size_t VolumeBuilder::buildTransformations(Handle_t handle)   {
0499   std::size_t len = transformations.size();
0500   for( xml_coll_t c(handle,_U(transformation)); c; ++c )   {
0501     std::string nam = xml_comp_t(c).nameStr();
0502     transformations.emplace(nam,std::make_pair(c,xml::createTransformation(c)));
0503   }
0504   return transformations.size() - len;
0505 }
0506 
0507 /// Place the detector object into the mother volume returned by the Detector instance
0508 dd4hep::PlacedVolume VolumeBuilder::placeDetector(Volume vol)    {
0509   return placeDetector(vol, x_det);
0510 }
0511 
0512 /// Place the detector object into the mother volume returned by the Detector instance
0513 dd4hep::PlacedVolume VolumeBuilder::placeDetector(Volume vol, xml_h handle)    {
0514   xml_comp_t   x     = handle;
0515   xml_dim_t    x_pos = x_det.child(_U(position),false);
0516   xml_dim_t    x_rot = x_det.child(_U(rotation),false);
0517   xml_dim_t    x_tr  = x_det.child(_U(transformation),false);
0518   Volume       mother = description.pickMotherVolume(detector);
0519   PlacedVolume pv;
0520 
0521   if( x_tr )   {
0522     Transform3D tr = createTransformation(x_tr);
0523     pv = mother.placeVolume(vol, tr);
0524   }
0525   else if( x_pos && x_rot )   {
0526     Transform3D tr = createTransformation(x_det);
0527     pv = mother.placeVolume(vol, tr);
0528   }
0529   else if( x_pos )  {
0530     pv = mother.placeVolume(vol, Position(x_pos.x(0),x_pos.y(0),x_pos.z(0)));
0531   }
0532   else  {
0533     pv = mother.placeVolume(vol);
0534   }
0535   vol.setVisAttributes(description, x.visStr());
0536   vol.setLimitSet(description, x.limitsStr());
0537   vol.setRegion(description, x.regionStr());
0538   if( detector.isValid() )  {
0539     detector.setPlacement(pv);
0540   }
0541   return pv;
0542 }
0543 
0544 #endif