Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-03-14 08:15:02

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       Solid  solid = xml::createShape(description, type, c);
0193       if ( !solid.isValid() )   {
0194         except("VolumeBuilder","+++ Failed to create shape %s of type: %s",
0195                nam.c_str(), type.c_str());
0196       }
0197       printout(debug ? ALWAYS : DEBUG,"VolumeBuilder",
0198                "+++ Building shape  from XML: %s of type: %s",
0199                nam.c_str(), solid->IsA()->GetName());
0200       shapes.emplace(nam,std::make_pair(c,solid));
0201       continue;
0202     }
0203     except("VolumeBuilder","+++ Shape %s is already known to this builder unit. "
0204            "Cannot be overridden.",nam.c_str());
0205   }
0206   return shapes.size()-len;
0207 }
0208 
0209 /// Build all <volume/> identifiers in the passed parent xml element
0210 std::size_t VolumeBuilder::buildVolumes(xml_h handle)    {
0211   std::size_t len = volumes.size();
0212   xml_elt_t  x_comp(0);
0213   for( xml_coll_t c(handle,_U(volume)); c; ++c )   {
0214     Solid       solid;
0215     xml_comp_t  x = c;
0216     std::string nam  = x.attr<std::string>(_U(name));
0217     xml_attr_t attr = c.attr_nothrow(_U(build));
0218     /// Check if this volume is part of the volumes to be built for this description type
0219     if ( attr )   {
0220       std::string build = c.attr<std::string>(attr);
0221       if ( !buildMatch(build,buildType) )  {
0222         printout(INFO,"VolumeBuilder",
0223                  "+++ Volume %s does NOT match build requirements. [Ignored]",nam.c_str());
0224         continue;
0225       }
0226     }
0227     bool   is_sensitive = c.attr_nothrow(_U(sensitive));
0228     /// Check if the volume is implemented by a factory
0229     if ( (attr=c.attr_nothrow(_U(type))) )   {
0230       std::string typ = c.attr<std::string>(attr);
0231       Volume vol = xml::createVolume(description, typ, c);
0232       vol.setAttributes(description,x.regionStr(),x.limitsStr(),x.visStr());
0233       volumes.emplace(nam,std::make_pair(c,vol));
0234       /// Check if the volume is sensitive
0235       if ( is_sensitive )   {
0236         vol.setSensitiveDetector(sensitive);
0237       }
0238       solid = vol.solid();
0239       printout(debug ? ALWAYS : DEBUG,"VolumeBuilder",
0240                "+++ Building volume   from XML: %-20s shape:%-24s vis:%s sensitive:%s",
0241                nam.c_str(), solid->IsA()->GetName(), x.visStr().c_str(),
0242                yes_no(is_sensitive));
0243       buildVolumes(c);
0244       continue;
0245     }
0246     
0247     /// Check if the volume has a shape attribute --> shape reference
0248     if ( (attr=c.attr_nothrow(_U(shape))) )   {
0249       std::string ref = c.attr<std::string>(attr);
0250       if ( !(solid=getShape(ref)).isValid() ) continue;
0251     }
0252     /// Else use anonymous shape embedded in volume
0253     else if ( (x_comp=x.child(_U(shape),false)) )  {
0254       if ( !(solid=makeShape(x_comp)).isValid() ) continue;
0255     }
0256 
0257     /// We have a real volume here with a concrete shape:
0258     if ( solid.isValid() )   {
0259       Material  mat = description.material(x.attr<std::string>(_U(material)));
0260       Volume    vol(nam, solid, mat);
0261       placeDaughters(detector, vol, x);
0262       vol.setAttributes(description,x.regionStr(),x.limitsStr(),x.visStr());
0263       volumes.emplace(nam,std::make_pair(c,vol));
0264       /// Check if the volume is sensitive
0265       if ( is_sensitive )   {
0266         vol.setSensitiveDetector(sensitive);
0267       }
0268       printout(debug ? ALWAYS : DEBUG,"VolumeBuilder",
0269                "+++ Building volume   from XML: %-20s shape:%-24s vis:%s sensitive:%s",
0270                nam.c_str(), solid->IsA()->GetName(), x.visStr().c_str(),
0271                yes_no(is_sensitive));
0272       buildVolumes(c);
0273       continue;
0274     }
0275     bool is_assembly = true;
0276     is_assembly |= x.child(_U(assembly),false) != 0;
0277     is_assembly |= c.attr_nothrow(_U(assembly)) != 0;
0278     if ( is_assembly )   {
0279       Assembly vol(nam);
0280       placeDaughters(detector, vol, x);
0281       vol.setAttributes(description,x.regionStr(),x.limitsStr(),x.visStr());
0282       volumes.emplace(nam,std::make_pair(c,vol));
0283       printout(debug ? ALWAYS : DEBUG,"VolumeBuilder",
0284                "+++ Building assembly from XML: %-20s shape:%-24s vis:%s",
0285                nam.c_str(), vol->GetShape()->IsA()->GetName(), x.visStr().c_str());
0286       buildVolumes(c);
0287       continue;
0288     }
0289     except("VolumeBuilder","+++ Failed to create volume %s - "
0290            "It is neither Volume nor assembly....", nam.c_str());
0291   }
0292   return volumes.size()-len;
0293 }
0294 
0295 /// Place single volumes
0296 void VolumeBuilder::_placeSingleVolume(DetElement parent, Volume vol, xml_h c)   {
0297   xml_attr_t attr = c.attr_nothrow(_U(logvol));
0298   if ( !attr )   {
0299     attr = c.attr_nothrow(_U(volume));
0300   }
0301   if ( !attr )   {
0302     except("VolumeBuilder","+++ The xml volume element has no 'logvol' or 'volume' attribute!");
0303   }
0304   std::string nam = c.attr<std::string>(attr);
0305   if ( vol_veto.find(nam) != vol_veto.end() )   {
0306     return;
0307   }
0308   auto iv = volumes.find(nam);
0309   if ( iv == volumes.end() )  {
0310     except("VolumeBuilder",
0311            "+++ Failed to locate volume %s [typo somewhere in the XML?]",
0312            nam.c_str());      
0313   }
0314   PlacedVolume pv;
0315   Volume daughter = (*iv).second.second;
0316   attr = c.attr_nothrow(_U(transformation));
0317   if ( attr )   {
0318     std::string tr_nam = c.attr<std::string>(attr);
0319     auto it = transformations.find(tr_nam);
0320     if ( it == transformations.end() )   {
0321       except("VolumeBuilder",
0322              "+++ Failed to locate name transformation %s [typo in the XML?]",
0323              nam.c_str());      
0324     }
0325     const Transform3D& tr = (*it).second.second;
0326     pv = vol.placeVolume(daughter, tr);
0327   }
0328   else  {
0329     Transform3D tr = xml::createTransformation(c);
0330     pv = vol.placeVolume(daughter, tr);
0331   }
0332   xml_attr_t attr_nam = c.attr_nothrow(_U(name));
0333   if ( attr_nam )  {
0334     std::string phys_nam = c.attr<std::string>(attr_nam);
0335     pv->SetName(phys_nam.c_str());
0336   }
0337   attr = c.attr_nothrow(_U(element));
0338   if ( attr && !parent.isValid() )  {
0339     except("VolumeBuilder",
0340            "+++ Failed to set DetElement placement for volume %s [Invalid parent]",
0341            nam.c_str());      
0342   }
0343   else if ( attr )  {
0344     int    elt_id = parent.id();
0345     std::string elt = c.attr<std::string>(attr);
0346     attr = c.attr_nothrow(_U(id));
0347     if ( attr )   {
0348       elt_id = c.attr<int>(attr);
0349       elt += c.attr<std::string>(attr);
0350     }
0351     DetElement de(parent, elt, elt_id);
0352     de.setPlacement(pv);
0353     placeDaughters(de, daughter, c);
0354   }
0355   else  {
0356     placeDaughters(parent, daughter, c);
0357   }
0358 }
0359 
0360 /// Place parametrized volumes
0361 void VolumeBuilder::_placeParamVolumes(DetElement parent, Volume vol, xml_h c)   {
0362   xml_attr_t attr_tr, attr_elt, attr_nam;
0363   xml_h      x_phys = c.child(_U(physvol));
0364   xml_attr_t attr   = x_phys.attr_nothrow(_U(logvol));
0365   if ( !attr )   {
0366     attr = x_phys.attr_nothrow(_U(volume));
0367   }
0368   if ( !attr )   {
0369     except("VolumeBuilder","+++ The xml volume element has no 'logvol' or 'volume' attribute!");
0370   }
0371   std::string nam = x_phys.attr<std::string>(attr);
0372   if ( vol_veto.find(nam) != vol_veto.end() )   {
0373     return;
0374   }
0375   auto iv = volumes.find(nam);
0376   if ( iv == volumes.end() )  {
0377     except("VolumeBuilder",
0378            "+++ Failed to locate volume %s [typo somewhere in the XML?]",
0379            nam.c_str());      
0380   }
0381   attr_elt = c.attr_nothrow(_U(element));
0382   if ( attr_elt && !parent.isValid() )  {
0383     except("VolumeBuilder",
0384            "+++ Failed to set DetElement placement for volume %s [Invalid parent]",
0385            nam.c_str());      
0386   }
0387   Volume daughter = (*iv).second.second;
0388   attr_tr = c.attr_nothrow(_U(transformation));
0389   Transform3D tr;
0390   if ( attr_tr )   {
0391     std::string tr_nam = c.attr<std::string>(attr_tr);
0392     auto it = transformations.find(tr_nam);
0393     if ( it == transformations.end() )   {
0394       except("VolumeBuilder",
0395              "+++ Failed to locate name transformation %s "
0396              "[typo somewhere in the XML?]",
0397              nam.c_str());      
0398     }
0399     tr = (*it).second.second;
0400   }
0401   else  {
0402     tr = xml::createTransformation(c);
0403   }
0404   Transform3D transformation(Position(0,0,0));
0405   int elt_id = -1;
0406   std::string elt, phys_nam;
0407   attr_nam = x_phys.attr_nothrow(_U(name));
0408   if ( attr_nam )  {
0409     phys_nam = x_phys.attr<std::string>(_U(name))+"_%d";
0410   }
0411   if ( attr_elt )  {
0412     elt_id = parent.id();
0413     elt = c.attr<std::string>(attr_elt);
0414   }
0415   int number = c.attr<int>(_U(number));
0416   printout(debug ? ALWAYS : DEBUG,"VolumeBuilder","+++ Mother:%s place volume %s  %d times.",
0417            vol.name(), daughter.name(), number);
0418   for(int i=0; i<number; ++i)    {
0419     PlacedVolume pv = vol.placeVolume(daughter, transformation);
0420     if ( attr_nam )  {
0421       //pv->SetName(_toStd::String(i,phys_nam.c_str()).c_str());
0422     }
0423     if ( attr_elt )  {
0424       DetElement de(parent,elt,elt_id);
0425       de.setPlacement(pv);
0426       //placeDaughters(de, daughter, c);
0427     }
0428     else  {
0429       //placeDaughters(parent, daughter, c);
0430     }
0431     transformation *= tr;
0432   }
0433 }
0434 
0435 /// Load include tags contained in the passed XML handle
0436 std::size_t VolumeBuilder::load(xml_h element, const std::string& tag)  {
0437   std::size_t count = 0;
0438   for( xml_coll_t c(element,Unicode(tag)); c; ++c )   {
0439     std::string ref = c.attr<std::string>(_U(ref));
0440     std::unique_ptr<xml::DocumentHolder> doc(new xml::DocumentHolder(xml::DocumentHandler().load(element, c.attr_value(_U(ref)))));
0441     xml_h vols = doc->root();
0442     printout(debug ? ALWAYS : DEBUG, "VolumeBuilder",
0443              "++ Processing xml document %s.", doc->uri().c_str());
0444     included_docs[ref] = std::unique_ptr<xml::DocumentHolder>(doc.release());
0445     buildShapes(vols);
0446     buildTransformations(vols);
0447     buildVolumes(vols);
0448     ++count;
0449   }
0450   return count;
0451 }
0452 
0453 /// Build all <physvol/> identifiers as PlaceVolume daughters. Ignores structure
0454 VolumeBuilder& VolumeBuilder::placeDaughters(Volume vol, xml_h handle)   {
0455   DetElement null_de;
0456   return placeDaughters(null_de, vol, handle);
0457 }
0458 
0459 /// Build all <physvol/> identifiers as PlaceVolume daughters. Also handles structure
0460 VolumeBuilder& VolumeBuilder::placeDaughters(DetElement parent, Volume vol, xml_h handle)   {
0461   for( xml_coll_t c(handle,_U(physvol)); c; ++c )
0462     _placeSingleVolume(parent, vol, c);
0463   for( xml_coll_t c(handle,_U(paramphysvol)); c; ++c )
0464     _placeParamVolumes(parent, vol, c);
0465   return *this;
0466 }
0467 
0468 /// Build all <transformation/> identifiers in the passed parent xml element
0469 std::size_t VolumeBuilder::buildTransformations(Handle_t handle)   {
0470   std::size_t len = transformations.size();
0471   for( xml_coll_t c(handle,_U(transformation)); c; ++c )   {
0472     std::string nam = xml_comp_t(c).nameStr();
0473     transformations.emplace(nam,std::make_pair(c,xml::createTransformation(c)));
0474   }
0475   return transformations.size() - len;
0476 }
0477 
0478 /// Place the detector object into the mother volume returned by the Detector instance
0479 dd4hep::PlacedVolume VolumeBuilder::placeDetector(Volume vol)    {
0480   return placeDetector(vol, x_det);
0481 }
0482 
0483 /// Place the detector object into the mother volume returned by the Detector instance
0484 dd4hep::PlacedVolume VolumeBuilder::placeDetector(Volume vol, xml_h handle)    {
0485   xml_comp_t   x     = handle;
0486   xml_dim_t    x_pos = x_det.child(_U(position),false);
0487   xml_dim_t    x_rot = x_det.child(_U(rotation),false);
0488   xml_dim_t    x_tr  = x_det.child(_U(transformation),false);
0489   Volume       mother = description.pickMotherVolume(detector);
0490   PlacedVolume pv;
0491 
0492   if ( x_tr )   {
0493     Transform3D tr = createTransformation(x_tr);
0494     pv = mother.placeVolume(vol, tr);
0495   }
0496   else if ( x_pos && x_rot )   {
0497     Transform3D tr = createTransformation(x_det);
0498     pv = mother.placeVolume(vol, tr);
0499   }
0500   else if ( x_pos )  {
0501     pv = mother.placeVolume(vol, Position(x_pos.x(0),x_pos.y(0),x_pos.z(0)));
0502   }
0503   else  {
0504     pv = mother.placeVolume(vol);
0505   }
0506   vol.setVisAttributes(description, x.visStr());
0507   vol.setLimitSet(description, x.limitsStr());
0508   vol.setRegion(description, x.regionStr());
0509   if ( detector.isValid() )  {
0510     detector.setPlacement(pv);
0511   }
0512   return pv;
0513 }
0514 
0515 #endif