diff --git a/DDCore/include/DD4hep/detail/ObjectsInterna.h b/DDCore/include/DD4hep/detail/ObjectsInterna.h index 9cfce7c7be5e67783d7c6efd857777b4bcca3505..c0f98d6e3ce3eaeab8f1380ef954c475b7f24923 100644 --- a/DDCore/include/DD4hep/detail/ObjectsInterna.h +++ b/DDCore/include/DD4hep/detail/ObjectsInterna.h @@ -88,9 +88,9 @@ namespace dd4hep { class VisAttrObject: public NamedObject { public: unsigned long magic; - TColor* col; - int color; - float alpha; + TColor* col; + int color; + float alpha; unsigned char drawingStyle, lineStyle, showDaughters, visible; /// Standard constructor VisAttrObject(); @@ -169,11 +169,11 @@ namespace dd4hep { class ReadoutObject: public NamedObject { public: /// Handle to the readout segmentation - Segmentation segmentation; //! not ROOT-persistent + Segmentation segmentation; //! not ROOT-persistent /// Handle to the volume - Volume readoutWorld; + Volume readoutWorld; /// Handle to the field descriptor - IDDescriptor id; + IDDescriptor id; /// Hit collection container (if defined) std::vector<HitCollection> hits; /// Standard constructor @@ -195,9 +195,9 @@ namespace dd4hep { typedef std::vector<std::pair<std::string, const BitFieldElement*> > FieldMap; typedef std::vector<std::pair<size_t, std::string> > FieldIDs; /// Map of id-fields in the descriptor - FieldMap fieldMap; + FieldMap fieldMap; /// String map of id descriptors - FieldIDs fieldIDs; + FieldIDs fieldIDs; /// Decoder object BitFieldCoder decoder; diff --git a/DDCore/src/plugins/Compact2Objects.cpp b/DDCore/src/plugins/Compact2Objects.cpp index d0e6555073cfe67a6e0f3a3dcc03f7246d7a3bac..391849e7ca184b05d72ad3bdf83c1f81f16941c3 100644 --- a/DDCore/src/plugins/Compact2Objects.cpp +++ b/DDCore/src/plugins/Compact2Objects.cpp @@ -595,11 +595,11 @@ template <> void Converter<VisAttr>::operator()(xml_h e) const { * */ template <> void Converter<Region>::operator()(xml_h elt) const { - xml_dim_t e = elt; - Region region(e.nameStr()); - vector<string>&limits = region.limits(); - xml_attr_t cut = elt.attr_nothrow(_U(cut)); - xml_attr_t threshold = elt.attr_nothrow(_U(threshold)); + xml_dim_t e = elt; + Region region(e.nameStr()); + vector<string>& limits = region.limits(); + xml_attr_t cut = elt.attr_nothrow(_U(cut)); + xml_attr_t threshold = elt.attr_nothrow(_U(threshold)); xml_attr_t store_secondaries = elt.attr_nothrow(_U(store_secondaries)); double ene = e.eunit(1.0), len = e.lunit(1.0); diff --git a/cmake/DD4hepBuild.cmake b/cmake/DD4hepBuild.cmake index 386b0004b69e32883ed00cfc4a766428ea091541..797a6095fd4398a83415c55ac344c22cd2aeba3e 100644 --- a/cmake/DD4hepBuild.cmake +++ b/cmake/DD4hepBuild.cmake @@ -1249,7 +1249,7 @@ function( dd4hep_add_dictionary dictionary ) if ( "${enabled}" STREQUAL "OFF" ) dd4hep_skipmsg ( "${tag} DISBALED -- package is not built!" ) else() - cmake_parse_arguments(ARG "" "" "SOURCES;EXCLUDE;LINKDEF;OPTIONS;OPTIONAL;INCLUDES" ${ARGN} ) + cmake_parse_arguments(ARG "" "" "SOURCES;EXCLUDE;LINKDEF;OPTIONS;OPTIONAL;INCLUDES;OUTPUT" ${ARGN} ) dd4hep_print ( "|++> ${tag} Building dictionary ..." ) if("${ARG_LINKDEF}" STREQUAL "") set(ARG_LINKDEF "${CMAKE_SOURCE_DIR}/DDCore/include/ROOT/LinkDef.h") @@ -1311,14 +1311,16 @@ function( dd4hep_add_dictionary dictionary ) dd4hep_debug ( "${tag} Unparsed:'${ARG_UNPARSED_ARGUMENTS}'" ) dd4hep_debug ( "${tag} Sources: '${CMAKE_CURRENT_SOURCE_DIR}'" ) # + set ( output_dir ${CMAKE_CURRENT_BINARY_DIR}/../lib ) + if ( NOT "${ARG_OUTPUT}" STREQUAL "" ) + set ( output_dir ${ARG_OUTPUT} ) + endif() add_custom_command(OUTPUT ${dictionary}.cxx COMMAND ${ROOT_rootcling_CMD} -cint -f ${dictionary}.cxx - -s ${CMAKE_CURRENT_BINARY_DIR}/../lib/${dictionary} -inlineInputHeader -c -p ${ARG_OPTIONS} ${comp_defs} -std=c++${CMAKE_CXX_STANDARD} ${inc_dirs} ${headers} ${linkdefs} + -s ${output_dir}/${dictionary} -inlineInputHeader -c -p ${ARG_OPTIONS} ${comp_defs} -std=c++${CMAKE_CXX_STANDARD} ${inc_dirs} ${headers} ${linkdefs} DEPENDS ${headers} ${linkdefs} ) # Install the binary to the destination directory - #set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/../lib/${dictionary}_rdict.pcm PROPERTIES GENERATED TRUE ) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/../lib/${dictionary}_rdict.pcm DESTINATION lib) - #set_source_files_properties( ${dictionary}.h ${dictionary}.cxx PROPERTIES GENERATED TRUE ) + install(FILES ${output_dir}/${dictionary}_rdict.pcm DESTINATION lib) endif() endfunction() diff --git a/examples/ClientTests/CMakeLists.txt b/examples/ClientTests/CMakeLists.txt index f7d19a0c463c45a9ac834e47ac442ad81635154a..6d229804101ffbbb96f9ca85a0ee82ebe226bd2e 100644 --- a/examples/ClientTests/CMakeLists.txt +++ b/examples/ClientTests/CMakeLists.txt @@ -233,4 +233,12 @@ if (DD4HEP_USE_GEANT4) REGEX_PASS NONE REGEX_FAIL "Exception;EXCEPTION;ERROR;Error" ) endforeach(script) + + dd4hep_add_test_reg( ClientTests_sim_UserAnalysis + COMMAND "${CMAKE_INSTALL_PREFIX}/bin/run_test_ClientTests.sh" + EXEC_ARGS python ${CMAKE_CURRENT_SOURCE_DIR}/scripts/MiniTelEnergyDeposits.py batch + REQUIRES DDG4 Geant4 + REGEX_PASS "Entries : 200 " + REGEX_FAIL "Exception;EXCEPTION;ERROR;Error" ) + endif(DD4HEP_USE_GEANT4) diff --git a/examples/ClientTests/scripts/MiniTelEnergyDeposits.py b/examples/ClientTests/scripts/MiniTelEnergyDeposits.py new file mode 100644 index 0000000000000000000000000000000000000000..3a6c40d3b25204c65998a26eb9b0eadf6df3a1ef --- /dev/null +++ b/examples/ClientTests/scripts/MiniTelEnergyDeposits.py @@ -0,0 +1,67 @@ +import os, sys, time, DDG4 +from DDG4 import OutputLevel as Output +from SystemOfUnits import * +# +# +""" + + dd4hep example setup using the python configuration + + \author M.Frank + \version 1.0 + +""" +def run(): + kernel = DDG4.Kernel() + install_dir = os.environ['DD4hepINSTALL'] + kernel.setOutputLevel('Geant4Converter',Output.DEBUG) + kernel.setOutputLevel('Gun',Output.INFO) + kernel.loadGeometry("file:"+install_dir+"/examples/ClientTests/compact/MiniTel.xml") + + geant4 = DDG4.Geant4(kernel) + geant4.printDetectors() + geant4.setupCshUI() + if len(sys.argv) >= 2 and sys.argv[1] =="batch": + kernel.NumEvents = 200 + kernel.UI = '' + + # Configure field + field = geant4.setupTrackingField(prt=True) + # Setup particle gun + geant4.setupGun("Gun",particle='pi-',energy=100*GeV,multiplicity=1) + # Now the calorimeters + seq,act = geant4.setupTracker('MyLHCBdetector1') + seq,act = geant4.setupTracker('MyLHCBdetector2') + seq,act = geant4.setupTracker('MyLHCBdetector3') + seq,act = geant4.setupTracker('MyLHCBdetector4') + act.OutputLevel = 4 + seq,act = geant4.setupTracker('MyLHCBdetector5') + seq,act = geant4.setupTracker('MyLHCBdetector6') + seq,act = geant4.setupTracker('MyLHCBdetector7') + seq,act = geant4.setupTracker('MyLHCBdetector8') + seq,act = geant4.setupTracker('MyLHCBdetector9') + seq,act = geant4.setupTracker('MyLHCBdetector10') + + # And handle the simulation particles. + part = DDG4.GeneratorAction(kernel,"Geant4ParticleHandler/ParticleHandler") + kernel.generatorAction().adopt(part) + part.SaveProcesses = ['conv','Decay'] + part.MinimalKineticEnergy = 1*MeV + part.OutputLevel = 5 # generator_output_level + part.enableUI() + + hit_tuple = DDG4.EventAction(kernel,'HitTupleAction/MiniTelTuple',True) + hit_tuple.OutputFile = 'MiniTel_EnergyDeposits_'+time.strftime('%Y-%m-%d_%H-%M')+'.root' + hit_tuple.Collections = ['*'] + kernel.eventAction().add(hit_tuple) + + + # Now build the physics list: + phys = kernel.physicsList() + phys.extends = 'QGSP_BERT' + phys.enableUI() + # and run + geant4.execute() + +if __name__ == "__main__": + run() diff --git a/examples/DDG4/CMakeLists.txt b/examples/DDG4/CMakeLists.txt index 7985b31ef8a7be2a8a406432a484d578451d736e..6555e6789b054fc372c555d08437f15af84a656b 100644 --- a/examples/DDG4/CMakeLists.txt +++ b/examples/DDG4/CMakeLists.txt @@ -20,6 +20,22 @@ dd4hep_package ( DDG4 MAJOR 0 MINOR 0 PATCH 1 #---Geant4 Testsing----------------------------------------------------------------- # if (DD4HEP_USE_GEANT4) + # + #---- Dictionary of classes to be written to the ROOT file -------------------- + dd4hep_add_dictionary(G__DDG4UserDict + SOURCES ${DD4hep_DIR}/include/ROOT/Warnings.h src/Dictionary.h + LINKDEF ${DD4hep_DIR}/include/ROOT/LinkDef.h + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/lib + ) + #---- Example of a client library with user defined plugins -------------------- + dd4hep_add_plugin( DDG4UserLib + GENERATED G__DDG4UserDict.cxx + SOURCES src/*.cpp + USES [GEANT4 REQUIRED] + [ROOT REQUIRED COMPONENTS Geom GenVector RIO] + [DD4hep REQUIRED COMPONENTS DDCore DDG4] + ) + # # dd4hep_install_dir(data DESTINATION ${DD4hep_DIR}/examples/DDG4 ) # diff --git a/examples/DDG4/src/Dictionary.h b/examples/DDG4/src/Dictionary.h new file mode 100644 index 0000000000000000000000000000000000000000..e6b8d1d1b86be0077f7ccc7fc238e3d470442e0f --- /dev/null +++ b/examples/DDG4/src/Dictionary.h @@ -0,0 +1,36 @@ +//========================================================================== +// 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 : M.Frank +// +//========================================================================== +// ------------------------------------------------------------------------- +// Regular dd4hep dictionaries +// ------------------------------------------------------------------------- +#ifdef DD4HEP_DICTIONARY_MODE + +#include <map> +#include <vector> + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + + +using namespace std; + +// Define here the classes we want to write to the output file: +#pragma link C++ class std::vector<double>+; +#pragma link C++ class std::pair<double, std::vector<double> >+; + +/// This is to make ROOT happy.... +struct Disctionary {}; + + +#endif // DD4HEP_DICTIONARY_MODE diff --git a/examples/DDG4/src/HitTupleAction.cpp b/examples/DDG4/src/HitTupleAction.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b77d1a0ed4a2fd58a591927a6b16307527fc9441 --- /dev/null +++ b/examples/DDG4/src/HitTupleAction.cpp @@ -0,0 +1,226 @@ +//========================================================================== +// 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 : M.Frank +// +//========================================================================== +#ifndef DD4HEP_DDG4_HITTUPLEACTION_H +#define DD4HEP_DDG4_HITTUPLEACTION_H + +// Framework include files +#include "DDG4/Geant4EventAction.h" + +// Forward declarations +class G4VHitsCollection; +class TFile; +class TTree; +class TBranch; + +/// Namespace example name of the user +namespace myanalysis { + + // Forward declarations + class Geant4ParticleMap; + + /// Class to measure the energy of escaping tracks + /** Class to measure the energy of escaping tracks of a detector using Geant 4 + * Measure escaping energy.... + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_SIMULATION + */ + class HitTupleAction : public dd4hep::sim::Geant4EventAction { + public: + typedef std::vector<std::string> CollectionNames; + /// Property: collection names to be dumped + CollectionNames m_containers; + /// Property: Output file name + std::string m_outFileName; + /// ROOT TFile instance + TFile* m_outFile = 0; + /// Tree object within the file + TTree* m_outTree = 0; + /// We want to write a separate branch for all deposits of one container(sub-detector) + typedef std::pair<double, std::vector<double> > Data; + /// The intermediate storage of the hit deposits to be written to ROOT + std::map<std::string, std::pair<TBranch*, Data> > m_deposits; + + public: + /// Standard constructor + HitTupleAction(dd4hep::sim::Geant4Context* context, const std::string& nam); + /// Default destructor + virtual ~HitTupleAction(); + /// Begin-of-run callback: Open output file + void beginRun(const G4Run* run); + /// End-of-run callback: Close output file + void endRun(const G4Run* run); + /// Geant4EventAction interface: Begin-of-event callback + virtual void begin(const G4Event* event) override; + /// Geant4EventAction interface: End-of-event callback + virtual void end(const G4Event* event) override; + }; +} // End namespace dd4hep +#endif /* DD4HEP_DDG4_HITTUPLEACTION_H */ + +//==================================================================== +// 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 : M.Frank +// +//==================================================================== + +// Framework include files +#include "DDG4/Geant4DataDump.h" +#include "DDG4/Geant4RunAction.h" +#include "DDG4/Geant4HitCollection.h" + +// Geant 4 includes +#include "G4HCofThisEvent.hh" +#include "G4Event.hh" + +// ROOT include files +#include "TFile.h" +#include "TTree.h" +#include "TROOT.h" +#include "TClass.h" +#include "TBranch.h" + +using namespace std; +using namespace dd4hep; +using namespace dd4hep::sim; + +/// Standard constructor +myanalysis::HitTupleAction::HitTupleAction(Geant4Context* ctxt, const string& nam) + : Geant4EventAction(ctxt, nam), m_containers{"*"} +{ + m_needsControl = true; + m_containers.push_back("*"); + declareProperty("OutputFile", m_outFileName); + declareProperty("Collections", m_containers); + runAction().callAtBegin(this, &HitTupleAction::beginRun); + runAction().callAtEnd(this, &HitTupleAction::endRun); +} + +/// Default destructor +myanalysis::HitTupleAction::~HitTupleAction() { +} + +/// Begin-of-run callback: Open output file +void myanalysis::HitTupleAction::beginRun(const G4Run* /* run */) { +} + +/// End-of-run callback: Close output file +void myanalysis::HitTupleAction::endRun(const G4Run* /* run */) { + if ( m_outFile ) { + if ( m_outTree ) { + m_outTree->Write(); + m_outTree->Print(); + } + m_outFile->Write(); + m_outFile->Close(); + delete m_outFile; + m_outFile = 0; + } +} + +/// Geant4EventAction interface: Begin-of-event callback +void myanalysis::HitTupleAction::begin(const G4Event* /* event */) { +} + +/// Geant4EventAction interface: End-of-event callback +void myanalysis::HitTupleAction::end(const G4Event* event) { + G4HCofThisEvent* hce = event->GetHCofThisEvent(); + if ( hce ) { + int nCol = hce->GetNumberOfCollections(); + if ( nCol <= 0 ) { + return; + } + else if ( !m_outFile ) { + // Name Option Title + m_outFile = TFile::Open(m_outFileName.c_str(), "RECREATE", "DDG4 User file"); + if ( m_outFile && !m_outFile->IsZombie() ) { + m_outTree = new TTree("DDG4 User Test","DDG4 data"); + printout(ALWAYS,"HitTupleAction","+++ Successfully opened ROOT file %s and created TTree:%s", + m_outFile->GetName(), "DDG4 User Test"); + if ( m_containers.size() == 1 && (m_containers[0] == "*" || m_containers[0] == "ALL") ) { + m_containers.clear(); + for (int i = 0; i < nCol; ++i) + m_containers.push_back(hce->GetHC(i)->GetName()); + } + // Seperate loop. We need fixed addresses when creating the branches + for(const auto& c : m_containers) { + m_deposits[c].first = 0; + m_deposits[c].second.first = 0e0; + m_deposits[c].second.second.clear(); + } + for(const auto& c : m_containers) { + std::pair<TBranch*, Data>& e = m_deposits[c]; + TClass* cl = gROOT->GetClass(typeid(Data)); + e.first = m_outTree->Branch(c.c_str(), cl->GetName(), (void*)0); + e.first->SetAutoDelete(false); + printout(ALWAYS,"HitTupleAction","+++ Prepare hit branch %s in root file.",c.c_str()); + } + } + else { + except("HitTupleAction","Failed to open ROOT N-tuple file: "+m_outFileName); + } + } + for ( auto& e : m_deposits ) { + e.second.first->SetAddress(0); + } + for (int i = 0; i < nCol; ++i) { + G4VHitsCollection* hc = hce->GetHC(i); + const string& nam = hc->GetName(); + if ( find(m_containers.begin(),m_containers.end(),nam) != m_containers.end() ) { + Geant4HitCollection* coll = dynamic_cast<Geant4HitCollection*>(hc); + if ( coll ) { + std::pair<TBranch*, Data>& e = m_deposits[nam]; + size_t nhits = coll->GetSize(); + Data* d = &e.second; + + e.second.first = 0e0; + e.second.second.clear(); + e.first->SetAddress(&d); + for ( size_t j=0; j<nhits; ++j ) { + double dep = 0e0; + Geant4HitData* h = coll->hit(j); + Geant4Tracker::Hit* trk_hit = dynamic_cast<Geant4Tracker::Hit*>(h); + if ( 0 != trk_hit ) { + dep = trk_hit->truth.deposit; + } + else { + Geant4Calorimeter::Hit* cal_hit = dynamic_cast<Geant4Calorimeter::Hit*>(h); + if ( 0 != cal_hit ) + dep = cal_hit->energyDeposit; + else + continue; + } + if ( dep > 0 ) { + e.second.first += dep; + e.second.second.push_back(dep); + } + } + } + } + } + m_outTree->Fill(); + return; + } + warning("+++ [Event:%d] The value of G4HCofThisEvent is NULL.",event->GetEventID()); +} + +#include "DDG4/Factories.h" +DECLARE_GEANT4ACTION_NS(myanalysis,HitTupleAction)