Skip to content
Snippets Groups Projects
Geant4SensDetAction.cpp 11.7 KiB
Newer Older
// $Id: Geant4Converter.cpp 603 2013-06-13 21:15:14Z markus.frank $
//====================================================================
//  AIDA Detector description implementation for LCD
//--------------------------------------------------------------------
//
//  Author     : M.Frank
//
//====================================================================

// Framework include files
#include "DD4hep/Printout.h"
#include "DD4hep/Primitives.h"
#include "DD4hep/InstanceCount.h"
#include "DDG4/Geant4Kernel.h"
#include "DDG4/Geant4Mapping.h"
#include "DDG4/Geant4SensDetAction.h"
#include "DDG4/Geant4StepHandler.h"
#include "DDG4/Geant4VolumeManager.h"

#include <G4SDManager.hh>
#include <G4VSensitiveDetector.hh>

// C/C++ include files
#include <stdexcept>

using namespace std;
using namespace DD4hep;
using namespace DD4hep::Simulation;

namespace {
  Geant4ActionSD* _getSensitiveDetector(const string& name)   {
    G4SDManager* mgr = G4SDManager::GetSDMpointer();
    G4VSensitiveDetector* sd = mgr->FindSensitiveDetector(name);
    if ( 0 == sd )   {
      throw runtime_error(format("Geant4Sensitive","DDG4: You requested to configure actions "
				 "for the sensitive detector %s,\nDDG4: which is not known to Geant4. "
				 "Are you sure you already converted the geometry?",name.c_str()));
    }
    Geant4ActionSD* action_sd = dynamic_cast<Geant4ActionSD*>(sd);
    if ( 0 == action_sd )    {
      throw runtime_error(format("Geant4Sensitive","DDG4: You may only configure actions "
				 "for sensitive detectors of type Geant4ActionSD.\n"
				 "DDG4: The sensitive detector of %s is of type %s, which is incompatible.",
				 name.c_str(),typeinfoName(typeid(*sd)).c_str()));
    }
    return action_sd;
  }
}

/// Standard action constructor
Geant4ActionSD::Geant4ActionSD(const std::string& name)
: Geant4Action(0,name)
{
  InstanceCount::increment(this);
}

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

/// Standard constructor
Geant4Filter::Geant4Filter(Geant4Context* context, const std::string& name)
: Geant4Action(context,name)
{
  InstanceCount::increment(this);
}

/// Standard destructor
Geant4Filter::~Geant4Filter()   {
  InstanceCount::decrement(this);
}

/// Filter action. Return true if hits should be processed
bool Geant4Filter::operator()(const G4Step*)  const  {
  return true;
}

/// Constructor. The detector element is identified by the name
Geant4Sensitive::Geant4Sensitive(Geant4Context* ctxt, const string& name, DetElement det, LCDD& lcdd)
: Geant4Action(ctxt,name), m_sensitiveDetector(0), m_sequence(0), m_lcdd(lcdd), 
  m_detector(det), m_sensitive(), m_readout()
{
  InstanceCount::increment(this);
  if ( !det.isValid() )   {
    throw runtime_error(format("Geant4Sensitive","DDG4: Detector elemnt for %s is invalid.",name.c_str()));
  }
  m_sequence  = ctxt->kernel().sensitiveAction(m_detector.name());
  m_sensitive = lcdd.sensitiveDetector(det.name());
  m_readout   = m_sensitive.readout();
}

/// Standard destructor
Geant4Sensitive::~Geant4Sensitive() {
  m_filters(&Geant4Filter::release);
  m_filters.clear();
  InstanceCount::decrement(this);
}

/// Add an actor responding to all callbacks. Sequence takes ownership.
void Geant4Sensitive::adopt(Geant4Filter* filter)   {
  if ( filter )  {
    filter->addRef();
    m_filters.add(filter);
    return;
  }
  throw runtime_error("Geant4SensDetActionSequence: Attempt to add invalid sensitive filter!");
}

/// Callback before hit processing starts. Invoke all filters. 
bool Geant4Sensitive::accept(const G4Step* step)   const {
  bool result = m_filters.filter(&Geant4Filter::operator(),step);
  return result;
}

/// Access to the sensitive detector object
void Geant4Sensitive::setDetector(Geant4ActionSD* sens_det)   {
  m_sensitiveDetector = sens_det;
}

/// Access to the sensitive detector object
Geant4ActionSD& Geant4Sensitive::detector()  const  {
  if (  m_sensitiveDetector ) return *m_sensitiveDetector;
  //m_sensitiveDetector = _getSensitiveDetector(m_detector.name());
  //if (  m_sensitiveDetector ) return *m_sensitiveDetector;
  throw runtime_error(format("Geant4Sensitive","DDG4: The sensitive detector for action %s "
			     "was not properly configured.",name().c_str()));
}      

/// Access to the hosting sequence
Geant4SensDetActionSequence& Geant4Sensitive::sequence()  const    {
  return *m_sequence;
}

/// Access HitCollection container names
const string& Geant4Sensitive::hitCollectionName(size_t which) const {
  return sequence().hitCollectionName(which);
}

/// Retrieve the hits collection associated with this detector by its serial number
Geant4HitCollection* Geant4Sensitive::collection(size_t which)   {
  return sequence().collection(which);
}

/// Retrieve the hits collection associated with this detector by its collection identifier
Geant4HitCollection* Geant4Sensitive::collectionByID(size_t id)   {
  return sequence().collectionByID(id);
}

/// Method invoked at the begining of each event. 
void Geant4Sensitive::begin(G4HCofThisEvent* /* HCE */) {
}

/// Method invoked at the end of each event. 
void Geant4Sensitive::end(G4HCofThisEvent* /* HCE */) {
}

/// Method for generating hit(s) using the information of G4Step object.
bool Geant4Sensitive::process(G4Step* /* step */, G4TouchableHistory* /* history */)   {
  return false;
}

/// Method is invoked if the event abortion is occured.
void Geant4Sensitive::clear(G4HCofThisEvent* /* HCE */) {
}

/// Returns the volumeID of the sensitive volume corresponding to the step
long long int Geant4Sensitive::volumeID(G4Step* s)   {
  Geant4StepHandler step(s);
  Geant4VolumeManager volMgr = Geant4Mapping::instance().volumeManager();  
  VolumeID id = volMgr.volumeID(step.preTouchable());
  return id;
}

/// Standard constructor
Geant4SensDetActionSequence::Geant4SensDetActionSequence(Geant4Context* context,const string& nam) 
: Geant4Action(context,nam), m_hce(0)
{
  InstanceCount::increment(this);
  context->sensitiveActions().insert(name(),this);
}

/// Default destructor
Geant4SensDetActionSequence::~Geant4SensDetActionSequence()  {
  m_filters(&Geant4Filter::release);
  m_actors(&Geant4Sensitive::release);
  m_filters.clear();
  m_actors.clear();
  InstanceCount::decrement(this);
}

/// Add an actor responding to all callbacks
void Geant4SensDetActionSequence::adopt(Geant4Sensitive* sensitive)   {
  if ( sensitive )  {
    sensitive->addRef();
    m_actors.add(sensitive);
    return;
  }
  throw runtime_error("Geant4SensDetActionSequence: Attempt to add invalid sensitive actor!");
}

/// Add an actor responding to all callbacks. Sequence takes ownership.
void Geant4SensDetActionSequence::adopt(Geant4Filter* filter)   {
  if ( filter )  {
    filter->addRef();
    m_filters.add(filter);
    return;
  }
  throw runtime_error("Geant4SensDetActionSequence: Attempt to add invalid sensitive filter!");
}

/// Initialize the usage of a hit collection. Returns the collection identifier
size_t Geant4SensDetActionSequence::defineCollection(const std::string& name,create_t func)    {
  m_collections.push_back(make_pair(name,func));
  return m_collections.size()-1;
}

/// Called at construction time of the sensitive detector to declare all hit collections
size_t Geant4SensDetActionSequence::Geant4SensDetActionSequence::defineCollections(Geant4ActionSD* sens_det)    {
  size_t count = 0;
  m_detector = sens_det;
  m_actors(&Geant4Sensitive::setDetector,sens_det);
  for(HitCollections::const_iterator i=m_collections.begin(); i!=m_collections.end(); ++i)  {
    sens_det->defineCollection((*i).first);
    ++count;
  }
  return count;
}

/// Access HitCollection container names
const std::string& Geant4SensDetActionSequence::hitCollectionName(size_t which) const   {
  if ( which < m_collections.size() ) {
    return m_collections[which].first;
  }
  static string blank="";
  except("The collection name index for subdetector %s is out of range!",c_name());
  return blank;
}

/// Retrieve the hits collection associated with this detector by its serial number
Geant4HitCollection* Geant4SensDetActionSequence::collection(size_t which) const    {
  if ( which < m_collections.size() ) {
    int hc_id = m_detector->GetCollectionID(which);
    Geant4HitCollection* c = (Geant4HitCollection*)m_hce->GetHC(hc_id);
    if ( c ) return c;
    except("The collection index for subdetector %s is wrong!",c_name());
  }
  except("The collection name index for subdetector %s is out of range!",c_name());
  return 0;
}

/// Retrieve the hits collection associated with this detector by its collection identifier
Geant4HitCollection* Geant4SensDetActionSequence::collectionByID(size_t id) const   {
  Geant4HitCollection* c = (Geant4HitCollection*)m_hce->GetHC(id);
  if ( c ) return c;
  except("The collection index for subdetector %s is wrong!",c_name());
  return 0;
}

/// Callback before hit processing starts. Invoke all filters. 
bool Geant4SensDetActionSequence::accept(const G4Step* step)   const {
  bool result = m_filters.filter(&Geant4Filter::operator(),step);
  return result;
}

/// Function to process hits
bool Geant4SensDetActionSequence::process(G4Step* step, G4TouchableHistory* hist) { 
  bool result = false;
  for(vector<Geant4Sensitive*>::iterator i=m_actors->begin(); i != m_actors->end(); ++i)  {
    Geant4Sensitive* s = *i;
    if ( s->accept(step) ) result |= s->process(step,hist);
  }
  m_process(step,hist);
  return result;
}

/** G4VSensitiveDetector interface: Method invoked at the begining of each event. 
 *  The hits collection(s) created by this sensitive detector must
 *  be set to the G4HCofThisEvent object at one of these two methods.
 */
void Geant4SensDetActionSequence::begin(G4HCofThisEvent* hce)   {
  m_hce = hce;
  for(size_t count = 0; count < m_collections.size(); ++count) {
    const std::pair<string,create_t>& cr = m_collections[count];
    G4VHitsCollection* c = (*cr.second)(name(), cr.first);
    int id = m_detector->GetCollectionID(count);
    m_hce->AddHitsCollection(id,c);
  }
  m_actors(&Geant4Sensitive::begin,m_hce);
  m_begin(m_hce);
}

/// G4VSensitiveDetector interface: Method invoked at the end of each event. 
void Geant4SensDetActionSequence::end(G4HCofThisEvent* hce)  {
  m_end(hce);
  m_actors(&Geant4Sensitive::end,hce);
  m_hce = 0;
}

/// G4VSensitiveDetector interface: Method invoked if the event was aborted.
/** Hits collections created but not beibg set to G4HCofThisEvent 
 *  at the event should be deleted.
 *  Collection(s) which have already set to G4HCofThisEvent 
 *  will be deleted automatically.
 */
void Geant4SensDetActionSequence::clear()  {
  m_clear(m_hce);
  m_actors(&Geant4Sensitive::clear,m_hce);
}

/// Default constructor
Geant4SensDetSequences::Geant4SensDetSequences()  {
}

/// Default destructor
Geant4SensDetSequences::~Geant4SensDetSequences()  {
  for_each(m_sequences.begin(),m_sequences.end(),releaseObjects(m_sequences));
  m_sequences.clear();
}

/// Access sequence member by name
Geant4SensDetActionSequence* Geant4SensDetSequences::operator[](const string& name) const   {
  string nam = "SD_Seq_"+name;
  Members::const_iterator i=m_sequences.find(nam);
  if ( i != m_sequences.end() )
    return (*i).second;
  throw runtime_error("Attempt to access undefined SensDetActionSequence!");
}

/// Access sequence member by name
Geant4SensDetActionSequence* Geant4SensDetSequences::find(const std::string& name) const   {
  string nam = "SD_Seq_"+name;
  Members::const_iterator i=m_sequences.find(nam);
  if ( i != m_sequences.end() )
    return (*i).second;
  return 0;
}

/// Insert sequence member
void Geant4SensDetSequences::insert(const string& name,Geant4SensDetActionSequence* seq)   {
  if ( seq )  {
    string nam = "SD_Seq_"+name;
    seq->addRef();
    m_sequences[nam] = seq;
    return;
  }
  throw runtime_error(format("Geant4SensDetSequences","Attempt to add invalid sensitive "
			     "sequence with name:%s",name.c_str()));
}