EDepSimRootGeometryManager.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////
2 //
4 #include "EDepSimException.hh"
5 
6 #include "EDepSimLog.hh"
7 
8 #include <TROOT.h>
9 #include <TMath.h>
10 #include <TGeoManager.h>
11 #include <TGeoVolume.h>
12 #include <TGeoMedium.h>
13 #include <TGeoElement.h>
14 #include <TGeoTube.h>
15 #include <TGeoTrd2.h>
16 #include <TGeoSphere.h>
17 #include <TGeoPgon.h>
18 #include <TGeoArb8.h>
19 #include <TGeoBoolNode.h>
20 #include <TGeoCompositeShape.h>
21 #include <TGeoMatrix.h>
22 #include <TGeoOverlap.h>
23 #include <TGeoXtru.h>
24 #include <TGeoPcon.h>
25 #include <TColor.h>
26 
27 #include <globals.hh>
28 
29 #include <G4LogicalVolume.hh>
30 #include <G4VPhysicalVolume.hh>
31 #include <G4Material.hh>
32 #include <G4Element.hh>
33 #include <G4Isotope.hh>
34 #include <G4UnitsTable.hh>
35 
36 #include <G4VisAttributes.hh>
37 #include <G4VSolid.hh>
38 #include <G4Box.hh>
39 #include <G4Trd.hh>
40 #include <G4Tubs.hh>
41 #include <G4Sphere.hh>
42 #include <G4Polyhedra.hh>
43 #include <G4Polycone.hh>
44 #include <G4Trap.hh>
45 #include <G4SubtractionSolid.hh>
46 #include <G4UnionSolid.hh>
47 #include <G4IntersectionSolid.hh>
48 #include <G4ExtrudedSolid.hh>
49 
50 #include <G4SystemOfUnits.hh>
51 #include <G4PhysicalConstants.hh>
52 
53 
54 #include <memory>
55 #include <cmath>
56 #include <cstdlib>
57 #include <set>
58 
60 
62 }
63 
66  return fThis;
67 }
68 
70 
72  EDepSimLog(" *** Export to " << file);
73  gGeoManager->Export(file);
74 }
75 
76 int EDepSim::RootGeometryManager::GetNodeId(const G4ThreeVector& pos) {
77  if (!gGeoManager) return -1;
78  gGeoManager->FindNode(pos.x(), pos.y(), pos.z());
79  return gGeoManager->GetCurrentNodeId();
80 }
81 
82 namespace {
83  int CountVolumes(G4LogicalVolume* volume) {
84  int count = 1;
85  for (std::size_t i = 0; i<volume->GetNoDaughters(); ++i) {
86  G4VPhysicalVolume* daughter = volume->GetDaughter(i);
87  count += CountVolumes(daughter->GetLogicalVolume());
88  }
89  return count;
90  }
91 }
92 
93 void EDepSim::RootGeometryManager::Update(const G4VPhysicalVolume* aWorld,
94  bool validateGeometry) {
95  EDepSimLog("%%%%%%%%%%%%%%%%%%%%%%%%%% Update ROOT Geometry "
96  << "%%%%%%%%%%%%%%%%%%%%%%%%%%" );
97  if (gGeoManager) {
98  EDepSimLog("%%%%%%%%%%%%%%% Warning: Replacing ROOT Geometry ");
99  delete gGeoManager;
100  // Clear the node counts definitions.
101  fNodeCount.clear();
102  // Clear the cached materials. The material objects are owned by the
103  // TGeoManager and are invalid after it has been deleted.
104  fMedium.clear();
105  // Clear the cached isotopes. This is a bit complicated since the
106  // isotope pointers may be duplicated in the map.
107  std::set<TGeoElement*> isotope;
109  i != fIsotope.end();
110  ++i) {
111  isotope.insert(i->second);
112  }
113  fIsotope.clear();
114  for (std::set<TGeoElement*>::iterator i = isotope.begin();
115  i != isotope.end();
116  ++i) {
117  delete *i;
118  }
119  }
120  // Create the new geometry.
121  gGeoManager = new TGeoManager("EDepSimGeometry",
122  "Simulated Detector Geometry");
123  gGeoManager->SetVisLevel(20);
124  // Create all of the materials.
125  EDepSimInfo("Create materials");
126  CreateMaterials(aWorld);
127 
128  //Check to see if we can create all of the volumes. This is done by
129  //traversing the GEANT physical volume tree.
130  fCreateAllVolumes = false;
131  if (CountVolumes(aWorld->GetLogicalVolume()) < 100000) {
132  EDepSimInfo("Create all volumes");
133  fCreateAllVolumes = true;
134  }
135 
136  // Create the ROOT geometry definitions.
137  fPrintedMass.clear();
138  fNameStack.clear();
139  fKnownVolumes.clear();
140  EDepSimInfo("Start defining envelope");
141  CreateEnvelope(aWorld,gGeoManager,NULL);
142  EDepSimInfo("Geometry is Filled");
143 
144  gGeoManager->CloseGeometry("di");
145 
146  EDepSimLog("Geometry initialized and closed");
147 
148  if (validateGeometry) return Validate();
149 }
150 
152  bool validateGeometry) {
153  EDepSimLog( "%%%%%%%%%%%%%%%%%% Update ROOT Geometry from GDML"
154  << "%%%%%%%%%%%%%%%%%%" );
155  if (gGeoManager) {
156  EDepSimLog("%%%%%%%%%%%%%%% Warning: Replacing ROOT Geometry ");
157  delete gGeoManager;
158  // Clear the node counts definitions.
159  fNodeCount.clear();
160  // Clear the cached materials. The material objects are owned by the
161  // TGeoManager and are invalid after it has been deleted.
162  fMedium.clear();
163  // Clear the cached isotopes. This is a bit complicated since the
164  // isotope pointers may be duplicated in the map.
165  std::set<TGeoElement*> isotope;
167  i != fIsotope.end();
168  ++i) {
169  isotope.insert(i->second);
170  }
171  fIsotope.clear();
172  for (std::set<TGeoElement*>::iterator i = isotope.begin();
173  i != isotope.end();
174  ++i) {
175  delete *i;
176  }
177  }
178 
179  // Create the new geometry.
180  TGeoManager::Import(gdmlFile.c_str());
181  gGeoManager->SetName("EDepSimGeometry");
182  gGeoManager->SetTitle("Simulated Detector Geometry");
183 
184  EDepSimLog("####################### Geometry initialized and closed");
185 
186  if (validateGeometry) return Validate();
187 }
188 
190 
191  int count = 0;
192  // Check for overlaps at volume corners. Look for overlaps at 0.1 mm size.
193  gGeoManager->CheckOverlaps(0.1*CLHEP::mm);
194  {
195  TIter next(gGeoManager->GetListOfOverlaps());
196  TGeoOverlap* overlap;
197  while ((overlap=(TGeoOverlap*)next())) {
198  ++count;
199  overlap->PrintInfo();
200  }
201  }
202 
203  // Check for overlaps with sampling. Look for overlaps at 0.1 mm size.
204  gGeoManager->CheckOverlaps(0.1*CLHEP::mm,"s100000");
205  {
206  TIter next(gGeoManager->GetListOfOverlaps());
207  TGeoOverlap* overlap;
208  while ((overlap=(TGeoOverlap*)next())) {
209  ++count;
210  overlap->PrintInfo();
211  }
212  }
213 
214  if (count > 0) {
215  EDepSimThrow(
216  "The geometry has overlaps and will produce incorrect"
217  " results. To use the geometry, specify the '-C' option"
218  " on the command line.");
219  }
220 
221  EDepSimLog("Geometry validated");
222 }
223 
224 TGeoShape* EDepSim::RootGeometryManager::CreateShape(const G4VSolid* theSolid,
225  TGeoMatrix **returnMatrix) {
226  const G4String geometryType = theSolid->GetEntityType();
227  TGeoShape* theShape = NULL;
228  if (geometryType == "G4Box") {
229  // Create a box
230  const G4Box* box = dynamic_cast<const G4Box*>(theSolid);
231  theShape = new TGeoBBox(box->GetXHalfLength()/CLHEP::mm,
232  box->GetYHalfLength()/CLHEP::mm,
233  box->GetZHalfLength()/CLHEP::mm);
234  }
235  else if (geometryType == "G4Tubs") {
236  const G4Tubs* tube = dynamic_cast<const G4Tubs*>(theSolid);
237  // Root takes the angles in degrees so there is no extra
238  // conversion.
239  double zhalf = tube->GetZHalfLength()/CLHEP::mm;
240  double rmin = tube->GetInnerRadius()/CLHEP::mm;
241  double rmax = tube->GetOuterRadius()/CLHEP::mm;
242  double minPhiDeg = tube->GetStartPhiAngle()/CLHEP::degree;
243  double maxPhiDeg = minPhiDeg + tube->GetDeltaPhiAngle()/CLHEP::degree;
244  theShape = new TGeoTubeSeg(rmin, rmax,
245  zhalf,
246  minPhiDeg, maxPhiDeg);
247  }
248  else if (geometryType == "G4Sphere") {
249  const G4Sphere* sphere = dynamic_cast<const G4Sphere*>(theSolid);
250  // Root takes the angles in degrees so there is no extra
251  // conversion.
252  double minPhiDeg = sphere->GetStartPhiAngle()/CLHEP::degree;
253  double maxPhiDeg = minPhiDeg + sphere->GetDeltaPhiAngle()/CLHEP::degree;
254  double minThetaDeg = sphere->GetStartThetaAngle()/CLHEP::degree;
255  double maxThetaDeg = minThetaDeg + sphere->GetDeltaThetaAngle()/CLHEP::degree;
256  theShape = new TGeoSphere(sphere->GetInnerRadius()/CLHEP::mm,
257  sphere->GetOuterRadius()/CLHEP::mm,
258  minThetaDeg, maxThetaDeg,
259  minPhiDeg, maxPhiDeg);
260  }
261  else if (geometryType == "G4Polyhedra") {
262  const G4Polyhedra* polyhedra
263  = dynamic_cast<const G4Polyhedra*>(theSolid);
264  double phi = polyhedra->GetStartPhi();
265  double dPhi = polyhedra->GetEndPhi() - phi;
266  if (dPhi>2*M_PI) dPhi -= 2*M_PI;
267  if (dPhi<0) dPhi += 2*M_PI;
268  int sides = polyhedra->GetNumSide();
269  int numZ = polyhedra->GetNumRZCorner()/2;
270  // Factor to take into account that ROOT uses the circle that can be
271  // inscribed inside the polygon, and G4 uses the corner
272  double g4Factor = std::cos(0.5*dPhi/sides);
273  TGeoPgon* pgon = new TGeoPgon(phi/CLHEP::degree,
274  dPhi/CLHEP::degree, sides, numZ);
275  for (int i = 0; i< numZ; ++i) {
276  double rMin = g4Factor*polyhedra->GetCorner(numZ-i-1).r;
277  double rMax = g4Factor*polyhedra->GetCorner(numZ+i).r;
278  if (rMax < rMin) std::swap(rMin,rMax);
279  pgon->DefineSection(i,
280  polyhedra->GetCorner(numZ-i-1).z/CLHEP::mm,
281  rMin/CLHEP::mm,
282  rMax/CLHEP::mm);
283  }
284  theShape = pgon;
285  }
286  else if (geometryType == "G4Polycone") {
287  const G4Polycone* polycone
288  = dynamic_cast<const G4Polycone*>(theSolid);
289  double phi = polycone->GetStartPhi();
290  double dPhi = polycone->GetEndPhi() - phi;
291  if (dPhi>2*M_PI) dPhi -= 2*M_PI;
292  if (dPhi<0) dPhi += 2*M_PI;
293 #ifdef G4GEOM_USE_USOLIDS
294 #warning GEANT HAS BEEN COMPILED WITH BROKEN USOLIDS.
295  int numZ = polycone->GetNumRZCorner()/2;
296  TGeoPcon* pcon = new TGeoPcon(phi/CLHEP::degree,
297  dPhi/CLHEP::degree, numZ);
298  // This depends on the (mostly) undocumented order of the corners in
299  // the G4Polycone internals. It's a little unstable...
300  for (int i = 0; i< numZ; ++i) {
301  pcon->DefineSection(i,
302  polycone->GetCorner(numZ-i-1).z/CLHEP::mm,
303  polycone->GetCorner(numZ-i-1).r/CLHEP::mm,
304  polycone->GetCorner(numZ+i).r/CLHEP::mm);
305  }
306 #else
307  const G4PolyconeHistorical* param = polycone->GetOriginalParameters();
308  int numZ = param->Num_z_planes;
309  TGeoPcon* pcon = new TGeoPcon(phi/CLHEP::degree, dPhi/CLHEP::degree, numZ);
310  // This depends on the older interface. It's not marked as
311  // deprecated, but the documentation discourages it's use.
312  for (int i = 0; i< numZ; ++i) {
313  pcon->DefineSection(i,
314  param->Z_values[i]/CLHEP::mm,
315  param->Rmin[i]/CLHEP::mm,
316  param->Rmax[i]/CLHEP::mm);
317  }
318 #endif
319  theShape = pcon;
320  }
321  else if (geometryType == "G4Trap") {
322  const G4Trap* trap
323  = dynamic_cast<const G4Trap*>(theSolid);
324  double dz = trap->GetZHalfLength()/CLHEP::mm;
325  double theta = 0;
326  double phi = 0;
327  double h1 = trap->GetYHalfLength1()/CLHEP::mm;
328  double bl1 = trap->GetXHalfLength1()/CLHEP::mm;
329  double tl1 = trap->GetXHalfLength2()/CLHEP::mm;
330  double alpha1 = std::atan(trap->GetTanAlpha1())/CLHEP::degree;
331  double h2 = trap->GetYHalfLength2()/CLHEP::mm;
332  double bl2 = trap->GetXHalfLength3()/CLHEP::mm;
333  double tl2 = trap->GetXHalfLength4()/CLHEP::mm;
334  double alpha2 = std::atan(trap->GetTanAlpha2())/CLHEP::degree;
335  theShape = new TGeoTrap(dz, theta, phi,
336  h1, bl1, tl1, alpha1,
337  h2, bl2, tl2, alpha2);
338  }
339  else if (geometryType == "G4Trd") {
340  const G4Trd* trd
341  = dynamic_cast<const G4Trd*>(theSolid);
342  double dz = trd->GetZHalfLength()/CLHEP::mm;
343  double dx1 = trd->GetXHalfLength1()/CLHEP::mm;
344  double dx2 = trd->GetXHalfLength2()/CLHEP::mm;
345  double dy1 = trd->GetYHalfLength1()/CLHEP::mm;
346  double dy2 = trd->GetYHalfLength2()/CLHEP::mm;
347  theShape = new TGeoTrd2(dx1,dx2,dy1,dy2,dz);
348  }
349  else if (geometryType == "G4SubtractionSolid") {
350  const G4SubtractionSolid* sub
351  = dynamic_cast<const G4SubtractionSolid*>(theSolid);
352  const G4VSolid* solidA = sub->GetConstituentSolid(0);
353  const G4VSolid* solidB = sub->GetConstituentSolid(1);
354  // solidA - solidB
355  TGeoMatrix* matrixA = NULL;
356  TGeoShape* shapeA = CreateShape(solidA, &matrixA);
357  TGeoMatrix* matrixB = NULL;
358  TGeoShape* shapeB = CreateShape(solidB, &matrixB);
359  TGeoSubtraction* subtractNode = new TGeoSubtraction(shapeA,shapeB,
360  matrixA, matrixB);
361  theShape = new TGeoCompositeShape("name",subtractNode);
362  }
363  else if (geometryType == "G4DisplacedSolid") {
364  const G4DisplacedSolid* disp
365  = dynamic_cast<const G4DisplacedSolid*>(theSolid);
366  const G4VSolid* movedSolid = disp->GetConstituentMovedSolid();
367  G4RotationMatrix rotation = disp->GetObjectRotation();
368  G4ThreeVector displacement = disp->GetObjectTranslation();
369  theShape = CreateShape(movedSolid);
370  if (returnMatrix) {
371  TGeoRotation* rotate
372  = new TGeoRotation("rot",
373  TMath::RadToDeg()*rotation.thetaX(),
374  TMath::RadToDeg()*rotation.phiX(),
375  TMath::RadToDeg()*rotation.thetaY(),
376  TMath::RadToDeg()*rotation.phiY(),
377  TMath::RadToDeg()*rotation.thetaZ(),
378  TMath::RadToDeg()*rotation.phiZ());
379  *returnMatrix = new TGeoCombiTrans(displacement.x()/CLHEP::mm,
380  displacement.y()/CLHEP::mm,
381  displacement.z()/CLHEP::mm,
382  rotate);
383  }
384  }
385  else if (geometryType == "G4UnionSolid") {
386  const G4UnionSolid* sub
387  = dynamic_cast<const G4UnionSolid*>(theSolid);
388  const G4VSolid* solidA = sub->GetConstituentSolid(0);
389  const G4VSolid* solidB = sub->GetConstituentSolid(1);
390  // solidA - solidB
391  TGeoMatrix* matrixA = NULL;
392  TGeoShape* shapeA = CreateShape(solidA, &matrixA);
393  TGeoMatrix* matrixB = NULL;
394  TGeoShape* shapeB = CreateShape(solidB, &matrixB);
395  TGeoUnion* unionNode = new TGeoUnion(shapeA, shapeB,
396  matrixA, matrixB);
397  theShape = new TGeoCompositeShape("name",unionNode);
398  }
399  else if (geometryType == "G4IntersectionSolid") {
400  const G4IntersectionSolid* sub
401  = dynamic_cast<const G4IntersectionSolid*>(theSolid);
402  const G4VSolid* solidA = sub->GetConstituentSolid(0);
403  const G4VSolid* solidB = sub->GetConstituentSolid(1);
404  // solidA - solidB
405  TGeoMatrix* matrixA = NULL;
406  TGeoShape* shapeA = CreateShape(solidA, &matrixA);
407  TGeoMatrix* matrixB = NULL;
408  TGeoShape* shapeB = CreateShape(solidB, &matrixB);
409  TGeoIntersection* intersectionNode = new TGeoIntersection(shapeA, shapeB,
410  matrixA, matrixB);
411  theShape = new TGeoCompositeShape("name",intersectionNode);
412  }
413 
414  else if (geometryType == "G4ExtrudedSolid"){
415  //This following only works when using the 'standard'
416  //G4ExtrudedSolid Constructor.
417 
418  const G4ExtrudedSolid* extr
419  = dynamic_cast<const G4ExtrudedSolid*>(theSolid);
420 
421  //number of z planes
422  const G4int nZ = extr->GetNofZSections();
423  //number of vertices in the polygon
424  const G4int nV = extr->GetNofVertices();
425 
426  //define and pointers
427  const int maxVertices = 1000;
428  double vertices_x[maxVertices];
429  double vertices_y[maxVertices];
430  if (maxVertices < nV) {
431  EDepSimThrow("Polygon with more than maxVertices");
432  }
433 
434 
435  //define an intermediate extrusion constructor with nZ z planes.
436  TGeoXtru *xtru = new TGeoXtru(nZ);
437 
438  //Get the polygons points.
439  std::vector<G4TwoVector> polyPoints = extr->GetPolygon();
440 
441  //fill the vertices arrays
442  for(int i = 0 ; i < nV ; i++){
443  vertices_x[i]= polyPoints[i].x();
444  vertices_y[i]= polyPoints[i].y();
445  }
446 
447  //Define the polygon
448  xtru->DefinePolygon(nV, vertices_x, vertices_y);
449 
450  double z_pos, x_off, y_off, scale;
451 
452  //fill the parameters to define the Root extruded solid
453  for(int i = 0 ; i < nZ ; i++){
454  z_pos = extr->GetZSection(i).fZ;
455  x_off = extr->GetZSection(i).fOffset.x() ;
456  y_off = extr->GetZSection(i).fOffset.y();
457  scale = extr->GetZSection(i).fScale;
458  xtru->DefineSection(i, z_pos, x_off, y_off, scale);
459  }
460  //now assign 'theShape' to this complete extruded object.
461  theShape = xtru;
462  }
463  else {
464  EDepSimThrow(geometryType+" --> shape not implemented");
465  }
466 
467  return theShape;
468 }
469 
470 TGeoVolume*
472  std::string theName,
473  TGeoMedium* theMedium) {
474  TGeoShape* theShape = CreateShape(theSolid);
475  TGeoVolume* theVolume = new TGeoVolume(theName.c_str(),
476  theShape,
477  theMedium);
478  return theVolume;
479 }
480 
481 // Determine if a volume should copied to the ROOT geometry representation.
482 // If this returns true, then the volume and all of it's children will not be
483 // exported.
484 bool EDepSim::RootGeometryManager::IgnoreVolume(const G4VPhysicalVolume* theVol) {
485  std::string theFullName = theVol->GetName();
486  std::string theShortName = theFullName;
487  theShortName.erase(0,theShortName.rfind("/")+1);
488 
489  // Don't save the internal structure of extruded scintillating bars. This
490  // is required to make sure that hits get assigned to the right geometry
491  // volume in the ROOT geometry.
492  if (theFullName.find("Bar/Core") != std::string::npos) return true;
493  if (theFullName.find("Bar/CrnrOfBar") != std::string::npos) return true;
494  if (theFullName.find("Bar/SideOfBar") != std::string::npos) return true;
495 
496  return false;
497 }
498 
499 // Determine if the volume should be printed to the output.
500 bool EDepSim::RootGeometryManager::PrintMass(const G4VPhysicalVolume* theVol) {
501  std::string theFullName = theVol->GetName();
502 
504  n != fPrintMass.end();
505  ++n) {
506  if (theFullName.find(*n) != std::string::npos) {
507  if (fPrintedMass.find(*n) != fPrintedMass.end()) continue;
508  fPrintedMass.insert(*n);
509  return true;
510  }
511  }
512 
513  return false;
514 }
515 
516 // Create all of the materials in the detector and make a translation table
517 // between material and material name, and element and isotope name.
519  const G4VPhysicalVolume* theG4PhysVol) {
520 
521  G4LogicalVolume* theLog = theG4PhysVol->GetLogicalVolume();
522 
523  // Find the medium for this volume and create it if it doesn't exist.
524  TGeoMedium *theMedium = fMedium[theLog->GetMaterial()->GetName()];
525 
526  if (!theMedium) {
527  G4Material *mat = theLog->GetMaterial();
528  if (mat->GetNumberOfElements()==0) {
529  EDepSimError("Material without elements " << mat->GetName());
530  EDepSimThrow("Material defined without elements");
531  }
532  // Make a mixture
533  TGeoMixture *theMix
534  = new TGeoMixture(mat->GetName(),
535  mat->GetNumberOfElements(),
536  mat->GetDensity());
537  unsigned ielement = 0;
538  theMix->SetTemperature(mat->GetTemperature());
539  // The minus sign is to make sure this over-rides the approximate ROOT
540  // radiation and interaction length calculations.
541  switch (mat->GetState()) {
542  case kStateSolid:
543  theMix->SetState(TGeoMaterial::kMatStateSolid);
544  break;
545  case kStateLiquid:
546  theMix->SetState(TGeoMaterial::kMatStateLiquid);
547  theMix->SetPressure(mat->GetPressure());
548  break;
549  case kStateGas:
550  theMix->SetState(TGeoMaterial::kMatStateGas);
551  theMix->SetPressure(mat->GetPressure());
552  break;
553  default:
554  theMix->SetState(TGeoMaterial::kMatStateUndefined);
555  }
556  for (unsigned i = 0; i < mat->GetNumberOfElements(); ++i) {
557  const G4Element *elem = mat->GetElement(i);
558  for (unsigned j = 0; j < elem->GetNumberOfIsotopes(); ++j) {
559  const G4Isotope *iso = elem->GetIsotope(j);
560  theMix->DefineElement(ielement,
561  iso->GetA()/(CLHEP::g/CLHEP::mole),
562  iso->GetZ(),
563  (mat->GetFractionVector()[i])*
564  (elem->GetRelativeAbundanceVector()[j]));
565  // Find the isotope for this element and create it if it
566  // doesn't exist
567  TGeoElement *theIsotope = fIsotope[iso->GetName()];
568  if (!theIsotope) {
569  // Make an element (isotope)
570  TGeoElement *theEle
571  = new TGeoElement(iso->GetName(),
572  elem->GetSymbol(),
573  iso->GetZ(),
574  iso->GetA()/(CLHEP::g/CLHEP::mole));
575  fIsotope[iso->GetName()] = theEle;
576  }
577  ielement++;
578  }
579  }
580  theMix->SetRadLen(-mat->GetRadlen(), -mat->GetNuclearInterLength());
581  int numed = fMedium.size() + 1;
582  theMedium = new TGeoMedium(mat->GetName(),numed,theMix);
583  fMedium[mat->GetName()] = theMedium;
584  }
585 
586  // Recurse through the children.
587  for (std::size_t child = 0;
588  child < theLog->GetNoDaughters();
589  ++child) {
590  G4VPhysicalVolume* theChild = theLog->GetDaughter(child);
591  CreateMaterials(theChild);
592  }
593 }
594 
595 // Method counts how many nodes there are in mother volume with the same name
596 // as daughter node. Will be used in setting index for daughter node.
598  TGeoVolume* theMother, std::string daughterName) {
599  daughterName = daughterName + "_";
600  int ndaughters = theMother->GetNdaughters();
601 
602  int ndaughters_samename = 0;
603  for(int i = 0; i < ndaughters; i++){
604  TGeoNode *node = theMother->GetNode(i);
605  if(node){
606  std::string name(node->GetName());
607  if(name.find(daughterName.c_str()) != std::string::npos)
608  ndaughters_samename++;
609  }
610  }
611 
612  return ndaughters_samename;
613 
614 }
615 
616 // Save the detector envelope. This is called recursively to fill in the
617 // entire detector. The G4 physical volume, theVol, is used to create a
618 // new root TGeoVolume which is added to the existing root TGeoVolume,
619 // theMother, as a daughter.
621  const G4VPhysicalVolume* theG4PhysVol,
622  TGeoManager* theEnvelope,
623  TGeoVolume* theMother) {
624 
625  if (IgnoreVolume(theG4PhysVol)) return true;
626 
627  // The new volume that will be added to the mother volume. This is
628  // created in this function.
629  TGeoVolume* theVolume = NULL;
630  G4LogicalVolume* theLog = theG4PhysVol->GetLogicalVolume();
631 
632  if (PrintMass(theG4PhysVol)) {
633  EDepSimLog("%%% Mass: "
634  << G4BestUnit(theLog->GetMass(true),"Mass")
635  << " Volume: " << theG4PhysVol->GetName());
636  }
637 
638  // Get the name of the expected name of the volume.
639  std::string theVolumeName;
641  n != fNameStack.end();
642  ++n) {
643  theVolumeName += "/";
644  theVolumeName += *n;
645  }
646 
647  // Get the volume information from G4.
648  const G4VSolid* theSolid = theLog->GetSolid();
649  const G4String geometryType = theSolid->GetEntityType();
650  std::string theFullName = theG4PhysVol->GetName();
651  std::string theShortName = theFullName;
652  theShortName.erase(0,theShortName.rfind("/")+1);
653 
654  // The volume name is built from all the short names in the path to this
655  // volume. This is different than the full name which is built based on
656  // the constructor tree.
657  theVolumeName += "/";
658  theVolumeName += theShortName;
659 
660  // Check the volume names for validity. If they don't match then just
661  // force it.
662  if (theShortName == theFullName) {
663  theFullName = theVolumeName;
664  }
665 
666  // Make sure there isn't a bug in the naming. There should never be a
667  // "//" in the name.
668  if (theFullName.find("//") != std::string::npos) {
669  EDepSimError("Invalid volume name: " << theFullName);
670  EDepSimError(" Expected name is: " << theVolumeName);
671  theFullName = theVolumeName;
672  }
673 
674  // Find the medium for this volume.
675  std::string materialName = theLog->GetMaterial()->GetName();
676  TGeoMedium *theMedium = fMedium[materialName];
677  if (!theMedium) {
678  EDepSimError("MISSING MATERIAL IS " << materialName);
679  EDepSimThrow("Material definition is missing");
680  }
681 
682  if (!fCreateAllVolumes) {
684  seenVolume = fKnownVolumes.find(theLog);
685  if (seenVolume != fKnownVolumes.end()) theVolume = seenVolume->second;
686  }
687 
688  if (!theVolume) {
689  // Create the root volume (the solid in G4 lingo).
690  theVolume = CreateVolume(theSolid, theShortName, theMedium);
691  if (!theVolume) theVolume = theMother;
692  theVolume->SetTitle(theVolumeName.c_str());
693 
694  // Set the visual properties of the new volume
695  int color = GetColor(theG4PhysVol);
696  double opacity = GetOpacity(theG4PhysVol);
697  theVolume->SetVisContainers(true);
698  if (color < 0 || opacity < 0.001) {
699  theVolume->SetVisibility(false);
700  }
701  else {
702  int i = 100.0*(1.0-opacity);
703  if (i>100) i = 100;
704  EDepSimInfo("Set color of " << theShortName
705  << " to " << color
706  << " " << opacity
707  << " " << i);
708  theVolume->SetLineColor(color);
709  theVolume->SetTransparency(i);
710  theVolume->SetVisibility(true);
711  }
712 
713  // There is no mother so set this as the top volume.
714  if (!theMother) {
715  EDepSimLog("Making \"" << theVolume->GetName() << "\" the top\n");
716  theEnvelope->SetTopVolume(theVolume);
717  }
718 
719  // Push the name of this volume onto the stack before creating the
720  // children.
721  fNameStack.push_back(theShortName);
722 
723  // Add the children to the daughter.
724  double missingMass = 0.0;
725  for (std::size_t child = 0;
726  child < theLog->GetNoDaughters();
727  ++child) {
728  G4VPhysicalVolume* theChild = theLog->GetDaughter(child);
729  if (theLog->GetNoDaughters() > 20000) {
730  G4LogicalVolume *skippedVolume = theChild->GetLogicalVolume();
731  missingMass += skippedVolume->GetMass(true);
732  }
733  else if (CreateEnvelope(theChild, theEnvelope, theVolume)) {
734  G4LogicalVolume *skippedVolume = theChild->GetLogicalVolume();
735  missingMass += skippedVolume->GetMass(true);
736  }
737  }
738  // Remove this volume from the name stack.
739  fNameStack.pop_back();
740 
741  // A some daughter volumes were ignored and so the density of this
742  // volume needs to be adjusted.
743  if (missingMass > 0.0) {
744  // The correction of the material needs to be implemented.
745  double totalMass = theLog->GetMass(true);
746  double totalVolume = theLog->GetSolid()->GetCubicVolume();
747  double totalDensity = totalMass/totalVolume;
749  "ROOTGeom", "Skipping sub-volumes. Correct "
750  << theMedium->GetName() << " density "
751  << theMedium->GetMaterial()->GetDensity()/(CLHEP::g/CLHEP::cm3)
752  << " g/cm3 to "
753  << totalDensity/(CLHEP::g/CLHEP::cm3) << " g/cm3");
754  TGeoMedium *avgMedium = AverageMaterial(theG4PhysVol);
755  if (avgMedium) theVolume->SetMedium(avgMedium);
756  }
757 
758  // Put this volume into the known volumes.
759  fKnownVolumes[theLog] = theVolume;
760  }
761 
762  // Apply the rotation for theMother volume. This is only done if the
763  // theMother is not the top level volume for the envelope so that the
764  // detector has the proper orientation.
765  if (theMother && (theMother != theVolume)) {
766  G4ThreeVector trans = theG4PhysVol->GetObjectTranslation();
767  G4RotationMatrix* rot = theG4PhysVol->GetObjectRotation();
768  TGeoRotation* rotate =
769  new TGeoRotation("rot",
770  TMath::RadToDeg()*rot->thetaX(),
771  TMath::RadToDeg()*rot->phiX(),
772  TMath::RadToDeg()*rot->thetaY(),
773  TMath::RadToDeg()*rot->phiY(),
774  TMath::RadToDeg()*rot->thetaZ(),
775  TMath::RadToDeg()*rot->phiZ());
776  if (theG4PhysVol->IsReplicated()) {
777  EAxis a; G4int nRep; G4double w; G4double o; G4bool c;
778  G4ThreeVector axis;
779  theG4PhysVol->GetReplicationData(a,nRep,w,o,c);
780  switch (a) {
781  case kXAxis: axis.set(1,0,0); break;
782  case kYAxis: axis.set(0,1,0); break;
783  case kZAxis: axis.set(0,0,1); break;
784  default:
785  EDepSimThrow("EDepSim::RootGeometryManager::CreateEnvelope:"
786  "Bad replication data.");
787  }
788  for (int i=0; i<nRep; ++i) {
789  G4ThreeVector pos = axis*w*(i-0.5*(nRep-1));
790  TGeoCombiTrans* combi
791  = new TGeoCombiTrans(pos.x()/CLHEP::mm,
792  pos.y()/CLHEP::mm,
793  pos.z()/CLHEP::mm,
794  rotate);
795  int index = HowManySimilarNodesInVolume(theMother,
796  theVolume->GetName());
797  theMother->AddNode(theVolume,index,combi);
798  }
799  }
800  else {
801  TGeoCombiTrans* combi
802  = new TGeoCombiTrans(trans.x()/CLHEP::mm,
803  trans.y()/CLHEP::mm,
804  trans.z()/CLHEP::mm,
805  rotate);
806  int index = HowManySimilarNodesInVolume(theMother,
807  theVolume->GetName());
808  theMother->AddNode(theVolume,index,combi);
809  }
810  }
811 
812  return false;
813 }
814 
816  int color, double opacity) {
817  G4String materialName = material->GetName();
818  fColorMap[materialName].color = color;
819  fColorMap[materialName].alpha = opacity;
820  if (opacity<0.01) fColorMap[materialName].fill = 0;
821  else if (opacity>0.99) fColorMap[materialName].fill = 1;
822  else {
823  fColorMap[materialName].fill = 4000+100*opacity;
824  }
825 }
826 
828  G4String materialName = material->GetName();
829  AttributeMap::const_iterator colorPair = fColorMap.find(materialName);
830 
831  int index = 0;
832  double alpha = 1.0;
833 
834  if (colorPair == fColorMap.end()) {
835  EDepSimError("Missing color for \"" << materialName << "\"");
836  fColorMap[materialName].color = kOrange+1;
837  fColorMap[materialName].fill = 0;
838  index = kOrange+1;
839  }
840  else {
841  index = colorPair->second.color;
842  alpha = colorPair->second.alpha;
843  }
844 
845 #include "rootColorToG4ColorMap.hxx"
846 
848 
849  return G4Color(color.GetRed(),color.GetGreen(),color.GetBlue(),
850  color.GetAlpha()*alpha);
851 }
852 
853 double EDepSim::RootGeometryManager::GetOpacity(const G4VPhysicalVolume* vol) {
854  const G4LogicalVolume* log = vol->GetLogicalVolume();
855  std::string theFullName = vol->GetName();
856 
857  const G4VisAttributes* visAttributes = log->GetVisAttributes();
858  if (!visAttributes) {
859  // Invisible if the visual attributes are missing...
860  return 0.0;
861  }
862 
863  G4Color g4Color = visAttributes->GetColor();
864  double opacity = g4Color.GetAlpha();
865  if (opacity > 1.0) opacity = 1.0;
866 
867  return opacity;
868 }
869 
870 int EDepSim::RootGeometryManager::GetColor(const G4VPhysicalVolume* vol) {
871  const G4LogicalVolume* log = vol->GetLogicalVolume();
872  std::string theFullName = vol->GetName();
873 
874  const G4VisAttributes* visAttributes = log->GetVisAttributes();
875  if (!visAttributes) {
876  return -1;
877  }
878 
879  int index = -1;
880  double minDist = 10000;
881  G4Color g4Color = visAttributes->GetColor();
882 
883  // Check the primary color wheel.
884  const int rootPrimaryColors[] = {
885  kRed, kMagenta, kBlue, kCyan, kGreen, kYellow, -1
886  };
887  for(const int* rootBaseColor = rootPrimaryColors;
888  0 <= *rootBaseColor;
889  ++rootBaseColor) {
890  for (int i = -10; i<5; ++i) {
891  int iColor = *rootBaseColor + i;
892  TColor* rootColor = gROOT->GetColor(iColor);
893  if (!rootColor) continue;
894  double dR = (rootColor->GetRed() - g4Color.GetRed());
895  double dG = (rootColor->GetGreen() - g4Color.GetGreen());
896  double dB = (rootColor->GetBlue() - g4Color.GetBlue());
897  double dist = std::sqrt(dR*dR + dG*dG + dB*dB);
898  if (dist > minDist) continue;
899  index = iColor;
900  minDist = dist;
901  }
902  }
903 
904  // Check the secondary colors defined by ROOT.
905  const int rootSecondaryColors[] = {
906  kPink, kMagenta, kViolet, kTeal, kSpring, kOrange, -1
907  };
908  for(const int* rootBaseColor = rootSecondaryColors;
909  0 <= *rootBaseColor;
910  ++rootBaseColor) {
911  for (int i = -9; i<=10; ++i) {
912  int iColor = *rootBaseColor + i;
913  TColor* rootColor = gROOT->GetColor(iColor);
914  if (!rootColor) continue;
915  double dR = (rootColor->GetRed() - g4Color.GetRed());
916  double dG = (rootColor->GetGreen() - g4Color.GetGreen());
917  double dB = (rootColor->GetBlue() - g4Color.GetBlue());
918  double dist = std::sqrt(dR*dR + dG*dG + dB*dB);
919  if (dist > minDist) continue;
920  index = iColor;
921  minDist = dist;
922  }
923  }
924 
925  // Check the different colors of "black"
926  const int rootBlackColors[] = {
927  kGray, kGray+1, kGray+2, kGray+3, kBlack, -1
928  };
929  for(const int* rootBaseColor = rootBlackColors;
930  0 <= *rootBaseColor;
931  ++rootBaseColor) {
932  TColor* rootColor = gROOT->GetColor(*rootBaseColor);
933  if (!rootColor) continue;
934  double dR = (rootColor->GetRed() - g4Color.GetRed());
935  double dG = (rootColor->GetGreen() - g4Color.GetGreen());
936  double dB = (rootColor->GetBlue() - g4Color.GetBlue());
937  double dist = std::sqrt(dR*dR + dG*dG + dB*dB);
938  if (dist > minDist) continue;
939  index = *rootBaseColor;
940  minDist = dist;
941  }
942 
943  // Check the basic colors (the first 50 colors in root).
944  for(int rootBaseColor = 1;
945  rootBaseColor < 50;
946  ++rootBaseColor) {
947  TColor* rootColor = gROOT->GetColor(rootBaseColor);
948  if (!rootColor) continue;
949  double dR = (rootColor->GetRed() - g4Color.GetRed());
950  double dG = (rootColor->GetGreen() - g4Color.GetGreen());
951  double dB = (rootColor->GetBlue() - g4Color.GetBlue());
952  double dist = std::sqrt(dR*dR + dG*dG + dB*dB);
953  if (dist > minDist) continue;
954  index = rootBaseColor;
955  minDist = dist;
956  }
957 
958  return index;
959 }
960 
962  const G4VPhysicalVolume* thePhys) {
963  std::string theFullName = thePhys->GetName();
964  G4LogicalVolume* theLog = thePhys->GetLogicalVolume();
965  std::string materialName = theLog->GetMaterial()->GetName();
966 
967  // If this is a scintillator bar, then the base material name should be
968  // either FGDScintillator or Scintillator.
969  if (theFullName.find("/Bar") != std::string::npos) {
970  if (theFullName.find("/FGD") != std::string::npos) {
971  materialName = "FGDScintillator";
972  }
973  else if (theFullName.find("/P0D/") != std::string::npos) {
974  materialName = "P0DScintillator";
975  }
976  else {
977  materialName = "Scintillator";
978  }
979  }
980 
981  return materialName;
982 }
983 
985  const G4VPhysicalVolume* thePhys) {
986  G4LogicalVolume* theLog = thePhys->GetLogicalVolume();
987  double totalMass = theLog->GetMass(true);
988  double totalVolume = theLog->GetSolid()->GetCubicVolume();
989  double totalDensity = totalMass/totalVolume;
990  std::ostringstream nameStream;
991  nameStream << MaterialName(thePhys)
992  << "Avg" << totalDensity/(CLHEP::g/CLHEP::cm3);
993  std::string averageName = nameStream.str();
994  TGeoMedium* avgMedium = fMedium[averageName];
995  if (avgMedium) return avgMedium;
996  // Create a map of the material pointer and the mass of that material that
997  // is contributing to the mixture. This will be used to calculate the
998  // average radiation length and interaction length.
999  std::map< const G4Material* , double > materialMass;
1000  // Create a map of element names and the amount of that element in the
1001  // mixture.
1002  std::map<std::string,double> componentMass;
1003  // Create a stack to walk the geometry tree.
1004  std::vector<const G4VPhysicalVolume*> stack;
1005  stack.push_back(thePhys);
1006  while (!stack.empty()) {
1007  // Get the new current volume off the stack.
1008  const G4VPhysicalVolume* currentPhys = stack.back();
1009  G4LogicalVolume* currentLog = currentPhys->GetLogicalVolume();
1010  stack.pop_back();
1011  // Add all of the current children to the stack.
1012  for (std::size_t child = 0;
1013  child < currentLog->GetNoDaughters();
1014  ++child) {
1015  stack.push_back(currentLog->GetDaughter(child));
1016  }
1017  // Add the mass of each element in the current volume.
1018  double mass = currentLog->GetMass(true,false);
1019  G4Material *mat = currentLog->GetMaterial();
1020  materialMass[mat] += mass;
1021  for (unsigned i = 0; i < mat->GetNumberOfElements(); ++i) {
1022  const G4Element *elem = mat->GetElement(i);
1023  for (unsigned j = 0; j < elem->GetNumberOfIsotopes(); ++j) {
1024  // Find the isotope for this element and create it if it
1025  // doesn't exist
1026  std::string isoName = elem->GetIsotope(j)->GetName();
1027  componentMass[isoName] += mass
1028  *(mat->GetFractionVector()[i])
1029  *(elem->GetRelativeAbundanceVector()[j]);
1030  }
1031  }
1032  }
1033  TGeoMixture *theMix
1034  = new TGeoMixture(averageName.c_str(),
1035  componentMass.size(),
1036  totalDensity);
1037  for (std::map<std::string,double>::iterator c = componentMass.begin();
1038  c != componentMass.end();
1039  ++c) {
1040  TGeoElement* elem = fIsotope[c->first];
1041  theMix->AddElement(elem,c->second/totalMass);
1042  }
1043  double radLen = 0;
1044  double intLen = 0;
1045  double massSum = 0;
1047  mat = materialMass.begin();
1048  mat != materialMass.end();
1049  ++mat) {
1050  const G4Material* material = mat->first;
1051  double mass = mat->second;
1052  massSum += mass;
1053  radLen += mass/material->GetRadlen();
1054  intLen += mass/material->GetNuclearInterLength();
1055  }
1056  if (massSum>0.0) {
1057  // The minus sign is to make sure this over-rides the approximate ROOT
1058  // radiation and interaction length calculations.
1059  theMix->SetRadLen(-massSum/radLen,-massSum/intLen);
1060  }
1061  int numed = fMedium.size() + 1;
1062  TGeoMedium* theMedium = new TGeoMedium(averageName.c_str(),numed,theMix);
1063  fMedium[averageName] = theMedium;
1064  return theMedium;
1065 }
static QCString name
Definition: declinfo.cpp:673
#define EDepSimLog(outStream)
Definition: EDepSimLog.hh:717
double GetOpacity(const G4VPhysicalVolume *vol)
intermediate_table::iterator iterator
std::map< G4String, int > fNodeCount
A map between G4 volume names and count of volumes with that name.
#define EDepSimNamedDebug(trace, outStream)
Definition: EDepSimLog.hh:634
std::map< G4String, TGeoMedium * > fMedium
A map between G4 material names and Root Material definitions.
static constexpr double g
Definition: Units.h:144
G4Color GetG4Color(G4Material *material)
void Update(const G4VPhysicalVolume *aWorld, bool validate)
Update the root geometry to match the g4 geometry.
AttributeMap fColorMap
A map between a material name and a color.
std::string string
Definition: nybbler.cc:12
static constexpr double cm3
Definition: Units.h:70
static const std::string volume[nvol]
virtual TGeoMedium * AverageMaterial(const G4VPhysicalVolume *theVol)
virtual bool IgnoreVolume(const G4VPhysicalVolume *theVol)
intermediate_table::const_iterator const_iterator
#define EDepSimThrow(message)
Print an error message, and then throw an exception.
virtual std::string MaterialName(const G4VPhysicalVolume *theVol)
#define EDepSimInfo(outStream)
Definition: EDepSimLog.hh:752
void Validate()
Make sure that the current geometry passes a bunch of tests.
static std::map< int, G4Color > sRootColorToG4ColorMap
int find(char c, int index=0, bool cs=TRUE) const
Definition: qcstring.cpp:41
std::vector< G4String > fPrintMass
A vector of volume names to print.
void Export(const char *file)
Export the geometry to a file.
TGeoVolume * CreateVolume(const G4VSolid *theSolid, std::string theName, TGeoMedium *theMedium)
Create a new ROOT volume object.
void CreateMaterials(const G4VPhysicalVolume *theVol)
static EDepSim::RootGeometryManager * fThis
The pointer to the instantiation of this object.
int GetColor(const G4VPhysicalVolume *vol)
void swap(Handle< T > &a, Handle< T > &b)
std::void_t< T > n
const double a
#define Import
double alpha
Definition: doAna.cpp:15
virtual bool PrintMass(const G4VPhysicalVolume *theVol)
A method to flag that a volume mass should be printed.
void SetDrawAtt(G4Material *material, int color, double opacity=1.0)
Set material color.
#define M_PI
Definition: includeROOT.h:54
std::size_t color(std::string const &procname)
int HowManySimilarNodesInVolume(TGeoVolume *theMother, std::string theName)
TGeoShape * CreateShape(const G4VSolid *theSolid, TGeoMatrix **mat=NULL)
bool CreateEnvelope(const G4VPhysicalVolume *theVol, TGeoManager *theEnvelope, TGeoVolume *theMother)
#define EDepSimError(outStream)
Definition: EDepSimLog.hh:503
constexpr double dist(const TReal *x, const TReal *y, const unsigned int dimension)
std::map< G4LogicalVolume *, TGeoVolume * > fKnownVolumes
std::map< G4String, TGeoElement * > fIsotope
A map between G4 isotope names and Root Element definitions.
static constexpr double mm
Definition: Units.h:65
int GetNodeId(const G4ThreeVector &pos)
Get a volume ID base on the volume position.
static constexpr double degree
Definition: Units.h:161
std::set< G4String > fPrintedMass
A map of which masses have been printed.
std::string sub(const std::string &a, const std::string &b)
Definition: TruthText.cxx:100
static EDepSim::RootGeometryManager * Get(void)
If a persistency manager has not been created, create one.