GGeo Orientation : Geometry Modelling and Persisting

GGeo
top level holder of geometry libraries : GMaterialLib, GSurfaceLib, GBndLib, GNodeLib, GGeoLib
GVolume
created from G4VPhysicalVolume by X4PhysicalVolume::convertNode
GNodeLib
collects GVolume instances GNodeLib::addVolume
GInstancer

Does multiple traversals over full GVolume tree, identifying repeated geometry and labelling the tree nodes with the repeat index (ridx). Remainder geometry that does not pass instancing cuts on numbers of repeats is left with repeat index zero.

  • used from GGeo::prepareVolumes
  • GInstancer::createInstancedMergedMeshes

Analytic Geometry Overview : GPt, GPts, GParts

GPt
minimally captures node(ndIdx) to solid(lvIdx,csgIdx) association and boundaryName, can also hold placement transforms
X4PhysicalVolume::convertNode
GPt structs instanciated and associated with GVolume (NB GParts instanciation now deferred )
GMergedMesh::mergeVolumeAnalytic
GPt instances are collected into GPts after GPt::setPlacement with the appropriate GVolume (base relative or global) transform during GMergedMesh::mergeVolume.
GPts
collects GPt struct and handles their persisting to/from two transport buffers (ipt and plc) and one GItemList of boundary spec
GGeo::deferredCreateGParts
invoked from GGeo::postLoadFromCache or GGeo::postDirectTranslation.
GParts
analytic geometry holding npy/NCSG NPY Orientation : array creation, updating and persisting
GParts::Create
from from the volume combined GPts and std::vector<NCSG*> from m_meshlib

GPt

GPt captures node placement of a solid within the full geometry tree in a minimal way, holding only:

placement
global transform
lvIdx, csgIdx
indices referencing the solid shape
ndIdx
index of the node in the full tree
spec
string representing the boundary of this node in the tree (material and surface omat/osur/isur/imat)

GPt are canonically instanciated in X4PhysicalVolume::convertNode where instances are associated with the GVolume of the structural tree.

vectors of GPt instances are collected into GPts m_pts within GMergedMesh. The GPts are persisted into the geocache which allows GParts creation to be deferred postcache.

GPts

GPts::export_ serializes a vector of GPt into transport arrays

m_ipt_buffer(n,4;int)
four indices from GPt struct referencing the solid and the node
m_plc_buffer(n,4,4;float)
placement transforms
m_specs(GItemList)
list of boundary spec strings

Canonical m_pts instances are residents of GMergedMesh and are instanciated by GMergedMesh::GMergedMesh with GPts::Make.

GPt instances are created in X4PhysicalVolume::convertNode and associated with the GVolume which are also instanciated there.

Motivation for GPts is to allow postcache deferred creation of merged GParts instances. This capability is needed in order to reconcile the different Opticks/Geant4 requirements regarding balanced/unbalanced CSG trees, see notes/issues/x016.rst

Can think of GPts as gathering and persisting the arguments needed for deferred GParts creation and merging.

This GParts creation is done in GGeo::deferredCreateGParts which is invoked from on high in OpticksHub::init after GGeo is loaded or adopted.

GParts

  • handles the concatenation of analytic geometry, by combination of GParts instances

  • creates primitive buffer from the parts buffer

  • holds boundary specifications as lists of strings that are only converted into actual boundaries with indices pointing at materials and surface by GParts::registerBoundaries which is invoked by GParts::close which happens late (typically within oxrap just before upload to GPU).

    This approach was adopted to allow dynamic addition of geometry and boundaries, which is convenient for testing.

  • the GParts name derives from the history of being used to hold single primitive parts of Daya Bay PMT which were created by detdesc partitioning from python (pmt-/tree.py)

Buffers

partBuffer
CSG nodes eg Sphere, Box, Cylinder
planBuffer
planes referenced by some shapes such as ConvexPolyhedron like Trapezoid (JUNO geometry does not have any of these)
primBuffer
higher level than the partBuffer : references into partBuffer with an offset and a number of nodes eg corresponding to trees of nodes So the primBuffer corresponds (roughly) to a G4VSolid that is used within a LogicalVolume
tranBuffer
holds transforms, inverse transforms and transposed-inverse-transforms these transforms are referenced by index from the partBuffer nodes
ITransformBuffer
instance transform buffer, for example holding the transforms that position every PMT together with a reference to the prim
InstanceIdentityBuffer
holds things like the boundary code of the instance and also identifi

Lifecycle Summary

  • single tree(ie single solid) GParts created from NCSG by X4PhysicalVolume::convertNode on first encountering an lvIdx, where they get attached to a GVolume
  • single tree GParts are merged together into combination GParts by GMergedMesh::mergeVolumeAnalytic where placement transforms are applied with GParts::applyPlacementTransform
  • combinend GParts are uses by OGeo::makeAnalyticGeometry to GParts::close and upload the GParts buffers into the OptiX context on GPU

Details on where GParts is used

Based on opticks-fl GParts.hh

./ggeo/CMakeLists.txt
./ggeo/GParts.cc
     setup

./ggeo/GPmt.cc
./ggeo/tests/GPmtTest.cc
./ggeo/GScene.cc
     near dead code : to be removed

./extg4/tests/X4PhysicalVolume2Test.cc
./extg4/tests/X4SolidTest.cc
./ggeo/tests/GPartsTest.cc
     tests

./extg4/X4PhysicalVolume.cc

     X4PhysicalVolume::convertNode
         within the visit of X4PhysicalVolume::convertStructure_r
         GParts::Make creates GParts instance from the NCSG
         associated to the GMesh for the lvIdx solid.  The GParts
         are associated with the GVolume nodes of the tree.

./ggeo/GMergedMesh.cc
     NB for full(not test?) geometry GMergedMesh is orchestrated
     from GGeo::prepare by the GInstancer, but most action is in GMergedMesh

     GMergedMesh::mergeMergedMesh
         GParts::add the pts from an "other" GMergedMesh into m_parts

     GMergedMesh::mergeVolume
         invokes GMergedMesh::mergeVolumeAnalytic with the pts
         and transform associated to the GVolume.
         The transform is the base or root relative flobal transform

     GMergedMesh::mergeVolumeAnalytic
         GParts::add the pts argument after GParts::applyPlacementTransform
         is applied to them, using transform argument

./ggeo/GGeoLib.cc

      GGeoLib::loadConstituents
          GParts::Load and associates them with corresponding GMergedMesh also loaded

      GGeoLib::saveConstituents
          GParts::save


./ggeo/GGeoTest.cc

     GGeoTest::importCSG
          GParts::setIndex to the collected m_meshes index

./ggeo/GMaker.cc

     GMaker::makeFromMesh
          GParts::Make from NCSG instance and spec : used
          from GGeoTest

     GMaker::make
     GMaker::makePrism
          GParts::Make from parameters, type and spec : used for
          creation of simple geometries


./optixrap/OGeo.cc

      OGeo::makeAnalyticGeometry
          GParts::close constructs the primBuffer, also uploads the
          various buffers prim/tran/part/identity into OptiX context on GPU

Mesh-type or node-type

Boundary spec is a node-type-qty, not a mesh-type-qty so it does not belong inside GParts (a mesh-type-qty) … there are relatively few mesh-type-qty for each distinct shape (~249 DYB), but much more node-type-qty (~12k DYB)

BUT: GParts combination means that it kinda transitions between mesh-type when just for a single unplaced shape into node-type once applyPlacementTransform is used by GMergedMesh::mergeVolumeAnalytic

persisted structure detailed in GParts.rst

  • for examination of structure of multi-complete tree buffers see GParts.rst

GGeo

HMM: thoughts on removing m_ok okc/Opticks to rebase this on top of sysrap skipping NPY and BRAP ?

  • removal is too big of a change, as it gets threaded thru most of the geo libs
    • also longterm this class can disappear once have a more direct G4->CSGFoundry translation : so it is not worthwhile doing such extreme surgery
  • could however change type from okc/Opticks to sysrap/SOpticks with just the subset of Opticks needed much more readily ?
    • BUT: there is a lot of code here based in NPY, BRAP so maybe not worthwile trying to change that until implement direct G4->CSGFoundry

GGeo::deferredCreateGParts

Canonically invoked from GGeo::postLoadFromCache and GGeo::postDirectTranslation. so this happens both on direct translation and on saving. But beware the –gparts_transform_offset setting : when creating a CSGFoundry geometry it needs to be enabled.

frame #3: 0x00000001069a76f5 libGGeo.dylib`GParts::Create(ok=0x0000000110100310, pts=0x000000010eed2e60, solids=size=7, num_mismatch_pt=0x00007ffeefbfa7c0, mismatch_placements=0x00007ffeefbfa7a8 size=0, imm=0, global_tranOffset=0)0>, std::__1::allocator<glm::mat<4, 4, float, (glm::qualifier)0> > >*, int, int) at GParts.cc:258
frame #4: 0x0000000106a1b01e libGGeo.dylib`GGeo::deferredCreateGParts(this=0x000000010ee8e360) at GGeo.cc:1472
frame #5: 0x0000000106a185d0 libGGeo.dylib`GGeo::deferred(this=0x000000010ee8e360) at GGeo.cc:622
frame #6: 0x0000000106a18aec libGGeo.dylib`GGeo::postDirectTranslation(this=0x000000010ee8e360) at GGeo.cc:602
frame #7: 0x00000001000e39c3 libG4OK.dylib`G4Opticks::translateGeometry(this=0x000000010ee79720, top=0x000000010ed1f570) at G4Opticks.cc:974
frame #8: 0x00000001000e2874 libG4OK.dylib`G4Opticks::setGeometry(this=0x000000010ee79720, world=0x000000010ed1f570) at G4Opticks.cc:602

This is needed prior to GPU upload of analytic geometry by OGeo, it requires the GMergedMesh from GGeoLib and the NCSG solids from GMeshLib. Thus it can be done postcache, as all the ingredients are loaded from cache.

See ../notes/issues/GPts_GParts_optimization

  • option –savegparts Opticks::isSaveGPartsEnabled() writes $TMP/GParts/0,1,2,.. which is read by ana/GParts.py to provide a python interface to the analytic geometry