Skip to content
Snippets Groups Projects
Geant4DetectorGeometryConstruction.cpp 10.6 KiB
Newer Older
//==========================================================================
Markus Frank's avatar
Markus Frank committed
//  AIDA Detector description implementation 
//--------------------------------------------------------------------------
// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
// All rights reserved.
//
// For the licensing terms see $DD4hepINSTALL/LICENSE.
// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
//
//  \author Markus Frank
//  \date   2015-11-09
//
//==========================================================================

// Framework include files
#include <DDG4/Geant4DetectorConstruction.h>

/// Namespace for the AIDA detector description toolkit
Markus Frank's avatar
Markus Frank committed
namespace dd4hep {

  /// Namespace for the Geant4 based simulation part of the AIDA detector description toolkit
Markus Frank's avatar
Markus Frank committed
  namespace sim {

    /// Class to create Geant4 detector geometry from TGeo representation in memory
    /**
Markus Frank's avatar
Markus Frank committed
     *  On demand (ie. when calling "Construct") the dd4hep geometry is converted
     *  to Geant4 with all volumes, assemblies, shapes, materials etc.
     *  The actuak work is performed by the Geant4Converter class called by this method.
     *
     *  \author  M.Frank
     *  \version 1.0
     *  \ingroup DD4HEP_SIMULATION
     */
    class Geant4DetectorGeometryConstruction : public Geant4DetectorConstruction   {
      /// Property: Dump geometry hierarchy
      /// Property: Flag to debug materials during conversion mechanism
      /// Property: Flag to debug elements during conversion mechanism
      bool m_debugElements   = false;
      /// Property: Flag to debug shapes during conversion mechanism
      bool m_debugShapes     = false;
      /// Property: Flag to debug volumes during conversion mechanism
      /// Property: Flag to debug placements during conversion mechanism
      /// Property: Flag to debug regions during conversion mechanism
      /// Property: Flag to debug regions during conversion mechanism
      bool m_debugSurfaces   = false;

      /// Property: Flag to dump all placements after the conversion procedure
      bool m_printPlacements = false;
      /// Property: Flag to dump all sensitives after the conversion procedure
      bool m_printSensitives = false;

      /// Property: Printout level of info object
      int  m_geoInfoPrintLevel;
      /// Property: G4 GDML dump file name (default: empty. If non empty, dump)
      std::string m_dumpGDML;
      /// Property: DD4hep path to volume to be printed (default: empty)
      std::string m_volumePath;

      /// Write GDML file
      int writeGDML();
      /// Print geant4 volume
      int printVolume();
      /// Check geant4 volume
      int checkVolume();

    public:
      /// Initializing constructor for DDG4
      Geant4DetectorGeometryConstruction(Geant4Context* ctxt, const std::string& nam);
      /// Default destructor
      virtual ~Geant4DetectorGeometryConstruction();
      /// Geometry construction callback. Called at "Construct()"
      void constructGeo(Geant4DetectorConstructionContext* ctxt)  override;
      /// Install command control messenger to write GDML file from command prompt.
      virtual void installCommandMessenger()   override;
Markus Frank's avatar
Markus Frank committed
  }    // End namespace sim
}      // End namespace dd4hep
#include <DD4hep/InstanceCount.h>
#include <DD4hep/DetectorTools.h>
#include <DD4hep/DD4hepUnits.h>
#include <DD4hep/Printout.h>
#include <DD4hep/Detector.h>
#include <DDG4/Geant4HierarchyDump.h>
#include <DDG4/Geant4UIMessenger.h>
#include <DDG4/Geant4Converter.h>
#include <DDG4/Geant4Kernel.h>
#include <DDG4/Factories.h>
#include <G4PVPlacement.hh>
//#ifdef GEANT4_HAS_GDML
#include <G4GDMLParser.hh>
Markus Frank's avatar
Markus Frank committed
using namespace dd4hep;
using namespace dd4hep::sim;
DECLARE_GEANT4ACTION(Geant4DetectorGeometryConstruction)

/// Initializing constructor for other clients
Geant4DetectorGeometryConstruction::Geant4DetectorGeometryConstruction(Geant4Context* ctxt, const string& nam)
: Geant4DetectorConstruction(ctxt,nam)
  declareProperty("DebugMaterials",    m_debugMaterials);
  declareProperty("DebugElements",     m_debugElements);
  declareProperty("DebugShapes",       m_debugShapes);
  declareProperty("DebugVolumes",      m_debugVolumes);
  declareProperty("DebugPlacements",   m_debugPlacements);
  declareProperty("DebugRegions",      m_debugRegions);
  declareProperty("DebugSurfaces",     m_debugSurfaces);

  declareProperty("PrintPlacements",   m_printPlacements);
  declareProperty("PrintSensitives",   m_printSensitives);
  declareProperty("GeoInfoPrintLevel", m_geoInfoPrintLevel = DEBUG);

  declareProperty("DumpHierarchy",     m_dumpHierarchy);
  declareProperty("DumpGDML",          m_dumpGDML="");
  declareProperty("VolumePath",        m_volumePath="");
  InstanceCount::increment(this);
}

/// Default destructor
Geant4DetectorGeometryConstruction::~Geant4DetectorGeometryConstruction() {
  InstanceCount::decrement(this);
}

/// Geometry construction callback. Called at "Construct()"
void Geant4DetectorGeometryConstruction::constructGeo(Geant4DetectorConstructionContext* ctxt)   {
  Geant4Mapping&  g4map = Geant4Mapping::instance();
  DetElement      world = ctxt->description.world();
Markus Frank's avatar
Markus Frank committed
  Geant4Converter conv(ctxt->description, outputLevel());
  conv.debugMaterials  = m_debugMaterials;
  conv.debugElements   = m_debugElements;
  conv.debugVolumes    = m_debugVolumes;
  conv.debugPlacements = m_debugPlacements;
  conv.debugRegions    = m_debugRegions;
  ctxt->geometry       = conv.create(world).detach();
  ctxt->geometry->printLevel = outputLevel();
  g4map.attach(ctxt->geometry);
  G4VPhysicalVolume* w = ctxt->geometry->world();
  // Save away the reference to the world volume
  context()->kernel().setWorld(w);
  // Create Geant4 volume manager only if not yet available
  g4map.volumeManager();
  if ( m_dumpHierarchy )   {
Markus Frank's avatar
Markus Frank committed
    Geant4HierarchyDump dmp(ctxt->description);
  ctxt->world = w;
  if ( !m_dumpGDML.empty() || ::getenv("DUMP_GDML") ) writeGDML();
  enableUI();
}

/// Print geant4 volume
int Geant4DetectorGeometryConstruction::printVolume()  {
  if ( !m_volumePath.empty() )   {
    Detector& det = context()->kernel().detectorDescription();
    PlacedVolume top = det.world().placement();
    PlacedVolume pv = detail::tools::findNode(top, m_volumePath);
    if ( pv.isValid() )   {
      auto& g4map = Geant4Mapping::instance().data();
      auto it = g4map.g4Volumes.find(pv.volume());
      if ( it != g4map.g4Volumes.end() )   {
        const G4LogicalVolume* vol = (*it).second;
        auto* sol = vol->GetSolid(); 
        string txt;
        stringstream str;
        str << *(vol->GetMaterial()) << endl;
        str << *sol;
        stringstream istr(str.str());
        printP2("+++  Dump of ROOT   solid: %s", m_volumePath.c_str());
        pv.volume().solid()->InspectShape();
        printP2("+++  Dump of GEANT4 solid: %s", m_volumePath.c_str());
        while(istr.good())   {
          getline(istr,txt);
          printP2(txt.c_str());
        }
        printP2("Shape: %s  cubic volume: %8.3g mm^3  area: %8.3g mm^2",
                sol->GetName().c_str(), sol->GetCubicVolume(), sol->GetSurfaceArea());
        return 1;
      }
    }
    warning("+++ printVolume: FAILED to find the volume %s from the top volume",m_volumePath.c_str());
  }
  warning("+++ printVolume: Property VolumePath not set. [Ignored]");
  return 0;
}

/// Check geant4 volume
int Geant4DetectorGeometryConstruction::checkVolume()  {
  if ( !m_volumePath.empty() )   {
    Detector& det = context()->kernel().detectorDescription();
    PlacedVolume top = det.world().placement();
    PlacedVolume pv = detail::tools::findNode(top, m_volumePath);
    if ( pv.isValid() )   {
      auto& g4map = Geant4Mapping::instance().data();
      auto it = g4map.g4Volumes.find(pv.volume());
      if ( it != g4map.g4Volumes.end() )   {
        const G4LogicalVolume* vol = (*it).second;
        auto* g4_sol = vol->GetSolid();
        Box   rt_sol = pv.volume().solid();
        printP2("Geant4 Shape: %s  cubic volume: %8.3g mm^3  area: %8.3g mm^2",
                g4_sol->GetName().c_str(), g4_sol->GetCubicVolume(), g4_sol->GetSurfaceArea());
#if G4VERSION_NUMBER>=1040
        G4ThreeVector pMin, pMax;
        double conv = (dd4hep::centimeter/CLHEP::centimeter)/2.0;
        g4_sol->BoundingLimits(pMin,pMax);
        printP2("Geant4 Bounding box extends:    %8.3g  %8.3g %8.3g",
                (pMax.x()-pMin.x())*conv, (pMax.y()-pMin.y())*conv, (pMax.z()-pMin.z())*conv);
        printP2("ROOT   Bounding box dimensions: %8.3g  %8.3g %8.3g",
                rt_sol->GetDX(), rt_sol->GetDY(), rt_sol->GetDZ());
        
        return 1;
      }
    }
    warning("+++ checkVolume: FAILED to find the volume %s from the top volume",m_volumePath.c_str());
  }
  warning("+++ checkVolume: Property VolumePath not set. [Ignored]");
  return 0;
}

/// Write GDML file
int Geant4DetectorGeometryConstruction::writeGDML()  {
  G4VPhysicalVolume* w  = context()->world();
  //#ifdef GEANT4_HAS_GDML
  if ( !m_dumpGDML.empty() ) {
    parser.Write(m_dumpGDML.c_str(), w);
    info("+++ writeGDML: Wrote GDML file: %s", m_dumpGDML.c_str());
    return 1;
  }
  else {
    const char* gdml_dmp = ::getenv("DUMP_GDML");
    if ( gdml_dmp )    {
      G4GDMLParser parser;
      info("+++ writeGDML: Wrote GDML file: %s", gdml_dmp);
      return 1;
  warning("+++ writeGDML: Neither property DumpGDML nor environment DUMP_GDML set. No file written!");
  return 0;
}

/// Install command control messenger to write GDML file from command prompt.
void Geant4DetectorGeometryConstruction::installCommandMessenger()   {
  this->Geant4DetectorConstruction::installCommandMessenger();
  m_control->addCall("writeGDML", "GDML: write geometry to file: '"+m_dumpGDML+"' [uses property DumpGDML]",
                     Callback(this).make(&Geant4DetectorGeometryConstruction::writeGDML));
  m_control->addCall("printVolume", "Print Geant4 volume properties [uses property VolumePath]",
                     Callback(this).make(&Geant4DetectorGeometryConstruction::printVolume));
  m_control->addCall("checkVolume", "Check Geant4 volume properties [uses property VolumePath]",
                     Callback(this).make(&Geant4DetectorGeometryConstruction::checkVolume));