DD4hep  1.30.0
Detector Description Toolkit for High Energy Physics
GdmlPlugins.cpp
Go to the documentation of this file.
1 //==========================================================================
2 // AIDA Detector description implementation
3 //--------------------------------------------------------------------------
4 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
5 // All rights reserved.
6 //
7 // For the licensing terms see $DD4hepINSTALL/LICENSE.
8 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
9 //
10 // Author : M.Frank
11 //
12 //==========================================================================
13 
14 // Framework include files
15 #include <DD4hep/Detector.h>
16 #include <DD4hep/Memory.h>
17 #include <DD4hep/DD4hepUI.h>
18 #include <DD4hep/Factories.h>
19 #include <DD4hep/Printout.h>
20 #include <DD4hep/DetectorTools.h>
22 #include <XML/DocumentHandler.h>
23 #include <XML/Utilities.h>
24 
25 // ROOT includes
26 #include <TInterpreter.h>
27 #include <TGeoElement.h>
28 #include <TGeoManager.h>
29 #include <TGDMLParse.h>
30 #include <TGDMLWrite.h>
31 #include <TUri.h>
32 
33 using namespace std;
34 using namespace dd4hep;
35 
37 
44 static long gdml_parse(Detector& description, int argc, char** argv) {
45  if ( argc > 0 ) {
46  string input, path;
47  bool wrld = false;
48  for(int i = 0; i < argc && argv[i]; ++i) {
49  if ( 0 == ::strncmp("-input",argv[i],2) )
50  input = argv[++i];
51  else if ( 0 == ::strncmp("-path", argv[i],2) )
52  path = argv[++i];
53  else if ( 0 == ::strncmp("-world", argv[i],2) )
54  wrld = true;
55  }
56  if ( input.empty() || (path.empty() && !wrld) ) {
57  cout <<
58  "Usage: -plugin <name> -arg [-arg] \n"
59  " name: factory name DD4hep_ROOTGDMLParse \n"
60  " -input <string> Input file name. \n"
61  " -path <string> Path to parent detector element to attach \n"
62  " top volume from GDML file. \n"
63  " -world <string> Name of the world object if to be imported from gdml.\n"
64  " Note: -path and -world options are exclusive. \n"
65  "\tArguments given: " << arguments(argc,argv) << endl << flush;
66  ::exit(EINVAL);
67  }
68  printout(INFO,"ROOTGDMLParse","+++ Read geometry from GDML file file:%s",input.c_str());
69  vector<string> elements = detail::tools::pathElements(path);
70  if ( !wrld && !elements.empty() ) {
71  DetElement world = description.world();
72  DetElement parent = world, child;
73  for(size_t i=0; i < elements.size(); ++i) {
74  const auto& e = elements[i];
75  if ( e == world.name() )
76  continue;
77  child = parent.child(e, false);
78  if ( child.isValid() ) {
79  parent = child;
80  continue;
81  }
82  child = DetElement(e, 0); // Inactive child, no sensitive detector, no ID
83  PlacedVolume pv;
84  Volume mother = (parent==world) ? description.pickMotherVolume(child) : parent.volume();
85  if ( i == elements.size()-1 ) {
86  TGDMLParse parser;
87  TUri uri(input.c_str());
88  input = uri.GetRelativePart();
89  Volume vol = parser.GDMLReadFile(input.c_str());
90  if ( vol.isValid() ) {
91  vol.import(); // We require the extensions in dd4hep.
92  pv = mother.placeVolume(vol);
93  child.setPlacement(pv);
94  if (parent == world) description.add(child);
95  else parent.add(child);
96  printout(INFO,"ROOTGDMLParse","+++ Attach GDML volume %s to Element path:%s",
97  vol.name(), path.c_str());
98  return 1;
99  }
100  except("ROOTGDMLParse","+++ Failed to parse GDML file:%s for path:%s",
101  input.c_str(),path.c_str());
102  }
103  pv = mother.placeVolume(Assembly(e));
104  child.setPlacement(pv);
105  if (parent == world) description.add(child);
106  else parent.add(child);
107  }
108  }
109  else if ( wrld ) {
110  TGDMLParse parser;
111  TUri uri(input.c_str());
112  input = uri.GetRelativePart();
113  Volume vol = parser.GDMLReadFile(input.c_str());
114  if ( vol.isValid() ) {
115  vol.import(); // We require the extensions in dd4hep.
116  description.manager().SetTopVolume(vol.ptr());
117  description.init();
118  description.endDocument();
119  printout(INFO,"ROOTGDMLParse","+++ Attach GDML volume %s", vol.name());
120  return 1;
121  }
122  except("ROOTGDMLParse","+++ Failed to parse GDML file:%s for path:%s",
123  input.c_str(),path.c_str());
124  }
125 
126  except("ROOTGDMLParse","+++ Invalid DetElement path given: %s", path.c_str());
127  }
128  except("ROOTGDMLParse","+++ No input file name given.");
129  return 0;
130 }
131 DECLARE_APPLY(DD4hep_ROOTGDMLParse,gdml_parse)
132 
133 
134 
142 static long gdml_extract(Detector& description, int argc, char** argv) {
143  if ( argc > 0 ) {
144  bool detector = true, volpath = false;
145  string output, path;
146  int precision = 12;
147  for(int i = 0; i < argc && argv[i]; ++i) {
148  if ( 0 == ::strncmp("-output",argv[i],2) )
149  output = argv[++i];
150  else if ( 0 == ::strncmp("-path", argv[i],4) )
151  path = argv[++i];
152  else if ( 0 == ::strncmp("-volpath", argv[i],7) )
153  volpath = true, detector = false;
154  else if ( 0 == ::strncmp("-volname", argv[i],7) )
155  volpath = false, detector = false;
156  else if ( 0 == ::strncmp("-detector", argv[i],8) )
157  volpath = false, detector = true;
158  else if ( 0 == ::strncmp("-precision", argv[i],5) )
159  precision = ::atol(argv[++i]);
160  }
161  if ( output.empty() || path.empty() ) {
162  cout <<
163  "Usage: -plugin <name> -arg [-arg] \n"
164  " name: factory name DD4hep_ROOTGDMLExtract \n"
165  " -output <string> Output file name. \n"
166  " -path <string> Path to parent detector element to extract \n"
167  " top volume to GDML file. \n"
168  " -detector Indicate that the path is a DetElement path \n"
169  " -volpath Indicate that the path is a volume path \n"
170  " -volname Indicate that the path is a volume name prefix \n"
171  " -precision <number> GDML output floating point precision \n"
172  "\tArguments given: " << arguments(argc,argv) << endl << flush;
173  ::exit(EINVAL);
174  }
175  if ( detector ) {
176  printout(INFO,"ROOTGDMLExtract","+++ Write geometry %s to GDML file file:%s",
177  path.c_str(), output.c_str());
178  DetElement de = detail::tools::findElement(description,path);
179  if ( de.isValid() ) {
180  TGDMLWrite extract;
181  TUri uri(output.c_str());
182  description.manager().SetExportPrecision(precision);
183 #if ROOT_VERSION_CODE > ROOT_VERSION(6,27,1)
184  extract.SetIgnoreDummyMaterial(true);
185  extract.SetNamingSpeed(TGDMLWrite::kfastButUglySufix);
186  extract.WriteGDMLfile(&description.manager(), de.placement().ptr(), uri.GetRelativePart());
187 #else
188  extract.WriteGDMLfile(&description.manager(), de.placement().ptr(), uri.GetRelativePart());
189 #endif
190  return 1;
191  }
192  except("ROOTGDMLExtract","+++ Invalid DetElement path given: %s", path.c_str());
193  }
194  else {
195  struct Actor {
196  bool _volpath;
197  const string& _path;
198  TGeoNode* _node = 0;
199  Actor(const string& p, bool vp) : _volpath(vp), _path(p) {}
200  void scan(TGeoNode* n, const std::string& p="") {
201  string nam;
202  if ( _volpath ) {
203  nam = p + '/';
204  nam += n->GetName();
205  if ( _volpath && nam.find(_path) == 0 ) {
206  _node = n;
207  }
208  for (Int_t idau = 0, ndau = n->GetNdaughters(); _node == 0 && idau < ndau; ++idau)
209  scan(n->GetDaughter(idau), p);
210  return;
211  }
212  nam = n->GetName();
213  if ( nam.find(_path) == 0 ) {
214  _node = n;
215  printout(ALWAYS,"Check","+++ Found required volume: %s",_path.c_str());
216  printout(ALWAYS,"Check","+++ -> %s",nam.c_str());
217  return;
218  }
219  for (Int_t idau = 0, ndau = n->GetNdaughters(); _node == 0 && idau < ndau; ++idau)
220  scan(n->GetDaughter(idau),nam);
221  }
222  };
223  Volume top = description.worldVolume();
224  TObjArray* ents = top->GetNodes();
225  Actor a(path, volpath ? true : false);
226  for (Int_t i = 0, n = ents->GetEntries(); i < n && a._node == 0; ++i) {
227  TGeoNode* node = (TGeoNode*)ents->At(i);
228  a.scan(node, node->GetName());
229  }
230  if ( a._node ) {
231  TGDMLWrite extract;
232  TUri uri(output.c_str());
233  description.manager().SetExportPrecision(precision);
234 #if ROOT_VERSION_CODE > ROOT_VERSION(6,27,1)
235  extract.SetIgnoreDummyMaterial(true);
236  extract.SetNamingSpeed(TGDMLWrite::kfastButUglySufix);
237  extract.WriteGDMLfile(&description.manager(), a._node, uri.GetRelativePart());
238 #else
239  extract.WriteGDMLfile(&description.manager(), a._node, uri.GetRelativePart());
240 #endif
241  return 1;
242  }
243  except("ROOTGDMLExtract","+++ Invalid volume path/name given: %s", path.c_str());
244  }
245  }
246  except("ROOTGDMLExtract","+++ No output file name given.");
247  return 0;
248 }
249 DECLARE_APPLY(DD4hep_ROOTGDMLExtract,gdml_extract)
250 
251 static long create_gdml_from_dd4hep(Detector& description, int argc, char** argv) {
253  if ( argc > 0 ) {
254  string output = argv[0];
255  if ( output.substr(0,5) == "file:" ) output = output.substr(6);
256  const char* av[] = {"DD4hepGeometry2GDML", "-output", output.c_str(), "-path", "/world", 0};
257  if ( 1 == gdml_extract(description, 5, (char**)av) ) {
258  printout(INFO,"Geometry2GDML","+++ Successfully extracted GDML to %s",output.c_str());
259  return 1;
260  }
261  except("Geometry2GDML","+++ FAILED to extract GDML file %s.",output.c_str());
262  }
263  except("Geometry2GDML","+++ No output file name given.");
264  return 0;
265 }
266 DECLARE_APPLY(DD4hepGeometry2GDML, create_gdml_from_dd4hep)
267 
268 static Ref_t create_detector(Detector& description, xml_h e, Ref_t /* sens_det */) {
270  using namespace dd4hep::detail;
271  xml_det_t x_det = e;
272  int id = x_det.hasAttr(_U(id)) ? x_det.id() : 0;
273  xml_dim_t x_pos (x_det.child(_U(position),false));
274  xml_dim_t x_rot (x_det.child(_U(rotation),false));
275  xml_dim_t x_gdml (x_det.child(_U(gdmlFile)));
276  xml_dim_t x_par (x_det.child(_U(parent)));
277  string name = x_det.nameStr();
278  string par_nam = x_par.nameStr();
279  string gdml = x_gdml.attr<string>(_U(ref));
280  string gdml_physvol = dd4hep::getAttrOrDefault<string>(x_gdml, _Unicode(physvol), "");
281  DetElement det_parent = description.detector(par_nam);
282  TGDMLParse parser;
283  if ( !gdml.empty() && gdml[0] == '/' ) {
284  TUri uri(gdml.c_str());
285  gdml = uri.GetRelativePart();
286  }
287  else {
288  string path = xml::DocumentHandler::system_path(e, gdml);
289  TUri uri(path.c_str());
290  gdml = uri.GetRelativePart();
291  }
292  if ( !det_parent.isValid() ) {
293  except(name,"+++ Cannot access detector parent: %s",par_nam.c_str());
294  }
295  DetElement sdet(name, id);
296  Volume volume = parser.GDMLReadFile(gdml.c_str());
297  if ( !volume.isValid() ) {
298  except("ROOTGDMLParse","+++ Failed to parse GDML file:%s",gdml.c_str());
299  }
300  volume.import(); // We require the extensions in dd4hep.
301  printout(INFO,"ROOTGDMLParse","+++ Attach GDML volume %s", volume.name());
302  Volume mother = det_parent.volume();
303  PlacedVolume pv;
304 
305  if ( !gdml_physvol.empty() ) {
306  PlacedVolume node = volume->FindNode(gdml_physvol.c_str());
307  if ( !node.isValid() ) {
308  printout(ERROR,"ROOTGDMLParse","+++ Invalid gdml placed volume %s", gdml_physvol.c_str());
309  printout(ERROR,"ROOTGDMLParse","+++ Valid top-level nodes are:");
310  volume->PrintNodes();
311  except("ROOTGDMLParse","+++ Failed to parse GDML file:%s for node:%s",
312  gdml.c_str(), gdml_physvol.c_str());
313  }
314  volume = node.volume();
315  }
316 
317  if ( x_pos && x_rot ) {
318  Rotation3D rot(RotationZYX(x_rot.z(),x_rot.y(),x_rot.x()));
319  Transform3D transform(rot,Position(x_pos.x(),x_pos.y(),x_pos.z()));
320  pv = mother.placeVolume(volume,transform);
321  }
322  else if ( x_rot ) {
323  Rotation3D rot(RotationZYX(x_rot.z(),x_rot.y(),x_rot.x()));
324  Transform3D transform(rot,Position(0,0,0));
325  pv = mother.placeVolume(volume,transform);
326  }
327  else if ( x_pos ) {
328  pv = mother.placeVolume(volume,Position(x_pos.x(),x_pos.y(),x_pos.z()));
329  }
330  else {
331  pv = mother.placeVolume(volume);
332  }
333  volume.setVisAttributes(description, x_det.visStr());
334  volume.setLimitSet(description, x_det.limitsStr());
335  volume.setRegion(description, x_det.regionStr());
336  if ( id != 0 ) {
337  pv.addPhysVolID("system", id);
338  }
339  sdet.setPlacement(pv);
340  return sdet;
341 }
342 
343 // first argument is the type from the xml file
344 DECLARE_DETELEMENT(DD4hep_GdmlDetector,create_detector)
dd4hep::Detector::manager
virtual TGeoManager & manager() const =0
Access the geometry manager of this instance.
dd4hep::Volume::setLimitSet
const Volume & setLimitSet(const Detector &description, const std::string &name) const
Set the limits to the volume. Note: If the name string is empty, the action is ignored.
Definition: Volumes.cpp:1261
dd4hep::Detector::world
virtual DetElement world() const =0
Return reference to the top-most (world) detector element.
dd4hep::Detector::detector
virtual DetElement detector(const std::string &name) const =0
Retrieve a subdetector element by its name from the detector description.
Detector.h
DECLARE_DETELEMENT
#define DECLARE_DETELEMENT(name, func)
Definition: Factories.h:339
dd4hep::PlacedVolume
Handle class holding a placed volume (also called physical volume)
Definition: Volumes.h:173
dd4hep::DetElement::placement
PlacedVolume placement() const
Access to the physical volume of this detector element.
Definition: DetElement.cpp:321
dd4hep::PlacedVolume::addPhysVolID
PlacedVolume & addPhysVolID(const std::string &name, int value)
Add identifier.
Definition: Volumes.cpp:485
DECLARE_APPLY
#define DECLARE_APPLY(name, func)
Definition: Factories.h:281
dd4hep::Handle::isValid
bool isValid() const
Check the validity of the object held by the handle.
Definition: Handle.h:128
dd4hep::Handle
Handle: a templated class like a shared pointer, which allows specialized access to tgeometry objects...
Definition: Handle.h:84
dd4hep::Volume::setRegion
const Volume & setRegion(const Detector &description, const std::string &name) const
Set the regional attributes to the volume. Note: If the name string is empty, the action is ignored.
Definition: Volumes.cpp:1242
dd4hep::Rotation3D
ROOT::Math::Rotation3D Rotation3D
Definition: Objects.h:113
dd4hep::Detector::pickMotherVolume
virtual Volume pickMotherVolume(const DetElement &sd) const =0
Access mother volume by detector element.
dd4hep::DetElement::add
DetElement & add(DetElement sub_element)
Add new child to the detector structure.
Definition: DetElement.cpp:258
dd4hep::xml::Handle_t
Class to easily access the properties of single XmlElements.
Definition: XMLElements.h:380
dd4hep::Detector::worldVolume
virtual Volume worldVolume() const =0
Return handle to the world volume containing everything.
Factories.h
dd4hep::Handle::name
const char * name() const
Access the object name (or "" if not supported by the object)
dd4hep::Assembly
Implementation class extending the ROOT assembly volumes (TGeoVolumeAssembly)
Definition: Volumes.h:762
dd4hep::Volume::placeVolume
PlacedVolume placeVolume(const Volume &volume) const
Place daughter volume. The position and rotation are the identity.
Definition: Volumes.cpp:830
parser
dd4hepDOMParser * parser
Definition: DocumentHandler.cpp:159
_Unicode
#define _Unicode(a)
Definition: Tags.h:24
dd4hep::detail::tools::findElement
DetElement findElement(const Detector &description, const std::string &path)
Find DetElement as child of the top level volume by its absolute path.
Definition: DetectorTools.cpp:214
DocumentHandler.h
dd4hep::DetElement
Handle class describing a detector element.
Definition: DetElement.h:188
dd4hep::Volume
Handle class holding a placed volume (also called physical volume)
Definition: Volumes.h:378
dd4hep::detail
DD4hep internal namespace.
Definition: Alignments.h:32
dd4hep::DetElement::volume
Volume volume() const
Access to the logical volume of the detector element's placement.
Definition: DetElement.cpp:352
dd4hep::Detector::init
virtual void init()=0
Initialize geometry.
DetectorTools.h
xml_det_t
dd4hep::xml::DetElement xml_det_t
Definition: XML.h:32
_U
#define _U(a)
Definition: Tags.h:23
dd4hep::Detector::endDocument
virtual void endDocument(bool close_geometry=true)=0
Finalize the geometry.
dd4hep::Detector::add
virtual Detector & add(Constant constant)=0
Add a new constant to the detector description.
dd4hep::Transform3D
ROOT::Math::Transform3D Transform3D
Definition: Objects.h:117
Memory.h
dd4hep::Position
ROOT::Math::XYZVector Position
Definition: Objects.h:81
dd4hep::detail::tools::pathElements
std::vector< std::string > pathElements(const std::string &path)
Extract all the path elements from a path.
Definition: DetectorTools.cpp:397
DetFactoryHelper.h
std
Definition: Plugins.h:30
dd4hep::Handle::ptr
T * ptr() const
Access to the held object.
Definition: Handle.h:153
dd4hep::Volume::setVisAttributes
const Volume & setVisAttributes(const VisAttr &obj) const
Set Visualization attributes to the volume.
Definition: Volumes.cpp:1127
DD4hepUI.h
dd4hep
Namespace for the AIDA detector description toolkit.
Definition: AlignmentsCalib.h:28
dd4hep::DetElement::child
DetElement child(const std::string &name) const
Access to individual children by name.
Definition: DetElement.cpp:212
dd4hep::PlacedVolume::volume
Volume volume() const
Logical volume of this placement.
Definition: Volumes.cpp:452
dd4hep::Detector
The main interface to the dd4hep detector description package.
Definition: Detector.h:90
create_gdml_from_dd4hep
long create_gdml_from_dd4hep(Detector &description, int argc, char **argv)
Definition: LCDDConverter.cpp:1297
dd4hep::RotationZYX
ROOT::Math::RotationZYX RotationZYX
Definition: Objects.h:105
dd4hep::xml::Handle_t::hasAttr
bool hasAttr(const XmlChar *t) const
Check for the existence of a named attribute.
Definition: XMLElements.cpp:673
dd4hep::xml::DocumentHandler::system_path
static std::string system_path(Handle_t base)
System ID of a given XML entity.
Definition: DocumentHandler.cpp:277
Printout.h
dd4hep::Volume::import
Volume & import()
If we import volumes from external sources, we have to attach the extensions to the tree.
Definition: Volumes.cpp:673
xml_dim_t
dd4hep::xml::Dimension xml_dim_t
Definition: XML.h:31
Utilities.h