Skip to content
Snippets Groups Projects
Geant4XMLSetup.cpp 21.1 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
Markus Frank's avatar
Markus Frank committed
#include "DD4hep/Detector.h"
#include "DD4hep/Printout.h"
#include "DD4hep/DetFactoryHelper.h"
#include "XML/Conversions.h"
#include "DDG4/Geant4Config.h"

/// Namespace for the AIDA detector description toolkit
Markus Frank's avatar
Markus Frank committed
namespace dd4hep {
  // Forward declarations
  class ActionSequence;
  using namespace std;
Markus Frank's avatar
Markus Frank committed
  using namespace dd4hep::sim;
  using namespace dd4hep::sim::Setup;

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

    // Forward declarations
    class XMLSetup;
    /// Action cast
    template <typename TYPE, typename PTR> TYPE* _action(PTR* in)  {
      return dynamic_cast<TYPE*>(in);

    /// Install Geant4 mesenger to action objects
    template <typename T> static void installMessenger(const T& handle)  {
      handle->installMessengers();

    /// Set the properties of a Geant4 Action object from XML object attributes
    template <typename T> static void _setAttributes(const T& handle, xml_h& e)  {
Markus Frank's avatar
Markus Frank committed
      xml::Handle_t props(e);
      // Now we set the object properties
Markus Frank's avatar
Markus Frank committed
      vector<xml::Attribute> attrs = props.attributes();
      for(vector<xml::Attribute>::iterator i=attrs.begin(); i!=attrs.end(); ++i)   {
        xml::Attribute a = *i;
        handle[xml::_toString(props.attr_name(a))].str(props.attr<string>(a));
Andre Sailer's avatar
Andre Sailer committed
    /// Set the properties of a Geant4 Action object from \<properties/\> XML subsection
    template <typename T> static void _setProperties(const T& handle, xml_h& e)  {
      xml_comp_t action(e);
      // Now we set the object properties
Markus Frank's avatar
Markus Frank committed
      xml::Handle_t  props = action.child(_Unicode(properties),false);
      if ( props )  {
      }
      if ( action.hasAttr(_Unicode(Control)) )   {
        handle["Control"].str(props.attr<string>(_Unicode(Control)));
    /// Create/Configure Geant4 sensitive action object from XML
Markus Frank's avatar
Markus Frank committed
    static Action _convertSensitive(Detector& description, xml_h e, const string& detector)  {
      xml_comp_t action(e);
Markus Frank's avatar
Markus Frank committed
      Kernel& kernel = Kernel::instance(description);
      TypeName tn = TypeName::split(action.attr<string>(_U(name)));
      // Create the object using the factory method
      Sensitive handle(kernel,action.attr<string>(_U(name)),detector);
      _setProperties(Action(handle.get()),e);
      for(xml_coll_t f(e,_Unicode(filter)); f; ++f)  {
        string nam = f.attr<string>(_U(name));
        Filter filter(kernel.globalFilter(nam,false));
        handle->adopt(filter);
      }
      installMessenger(handle);
      printout(INFO,"Geant4Setup","+++ Added sensitive element %s of type %s",
      return Action(handle);
    }

    /// Create/Configure Action object from XML
Markus Frank's avatar
Markus Frank committed
    static Action _convertAction(Detector& description, xml_h e)  {
      xml_comp_t action(e);
Markus Frank's avatar
Markus Frank committed
      Kernel& kernel = Kernel::instance(description);
      TypeName tn = TypeName::split(action.attr<string>(_U(name)));
      // Create the object using the factory method
      Action handle(kernel,action.attr<string>(_U(name)));
      _setProperties(handle,e);
      printout(INFO,"Geant4Setup","+++ Added action %s of type %s",tn.second.c_str(),tn.first.c_str());
      installMessenger(handle);
      if ( action.hasChild(_Unicode(adopt)) )  {
        xml_comp_t child = action.child(_Unicode(adopt));
        Geant4Action* user = kernel.globalAction(child.nameStr());
        Geant4ParticleHandler* ph = dynamic_cast<Geant4ParticleHandler*>(handle.get());
        if ( ph )  {
          ph->adopt(user);
        }
      return handle;
    enum { SENSITIVE, ACTION, FILTER };
    /// Create/Configure Action object from XML
Markus Frank's avatar
Markus Frank committed
    Action _createAction(Detector& description, xml_h a, const string& seqType, int what)  {
      string   nam = a.attr<string>(_U(name));
      TypeName typ    = TypeName::split(nam);
Markus Frank's avatar
Markus Frank committed
      Kernel&  kernel = Kernel::instance(description);
      Action action((what==FILTER) ? (Geant4Action*)kernel.globalFilter(typ.second,false)
                    : (what==ACTION) ? kernel.globalAction(typ.second,false)
                    ///  : (what==FILTER) ? kernel.globalAction(typ.second,false)
                    : 0);
      // Create the object using the factory method
      if ( !action )  {
Markus Frank's avatar
Markus Frank committed
        action = (what == SENSITIVE) ? Action(_convertSensitive(description, a, seqType))
          : (what==ACTION) ? _convertAction(description, a)
          : (what==FILTER) ? _convertAction(description, a)
          : Action();
        if ( !action )  {
          throw runtime_error(format("Geant4ActionSequence","DDG4: The action '%s'"
                                     " cannot be created. [Action-Missing]",nam.c_str()));
        }
      return action;
  /// Convert Geant4Action objects
  /**
   *  <actions>
   *    <action name="Geant4PostTrackingAction/PostTrackAction"
   *         NAME1="Value1"
   *         NAME2="Value2" />
   *    </action>
   *  </actions>
   */
  template <> void Converter<Action>::operator()(xml_h e)  const  {
Markus Frank's avatar
Markus Frank committed
    Action a = _convertAction(description, e);
    Kernel::instance(description).registerGlobalAction(a);
  /// Convert Sensitive detector filters
  /**
   *  Note: Filters are Geant4Actions and - if global - may also receive properties!
   *
   *  <filters>
   *    <filter name="GeantinoRejector"/>
   *    <filter name="EnergyDepositMinimumCut">
   *      <properties cut="10*MeV"/>
   *    </filter>
   *  </filters>
   */
  template <> void Converter<Filter>::operator()(xml_h e)  const  {
Markus Frank's avatar
Markus Frank committed
    Action a = _convertAction(description, e);
    Kernel::instance(description).registerGlobalFilter(a);
  /// Convert Geant4Phase objects
  /**
   *  <phases>
   *    <phase name="Geant4PostTrackingPhase/PostTrackPhase"
   *         NAME1="Value1"
   *         NAME2="Value2" />
   *    </phase>
   *  </phases>
   */
  template <> void Converter<Phase>::operator()(xml_h e)  const  {
    xml_comp_t x_phase(e);
Markus Frank's avatar
Markus Frank committed
    Kernel& kernel = Kernel::instance(description);
    string nam = x_phase.attr<string>(_U(type));
    typedef Geant4ActionPhase PH;
    Phase p;

    if ( nam == "RunAction/begin" )  {
      void (Geant4ActionPhase::*func)(const G4Run*) = &Geant4ActionPhase::call;
      kernel.runAction().callAtBegin((p=kernel.addPhase<const G4Run*>(nam)).get(),func);
      //&Geant4ActionPhase::call<const G4Run*>);
    }
    else if ( nam == "RunAction/end" )  {
      void (Geant4ActionPhase::*func)(const G4Run*) = &Geant4ActionPhase::call;
      kernel.runAction().callAtEnd((p=kernel.addPhase<const G4Run*>(nam)).get(),func);
      //&PH::call<const G4Run*>);
    }
    else if ( nam == "EventAction/begin" )  {
      void (Geant4ActionPhase::*func)(const G4Event*) = &Geant4ActionPhase::call;
      kernel.eventAction().callAtBegin((p=kernel.addPhase<const G4Event*>(nam)).get(),func);
      //&PH::call<const G4Event*>);
    }
    else if ( nam == "EventAction/end" )  {
      void (Geant4ActionPhase::*func)(const G4Event*) = &Geant4ActionPhase::call;
      kernel.eventAction().callAtEnd((p=kernel.addPhase<const G4Event*>(nam)).get(),func);
      //&PH::call<const G4Event*>);
    }
    else if ( nam == "TrackingAction/begin" )  {
      void (Geant4ActionPhase::*func)(const G4Track*) = &Geant4ActionPhase::call;
      kernel.trackingAction().callAtBegin((p=kernel.addPhase<const G4Track*>(nam)).get(),func);
      //&PH::call<const G4Track*>);
    }
    else if ( nam == "TrackingAction/end" )  {
      void (Geant4ActionPhase::*func)(const G4Track*) = &Geant4ActionPhase::call;
      kernel.trackingAction().callAtEnd((p=kernel.addPhase<const G4Track*>(nam,false)).get(),func);
      //&PH::call<const G4Track*>);
    }
    else if ( nam == "StackingAction/newStage" )  {
      kernel.stackingAction().callAtNewStage((p=kernel.addPhase<void>(nam,false)).get(),&PH::call);
    }
    else if ( nam == "StackingAction/prepare" )  {
      kernel.stackingAction().callAtPrepare((p=kernel.addPhase<void>(nam,false)).get(),&PH::call);
    }
    else if ( nam == "SteppingAction" )  {
      void (Geant4ActionPhase::*func)(const G4Step*,G4SteppingManager*) = &Geant4ActionPhase::call;
      kernel.steppingAction().call((p=kernel.addPhase<const G4Step*>(nam)).get(),func);
      //&PH::call<const G4Step*,G4SteppingManager*>);
    }
    else if ( nam == "GeneratorAction/primaries" )  {
      void (Geant4ActionPhase::*func)(G4Event*) = &Geant4ActionPhase::call;
      kernel.generatorAction().call((p=kernel.addPhase<G4Event*>(nam)).get(),func);
      //&PH::call<G4Event*>);
    }
    else   {
      TypeName tn = TypeName::split(nam);
Markus Frank's avatar
Markus Frank committed
      DetElement det = description.detector(tn.first);
      if ( !det.isValid() )   {
        throw runtime_error(format("Phase","DDG4: The phase '%s' of type SensitiveSeq"
                                   " cannot be attached to a non-existing detector"
                                   " [Detector-Missing]",nam.c_str()));
Markus Frank's avatar
Markus Frank committed
      SensitiveDetector sd = description.sensitiveDetector(tn.first);
      if ( !sd.isValid() )  {
        throw runtime_error(format("Phase","DDG4: The phase '%s' of type SensitiveSeq"
                                   " cannot be attached to a non-existing sensitive detector"
                                   " [Sensitive-Missing]",nam.c_str()));
      }
      SensitiveSeq sdSeq = SensitiveSeq(kernel,tn.first);
      if ( tn.second == "begin" )
        sdSeq->callAtBegin((p=kernel.addPhase<G4HCofThisEvent*>(tn.second)).get(),
                           &PH::call<G4HCofThisEvent*>);
      else if ( tn.second == "end" )
        sdSeq->callAtEnd((p=kernel.addPhase<G4HCofThisEvent*>(tn.second)).get(),
                         &PH::call<G4HCofThisEvent*>);
      else if ( tn.second == "clear" )
        sdSeq->callAtClear((p=kernel.addPhase<G4HCofThisEvent*>(tn.second)).get(),
                           &PH::call<G4HCofThisEvent*>);
      else if ( tn.second == "process" )
        sdSeq->callAtProcess((p=kernel.addPhase<G4Step*>(tn.second)).get(),
                             &PH::call<G4Step*,G4TouchableHistory*>);
      else
        throw runtime_error(format("Phase","DDG4: The phase '%s' of type SensitiveSeq"
                                   " cannot be attached to the call '%s'."
                                   " [Callback-Missing]",tn.first.c_str(), tn.second.c_str()));
  /// Convert Action sequences into objects
  /**
   *  <sequences>
   *    <sequence name="Geant4EventActionSequence/EventAction"
   *      <member name="" type="Geant4TrackerEventMonitor/TrackerEvtAction"/>
   *    </sequence>
   *    <sequence name="Geant4SensdetActionSequence/SiVertexBarrel"
   *      <member type="Geant4TrackerSensitiveMonitor/TrackerHitMonitor">
   *           NAME1="Value1"
   *           NAME2="Value2" />
   *      </member>
   *    </sequence>
   *  </sequences>
   */
  template <> void Converter<ActionSequence>::operator()(xml_h e)  const  {
    xml_comp_t seq(e);
    SensitiveSeq sdSeq;
    string       seqNam;
    TypeName     seqType;
    int          what = ACTION;
Markus Frank's avatar
Markus Frank committed
    Kernel& kernel = Kernel::instance(description);

    if ( seq.hasAttr(_U(sd)) )   {
      string sd_nam = seq.attr<string>(_U(sd));
Markus Frank's avatar
Markus Frank committed
      SensitiveDetector sensitive = description.sensitiveDetector(sd_nam);
      seqNam  = seq.attr<string>(_U(type))+"/"+sd_nam;
      if ( !sensitive.isValid() )  {
        printout(ALWAYS,"Geant4Setup","+++ ActionSequence %s is defined, "
                 "but no sensitive detector present.",seqNam.c_str());
        printout(ALWAYS,"Geant4Setup","+++ ---> Sequence for detector %s IGNORED on popular request!",
                 sd_nam.c_str());
        return;
      seqType = TypeName::split(seqNam);
      sdSeq   = SensitiveSeq(kernel,seqNam);
      what    = SENSITIVE;
    }
    else {
      seqNam = seq.attr<string>(_U(name));
      seqType = TypeName::split(seqNam);
    }
    printout(INFO,"Geant4Setup","+++ ActionSequence %s of type %s added.",
             seqType.second.c_str(),seqType.first.c_str());

    if ( seqType.second == "PhysicsList" )  {
      PhysicsActionSeq pl(&kernel.physicsList());
Markus Frank's avatar
Markus Frank committed
      PropertyManager& props = kernel.physicsList().properties();
      props.dump();
      _setAttributes(pl,e);
Markus Frank's avatar
Markus Frank committed
      props.dump();
    }

    for(xml_coll_t a(seq,_Unicode(action)); a; ++a)  {
      string   nam = a.attr<string>(_U(name));
Markus Frank's avatar
Markus Frank committed
      Action action(_createAction(description,a,seqType.second,what));
      if ( seqType.second == "RunAction" )
Markus Frank's avatar
Markus Frank committed
        kernel.runAction().adopt(_action<Geant4RunAction>(action.get()));
      else if ( seqType.second == "EventAction" )
Markus Frank's avatar
Markus Frank committed
        kernel.eventAction().adopt(_action<Geant4EventAction>(action.get()));
      else if ( seqType.second == "GeneratorAction" )
Markus Frank's avatar
Markus Frank committed
        kernel.generatorAction().adopt(_action<Geant4GeneratorAction>(action.get()));
      else if ( seqType.second == "TrackingAction" )
Markus Frank's avatar
Markus Frank committed
        kernel.trackingAction().adopt(_action<Geant4TrackingAction>(action.get()));
      else if ( seqType.second == "StackingAction" )
Markus Frank's avatar
Markus Frank committed
        kernel.stackingAction().adopt(_action<Geant4StackingAction>(action.get()));
      else if ( seqType.second == "SteppingAction" )
Markus Frank's avatar
Markus Frank committed
        kernel.steppingAction().adopt(_action<Geant4SteppingAction>(action.get()));
      else if ( seqType.second == "PhysicsList" )
Markus Frank's avatar
Markus Frank committed
        kernel.physicsList().adopt(_action<Geant4PhysicsList>(action.get()));
      else if ( sdSeq.get() )
Markus Frank's avatar
Markus Frank committed
        sdSeq->adopt(_action<Geant4Sensitive>(action.get()));
      else   {
        throw runtime_error(format("ActionSequence","DDG4: The action '%s'"
                                   " cannot be attached to any sequence '%s'."
                                   " [Sequence-Missing]",nam.c_str(), seqNam.c_str()));
      printout(INFO,"Geant4Setup","+++ ActionSequence %s added filter object:%s",
               seqType.second.c_str(),action->name().c_str());
    }
    if ( what == SENSITIVE )  {
      for(xml_coll_t a(seq,_Unicode(filter)); a; ++a)  {
Markus Frank's avatar
Markus Frank committed
        Action action(_createAction(description,a,"",FILTER));
        installMessenger(action);
        printout(INFO,"Geant4Setup","+++ ActionSequence %s added filter object:%s",
                 seqType.second.c_str(),action->name().c_str());
        if ( sdSeq.get() )
Markus Frank's avatar
Markus Frank committed
          sdSeq->adopt(_action<Geant4Filter>(action.get()));
        else   {
          throw runtime_error(format("ActionSequence","DDG4: The action '%s'"
                                     " cannot be attached to any sequence '%s'."
                                     " [Sequence-Missing]",nam.c_str(), seqNam.c_str()));
        }
  /// Create/Configure PhysicsList objects
  /**
   *  <physicslist>
   *    <processes>
   *      <particle name="'e-'">
   *        <process name="G4eMultipleScattering" ordAtRestDoIt="-1" ordAlongSteptDoIt="1" ordPostStepDoIt="1"/>
   *        <process name="G4eIonisation"         ordAtRestDoIt="-1" ordAlongSteptDoIt="2" ordPostStepDoIt="2"/>
   *      </particle>
   *    </processes>
   *  </physicslist>
   */
  template <> void Converter<Geant4PhysicsList::ParticleProcesses>::operator()(xml_h e) const {
    xml_comp_t part(e);
    string part_name = part.nameStr();
    Geant4PhysicsList::ParticleProcesses& procs =
      _object<Geant4PhysicsList>().processes(part_name);
    for(xml_coll_t q(part,_Unicode(process)); q; ++q)  {
      xml_comp_t proc(q);
      Geant4PhysicsList::Process p;
      p.name = proc.nameStr();
      p.ordAtRestDoIt     = proc.attr<int>(_Unicode(ordAtRestDoIt));
      p.ordAlongSteptDoIt = proc.attr<int>(_Unicode(ordAlongSteptDoIt));
      p.ordPostStepDoIt   = proc.attr<int>(_Unicode(ordPostStepDoIt));
      procs.push_back(p);
      printout(INFO,"Geant4Setup","+++ Converter<ParticleProcesses: Particle:%s add process %s %d %d %d",
               part_name.c_str(),p.name.c_str(),p.ordAtRestDoIt,p.ordAlongSteptDoIt,p.ordPostStepDoIt);
  /// Create/Configure PhysicsList objects: Particle constructors
  /**
   *  <physicslist>
   *    <particles>
   *      <construct name="G4Electron"/>
   *      <construct name="G4Gamma"/>
   *      <construct name="G4BosonConstructor"/>
   *      <construct name="G4LeptonConstructor"/>
   *      <construct name="G4BaryonConstructor"/>
   *    </particles>
   *  </physicslist>
   */
  template <> void Converter<Geant4PhysicsList::ParticleConstructor>::operator()(xml_h e) const {
    Geant4PhysicsList::ParticleConstructors& parts = _object<Geant4PhysicsList>().particles();
    xml_comp_t part(e);
    string n = part.nameStr();
    parts.push_back(n);
    printout(INFO,"Geant4Setup","+++ ParticleConstructor: Add Geant4 particle constructor '%s'",n.c_str());
  /// Create/Configure PhysicsList objects: Physics constructors
  /**
   *  <physicslist>
   *    <physics>
   *      <construct name="G4EmStandardPhysics"/>
   *      <construct name="HadronPhysicsQGSP"/>
   *    </physics>
   *  </physicslist>
   */
  template <> void Converter<Geant4PhysicsList::PhysicsConstructor>::operator()(xml_h e) const {
    Geant4PhysicsList::PhysicsConstructors& parts = _object<Geant4PhysicsList>().physics();
    xml_comp_t part(e);
    string n = part.nameStr();
    parts.push_back(n);
    printout(INFO,"Geant4Setup","+++ PhysicsConstructor: Add Geant4 physics constructor '%s'",n.c_str());
  }

  /// Create/Configure PhysicsList extension objects: Predefined Geant4 Physics lists
  /**
   *  <physicslist>
   *    <list name="TQGSP_FTFP_BERT_95"/>
   *  </physicslist>
   *  Note: list items are Geant4Actions and - if global - may receive properties!
   */
  struct PhysicsListExtension;
  template <> void Converter<PhysicsListExtension>::operator()(xml_h e) const {
Markus Frank's avatar
Markus Frank committed
    Kernel& kernel = Kernel::instance(description);
    string ext = xml_comp_t(e).nameStr();
    kernel.physicsList().properties()["extends"].str(ext);
    printout(INFO,"Geant4Setup","+++ PhysicsListExtension: Set predefined Geant4 physics list to '%s'",ext.c_str());
  /// Create/Configure PhysicsList objects: Predefined Geant4 Physics lists
  template <> void Converter<PhysicsList>::operator()(xml_h e)  const  {
    string name = e.attr<string>(_U(name));
Markus Frank's avatar
Markus Frank committed
    Kernel& kernel = Kernel::instance(description);
    PhysicsList handle(kernel,name);
    _setAttributes(handle,e);
Markus Frank's avatar
Markus Frank committed
    xml_coll_t(e,_Unicode(particles)).for_each(_Unicode(construct),Converter<Geant4PhysicsList::ParticleConstructor>(description,handle.get()));
    xml_coll_t(e,_Unicode(processes)).for_each(_Unicode(particle),Converter<Geant4PhysicsList::ParticleProcesses>(description,handle.get()));
    xml_coll_t(e,_Unicode(physics)).for_each(_Unicode(construct),Converter<Geant4PhysicsList::PhysicsConstructor>(description,handle.get()));
    xml_coll_t(e,_Unicode(extends)).for_each(Converter<PhysicsListExtension>(description,handle.get()));
    kernel.physicsList().adopt(handle);
  }

  /// Create/Configure Geant4Kernel objects
  template <> void Converter<Kernel>::operator()(xml_h e) const {
Markus Frank's avatar
Markus Frank committed
    Kernel& kernel = Kernel::instance(description);
    xml_comp_t k(e);
      kernel.property("NumEvents").str(k.attr<string>(_Unicode(NumEvents)));
      kernel.property("UI").str(k.attr<string>(_Unicode(UI)));
  }

  /// Main entry point to configure Geant4 with XML
  template <> void Converter<XMLSetup>::operator()(xml_h seq)  const  {
    xml_elt_t compact(seq);
    // First execute the basic setup from the plugins module
Markus Frank's avatar
Markus Frank committed
    long result = PluginService::Create<long>("geant4_XML_reader",&description,&seq);
    if ( 0 == result )  {
Markus Frank's avatar
Markus Frank committed
      throw runtime_error("dd4hep: Failed to locate plugin to interprete files of type"
                          " \"" + seq.tag() + "\" - no factory of type geant4_XML_reader.");
    }
    result = *(long*) result;
    if (result != 1) {
Markus Frank's avatar
Markus Frank committed
      throw runtime_error("dd4hep: Failed to parse the XML tag " + seq.tag() + " with the plugin geant4_XML_reader");
Markus Frank's avatar
Markus Frank committed
    xml_coll_t(compact,_Unicode(kernel)).for_each(Converter<Kernel>(description,param));
    // Now deal with the new stuff.....
Markus Frank's avatar
Markus Frank committed
    xml_coll_t(compact,_Unicode(actions) ).for_each(_Unicode(action),Converter<Action>(description,param));
    xml_coll_t(compact,_Unicode(filters) ).for_each(_Unicode(filter),Converter<Filter>(description,param));
    xml_coll_t(compact,_Unicode(sequences) ).for_each(_Unicode(sequence),Converter<ActionSequence>(description,param));
    xml_coll_t(compact,_Unicode(phases) ).for_each(_Unicode(phase),Converter<Phase>(description,param));
    xml_coll_t(compact,_Unicode(physicslist)).for_each(Converter<PhysicsList>(description,param));

/// Factory method
Markus Frank's avatar
Markus Frank committed
static long setup_Geant4(dd4hep::Detector& description, const xml_h& element) {
  (dd4hep::Converter<dd4hep::sim::XMLSetup>(description))(element);
  return 1;
}
// Factory declaration
DECLARE_XML_DOC_READER(geant4_setup,setup_Geant4)