GDML Export Implementation
==========================

Intend to borrow from here for Collada export, so need to know details of
the exporter implementation.

* http://www-geant4.kek.jp/Reference/9.6.p02/classG4GDMLWrite.html

Inverted inheritance chain structure:: 

    G4GDMLWrite < ... < G4GDMLWriteStructure 

Contary to expectations from the name `G4GDMLWriteStructure` is top dog inheriting
from all the other `G4GDMLWrite*` classes including `G4GDMLWrite` at the base.
Inheritance misused for categorisation.

$DYB/NuWa-trunk/lhcb/Sim/GaussTools/src/Components/GiGaRunActionGDML.cpp::

     55    G4VPhysicalVolume* wpv = G4TransportationManager::GetTransportationManager()->
     56       GetNavigatorForTracking()->GetWorldVolume();
     57 
     58    G4String outFilePath("g4_00.gdml");
     59    G4GDMLParser parser ;
     60    if(wpv)
     61    {
     62        std::cout << "GiGaRunActionGDML::BeginOfRunAction writing to " << m_outFilePath << std::endl ;
     63        parser.Write(outFilePath, wpv);
     64    }

$DYB/external/build/LCG/geant4.9.2.p01/source/persistency/gdml/src/G4GDMLParser.cc::

     37 G4GDMLParser::G4GDMLParser()
     38   : ucode(false)
     39 {
     40   reader = new G4GDMLReadStructure;
     41   writer = new G4GDMLWriteStructure;
     42   xercesc::XMLPlatformUtils::Initialize();
     43 }

$DYB/external/build/LCG/geant4.9.2.p01/source/persistency/gdml/include/G4GDMLParser.icc::

     47 inline
     48 void G4GDMLParser::Write(const G4String& filename,
     49                          const G4VPhysicalVolume* const pvol,
     50                                G4bool refs,
     51                          const G4String& schemaLocation)
     52 {
     53   const G4int depth = 0;
     54   G4LogicalVolume* lvol = 0;
     55 
     56   if (!pvol)
     57   {
     58     G4VPhysicalVolume* worldPV = GetWorldVolume();
     59     if (!worldPV)
     60     {
     61       G4Exception("G4DMLParser::Write()", "InvalidSetup", FatalException,
     62                   "Detector-Construction needs to be registered first!");
     63     }
     64     lvol = worldPV->GetLogicalVolume();
     65   }
     66   else
     67   {
     68     lvol = pvol->GetLogicalVolume();
     69   }
     70   writer->Write(filename,lvol,schemaLocation,depth,refs);
     71 }

$DYB/external/build/LCG/geant4.9.2.p01/source/persistency/gdml/src/G4GDMLWrite.cc::

    107 G4Transform3D G4GDMLWrite::Write(const G4String& fname,
    108                                  const G4LogicalVolume* const logvol,
    109                                  const G4String& setSchemaLocation,
    110                                  const G4int depth,
    111                                        G4bool refs)
    112 {
    ///   
    ///    xercesc XML writer/doc setup
    ///
    161    DefineWrite(gdml);         // open "define" element
    162    MaterialsWrite(gdml);      // open "materials" element and clear materialsList, isotopeList 
    163    SolidsWrite(gdml);         // open "solids" element and clear solidsList
    164    StructureWrite(gdml);      // open "structure" element     
    165    SetupWrite(gdml,logvol);   // open "setup" element and populate
    166 
    167    G4Transform3D R = TraverseVolumeTree(logvol,depth);   // the meat, kicking off the recursive traverse 
    168 
    ///
    ///    xercesc XML writing 
    ///
    216    return R;
    217 }


$DYB/external/build/LCG/geant4.9.2.p01/source/persistency/gdml/src/G4GDMLWriteStructure.cc::

    189 G4Transform3D G4GDMLWriteStructure::
    190 TraverseVolumeTree(const G4LogicalVolume* const volumePtr, const G4int depth)
    191 {
    192    if (VolumeMap().find(volumePtr) != VolumeMap().end())
    193    {
    194      return VolumeMap()[volumePtr]; // Volume is already processed
    195    }
    196 
    197    G4VSolid* solidPtr = volumePtr->GetSolid();
    198    G4Transform3D R,invR;
    ///
    ///    reflected solid handling skipped
    ///
    235    const G4String name
    236          = GenerateName(volumePtr->GetName(),volumePtr);      // lvName
    237    const G4String materialref
    238          = GenerateName(volumePtr->GetMaterial()->GetName(),  
    239                         volumePtr->GetMaterial());
    240    const G4String solidref
    241          = GenerateName(solidPtr->GetName(),solidPtr);
    ...    
    ...    prep the volumeElement using name/materialref/solidref but dont append to structure yet
    ...
    ...    2181     <volume name="/dd/Geometry/RPC/lvRPCGasgap140xb7491f8">
    ...    2182       <materialref ref="/dd/Materials/Air0xb830740"/>
    ...    2183       <solidref ref="RPCGasgap140xbad5938"/>
    ... 
    ...
    232    if (reflected>0) { invR = R.inverse(); }
    233      // Only compute the inverse when necessary!
    ...
    252    const G4int daughterCount = volumePtr->GetNoDaughters();
    253 
    254    for (G4int i=0;i<daughterCount;i++)   // Traverse all the children!
    255    {
    256       const G4VPhysicalVolume* const physvol = volumePtr->GetDaughter(i);
    257       const G4String ModuleName = Modularize(physvol,depth);
    258 
    259       G4Transform3D daughterR;
    260 
    261       if (ModuleName.empty())   // Check if subtree requested to be 
    262       {                         // a separate module!
    263          daughterR = TraverseVolumeTree(physvol->GetLogicalVolume(),depth+1);
    ...
    ...   Q: hmm, how come not getting a deeper GDML structure then ?
    ...   A: because no matter what depth of the recursion the resulting volumeElement with 0 or more child physvol
    ...      are appended to the fixed structureElement gdml/structure/
    ...
    264       }
    265       else
    266       {
    267          G4GDMLWriteStructure writer;
    268          daughterR = writer.Write(ModuleName,physvol->GetLogicalVolume(),
    269                                   SchemaLocation,depth+1);
    270       }
    ...
    272       if (const G4PVDivision* const divisionvol
    273          = dynamic_cast<const G4PVDivision*>(physvol)) // Is it division?
    274       {
    ///
    ///              divisional/replica/parameterized skipped
    ///
    309       else   // Is it a physvol?
    310       {
    311          G4RotationMatrix rot;
    312 
    313          if (physvol->GetFrameRotation() != 0)
    314          {
    315            rot = *(physvol->GetFrameRotation());
    316          }
    317          G4Transform3D P(rot,physvol->GetObjectTranslation());           // placement transform of daughter pv wrt mother
    318          PhysvolWrite(volumeElement,physvol,invR*P*daughterR,ModuleName);
    ...
    ...             R, invR are identity transforms when not dealing with reflections.. ?
    ...
    319       }
    320    }
    321 
    322    structureElement->appendChild(volumeElement);
    323      // Append the volume AFTER traversing the children so that
    324      // the order of volumes will be correct!
    325 
    326    VolumeMap()[volumePtr] = R;
    327 
    328    G4GDMLWriteMaterials::AddMaterial(volumePtr->GetMaterial());
    329      // Add the involved materials and solids!
    330 
    331    G4GDMLWriteSolids::AddSolid(solidPtr);
    332 
    333    return R;
    334 }




::

     76 void G4GDMLWriteStructure::PhysvolWrite(xercesc::DOMElement* volumeElement,
     77                                         const G4VPhysicalVolume* const physvol,
     78                                         const G4Transform3D& T,
     79                                         const G4String& ModuleName)
     80 {
     81    HepGeom::Scale3D scale;
     82    HepGeom::Rotate3D rotate;
     83    HepGeom::Translate3D translate;
     84 
     85    T.getDecomposition(scale,rotate,translate);
     86 
     87    const G4ThreeVector scl(scale(0,0),scale(1,1),scale(2,2));
     88    const G4ThreeVector rot = GetAngles(rotate.getRotation());
     89    const G4ThreeVector pos = T.getTranslation();
     90 
     91    const G4String name = GenerateName(physvol->GetName(),physvol);
     92 
     93    xercesc::DOMElement* physvolElement = NewElement("physvol");
     94    physvolElement->setAttributeNode(NewAttribute("name",name));
     95    volumeElement->appendChild(physvolElement);
     96 
     97    const G4String volumeref
     98          = GenerateName(physvol->GetLogicalVolume()->GetName(),
     99                         physvol->GetLogicalVolume());
     100 
     101    if (ModuleName.empty())
     102    {
     103       xercesc::DOMElement* volumerefElement = NewElement("volumeref");
     104       volumerefElement->setAttributeNode(NewAttribute("ref",volumeref));
     105       physvolElement->appendChild(volumerefElement);
     106    }
     ...
     ...       physvol are the children of the mother lv. 
     ...       volumeref/@ref point to the lv of the child physvol
     ...
     ...       2181     <volume name="/dd/Geometry/RPC/lvRPCGasgap140xb7491f8">
     ...       2182       <materialref ref="/dd/Materials/Air0xb830740"/>
     ...       2183       <solidref ref="RPCGasgap140xbad5938"/>
     ...       2184       <physvol name="/dd/Geometry/RPC/lvRPCGasgap14#pvStrip14Array#pvStrip14ArrayOne:1#pvStrip14Unit0xbc1e930">
     ...       2185         <volumeref ref="/dd/Geometry/RPC/lvRPCStrip0xb839910"/>
     ...       2186         <position name="/dd/Geometry/RPC/lvRPCGasgap14#pvStrip14Array#pvStrip14ArrayOne:1#pvStrip14Unit0xbc1e930_pos" unit="mm" x="-910" y="0" z="0"/>
     ...       2187         <rotation name="/dd/Geometry/RPC/lvRPCGasgap14#pvStrip14Array#pvStrip14ArrayOne:1#pvStrip14Unit0xbc1e930_rot" unit="deg" x="0" y="0" z="-90"/>
     ...       2188       </physvol>
     ...
     ...
     107    else
     108    {
     109       xercesc::DOMElement* fileElement = NewElement("file");
     110       fileElement->setAttributeNode(NewAttribute("name",ModuleName));
     111       fileElement->setAttributeNode(NewAttribute("volname",volumeref));
     112       physvolElement->appendChild(fileElement);
     113    }
     114 
     115    if (std::fabs(pos.x()) > kLinearPrecision
     116     || std::fabs(pos.y()) > kLinearPrecision
     117     || std::fabs(pos.z()) > kLinearPrecision)
     118    {
     119      PositionWrite(physvolElement,name+"_pos",pos);
     120    }
     121    if (std::fabs(rot.x()) > kAngularPrecision
     122     || std::fabs(rot.y()) > kAngularPrecision
     123     || std::fabs(rot.z()) > kAngularPrecision)
     124    {
     125      RotationWrite(physvolElement,name+"_rot",rot);
     126    }
     127    if (std::fabs(scl.x()-1.0) > kRelativePrecision
     128     || std::fabs(scl.y()-1.0) > kRelativePrecision
     129     || std::fabs(scl.z()-1.0) > kRelativePrecision)
     130    {
     131      ScaleWrite(physvolElement,name+"_scl",scl);
     132    }
     133 }



$LOCAL_BASE/env/geant4/geometry/gdml/g4_01.gdml::

    ...
    ...     structure only goes to two levels ?  structure/volume/physvol/volumeref
    ...     presumably depth heirarchy being repesented via the volumeref linking up multiple such relations 
    ...
    ...     Logical volumes with @name are pointed to by physvol/volumeref/@ref 
    ...
    2172   <structure>
    2173     <volume name="/dd/Geometry/PoolDetails/lvNearTopCover0xbad46a0">
    2174       <materialref ref="/dd/Materials/PPE0xb8310e0"/>
    2175       <solidref ref="near_top_cover_box0xbad4490"/>
    2176     </volume>
    2177     <volume name="/dd/Geometry/RPC/lvRPCStrip0xb839910">
    2178       <materialref ref="/dd/Materials/MixGas0xbad5d28"/>
    2179       <solidref ref="RPCStrip0xb751cc0"/>
    2180     </volume>
    2181     <volume name="/dd/Geometry/RPC/lvRPCGasgap140xb7491f8">
    2182       <materialref ref="/dd/Materials/Air0xb830740"/>
    2183       <solidref ref="RPCGasgap140xbad5938"/>
    2184       <physvol name="/dd/Geometry/RPC/lvRPCGasgap14#pvStrip14Array#pvStrip14ArrayOne:1#pvStrip14Unit0xbc1e930">
    2185         <volumeref ref="/dd/Geometry/RPC/lvRPCStrip0xb839910"/>
    2186         <position name="/dd/Geometry/RPC/lvRPCGasgap14#pvStrip14Array#pvStrip14ArrayOne:1#pvStrip14Unit0xbc1e930_pos" unit="mm" x="-910" y="0" z="0"/>
    2187         <rotation name="/dd/Geometry/RPC/lvRPCGasgap14#pvStrip14Array#pvStrip14ArrayOne:1#pvStrip14Unit0xbc1e930_rot" unit="deg" x="0" y="0" z="-90"/>
    2188       </physvol>
    2189       <physvol name="/dd/Geometry/RPC/lvRPCGasgap14#pvStrip14Array#pvStrip14ArrayOne:2#pvStrip14Unit0xbc1f8b8">
    2190         <volumeref ref="/dd/Geometry/RPC/lvRPCStrip0xb839910"/>
    2191         <position name="/dd/Geometry/RPC/lvRPCGasgap14#pvStrip14Array#pvStrip14ArrayOne:2#pvStrip14Unit0xbc1f8b8_pos" unit="mm" x="-650" y="0" z="0"/>
    2192         <rotation name="/dd/Geometry/RPC/lvRPCGasgap14#pvStrip14Array#pvStrip14ArrayOne:2#pvStrip14Unit0xbc1f8b8_rot" unit="deg" x="0" y="0" z="-90"/>
    2193       </physvol>
    .... 
    2219       <physvol name="/dd/Geometry/RPC/lvRPCGasgap14#pvStrip14Array#pvStrip14ArrayOne:8#pvStrip14Unit0xbc1feb0">
    2220         <volumeref ref="/dd/Geometry/RPC/lvRPCStrip0xb839910"/>
    2221         <position name="/dd/Geometry/RPC/lvRPCGasgap14#pvStrip14Array#pvStrip14ArrayOne:8#pvStrip14Unit0xbc1feb0_pos" unit="mm" x="910" y="0" z="0"/>
    2222         <rotation name="/dd/Geometry/RPC/lvRPCGasgap14#pvStrip14Array#pvStrip14ArrayOne:8#pvStrip14Unit0xbc1feb0_rot" unit="deg" x="0" y="0" z="-90"/>
    2223       </physvol>
    2224     </volume>
    2225     <volume name="/dd/Geometry/RPC/lvRPCBarCham140xbad5978">
    2226       <materialref ref="/dd/Materials/Bakelite0xb830008"/>
    2227       <solidref ref="RPCBarCham140xbd59170"/>
    2228       <physvol name="/dd/Geometry/RPC/lvRPCBarCham14#pvRPCGasgap140xbc1f360">
    2229         <volumeref ref="/dd/Geometry/RPC/lvRPCGasgap140xb7491f8"/>
    2230       </physvol>
    2231     </volume>
    ....
    30919     <volume name="/dd/Geometry/Sites/lvNearSiteRock0xb82e578">
    30920       <materialref ref="/dd/Materials/Rock0xb849090"/>
    30921       <solidref ref="near_rock0xb8499c8"/>
    30922       <physvol name="/dd/Geometry/Sites/lvNearSiteRock#pvNearHallTop0xb7dd068">
    30923         <volumeref ref="/dd/Geometry/Sites/lvNearHallTop0xb745f10"/>
    30924         <position name="/dd/Geometry/Sites/lvNearSiteRock#pvNearHallTop0xb7dd068_pos" unit="mm" x="2500" y="-500" z="7500"/>
    30925       </physvol>
    30926       <physvol name="/dd/Geometry/Sites/lvNearSiteRock#pvNearHallBot0xc5065d0">
    30927         <volumeref ref="/dd/Geometry/Sites/lvNearHallBot0xb7dd4a8"/>
    30928         <position name="/dd/Geometry/Sites/lvNearSiteRock#pvNearHallBot0xc5065d0_pos" unit="mm" x="0" y="0" z="-5150"/>
    30929       </physvol>
    30930     </volume>
    30931     <volume name="World0xc6337a8">
    30932       <materialref ref="/dd/Materials/Vacuum0xbaff828"/>
    30933       <solidref ref="WorldBox0xc6328f0"/>
    30934       <physvol name="/dd/Structure/Sites/db-rock0xc633af8">
    30935         <volumeref ref="/dd/Geometry/Sites/lvNearSiteRock0xb82e578"/>
    30936         <position name="/dd/Structure/Sites/db-rock0xc633af8_pos" unit="mm" x="-16519.9999999999" y="-802110" z="-2110"/>
    30937         <rotation name="/dd/Structure/Sites/db-rock0xc633af8_rot" unit="deg" x="0" y="0" z="-122.9"/>
    30938       </physvol>
    30939     </volume>
    30940   </structure>
 


$LOCAL_BASE/env/geant4/geometry/gdml/g4_01.gdml::

    1 <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
    2 <gdml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://service-spi.web.cern.ch/service-spi/app/releases/GDML/schema/gdml.xsd">
    3 
    4   <define/>
    5 
    6   <materials>
    7     <element Z="6" name="/dd/Materials/Carbon0xbad48f8">
    8       <atom unit="g/mole" value="12.0109936803044"/>
    9     </element>
    10     <element Z="1" name="/dd/Materials/Hydrogen0xbad34d0">
    11       <atom unit="g/mole" value="1.00793946966331"/>
    12     </element>
    13     <material name="/dd/Materials/PPE0xb8310e0" state="solid">
    14       <P unit="pascal" value="101324.946686941"/>
    15       <D unit="g/cm3" value="0.919999515933733"/>
    16       <fraction n="0.798874855998063" ref="/dd/Materials/Carbon0xbad48f8"/>
    17       <fraction n="0.201125144001937" ref="/dd/Materials/Hydrogen0xbad34d0"/>
    18     </material>    
    ..
    401   <solids>
    402     <box lunit="mm" name="near_top_cover0xbb2aa88" x="16000" y="10000" z="44"/>
    403     <box lunit="mm" name="near_top_cover_sub00xbad4c78" x="4249.00272282321" y="4249.00272282321" z="54"/>
    404     <subtraction name="near_top_cover-ChildFornear_top_cover_box0xbad6708">
    405       <first ref="near_top_cover0xbb2aa88"/>
    406       <second ref="near_top_cover_sub00xbad4c78"/>
    407       <position name="near_top_cover-ChildFornear_top_cover_box0xbad6708_pos" unit="mm" x="8000" y="5000" z="0"/>
    408       <rotation name="near_top_cover-ChildFornear_top_cover_box0xbad6708_rot" unit="deg" x="0" y="0" z="45"/>
    409     </subtraction>
    ...
    2172   <structure>
    ....
    ....     dealt with above
    ....
    30940   </structure>
    30941 
    30942   <setup name="Default" version="1.0">
    30943     <world ref="World0xc6337a8"/>
    30944   </setup>
    30945 
    30946 </gdml>