Tutorials
GDML Loading
In directory pyg4ometry/pyg4ometry/test/gdmlG4examples/ChargeExchangeMC/
1import pyg4ometry
2r = pyg4ometry.gdml.Reader("lht.gdml")
3l = r.getRegistry().getWorldVolume()
4v = pyg4ometry.visualisation.VtkViewer()
5v.addLogicalVolume(l)
6v.view()

STL Loading
STL files are typically used for a single watertight solid mesh. This mesh is
converted to a TesselatedSolid and then a logical volume which can be placed
in a geometry. In directory pyg4ometry/pyg4ometry/test/stl
.
import pyg4ometry
reg = pyg4ometry.geant4.Registry()
r = pyg4ometry.stl.Reader("utahteapot.stl" registry=reg)
s = r.getSolid()
copper = pyg4ometry.geant4.MaterialPredefined("G4_Cu")
l = pyg4ometry.geant4.LogicalVolume(s, copper, "utahteapot_lv", reg)
v = pyg4ometry.visualisation.VtkViewer()
v.addLogicalVolume(l)
v.view()

STEP/STP Loading
In directory pyg4ometry/pyg4ometry/test/freecad
1import pyg4ometry
2r = pyg4ometry.freecad.Reader("./08_AshTray.step")
3r.relabelModel()
4r.convertFlat()
5l = r.getRegistry().getWorldVolume()
6v = pyg4ometry.visualisation.VtkViewer()
7v.addLogicalVolume(l)
8v.view()

Merging Geometry
There are ways to incorporate geometry from multiple sources in GDML. This has potentially
lots of problems as each file needs to be a well formed GDML file and care has to be taken
with degenerate names from the different sources. For example a volume can be extracted
from GdmlFile1 and added to GdmlFile2, clearly all solids, materials and variables need
to also transferred. For this example we need two GDML files, so pyg4ometry/test/pythonGeant4/T001_Box.py
and pyg4ometry/test/pythonGeant4/T002_Tubs.py
, so run them
1import T001_Box
2T001_Box.Test(True,True)
3
4import T002_Tubs
5T002_Tubs(True,True)
This will create two GDML files T001_Box.gdml
and T002_Tubs.gdml
. It is possible to
find the volumes contained in each file (using the tubs gdml file as the example)
by performing the following
1import pyg4ometry
2r = pyg4ometry.gdml.Reader("T002_Tubs.gdml")
3reg = r.getRegistry()
4
5# printing the names of the logical volumes
6print(reg.logicalVolumeDict.keys())
7
8# printing the names of the physical volumes
9print(reg.physicalVolumeDict.keys())
10
11lv = reg.logicalVolume["tl"]
Now merging the tl
logicalVolume (which is a simple tubs) with the box gdml file
1import pyg4ometry
2r1 = pyg4ometry.gdml.Reader("T001_Box.gdml")
3reg1 = r1.getRegistry()
4
5r2 = pyg4ometry.gdml.Reader("T002_Tubs.gdml")
6reg2 = r2.getRegistry()
7
8lv = reg2.logicalVolumeDict["tl"]
9
10# create physical volume with placement
11pv = pyg4ometry.geant4.PhysicalVolume([0,0,0],[50,0,0], lv, "tl_pv", reg1.getWorldVolume(), reg1)
12
13reg1.addVolumeRecursive(pv)
14
15# gdml output
16w = pyg4ometry.gdml.Writer()
17w.addDetector(reg1)
18w.write("MergeRegistry.gdml")
Note
In the example two registry objects are created and objects from reg2 are merged into reg1. Of course one registry might be formed by pyg4ometry commands opposed created from a file.
Warning
The pv needs to added with addVolumeRecursive otherwise it is possible that GDML definitions which lv depends on are not transferred over.
Assembly Conversion
Given two sources of geometry, placement of top level world logical volume solids will likely result in an overlap. To avoid these types of problems, it might required to convert one of the logical volumes to an AssemblyVolume.
STL Output
To write an STL file from m = volume.pycsgmesh()
1 vtkConverter = vtk.Convert()
2 vtkPD = vtkConverter.MeshListToPolyData(m)
3 r = vtk.WriteSTL("file.stl",vtkPD)
GDML Conversion to FLUKA
It is possible convert a pyg4ometry geometry to FLUKA. This is currently a work in
progress and not all Geant4-GDML constructions are implemented, although they can
be quickly added. Given a LV variable named logical
1import pyg4ometry
2reader = pyg4ometry.gdml.Reader("input.gdml")
3logical = reader.getRegistry().getWorldVolume()
4freg = pyg4ometry.convert.geant4Logical2Fluka(logical)
5w = pyg4ometry.fluka.Writer()
6w.addDetector(freg)
7w.write("FileName.inp")
If you want to load a file into Flair then a flair file can be written based on FileName.inp
using the following
1 extent = logical.extent(includeBoundingSolid=True)
2 f = pyg4ometry.fluka.Flair("FileName.inp",extent)
3 f.write("FileName.flair")
Here is an example (viewed in Flair) of a simple Geant G4 solid that has been converted to FLUKA using this method


Note
All GDML placements are respected in the conversion from GDML to FLUKA, for both Placements and Boolean Solids. So for example a tree of LV-PV placements are reduced into a single transformation of a LV into a global coordinate space for FLUKA. A similar process is used for a tree of CSG operations.
Warning
Currently there are some things which are not implemented in the conversion. 1) Materials, 2) Scaled solids, 3) Reflections in placements, 4) Division, replica and parameterised placements. Some of these are straight forward to implement, like Materials and the non-Placement physical volumes can be done quickly if a user requires it.
Conversion of FLUKA To GDML
FLUKA geometry can be converted to GDML using
pyg4ometry.convert.fluka2geant4
. The conversion process is robust and
supports all FLUKA geometry constructs. Given a FLUKA file model.inp,
the following code can be used to translate it to a GDML file.
1import pyg4ometry.fluka as fluka
2import pyg4ometry.gdml as gdml
3from pyg4ometry.convert import fluka2Geant4
4
5# Read the FLUKA file, get the FlukaRegistry, convert the registry to a
6# Geant4 Registry
7reader = fluka.Reader("model.inp")
8flukaregistry = reader.flukaregistry
9geant4Registry = fluka2Geant4(flukaRegistry)
10
11worldLogicalVolume = geant4Registry.getWorldVolume()
12worldLogicalVolume.clipSolid()
13
14writer = gdml.Writer()
15writer.addDetector(geant4Registry)
16writer.write("model.gdml")
The core of this functionality is the translation of the FlukaRegistry instance into the equivalent Registry (i.e. Geant4) instance.
Here is an example of a model viewed in flair and the resulting visualisation in VTK of the Geant4 model


A number of keyword arguments are available to further modify the conversion. The fluka2Geant4 keyword arguments region and omitRegions allow the user to select a subset of the named regions to be translated.
The conversion of QUA bodies (fluka2geant4 kwarg quadricRegionAABBs) is complex and requires further explanation. In Pyg4ometry the mesh and GDML representations of FLUKA infinite circular cylinders, elliptical cylinders and half-spaces are all finite (but very large) cylinders, elliptical cylinders and boxes. This is robust as increasing the length of cylinders and depth/bredth of boxes does not increase the number of polygons used in the underlying mesh representation for that solid. However, this is not true of the quadric surface. A quadric surface cannot simply be generated to be “very large”, as the number of polygons will grow quickly, along with the memory consumption and facets in the resulting GDML TesselatedSolid, which will also slowing down tracking time in Geant4. For this reason the user must provide axis-aligned bounding boxes of the regions where any QUA bodies are present. It is recommended that these boxes be a centimetre larger than formally necessary to ensure a correct conversion. Providing the bounding box ensures that an efficient and accurate mesh of the QUA bodies can be generated meaning that the conversion to be performed in a tractable amount of time as well giving more performant tracking in Geant4.
Geometry Complexity Analysis
For a given logical volume we can get some statistics on the complexity of the geometry. A simple class called GeometryComplexityInformation is returned that has a serious of dictionaries with information.
cd pyg4ometry/pyg4ometry/test/gdmlCompoundExamples/bdsim_2
ipython
>>> import pyg4ometry
>>> r = pyg4ometry.gdml.Reader("22-size-variation-facetcrop-quad.gdml")
>>> info = pyg4ometry.geant4.AnalyseGeometryComplexity(r.getRegistry().getWorldVolume())
>>> info.printSummary()
Types of solids
ExtrudedSolid : 96
Tubs : 51
Intersection : 24
Polyhedra : 12
Subtraction : 6
Box : 1
# of daughters count
0 : 152
2 : 19
4 : 12
13 : 6
25 : 1
Depth of booleans count
1 : 30
Booleans width depth over 3
Solid name : n Booleans
>>> info. <tab>
comp.booleanDepth comp.nDaughtersPerLV
comp.booleanDepthCount comp.printSummary
comp.nDaughters comp.solids