Skip to content
Snippets Groups Projects
Geant4MaterialScanner.cpp 8.06 KiB
Newer Older
//==========================================================================
Markus Frank's avatar
Markus Frank committed
//  AIDA Detector description implementation 
//--------------------------------------------------------------------------
Markus Frank's avatar
Markus Frank committed
// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
// For the licensing terms see $DD4hepINSTALL/LICENSE.
// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
// Author     : M.Frank
//
//==========================================================================

// Framework include files
#include "DD4hep/Objects.h"
#include "DDG4/Geant4SteppingAction.h"

// Forward declarations
class G4LogicalVolume;

/// 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 perform directional material scans using Geantinos.
    /**
     *
     *  \author  M.Frank
     *  \version 1.0
     *  \ingroup DD4HEP_SIMULATION
     */
    class Geant4MaterialScanner : public Geant4SteppingAction  {
    protected:
      /// Structure to hold the information of one simulation step.
      class StepInfo {
      public:
        /// Pre-step and Post-step position
        Position pre, post;
        /// Reference to the logical volue
        const G4LogicalVolume* volume;

        /// Initializing constructor
        StepInfo(const Position& pre, const Position& post, const G4LogicalVolume* volume);
        /// Copy constructor
        StepInfo(const StepInfo& c);
        /// Default destructor
        ~StepInfo() {}
        /// Assignment operator
        StepInfo& operator=(const StepInfo& c);
      };
      typedef std::vector<StepInfo*> Steps;

      double m_sumX0     = 0E0;
      double m_sumLambda = 0E0;
      double m_sumPath   = 0E0;
      Steps  m_steps;

    public:
      /// Standard constructor
      Geant4MaterialScanner(Geant4Context* context, const std::string& name);
      /// Default destructor
      virtual ~Geant4MaterialScanner();
      /// User stepping callback
      virtual void operator()(const G4Step* step, G4SteppingManager* mgr);
      /// Begin-of-tracking callback
      virtual void begin(const G4Track* track);
      /// End-of-tracking callback
      virtual void end(const G4Track* track);
      /// Registered callback on Begin-event
      void beginEvent(const G4Event* event);
    };
  }
}

//====================================================================
Markus Frank's avatar
Markus Frank committed
//  AIDA Detector description implementation 
//--------------------------------------------------------------------
//
//  Author     : M.Frank
//
//====================================================================

// Framework include files
#include "DD4hep/InstanceCount.h"
#include "DD4hep/Printout.h"
#include "DDG4/Geant4TouchableHandler.h"
#include "DDG4/Geant4StepHandler.h"
#include "DDG4/Geant4EventAction.h"
#include "DDG4/Geant4TrackingAction.h"
#include "CLHEP/Units/SystemOfUnits.h"
#include "G4LogicalVolume.hh"
#include "G4Material.hh"

using namespace std;
Markus Frank's avatar
Markus Frank committed
using namespace dd4hep::sim;
#include "DDG4/Factories.h"
DECLARE_GEANT4ACTION(Geant4MaterialScanner)

/// Initializing constructor
Geant4MaterialScanner::StepInfo::StepInfo(const Position& prePos, const Position& postPos, const G4LogicalVolume* vol)
: pre(prePos), post(postPos), volume(vol)
{
}

/// Copy constructor
Geant4MaterialScanner::StepInfo::StepInfo(const StepInfo& c)
: pre(c.pre), post(c.post), volume(c.volume)
{
}

/// Assignment operator
Geant4MaterialScanner::StepInfo& Geant4MaterialScanner::StepInfo::operator=(const StepInfo& c)  {
  pre = c.pre;
  post = c.post;
  volume = c.volume;
  return *this;
}

/// Standard constructor
Geant4MaterialScanner::Geant4MaterialScanner(Geant4Context* ctxt, const string& nam)
  : Geant4SteppingAction(ctxt,nam)
{
  m_needsControl = true;
  eventAction().callAtBegin(this,&Geant4MaterialScanner::beginEvent);
  trackingAction().callAtEnd(this,&Geant4MaterialScanner::end);
  trackingAction().callAtBegin(this,&Geant4MaterialScanner::begin);
  InstanceCount::increment(this);
}

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

/// User stepping callback
void Geant4MaterialScanner::operator()(const G4Step* step, G4SteppingManager*) {
  Geant4StepHandler h(step);
#if 0
  Geant4TouchableHandler pre_handler(step);
  string prePath = pre_handler.path();
  Geant4TouchableHandler post_handler(step);
  string postPath = post_handler.path();
#endif
  G4LogicalVolume* logVol = h.logvol(h.pre);
  m_steps.emplace_back(new StepInfo(h.prePos(), h.postPos(), logVol));
}

/// Registered callback on Begin-event
void Geant4MaterialScanner::beginEvent(const G4Event* /* event */)   {
Markus Frank's avatar
Markus Frank committed
  for_each(m_steps.begin(),m_steps.end(),detail::DestroyObject<StepInfo*>());
  m_steps.clear();
  m_sumX0 = 0;
  m_sumLambda = 0;
  m_sumPath = 0;
}

/// Begin-of-tracking callback
void Geant4MaterialScanner::begin(const G4Track* track) {
  printP2("Starting tracking action for track ID=%d",track->GetTrackID());
Markus Frank's avatar
Markus Frank committed
  for_each(m_steps.begin(),m_steps.end(),detail::DestroyObject<StepInfo*>());
  m_steps.clear();
  m_sumX0 = 0;
  m_sumLambda = 0;
  m_sumPath = 0;
}

/// End-of-tracking callback
void Geant4MaterialScanner::end(const G4Track* track) {
  if ( !m_steps.empty() )  {
    constexpr const char* line = " +--------------------------------------------------------------------------------------------------------------------------------------------------\n";
    constexpr const char* fmt1 = " | %5d %-20s %3.0f %8.3f %8.4f %11.4f  %11.4f %10.3f %8.2f %11.6f %11.6f  (%7.2f,%7.2f,%7.2f)\n";
    constexpr const char* fmt2 = " | %5d %-20s %3.0f %8.3f %8.4f %11.6g  %11.6g %10.3f %8.2f %11.6f %11.6f  (%7.2f,%7.2f,%7.2f)\n";
    const Position& pre = m_steps[0]->pre;
    const Position& post = m_steps[m_steps.size()-1]->post;

    ::printf("%s + Material scan between: x_0 = (%7.2f,%7.2f,%7.2f) [cm] and x_1 = (%7.2f,%7.2f,%7.2f) [cm]  TrackID:%d: \n%s",
             line,pre.X()/CLHEP::cm,pre.Y()/CLHEP::cm,pre.Z()/CLHEP::cm,post.X()/CLHEP::cm,post.Y()/CLHEP::cm,post.Z()/CLHEP::cm,track->GetTrackID(),line);
    ::printf(" |     \\   %-11s        Atomic                 Radiation   Interaction               Path   Integrated  Integrated    Material\n","Material");
    ::printf(" | Num. \\  %-11s   Number/Z   Mass/A  Density    Length       Length    Thickness   Length      X0        Lambda      Endpoint  \n","Name");
    ::printf(" | Layer \\ %-11s            [g/mole]  [g/cm3]     [cm]        [cm]          [cm]      [cm]     [cm]        [cm]     (     cm,     cm,     cm)\n","");
    ::printf("%s",line);
    int count = 1;
    for(Steps::const_iterator i=m_steps.begin(); i!=m_steps.end(); ++i, ++count)  {
      const G4LogicalVolume* logVol = (*i)->volume;
      G4Material* material = logVol->GetMaterial();
      const Position& prePos  = (*i)->pre;
      const Position& postPos = (*i)->post;
      Position direction = postPos - prePos;
      double length  = direction.R()/CLHEP::cm;
      double intLen  = material->GetNuclearInterLength()/CLHEP::cm;
      double radLen  = material->GetRadlen()/CLHEP::cm;
      double density = material->GetDensity()/(CLHEP::gram/CLHEP::cm3);
      double nLambda = length / intLen;
      double nx0     = length / radLen;
      double Aeff    = 0.0;
      double Zeff    = 0.0;
      const char* fmt = radLen >= 1e5 ? fmt2 : fmt1;
      const double* fractions = material->GetFractionVector();
      for(size_t j=0; j<material->GetNumberOfElements(); ++j)  {
        Zeff += fractions[j]*(material->GetElement(j)->GetZ());
        Aeff += fractions[j]*(material->GetElement(j)->GetA())/CLHEP::gram;
      }
      m_sumX0     += nx0;
      m_sumLambda += nLambda;
      m_sumPath   += length;
      ::printf(fmt,count,material->GetName().c_str(),
               Zeff, Aeff, density, radLen, intLen, length,
               m_sumPath,m_sumX0,m_sumLambda,
               postPos.X()/CLHEP::cm,postPos.Y()/CLHEP::cm,postPos.Z()/CLHEP::cm);
Markus Frank's avatar
Markus Frank committed
    for_each(m_steps.begin(),m_steps.end(),detail::DestroyObject<StepInfo*>());