Skip to content
Snippets Groups Projects
Geant4RegexSensitivesConstruction.cpp 6.26 KiB
Newer Older
//==========================================================================
//  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>

// C/C++ include files
#include <set>
#include <regex>

/// Namespace for the AIDA detector description toolkit
namespace dd4hep {

  /// Namespace for the Geant4 based simulation part of the AIDA detector description toolkit
  namespace sim {

    /// Class to create Geant4 detector geometry from TGeo representation in memory
    /**
     *  On demand the sensitive detectors are created and attached to all sensitive
     *  volumes. The relevant  callback is executed when the call to 
     *  ConstructSDandField() of the corresponding G4VUserDetectorConstruction
     *  instance is called. The call is thread-local!
     *
     *  \author  M.Frank
     *  \version 1.0
     *  \ingroup DD4HEP_SIMULATION
     */
    class Geant4RegexSensitivesConstruction : public Geant4DetectorConstruction   {
    public:
      std::string detector_name;
      std::vector<std::string> regex_values;
      std::size_t collect_volumes(std::set<Volume>&  volumes,
                                  PlacedVolume       pv,
                                  const std::string& path,
                                  const std::vector<std::regex>& matches);
    public:
      /// Initializing constructor for DDG4
      Geant4RegexSensitivesConstruction(Geant4Context* ctxt, const std::string& nam);
      /// Default destructor
      virtual ~Geant4RegexSensitivesConstruction();
      /// Sensitives construction callback. Called at "ConstructSDandField()"
      void constructSensitives(Geant4DetectorConstructionContext* ctxt);
    };
  }    // End namespace sim
}      // End namespace dd4hep


// Framework include files
#include <DD4hep/InstanceCount.h>
#include <DD4hep/Printout.h>
#include <DD4hep/Plugins.h>
#include <DD4hep/Detector.h>
#include <DD4hep/DetectorTools.h>

#include <DDG4/Geant4Mapping.h>
#include <DDG4/Geant4Kernel.h>
#include <DDG4/Factories.h>

// ROOT include files
#include <TTimeStamp.h>
#include <TGeoManager.h>
// Geant4 include files
#include <G4PVPlacement.hh>
#include <G4VSensitiveDetector.hh>

using namespace dd4hep::sim;

DECLARE_GEANT4ACTION(Geant4RegexSensitivesConstruction)

/// Initializing constructor for other clients
Geant4RegexSensitivesConstruction::Geant4RegexSensitivesConstruction(Geant4Context* ctxt, const std::string& nam)
: Geant4DetectorConstruction(ctxt,nam)
{
  declareProperty("Detector", detector_name);
  declareProperty("Match",    regex_values);
  InstanceCount::increment(this);
}

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

std::size_t
Geant4RegexSensitivesConstruction::collect_volumes(std::set<Volume>&  volumes,
                                                   PlacedVolume       pv,
                                                   const std::string& path,
                                                   const std::vector<std::regex>& matches)
{
  std::size_t count = 0;
  // Try to minimize a bit the number of regex matches.
  if ( volumes.find(pv.volume()) == volumes.end() )  {
    if( !path.empty() )  {
      for( const auto& match : matches )  {
        if( stat )  {
          volumes.insert(pv.volume());
          ++count;
          break;
        }
      }
    }
    // Now recurse down the daughters
    for( int i=0, num = pv->GetNdaughters(); i < num; ++i )  {
      PlacedVolume daughter = pv->GetDaughter(i);
      std::string  daughter_path = path + "/" + daughter.name();
      count += this->collect_volumes(volumes, daughter, daughter_path, matches);
    }
  }
  return count;
}

/// Sensitive detector construction callback. Called at "ConstructSDandField()"
void Geant4RegexSensitivesConstruction::constructSensitives(Geant4DetectorConstructionContext* ctxt)   {
  Geant4GeometryInfo* g4info = Geant4Mapping::instance().ptr();
  const Geant4Kernel& kernel = context()->kernel();
  const auto&         types  = kernel.sensitiveDetectorTypes();
  const std::string&  dflt   = kernel.defaultSensitiveDetectorType();
  const char*         det    = detector_name.c_str();
  
  DetElement de = detail::tools::findElement(ctxt->description, detector_name);
  if( !de.isValid() )  {
    except("Failed to locate subdetector DetElement %s to manage Geant4 energy deposits.", det);
  }
  SensitiveDetector sd = ctxt->description.sensitiveDetector(detector_name);
  if( !sd.isValid() )  {
    except("Failed to locate sensitive detector %s to manage Geant4 energy deposits.", det);
  }
  std::string nam  = sd.name();
  auto        iter = types.find(nam);
  std::string typ  = (iter != types.end()) ? (*iter).second : dflt;
  G4VSensitiveDetector* g4sd = this->createSensitiveDetector(typ, nam);

  std::set<Volume> volumes;
  int flags = std::regex_constants::icase | std::regex_constants::ECMAScript;
  std::vector<std::regex> expressions;
  for( const auto& val : regex_values )  {
    std::regex e(val, (std::regex_constants::syntax_option_type)flags);
    expressions.emplace_back(e);
  }
  info("%s Starting to scan volume....", det);
  std::size_t num_nodes = this->collect_volumes(volumes, de.placement(), de.placementPath(), expressions);
  for( const auto& vol : volumes )  {
    G4LogicalVolume* g4vol = g4info->g4Volumes[vol];
    if( !g4vol )  {
      except("+++ Failed to access G4LogicalVolume for SD %s of type %s", nam.c_str(), typ.c_str());
    debug("%s Assign sensitive detector [%s] to volume: %s.",
          nam.c_str(), typ.c_str(), vol.name());
    ctxt->setSensitiveDetector(g4vol, g4sd);
  }
  TTimeStamp stop;
  info("%s Handled %ld nodes with %ld sensitive volume type(s). Total of %7.3f seconds.",
       det, num_nodes, volumes.size(), stop.AsDouble()-start.AsDouble() );