Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:13:25

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 
0014 /// Framework include files
0015 #include <DD4hep/DetFactoryHelper.h>
0016 #include <DD4hep/DetectorTools.h>
0017 #include <DD4hep/Printout.h>
0018 #include <XML/Utilities.h>
0019 #include <DDCAD/ASSIMPReader.h>
0020 #include <DDCAD/ASSIMPWriter.h>
0021 
0022 // C/C++ include files
0023 #include <filesystem>
0024 
0025 using dd4hep::except;
0026 using dd4hep::printout;
0027 
0028 /// If the path to the CAD file does not directly exist try to resolve it:
0029 static std::string resolve_path(xml_h e, const std::string& file)   {
0030   std::error_code errc;
0031   std::string fname;
0032   /// Use the xml utilities in the DocumentHandler to resolve the relative path
0033   if ( file.length() > 7 && file.substr(0,7) == "file://" )
0034     fname = file.substr(7);
0035   else
0036     fname = file;
0037   if ( !std::filesystem::exists(fname, errc) )   {
0038     std::string fn = dd4hep::xml::DocumentHandler::system_path(e, fname);
0039     if ( fn.length() > 7 && fn.substr(0,7) == "file://" )
0040       fn = fn.substr(7);
0041     if ( !std::filesystem::exists(fn, errc) )   {
0042       auto fp = std::filesystem::path(dd4hep::xml::DocumentHandler::system_path(e)).parent_path();
0043       except("CAD_Shape","+++ CAD file: %s (= %s + %s) is not accessible [%d: %s]",
0044              fn.c_str(), fp.c_str(), fname.c_str(),
0045              errc.value(), errc.message().c_str());
0046     }
0047     return fn;
0048   }
0049   return fname;
0050 }
0051 
0052 static void* read_CAD_Volume(dd4hep::Detector& dsc, int argc, char** argv)   {
0053   std::string fname;
0054   double scale = 1.0;
0055   bool   help  = false;
0056   for(int i = 0; i < argc && argv[i]; ++i)  {
0057     if (      0 == ::strncmp( "-input",argv[i],4) )  fname = argv[++i];
0058     else if ( 0 == ::strncmp("--input",argv[i],5) )  fname = argv[++i];
0059     else if ( 0 == ::strncmp( "-scale",argv[i],4) )  scale = ::atof(argv[++i]);
0060     else if ( 0 == ::strncmp("--scale",argv[i],5) )  scale = ::atof(argv[++i]);
0061     else if ( 0 == ::strncmp( "-help",argv[i],2) )   help  = true;
0062     else if ( 0 == ::strncmp("--help",argv[i],3) )   help  = true;
0063   }
0064 
0065   if ( fname.empty() || help )    {
0066     std::cout <<
0067       "Usage: -plugin DD4hep_CAD_export -arg [-arg]                           \n\n"
0068       "     -input    <string> Input file name.                                 \n"
0069       "     -scale    <float>  Scale factor when importing shapes.              \n"
0070       "     -help              Print this help output.                          \n"
0071       "     Arguments given: " << dd4hep::arguments(argc,argv) << std::endl << std::flush;
0072     ::exit(EINVAL);
0073   }
0074 
0075   auto volumes = dd4hep::cad::ASSIMPReader(dsc).readVolumes(fname, scale);
0076   if ( volumes.empty() )   {
0077     except("CAD_Volume","+++ CAD file: %s does not contain any "
0078            "understandable tessellated volumes.", fname.c_str());
0079   }
0080   auto* result = new std::vector<std::unique_ptr<TGeoVolume> >(move(volumes));
0081   return result;
0082 }
0083 DECLARE_DD4HEP_CONSTRUCTOR(DD4hep_read_CAD_volumes,read_CAD_Volume)
0084 
0085 static dd4hep::Handle<TObject> create_CAD_Shape(dd4hep::Detector& dsc, xml_h e)   {
0086   xml_elt_t elt(e);
0087   dd4hep::cad::ASSIMPReader rdr(dsc);
0088   std::string fname = resolve_path(e, elt.attr<std::string>(_U(ref)));
0089   long        flags = elt.hasAttr(_U(flags)) ? elt.attr<long>(_U(flags))  : 0;
0090   double      unit  = elt.hasAttr(_U(unit))  ? elt.attr<double>(_U(unit)) : dd4hep::cm;
0091 
0092   if ( flags ) rdr.flags = flags;
0093   auto shapes = rdr.readShapes(fname, unit);
0094   if ( shapes.empty() )   {
0095     except("CAD_Shape","+++ CAD file: %s does not contain any "
0096            "understandable tessellated shapes.", fname.c_str());
0097   }
0098   dd4hep::Solid solid;
0099   std::size_t count = shapes.size();
0100   if ( count == 1 )   {
0101     solid = shapes[0].release();
0102   }
0103   else   {
0104     if ( elt.hasAttr(_U(item)) )  {
0105       std::size_t which = elt.attr<std::size_t>(_U(item));
0106       solid = shapes[which].release();
0107     }
0108     else if ( elt.hasAttr(_U(mesh)) )  {
0109       std::size_t which = elt.attr<std::size_t>(_U(mesh));
0110       solid = shapes[which].release();
0111     }
0112     else  {
0113       except("CAD_Shape","+++ CAD file: %s does contains %ld tessellated shapes. "
0114              "You need to add a selector.", fname.c_str(), shapes.size());
0115     }
0116   }
0117   if ( elt.hasAttr(_U(name)) ) solid->SetName(elt.attr<std::string>(_U(name)).c_str());
0118   return solid;
0119 }
0120 DECLARE_XML_SHAPE(CAD_Shape__shape_constructor,create_CAD_Shape)
0121 
0122 static dd4hep::Handle<TObject> create_CAD_Assembly(dd4hep::Detector& dsc, xml_h e)   {
0123   xml_elt_t   elt(e);
0124   std::string fname = resolve_path(e, elt.attr<std::string>(_U(ref)));
0125   double      unit  = elt.hasAttr(_U(unit)) ? elt.attr<double>(_U(unit)) : dd4hep::cm;
0126   auto volumes = dd4hep::cad::ASSIMPReader(dsc).readVolumes(fname, unit);
0127   if ( volumes.empty() )   {
0128     except("CAD_Shape","+++ CAD file: %s does not contain any "
0129            "understandable tessellated volumes.", fname.c_str());
0130   }
0131   dd4hep::Assembly assembly("assembly");
0132   for(std::size_t i=0; i < volumes.size(); ++i)  {
0133     dd4hep::Volume vol(volumes[i].release());
0134     assembly.placeVolume(vol);
0135   }
0136 
0137   if ( elt.hasAttr(_U(name)) ) assembly->SetName(elt.attr<std::string>(_U(name)).c_str());
0138   return assembly;
0139 }
0140 DECLARE_XML_VOLUME(CAD_Assembly__volume_constructor,create_CAD_Assembly)
0141 
0142 /// CAD volume importer plugin
0143 /**
0144  *
0145  * The CAD volume plugin allows to embed valumes and shapes originating from
0146  * Computer Aided Design drawings using multiple formats as they are supported
0147  * by the open asset importer library (http://assimp.org ).
0148  * The plugin can be used whenever the xmnl fragment matches the following pattern:
0149  *
0150  *   <XXX ref="file-name"  material="material-name">   
0151  *     <material name="material-name"/>                        <!-- alternative: child or attr -->
0152  *
0153  *     Envelope:  Use special envelop shape (default: assembly)
0154  *                The envelope tag must match the expected pattern of the utility
0155  *                dd4hep::xml::createStdVolume(Detector& desc, xml::Element e)
0156  *     <envelope name="volume-name" material="material-name">
0157  *       <shape name="shape-name" type="shape-type" args....>
0158  *       </shape>
0159  *     </envelope>
0160  *
0161  *     Option 1:  No additional children. use default material 
0162  *                and place all children in the origin of the envelope
0163  *
0164  *     Option 2:  Volume with default material
0165  *     <volume name="vol-name"/>
0166  *
0167  *     Option 3:  Volume with non-default material
0168  *     <volume name="vol-name" material="material-name"/>
0169  *
0170  *     Option 4:  Volume with optional placement. No position = (0,0,0), No rotation = (0,0,0)
0171  *     <volume name="vol-name" material="material-name"/>
0172  *       <position x="0" y="0" z="5*cm"/>
0173  *       <rotation x="0" y="0" z="0.5*pi*rad"/>
0174  *     </volume>
0175  *
0176  *     For sensitive volumes: add physical volume IDs:
0177  *     <volume name="vol-name" material="material-name"/>
0178  *       <physvolid name="layer" value="1"/>
0179  *       <physvolid name="slice" value="10"/>
0180  *     </volume>
0181  *
0182  *     If flags: (flags>>8)&1 == 1 (257): dump facets
0183  *
0184  *   </XXX>
0185  */
0186 static dd4hep::Handle<TObject> create_CAD_Volume(dd4hep::Detector& dsc, xml_h e)   {
0187   xml_elt_t   elt(e);
0188   double      unit  = elt.attr<double>(_U(unit));
0189   std::string fname = resolve_path(e, elt.attr<std::string>(_U(ref)));
0190   long        flags = elt.hasAttr(_U(flags)) ? elt.attr<long>(_U(flags))  : 0;
0191   dd4hep::cad::ASSIMPReader rdr(dsc);
0192 
0193   if ( flags ) rdr.flags = flags;
0194   auto volumes = rdr.readVolumes(fname, unit);
0195   if ( volumes.empty() )   {
0196     except("CAD_Volume","+++ CAD file: %s does not contain any "
0197            "understandable tessellated volumes.", fname.c_str());
0198   }
0199   dd4hep::Volume envelope;
0200   if ( elt.hasChild(_U(envelope)) )   {
0201     std::string   typ   = "DD4hep_StdVolume";
0202     xml_h    x_env = elt.child(_U(envelope));
0203     TObject* pvol  = dd4hep::PluginService::Create<TObject*>(typ, &dsc, &x_env);
0204     envelope = dynamic_cast<TGeoVolume*>(pvol);
0205     if ( !envelope.isValid() )   {
0206       except("CAD_Volume", "+++ Unable to determine envelope to CAD shape: %s",fname.c_str());
0207     }
0208   }
0209   else   {
0210     envelope = dd4hep::Assembly("envelope");
0211   }
0212   xml_dim_t x_envpos = elt.child(_U(position),false);
0213   xml_dim_t x_envrot = elt.child(_U(rotation),false);
0214   dd4hep::Position env_pos;
0215   dd4hep::RotationZYX env_rot;
0216   if ( x_envpos && x_envrot )   {
0217     env_rot = dd4hep::RotationZYX(x_envrot.z(0), x_envrot.y(0), x_envrot.x(0));
0218     env_pos = dd4hep::Position(x_envpos.x(0), x_envpos.y(0), x_envpos.z(0));
0219   }
0220   else if ( x_envpos )
0221     env_pos = dd4hep::Position(x_envpos.x(0), x_envpos.y(0), x_envpos.z(0));
0222   else if ( x_envrot )
0223     env_rot = dd4hep::RotationZYX(x_envrot.z(0), x_envrot.y(0), x_envrot.x(0));
0224 
0225   dd4hep::Transform3D env_trafo(env_rot, env_pos);
0226   dd4hep::Material    default_material;
0227   xml_dim_t x_mat = elt.child(_U(material),false);
0228   if      ( x_mat.ptr() ) default_material = dsc.material(x_mat.nameStr());
0229   else if ( elt.hasAttr(_U(material)) ) default_material = dsc.material(elt.attr<std::string>(_U(material)));
0230 
0231   if ( elt.hasChild(_U(volume)) )   {
0232     std::map<int, xml_h> volume_map;
0233     for (xml_coll_t c(elt,_U(volume)); c; ++c )
0234       volume_map.emplace(xml_dim_t(c).id(),c);
0235 
0236     for (std::size_t i=0; i < volumes.size(); ++i)   {
0237       dd4hep::Volume   vol = volumes[i].release();
0238       dd4hep::Material mat = default_material;
0239       auto is = volume_map.find(i);
0240       if ( is == volume_map.end() )   {
0241         envelope.placeVolume(vol);
0242       }
0243       else   {
0244         xml_dim_t x_vol = (*is).second;
0245         xml_dim_t x_pos = x_vol.child(_U(position),false);
0246         xml_dim_t x_rot = x_vol.child(_U(rotation),false);
0247 
0248         if ( x_vol.hasAttr(_U(material)) )  {
0249           std::string mat_name = x_vol.attr<std::string>(_U(material));
0250           mat = dsc.material(mat_name);
0251           if ( !mat.isValid() )
0252             except("CAD_MultiVolume","+++ Failed to access material "+mat_name);
0253           vol.setMaterial(mat);
0254         }
0255         dd4hep::Position    pos;
0256         dd4hep::RotationZYX rot;
0257         if ( x_pos && x_rot )   {
0258           rot = dd4hep::RotationZYX(x_rot.z(0), x_rot.y(0), x_rot.x(0));
0259           pos = dd4hep::Position(x_pos.x(0), x_pos.y(0), x_pos.z(0));
0260         }
0261         else if ( x_pos )
0262           pos = dd4hep::Position(x_pos.x(0), x_pos.y(0), x_pos.z(0));
0263         else if ( x_rot )
0264           rot = dd4hep::RotationZYX(x_rot.z(0), x_rot.y(0), x_rot.x(0));
0265       
0266         dd4hep::PlacedVolume pv = envelope.placeVolume(vol,env_trafo*dd4hep::Transform3D(rot, pos));
0267         vol.setAttributes(dsc, x_vol.regionStr(), x_vol.limitsStr(), x_vol.visStr());
0268         for (xml_coll_t cc(x_vol,_U(physvolid)); cc; ++cc )   {
0269           xml_dim_t vid = cc;
0270           pv.addPhysVolID(vid.nameStr(), vid.attr<int>(_U(value)));
0271         }
0272       }
0273     }
0274   }
0275   else   {
0276     for(std::size_t i=0; i < volumes.size(); ++i)   {
0277       dd4hep::Volume vol = volumes[i].release();
0278       if ( vol.isValid() )   {
0279         if ( (vol.material() == dsc.air()) && default_material.isValid() )
0280           vol.setMaterial(default_material);
0281         envelope.placeVolume(vol,env_trafo);
0282       }
0283     }
0284   }
0285   if ( elt.hasAttr(_U(name)) ) envelope->SetName(elt.attr<std::string>(_U(name)).c_str());
0286   return envelope;
0287 }
0288 DECLARE_XML_VOLUME(CAD_MultiVolume__volume_constructor,create_CAD_Volume)
0289 
0290 /// CAD volume importer plugin
0291 /**
0292  *
0293  */
0294 static long CAD_export(dd4hep::Detector& description, int argc, char** argv)   {
0295   bool        recursive = false, help = false;
0296   std::string volume, detector, fname, ftype;
0297   double      scale = 1.0;
0298   int         flags = 0;
0299   
0300   for(int i = 0; i < argc && argv[i]; ++i)  {
0301     if (      0 == ::strncmp( "-output",argv[i],4) )    fname     = argv[++i];
0302     else if ( 0 == ::strncmp("--output",argv[i],5) )    fname     = argv[++i];
0303     else if ( 0 == ::strncmp( "-type",argv[i],4) )      ftype     = argv[++i];
0304     else if ( 0 == ::strncmp("--type",argv[i],5) )      ftype     = argv[++i];
0305     else if ( 0 == ::strncmp( "-detector",argv[i],4) )  detector  = argv[++i];
0306     else if ( 0 == ::strncmp("--detector",argv[i],5) )  detector  = argv[++i];
0307     else if ( 0 == ::strncmp( "-volume",argv[i],4) )    volume    = argv[++i];
0308     else if ( 0 == ::strncmp("--volume",argv[i],5) )    volume    = argv[++i];
0309     else if ( 0 == ::strncmp( "-recursive",argv[i],4) ) recursive = true;
0310     else if ( 0 == ::strncmp("--recursive",argv[i],5) ) recursive = true;
0311     else if ( 0 == ::strncmp( "-scale",argv[i],4) )     scale     = ::atof(argv[++i]);
0312     else if ( 0 == ::strncmp("--scale",argv[i],5) )     scale     = ::atof(argv[++i]);
0313     else if ( 0 == ::strncmp( "-flags",argv[i],4) )     flags     = ::atol(argv[++i]);
0314     else if ( 0 == ::strncmp("--flags",argv[i],5) )     flags     = ::atol(argv[++i]);
0315     else if ( 0 == ::strncmp( "-help",argv[i],2) )      help      = true;
0316     else if ( 0 == ::strncmp("--help",argv[i],3) )      help      = true;
0317   }
0318 
0319   if ( fname.empty() || ftype.empty() ) help = true;
0320   if ( volume.empty() && detector.empty() ) help = true;
0321   if ( help )   {
0322     std::cout <<
0323       "Usage: -plugin DD4hep_CAD_export -arg [-arg]                           \n\n"
0324       "     -output   <string> Output file name.                                \n"
0325       "     -type     <string> Output file type.                                \n"
0326       "     -recursive         Export volume/detector element and all daughters.\n"
0327       "     -volume   <string> Path to the volume to be exported.               \n"
0328       "     -detector <string> Path to the detector element to be exported.     \n"
0329       "     -help              Print this help output.                          \n"
0330       "     -scale    <number> Unit scale before writing output data.           \n"
0331       "     -flags    <number> Flagsging helper to pass args -- Experts only.   \n"
0332       "     Arguments given: " << dd4hep::arguments(argc,argv) << std::endl << std::flush;
0333     ::exit(EINVAL);
0334   }
0335 
0336   dd4hep::PlacedVolume pv;
0337   if ( !detector.empty() )   {
0338     dd4hep::DetElement elt;
0339     if ( detector == "/world" )
0340       elt = description.world();
0341     else
0342       elt = dd4hep::detail::tools::findElement(description,detector);
0343     if ( !elt.isValid() )  {
0344       except("DD4hep_CAD_export","+++ Invalid DetElement path: %s",detector.c_str());
0345     }
0346     if ( !elt.placement().isValid() )   {
0347       except("DD4hep_CAD_export","+++ Invalid DetElement placement: %s",detector.c_str());
0348     }
0349     pv = elt.placement();
0350   }
0351   else if ( !volume.empty() )   {
0352     pv = dd4hep::detail::tools::findNode(description.world().placement(), volume);
0353     if ( !pv.isValid() )   {
0354       except("DD4hep_CAD_export","+++ Invalid placement path: %s",volume.c_str());
0355     }
0356   }
0357   dd4hep::cad::ASSIMPWriter wr(description);
0358   if ( flags ) wr.flags = flags;
0359   std::vector<dd4hep::PlacedVolume> places {pv};
0360   auto num_mesh = wr.write(fname, ftype, places, recursive, scale);
0361   if ( num_mesh < 0 )   {
0362     printout(dd4hep::ERROR, "DD4hep_CAD_export",
0363              "+++ Failed to export shapes to CAD file: %s [%s]",
0364              fname.c_str(), ftype.c_str());
0365   }
0366   return 1;
0367 }
0368 DECLARE_APPLY(DD4hep_CAD_export,CAD_export)