diff --git a/Simulation/ISF/ISF_Core/ISF_Services/CMakeLists.txt b/Simulation/ISF/ISF_Core/ISF_Services/CMakeLists.txt index 85f315959c231816328750723e2675d424540968..787d91a405fae0ea19c643fe22fd9098247e0f48 100644 --- a/Simulation/ISF/ISF_Core/ISF_Services/CMakeLists.txt +++ b/Simulation/ISF/ISF_Core/ISF_Services/CMakeLists.txt @@ -18,26 +18,29 @@ atlas_depends_on_subdirs( PUBLIC Generators/GeneratorObjects InnerDetector/InDetSimEvent MuonSpectrometer/MuonSimEvent + Simulation/Barcode/BarcodeEvent Simulation/Barcode/BarcodeInterfaces - Simulation/Barcode/BarcodeServices Simulation/G4Atlas/G4AtlasInterfaces Simulation/G4Sim/SimHelpers Simulation/G4Sim/TrackRecord Simulation/ISF/ISF_Core/ISF_Event Simulation/ISF/ISF_Core/ISF_Interfaces + Simulation/ISF/ISF_HepMC/ISF_HepMC_Interfaces TileCalorimeter/TileSimEvent Tools/PmbCxxUtils ) # External dependencies: +find_package( CLHEP ) find_package( HepMC ) +find_package( HepPDT ) find_package( ROOT COMPONENTS Core Tree MathCore Hist RIO pthread ) # Component(s) in the package: atlas_add_component( ISF_Services src/*.cxx src/components/*.cxx - INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${HEPMC_INCLUDE_DIRS} - LINK_LIBRARIES ${ROOT_LIBRARIES} ${HEPMC_LIBRARIES} GaudiKernel CaloIdentifier CaloSimEvent AthenaBaseComps StoreGateLib SGtests AtlasDetDescr GeneratorObjects InDetSimEvent MuonSimEvent BarcodeServicesLib G4AtlasInterfaces SimHelpers ISF_Event ISF_Interfaces TileSimEvent PmbCxxUtils ) + INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${HEPMC_INCLUDE_DIRS} ${CLHEP_INCLUDE_DIRS} ${HEPPDT_INCLUDE_DIRS} + LINK_LIBRARIES ${ROOT_LIBRARIES} ${HEPMC_LIBRARIES} ${CLHEP_LIBRARIES} ${HEPPDT_LIBRARIES} GaudiKernel CaloIdentifier CaloSimEvent AthenaBaseComps StoreGateLib SGtests AtlasDetDescr GeneratorObjects InDetSimEvent MuonSimEvent G4AtlasInterfaces SimHelpers ISF_Event ISF_Interfaces TileSimEvent PmbCxxUtils ) # Install files from the package: atlas_install_headers( ISF_Services ) diff --git a/Simulation/ISF/ISF_Core/ISF_Services/cmt/requirements b/Simulation/ISF/ISF_Core/ISF_Services/cmt/requirements index a2e7b8a9026613f8e8b4c7012ffb182873c43e23..51a24f0e619dc69ddbf767a65f7af1c6f61cd5fb 100644 --- a/Simulation/ISF/ISF_Core/ISF_Services/cmt/requirements +++ b/Simulation/ISF/ISF_Core/ISF_Services/cmt/requirements @@ -13,17 +13,20 @@ use AthenaBaseComps AthenaBaseComps-* Control use AtlasDetDescr AtlasDetDescr-* DetectorDescription use AtlasHepMC AtlasHepMC-* External use AtlasROOT AtlasROOT-* External +use BarcodeEvent BarcodeEvent-* Simulation/Barcode use BarcodeInterfaces BarcodeInterfaces-* Simulation/Barcode -use BarcodeServices BarcodeServices-* Simulation/Barcode use GeneratorObjects GeneratorObjects-* Generators use G4AtlasInterfaces G4AtlasInterfaces-* Simulation/G4Atlas use InDetSimEvent InDetSimEvent-* InnerDetector use ISF_Interfaces ISF_Interfaces-* Simulation/ISF/ISF_Core use ISF_Event ISF_Event-* Simulation/ISF/ISF_Core +use ISF_HepMC_Interfaces ISF_HepMC_Interfaces-* Simulation/ISF/ISF_HepMC use MuonSimEvent MuonSimEvent-* MuonSpectrometer use PmbCxxUtils PmbCxxUtils-* Tools use StoreGate StoreGate-* Control use SubDetectorEnvelopes SubDetectorEnvelopes-* AtlasGeometryCommon +use HepPDT * LCG_Interfaces +use AtlasCLHEP AtlasCLHEP-* External end_private public @@ -31,6 +34,26 @@ library ISF_Services *.cxx components/*.cxx apply_pattern declare_python_modules files="*.py" apply_pattern component_library +# tests +private +pattern GTest_run \ + application <unit_test>_test -group=$(whichGroup) ../test/<unit_test>_test.cxx <extra_sources> ; \ + document athenarun_launcher <unit_test>_utest -group=$(whichGroup) \ + athenarun_exe="'../${CMTCONFIG}/<unit_test>_test.exe'" \ + athenarun_pre="'. ../cmt/setup.sh'" \ + athenarun_out="' 2>&1 | tee <unit_test>_test.log'" \ + athenarun_post="'../test/gtest_post_check.sh <unit_test>_test.log'" ; \ + private ; \ + macro_append <unit_test>_utest_dependencies " <unit_test>_test " ; \ + +use AtlasGoogleTest AtlasGoogleTest-* External +use TestTools TestTools-* AtlasTest +use GeoPrimitives GeoPrimitives-* DetectorDescription +apply_pattern GTest_run unit_test=InputConverter extra_sources=../src/InputConverter.cxx + +end_private + + private # use this to activate debug info in this package: #macro cppdebugflags '$(cppdebugflags_s)' diff --git a/Simulation/ISF/ISF_Core/ISF_Services/python/ISF_ServicesConfig.py b/Simulation/ISF/ISF_Core/ISF_Services/python/ISF_ServicesConfig.py index 61d8e07ce6bc992e2bdb13144fd1fdf06c1a37b0..e49026674487396f246f02f0764c4592a253a57e 100644 --- a/Simulation/ISF/ISF_Core/ISF_Services/python/ISF_ServicesConfig.py +++ b/Simulation/ISF/ISF_Core/ISF_Services/python/ISF_ServicesConfig.py @@ -11,67 +11,159 @@ from AthenaCommon.Constants import * # FATAL,ERROR etc. from AthenaCommon.SystemOfUnits import * def getParticleBrokerSvcNoOrdering(name="ISF_ParticleBrokerSvcNoOrdering", **kwargs): - kwargs.setdefault('StackFiller' , 'ISF_StackFiller' ) - kwargs.setdefault('EntryLayerTool' , 'ISF_EntryLayerTool' ) - kwargs.setdefault('GeoIDSvc' , 'ISF_GeoIDSvc' ) - kwargs.setdefault('AlwaysUseGeoIDSvc' , False ) + kwargs.setdefault('EntryLayerTool', 'ISF_EntryLayerTool') + kwargs.setdefault('GeoIDSvc', 'ISF_GeoIDSvc') + kwargs.setdefault('AlwaysUseGeoIDSvc', False) from ISF_Config.ISF_jobProperties import ISF_Flags - kwargs.setdefault('ValidateGeoIDs' , ISF_Flags.ValidationMode() ) - kwargs.setdefault('ValidationOutput' , ISF_Flags.ValidationMode() ) - kwargs.setdefault('ValidationStreamName' , "ParticleBroker" ) - kwargs.setdefault('BarcodeService' , ISF_Flags.BarcodeService() ) + kwargs.setdefault('ValidateGeoIDs', ISF_Flags.ValidationMode()) + kwargs.setdefault('ValidationOutput', ISF_Flags.ValidationMode()) + kwargs.setdefault('ValidationStreamName', "ParticleBroker") + kwargs.setdefault('BarcodeService', ISF_Flags.BarcodeService()) return CfgMgr.ISF__ParticleBrokerDynamicOnReadIn(name, **kwargs) def getParticleBrokerSvc(name="ISF_ParticleBrokerSvc", **kwargs): - #kwargs.setdefault('ParticleOrderingTool' , 'ISF_InToOutSubDetOrderingTool' ) - kwargs.setdefault('ParticleOrderingTool' , 'ISF_ParticleOrderingTool' ) - return getParticleBrokerSvcNoOrdering(name, **kwargs) - -def getLongLivedParticleBrokerSvc(name="ISF_LongLivedParticleBrokerSvc", **kwargs): - kwargs.setdefault('StackFiller' , 'ISF_LongLivedStackFiller' ) + #kwargs.setdefault('ParticleOrderingTool', 'ISF_InToOutSubDetOrderingTool') + kwargs.setdefault('ParticleOrderingTool', 'ISF_ParticleOrderingTool') return getParticleBrokerSvcNoOrdering(name, **kwargs) def getAFIIParticleBrokerSvc(name="ISF_AFIIParticleBrokerSvc", **kwargs): - kwargs.setdefault('EntryLayerTool' , 'ISF_AFIIEntryLayerTool' ) + kwargs.setdefault('EntryLayerTool', 'ISF_AFIIEntryLayerTool') return getParticleBrokerSvc(name, **kwargs) def getSimHitService(name="ISF_SimHitService", **kwargs): from ISF_Config.ISF_jobProperties import ISF_Flags - kwargs.setdefault('ValidationOutput' , ISF_Flags.ValidationMode() ) + kwargs.setdefault('ValidationOutput', ISF_Flags.ValidationMode()) return CfgMgr.ISF__SimHitSvc(name, **kwargs) def getNoG4SimHitService(name="ISF_NoG4SimHitService", **kwargs): - kwargs.setdefault("SensitiveDetectorMasterTool","EmptySensitiveDetectorMasterTool") - kwargs.setdefault("FastSimulationMasterTool" ,"EmptyFastSimulationMasterTool" ) + kwargs.setdefault("SensitiveDetectorMasterTool", "EmptySensitiveDetectorMasterTool") + kwargs.setdefault("FastSimulationMasterTool", "EmptyFastSimulationMasterTool") return getSimHitService(name, **kwargs) def getPileupSimHitService(name="ISF_PileupSimHitService", **kwargs): - kwargs.setdefault('SeparateInDetPileupHits' , True ) + kwargs.setdefault('SeparateInDetPileupHits', True) return getNoG4SimHitService(name, **kwargs) def getISFEnvelopeDefSvc(name="ISF_ISFEnvelopeDefSvc", **kwargs): # ATLAS common envlope definitions - kwargs.setdefault("ATLASEnvelopeDefSvc" , "AtlasGeometry_EnvelopeDefSvc") + kwargs.setdefault("ATLASEnvelopeDefSvc", "AtlasGeometry_EnvelopeDefSvc") + return CfgMgr.ISF__ISFEnvelopeDefSvc(name, **kwargs) return CfgMgr.ISF__ISFEnvelopeDefSvc(name, **kwargs) def getAFIIEnvelopeDefSvc(name="ISF_AFIIEnvelopeDefSvc", **kwargs): from AthenaCommon.SystemOfUnits import mm # ATLAS common envlope definitions - kwargs.setdefault("ISFEnvelopeDefSvc" , "ISF_ISFEnvelopeDefSvc" ) - kwargs.setdefault("InDetMaxExtentZ" , 3549.5*mm ) + kwargs.setdefault("ISFEnvelopeDefSvc", "ISF_ISFEnvelopeDefSvc") + kwargs.setdefault("InDetMaxExtentZ", 3549.5*mm) + return CfgMgr.ISF__AFIIEnvelopeDefSvc(name, **kwargs) return CfgMgr.ISF__AFIIEnvelopeDefSvc(name, **kwargs) def getGeoIDSvc(name="ISF_GeoIDSvc", **kwargs): # with ISF volume definitions - kwargs.setdefault("EnvelopeDefSvc" , "ISF_ISFEnvelopeDefSvc" ) + kwargs.setdefault("EnvelopeDefSvc", "ISF_ISFEnvelopeDefSvc") + return CfgMgr.ISF__GeoIDSvc(name, **kwargs) return CfgMgr.ISF__GeoIDSvc(name, **kwargs) def getAFIIGeoIDSvc(name="ISF_AFIIGeoIDSvc", **kwargs): - kwargs.setdefault("EnvelopeDefSvc" , "ISF_AFIIEnvelopeDefSvc" ) + kwargs.setdefault("EnvelopeDefSvc", "ISF_AFIIEnvelopeDefSvc") return getGeoIDSvc(name, **kwargs) def getParticleKillerSvc(name="ISF_ParticleKillerSvc", **kwargs): kwargs.setdefault('Identifier', "ParticleKiller") return CfgMgr.ISF__ParticleKillerSimSvc(name, **kwargs) + +def getInputConverter(name="ISF_InputConverter", **kwargs): + kwargs.setdefault("UseGeneratedParticleMass", False) + genParticleFilters = ['ISF_ParticleFinalStateFilter'] + from AthenaCommon.BeamFlags import jobproperties + if jobproperties.Beam.beamType() != "cosmics": + genParticleFilters += ['ISF_ParticlePositionFilterDynamic', + 'ISF_EtaPhiFilter'] + genParticleFilters += ['ISF_GenParticleInteractingFilter'] + kwargs.setdefault("GenParticleFilters", genParticleFilters) + return CfgMgr.ISF__InputConverter(name, **kwargs) + +def getLongLivedInputConverter(name="ISF_LongLivedInputConverter", **kwargs): + kwargs.setdefault("GenParticleFilters" , [ 'ISF_ParticleSimWhiteList', + 'ISF_ParticlePositionFilterDynamic', + 'ISF_EtaPhiFilter', + 'ISF_GenParticleInteractingFilter', ] ) + return getInputConverter(name, **kwargs) + +def getGenericTruthService(name="ISF_TruthService", **kwargs): + from ISF_Config.ISF_jobProperties import ISF_Flags + kwargs.setdefault('BarcodeSvc', ISF_Flags.BarcodeService()) + kwargs.setdefault('SkipIfNoChildren', True) + kwargs.setdefault('SkipIfNoParentBarcode', True) + kwargs.setdefault('ForceEndVtxInRegions', []) + if 'longLived' in ISF_Flags.Simulator(): #FIXME this should be configured in a nicer way. ATLASSIM-526 + kwargs.setdefault('QuasiStableParticlesIncluded', True) + return CfgMgr.ISF__TruthSvc(name, **kwargs) + +def getMC15TruthService(name="ISF_MC15TruthService", **kwargs): + # importing Reflex dictionary to access AtlasDetDescr::AtlasRegion enum + import ROOT, cppyy + cppyy.loadDictionary('AtlasDetDescrDict') + AtlasRegion = ROOT.AtlasDetDescr + kwargs.setdefault('BeamPipeTruthStrategies', ['ISF_MCTruthStrategyGroupID_MC15']) # this is used for beam pipe but not BeamPipeCentral which uses same as ID + kwargs.setdefault('IDTruthStrategies', ['ISF_MCTruthStrategyGroupID_MC15', 'ISF_MCTruthStrategyGroupIDHadInt_MC15']) + kwargs.setdefault('CaloTruthStrategies', ['ISF_MCTruthStrategyGroupCaloMuBrem', 'ISF_MCTruthStrategyGroupCaloDecay_MC15']) + kwargs.setdefault('MSTruthStrategies', []) + kwargs.setdefault('IgnoreUndefinedBarcodes', False) + kwargs.setdefault('PassWholeVertices', False) # new for MC15 - can write out partial vertices. + kwargs.setdefault('ForceEndVtxInRegions', [AtlasRegion.fAtlasID]) + return getGenericTruthService(name, **kwargs) + +def getMC15aTruthService(name="ISF_MC15aTruthService", **kwargs): + kwargs.setdefault('ForceEndVtxInRegions', []) + return getMC15TruthService(name, **kwargs) + +def getMC15aPlusTruthService(name="ISF_MC15aPlusTruthService", **kwargs): + # importing Reflex dictionary to access AtlasDetDescr::AtlasRegion enum + import ROOT, cppyy + cppyy.loadDictionary('AtlasDetDescrDict') + AtlasRegion = ROOT.AtlasDetDescr + kwargs.setdefault('ForceEndVtxInRegions', [AtlasRegion.fAtlasID]) + return getMC15TruthService(name, **kwargs) + +def getMC12TruthService(name="ISF_MC12TruthService", **kwargs): + kwargs.setdefault('BeamPipeTruthStrategies', ['ISF_MCTruthStrategyGroupID']) # this is used for beam pipe but not BeamPipeCentral which uses same as ID + kwargs.setdefault('IDTruthStrategies', ['ISF_MCTruthStrategyGroupID', 'ISF_MCTruthStrategyGroupIDHadInt']) + kwargs.setdefault('CaloTruthStrategies', ['ISF_MCTruthStrategyGroupCaloMuBrem']) + kwargs.setdefault('MSTruthStrategies', []) + kwargs.setdefault('IgnoreUndefinedBarcodes', False) + kwargs.setdefault('PassWholeVertices', True) + return getGenericTruthService(name, **kwargs) + +def getMC12LLPTruthService(name="ISF_MC12TruthLLPService", **kwargs): + kwargs.setdefault('BeamPipeTruthStrategies', ['ISF_MCTruthStrategyGroupID', 'ISF_LLPTruthStrategy']) # this is used for beam pipe but not BeamPipeCentral which uses same as ID + kwargs.setdefault('IDTruthStrategies', ['ISF_MCTruthStrategyGroupID', 'ISF_MCTruthStrategyGroupIDHadInt', 'ISF_LLPTruthStrategy']) + kwargs.setdefault('CaloTruthStrategies', ['ISF_MCTruthStrategyGroupCaloMuBrem', 'ISF_LLPTruthStrategy']) + kwargs.setdefault('MSTruthStrategies', ['ISF_LLPTruthStrategy']) + return getMC12TruthService(name, **kwargs) + +def getMC12PlusTruthService(name="ISF_MC12PlusTruthService", **kwargs): + # importing Reflex dictionary to access AtlasDetDescr::AtlasRegion enum + import ROOT, cppyy + cppyy.loadDictionary('AtlasDetDescrDict') + AtlasRegion = ROOT.AtlasDetDescr + kwargs.setdefault('ForceEndVtxInRegions', [AtlasRegion.fAtlasID] ) + return getMC12TruthService(name, **kwargs) + +def getValidationTruthService(name="ISF_ValidationTruthService", **kwargs): + kwargs.setdefault('BeamPipeTruthStrategies', []) + kwargs.setdefault('IDTruthStrategies', ['ISF_ValidationTruthStrategy'] ) + kwargs.setdefault('CaloTruthStrategies', ['ISF_ValidationTruthStrategy'] ) + kwargs.setdefault('MSTruthStrategies', []) + kwargs.setdefault('IgnoreUndefinedBarcodes', True) + kwargs.setdefault('PassWholeVertices', True) + return getGenericTruthService(name, **kwargs) + +def getTruthService(name="ISF_TruthService", **kwargs): + from ISF_Config.ISF_jobProperties import ISF_Flags + if ISF_Flags.ValidationMode() : + return getValidationTruthService(name, **kwargs) + else : + return getMC12TruthService(name, **kwargs) diff --git a/Simulation/ISF/ISF_Core/ISF_Services/python/ISF_ServicesConfigDb.py b/Simulation/ISF/ISF_Core/ISF_Services/python/ISF_ServicesConfigDb.py index 7e1a333128bbd7dcd11600f9301371f8fdc0f88d..3c60c7152e2b0ddc3ded276fd505358464e9ff2f 100644 --- a/Simulation/ISF/ISF_Core/ISF_Services/python/ISF_ServicesConfigDb.py +++ b/Simulation/ISF/ISF_Core/ISF_Services/python/ISF_ServicesConfigDb.py @@ -8,15 +8,24 @@ Elmar Ritsch, 16/12/2014 from AthenaCommon.CfgGetter import addService # Common tools, services and algorithms used by jobs -addService("ISF_Services.ISF_ServicesConfig.getISFEnvelopeDefSvc" , "ISF_ISFEnvelopeDefSvc" ) -addService("ISF_Services.ISF_ServicesConfig.getAFIIEnvelopeDefSvc" , "ISF_AFIIEnvelopeDefSvc" ) -addService("ISF_Services.ISF_ServicesConfig.getGeoIDSvc" , "ISF_GeoIDSvc" ) -addService("ISF_Services.ISF_ServicesConfig.getAFIIGeoIDSvc" , "ISF_AFIIGeoIDSvc" ) -addService("ISF_Services.ISF_ServicesConfig.getParticleBrokerSvc" , "ISF_ParticleBrokerSvc" ) -addService("ISF_Services.ISF_ServicesConfig.getLongLivedParticleBrokerSvc" , "ISF_LongLivedParticleBrokerSvc" ) -addService("ISF_Services.ISF_ServicesConfig.getParticleBrokerSvcNoOrdering" , "ISF_ParticleBrokerSvcNoOrdering" ) -addService("ISF_Services.ISF_ServicesConfig.getAFIIParticleBrokerSvc" , "ISF_AFIIParticleBrokerSvc" ) -addService("ISF_Services.ISF_ServicesConfig.getSimHitService" , "ISF_SimHitService" ) -addService("ISF_Services.ISF_ServicesConfig.getNoG4SimHitService" , "ISF_NoG4SimHitService" ) -addService("ISF_Services.ISF_ServicesConfig.getPileupSimHitService" , "ISF_PileupSimHitService" ) -addService("ISF_Services.ISF_ServicesConfig.getParticleKillerSvc" , "ISF_ParticleKillerSvc" ) +addService("ISF_Services.ISF_ServicesConfig.getISFEnvelopeDefSvc", "ISF_ISFEnvelopeDefSvc") +addService("ISF_Services.ISF_ServicesConfig.getAFIIEnvelopeDefSvc", "ISF_AFIIEnvelopeDefSvc") +addService("ISF_Services.ISF_ServicesConfig.getGeoIDSvc", "ISF_GeoIDSvc") +addService("ISF_Services.ISF_ServicesConfig.getAFIIGeoIDSvc", "ISF_AFIIGeoIDSvc") +addService("ISF_Services.ISF_ServicesConfig.getParticleBrokerSvc", "ISF_ParticleBrokerSvc") +addService("ISF_Services.ISF_ServicesConfig.getParticleBrokerSvcNoOrdering", "ISF_ParticleBrokerSvcNoOrdering") +addService("ISF_Services.ISF_ServicesConfig.getAFIIParticleBrokerSvc", "ISF_AFIIParticleBrokerSvc") +addService("ISF_Services.ISF_ServicesConfig.getSimHitService", "ISF_SimHitService") +addService("ISF_Services.ISF_ServicesConfig.getNoG4SimHitService", "ISF_NoG4SimHitService") +addService("ISF_Services.ISF_ServicesConfig.getPileupSimHitService", "ISF_PileupSimHitService") +addService("ISF_Services.ISF_ServicesConfig.getInputConverter", "ISF_InputConverter") +addService("ISF_Services.ISF_ServicesConfig.getLongLivedInputConverter", "ISF_LongLivedInputConverter") +addService("ISF_Services.ISF_ServicesConfig.getTruthService", "ISF_TruthService") +addService("ISF_Services.ISF_ServicesConfig.getMC12TruthService", "ISF_MC12TruthService") +addService("ISF_Services.ISF_ServicesConfig.getMC12PlusTruthService", "ISF_MC12PlusTruthService") +addService("ISF_Services.ISF_ServicesConfig.getMC12LLPTruthService", "ISF_MC12LLPTruthService") +addService("ISF_Services.ISF_ServicesConfig.getMC15aTruthService", "ISF_MC15aTruthService") +addService("ISF_Services.ISF_ServicesConfig.getMC15aPlusTruthService", "ISF_MC15aPlusTruthService") +addService("ISF_Services.ISF_ServicesConfig.getMC15TruthService", "ISF_MC15TruthService") +addService("ISF_Services.ISF_ServicesConfig.getValidationTruthService", "ISF_ValidationTruthService") +addService("ISF_Services.ISF_ServicesConfig.getParticleKillerSvc", "ISF_ParticleKillerSvc") diff --git a/Simulation/ISF/ISF_Core/ISF_Services/src/InputConverter.cxx b/Simulation/ISF/ISF_Core/ISF_Services/src/InputConverter.cxx new file mode 100644 index 0000000000000000000000000000000000000000..7e712640ddf90f1713e38a0a0956cac7db1927c5 --- /dev/null +++ b/Simulation/ISF/ISF_Core/ISF_Services/src/InputConverter.cxx @@ -0,0 +1,296 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/////////////////////////////////////////////////////////////////// +// InputConverter.cxx, (c) ATLAS Detector software +/////////////////////////////////////////////////////////////////// + +// class header include +#include "InputConverter.h" + +// framework +#include "GaudiKernel/IPartPropSvc.h" +#include "GaudiKernel/PhysicalConstants.h" + +// ISF_HepMC include +#include "ISF_Event/TruthBinding.h" +#include "ISF_HepMC_Interfaces/IGenParticleFilter.h" +// barcode event and interfaces for bc creation +#include "BarcodeEvent/Barcode.h" +#include "BarcodeInterfaces/IBarcodeSvc.h" +// ISF_Event include +#include "ISF_Event/ISFParticle.h" +#include "ISF_Event/ISFParticleContainer.h" +#include "ISF_Event/ParticleUserInformation.h" +// HepMC includes +#include "HepMC/GenParticle.h" +#include "HepMC/GenEvent.h" +// McEventCollection +#include "GeneratorObjects/McEventCollection.h" +// CLHEP includes +#include "CLHEP/Geometry/Point3D.h" +#include "CLHEP/Geometry/Vector3D.h" +// HepPDT +#include "HepPDT/ParticleID.hh" +#include "HepPDT/DecayData.hh" +#include "HepPDT/ParticleDataTable.hh" + + +/** Constructor **/ +ISF::InputConverter::InputConverter(const std::string& name, ISvcLocator* svc) + : AthService(name,svc), + m_particlePropSvc("PartPropSvc",name), + m_particleDataTable(nullptr), + m_useGeneratedParticleMass(false), + m_genParticleFilters() +{ + // particle mass from particle data table? + declareProperty("UseGeneratedParticleMass", + m_useGeneratedParticleMass, + "Use particle mass assigned to GenParticle."); + // particle filters + declareProperty("GenParticleFilters", + m_genParticleFilters, + "Tools for filtering out GenParticles."); + // the particle property service + declareProperty("ParticlePropertyService", + m_particlePropSvc, + "ParticlePropertyService to retrieve the PDT."); +} + + +/** Destructor **/ +ISF::InputConverter::~InputConverter() +{ +} + + +// Athena algtool's Hooks +StatusCode +ISF::InputConverter::initialize() +{ + ATH_MSG_VERBOSE("initialize() begin"); + + // setup PDT if requested (to get particle masses later on) + if (!m_useGeneratedParticleMass) { + ATH_CHECK( m_particlePropSvc.retrieve() ); + m_particleDataTable = m_particlePropSvc->PDT(); + if (!m_particleDataTable) { + ATH_MSG_FATAL( "Could not get ParticleDataTable from " << m_particlePropSvc << ". Abort" ); + return StatusCode::FAILURE; + } + } + + if (!m_genParticleFilters.empty()){ + ATH_CHECK(m_genParticleFilters.retrieve()); + } + + ATH_MSG_VERBOSE("initialize() successful"); + return StatusCode::SUCCESS; +} + + +/** Athena algtool Hook */ +StatusCode +ISF::InputConverter::finalize() +{ + ATH_MSG_DEBUG("Finalizing ..."); + return StatusCode::SUCCESS; +} + + +/** Convert selected particles from the given McEventCollection into ISFParticles + and push them into the given ISFParticleContainer */ +StatusCode +ISF::InputConverter::convert(const McEventCollection& inputGenEvents, + ISF::ISFParticleContainer& simParticles, + bool isPileup) const +{ + for ( const auto& eventPtr : inputGenEvents ) { + // skip empty events + if (eventPtr == nullptr) continue; + + // @FIXME: set the bunch-crossing identifier for pileup dynamically + // rather than a constant '1' (e.g. could use GenEvent index for that?) + int bcid = isPileup ? 1 : 0; + + ATH_MSG_DEBUG("Starting conversion of GenEvent with" + " signal_process_id=" << eventPtr->signal_process_id() << + " and event_number=" << eventPtr->event_number() ); + + // new collection containing all gen particles that passed filters + bool legacyOrdering = true; // FIXME: this is only to keep the same order of particles + // as the prior 'StackFiller' implementation + // TODO: remove this functionality from the + // getSelectedParticles function once + // happy with the results + const auto passedGenParticles = getSelectedParticles(*eventPtr, legacyOrdering); + + for ( auto& genPartPtr : passedGenParticles ) { + ATH_MSG_VERBOSE("Picking up following GenParticle for conversion to ISFParticle: " << *genPartPtr); + auto simParticlePtr = convertParticle(genPartPtr, bcid); + if (!simParticlePtr) { + ATH_MSG_ERROR("Error while trying to convert input generator particles. Aborting."); + return StatusCode::FAILURE; + } + // add to collection that will be returned + simParticles.push_back(simParticlePtr); + + } // loop over passed gen particles + + } // loop over gen events + + ATH_MSG_DEBUG( "Created initial simulation particle collection with size " << simParticles.size() ); + + return StatusCode::SUCCESS; +} + + +/** get all generator particles which pass filters */ +std::vector<HepMC::GenParticle*> +ISF::InputConverter::getSelectedParticles(const HepMC::GenEvent& evnt, bool legacyOrdering) const { + auto allGenPartBegin = evnt.particles_begin(); + auto allGenPartEnd = evnt.particles_end(); + + // reserve destination container with maximum size, i.e. number of particles in input event + std::vector<HepMC::GenParticle*> passedGenParticles{}; + size_t maxParticles = std::distance(allGenPartBegin, allGenPartEnd); + passedGenParticles.reserve(maxParticles); + + if (legacyOrdering) { + // FIXME: remove this block and the 'legacyOrdering' flag + // once we don't need the legacy order any longer + auto vtxIt = evnt.vertices_begin(); + auto vtxItEnd = evnt.vertices_end(); + for ( ; vtxIt != vtxItEnd; ++vtxIt ) { + const auto vtxPtr = *vtxIt; + std::copy_if(vtxPtr->particles_begin(HepMC::children), + vtxPtr->particles_end(HepMC::children), + std::back_inserter(passedGenParticles), + [this](HepMC::GenParticle* p){return this->passesFilters(*p);}); + } + + } else { + std::copy_if(allGenPartBegin, + allGenPartEnd, + std::back_inserter(passedGenParticles), + [this](HepMC::GenParticle* p){return this->passesFilters(*p);}); + } + + passedGenParticles.shrink_to_fit(); + + return passedGenParticles; +} + + +/** get all generator particles which pass filters */ +ISF::ISFParticle* +ISF::InputConverter::convertParticle(HepMC::GenParticle* genPartPtr, int bcid) const { + + if (!genPartPtr) + return nullptr; + + auto& genPart = *genPartPtr; + + // -> particle origin (TODO: add proper GeoID, collision/cosmics) + DetRegionSvcIDPair origin(AtlasDetDescr::fUndefinedAtlasRegion, ISF::fEventGeneratorSimID); + + // -> truth binding + ISF::TruthBinding* tBinding = new ISF::TruthBinding(genPartPtr); + + // 4-vectors: position, momentum + HepMC::GenVertex* pVertex = genPart.production_vertex(); + if (!pVertex) { + ATH_MSG_ERROR("Unable to convert following generator particle due to missing " + << "production vertex: " << genPart); + return nullptr; + } + const auto& pVertexPos(pVertex->point3d()); + const Amg::Vector3D pos(pVertexPos.x(), pVertexPos.y(), pVertexPos.z()); + const auto& pMomentum(genPart.momentum()); + const Amg::Vector3D mom(pMomentum.px(), pMomentum.py(), pMomentum.pz()); + + // get the pdg_id, mass & time, barcode + int pPdgId = genPart.pdg_id(); + double pMass = getParticleMass(genPart); + double pTime = pVertex->position().t() / Gaudi::Units::c_light; + double charge = HepPDT::ParticleID(pPdgId).charge(); + auto pBarcode = genPart.barcode(); + + auto sParticle = new ISF::ISFParticle( std::move(pos), + std::move(mom), + pMass, + charge, + pPdgId, + pTime, + origin, + bcid, + pBarcode, + tBinding ); + return sParticle; +} + + +/** get right GenParticle mass */ +double +ISF::InputConverter::getParticleMass(const HepMC::GenParticle &part) const { + // default value: generated particle mass + double mass = part.generated_mass(); + ATH_MSG_VERBOSE("part.generated_mass, mass="<<mass); + + // 1. use PDT mass? + if ( !m_useGeneratedParticleMass) { + int absPDG = abs(part.pdg_id()); + HepPDT::ParticleData const *pData = (m_particleDataTable) + ? m_particleDataTable->particle(absPDG) + : nullptr ; + if (pData) { + mass = pData->mass(); + ATH_MSG_VERBOSE("using pData mass, mass="<<mass); + } + else + ATH_MSG_WARNING( "Unable to find mass of particle with PDG ID '" << absPDG << "' in ParticleDataTable. Will set mass to generated_mass: " << mass); + } + return mass; +} + + +/** check if the given particle passes all filters */ +bool +ISF::InputConverter::passesFilters(const HepMC::GenParticle& part) const { + // TODO: implement this as a std::find_if with a lambda function + for ( const auto& filter : m_genParticleFilters ) { + // determine if the particle passes current filter + bool passFilter = filter->pass(part); + ATH_MSG_VERBOSE("GenParticleFilter '" << filter.typeAndName() << "' returned: " + << (passFilter ? "true, will keep particle." + : "false, will remove particle.")); + const auto& momentum = part.momentum(); + ATH_MSG_VERBOSE("Particle: (" + <<momentum.px()<<", " + <<momentum.py()<<", " + <<momentum.pz()<<"), pdgCode: " + <<part.pdg_id() ); + + if (!passFilter) { + return false; + } + } + + return true; +} + + +/** Query the interfaces. */ +StatusCode ISF::InputConverter::queryInterface(const InterfaceID& riid, void** ppvInterface) { + + if ( IID_IInputConverter == riid ) + *ppvInterface = (IInputConverter*)this; + else { + // Interface is not directly available: try out a base class + return Service::queryInterface(riid, ppvInterface); + } + addRef(); + return StatusCode::SUCCESS; +} diff --git a/Simulation/ISF/ISF_Core/ISF_Services/src/InputConverter.h b/Simulation/ISF/ISF_Core/ISF_Services/src/InputConverter.h new file mode 100644 index 0000000000000000000000000000000000000000..fa3449343f59383fa3d9e222b6cecb8e826336eb --- /dev/null +++ b/Simulation/ISF/ISF_Core/ISF_Services/src/InputConverter.h @@ -0,0 +1,100 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/////////////////////////////////////////////////////////////////// +// InputConverter.h, (c) ATLAS Detector software +/////////////////////////////////////////////////////////////////// + +#ifndef ISF_INPUTCONVERTER_H +#define ISF_INPUTCONVERTER_H 1 + +// STL includes +#include <string> +// ISF include +#include "ISF_Interfaces/IInputConverter.h" +// FrameWork includes +#include "GaudiKernel/ToolHandle.h" +#include "GaudiKernel/ServiceHandle.h" +#include "AthenaBaseComps/AthService.h" + +// forward declarations +namespace Barcode { + class IBarcodeSvc; +} +namespace HepPDT { + class ParticleDataTable; +} +namespace HepMC { + class GenParticle; + class GenEvent; +} +class IPartPropSvc; +class McEventCollection; +namespace ISFTesting { + class InputConverter_test; +} +namespace ISF { + class ISFParticle; + class IGenParticleFilter; +} + +namespace ISF { + + /** @class InputConverter + + Convert simulation input collections to ISFParticles for subsequent ISF simulation. + + @author Elmar.Ritsch -at- cern.ch + */ + class InputConverter : public IInputConverter, public AthService { + + // allow test to access private data + friend ISFTesting::InputConverter_test; + + public: + InputConverter(const std::string& name, ISvcLocator* svc); + virtual ~InputConverter(); + + /** Athena algtool Hooks */ + StatusCode initialize(); + StatusCode finalize(); + + /** ReturnGaudi InterfaceID */ + static const InterfaceID& interfaceID() { return IID_IInputConverter; } + + /** Convert selected particles from the given McEventCollection into ISFParticles + and push them into the given ISFParticleContainer */ + virtual StatusCode convert(const McEventCollection& inputGenEvents, + ISF::ISFParticleContainer& simParticles, + bool isPileup=false) const override final; + + /** Query the interfaces. **/ + StatusCode queryInterface( const InterfaceID& riid, void** ppvInterface ); + + private: + /** get right GenParticle mass */ + double getParticleMass(const HepMC::GenParticle& p) const; + + /** get all generator particles which pass filters */ + std::vector<HepMC::GenParticle*> getSelectedParticles(const HepMC::GenEvent& evnt, bool legacyOrdering=false) const; + + /** check if the given particle passes all filters */ + bool passesFilters(const HepMC::GenParticle& p) const; + + /** convert GenParticle to ISFParticle */ + ISF::ISFParticle* convertParticle(HepMC::GenParticle* genPartPtr, int bcid) const; + + /** ParticlePropertyService and ParticleDataTable */ + ServiceHandle<IPartPropSvc> m_particlePropSvc; //!< particle properties svc to retrieve PDT + const HepPDT::ParticleDataTable *m_particleDataTable; //!< PDT used to look up particle masses + + bool m_useGeneratedParticleMass; //!< use GenParticle::generated_mass() in simulation + + ToolHandleArray<IGenParticleFilter> m_genParticleFilters; //!< HepMC::GenParticle filters + }; + +} + + +#endif //> !ISF_INPUTCONVERTER_H diff --git a/Simulation/ISF/ISF_Core/ISF_Services/src/ParticleBrokerDynamicOnReadIn.cxx b/Simulation/ISF/ISF_Core/ISF_Services/src/ParticleBrokerDynamicOnReadIn.cxx index be743f021e4e17f3bea2c84f57b556f6e4016e12..360cc86b52915c0ea60488e386dc6ef9e9af0111 100644 --- a/Simulation/ISF/ISF_Core/ISF_Services/src/ParticleBrokerDynamicOnReadIn.cxx +++ b/Simulation/ISF/ISF_Core/ISF_Services/src/ParticleBrokerDynamicOnReadIn.cxx @@ -14,7 +14,6 @@ #include "ISF_Event/ISFParticleContainer.h" #include "ISF_Event/ISFBenchmarkHelper.h" -#include "ISF_Interfaces/IStackFiller.h" #include "ISF_Interfaces/IEntryLayerTool.h" #include "ISF_Interfaces/IGeoIDSvc.h" #include "ISF_Interfaces/SimulationFlavor.h" @@ -22,9 +21,6 @@ // DetectorDescription #include "AtlasDetDescr/AtlasRegionHelper.h" -// barcode utils -#include "BarcodeServices/BitCalculator.h" - // Benchmarking #include "PmbCxxUtils/CustomBenchmark.h" @@ -40,11 +36,9 @@ /** Constructor **/ ISF::ParticleBrokerDynamicOnReadIn::ParticleBrokerDynamicOnReadIn(const std::string& name,ISvcLocator* svc) : AthService(name,svc), - m_particleStackFiller("ISF::ISF_GenEventStackFiller/StackFiller"), m_entryLayerTool("iGeant4::EntryLayerTool/ISF_EntryLayerTool"), - m_entryLayerToolQuick(0), m_orderingTool(""), - m_orderingToolQuick(0), + m_hasOrderingTool(false), m_geoIDSvc("", name), m_geoIDSvcQuick(0), m_forceGeoIDSvc(false), @@ -54,7 +48,6 @@ ISF::ParticleBrokerDynamicOnReadIn::ParticleBrokerDynamicOnReadIn(const std::str m_simSelector(), m_simSelectorSet(), m_screenOutputPrefix("isf >> "), - m_screenEmptyPrefix(), m_barcodeSvc("", name), m_doSelectorCPUMon(false), m_benchPDGCode(0), @@ -68,11 +61,8 @@ ISF::ParticleBrokerDynamicOnReadIn::ParticleBrokerDynamicOnReadIn(const std::str m_val_p(0.), m_val_x(0.), m_val_y(0.), - m_val_z(0.), - m_simflavor(ISF::UndefinedSim) + m_val_z(0.) { - // the particle stack filler tool - declareProperty("StackFiller" , m_particleStackFiller ); // the entry layer tool to write TrackRecordCollections declareProperty("EntryLayerTool" , m_entryLayerTool ); // particle ing tool @@ -83,8 +73,6 @@ ISF::ParticleBrokerDynamicOnReadIn::ParticleBrokerDynamicOnReadIn(const std::str declareProperty("ValidateGeoIDs" , m_validateGeoID ); // collect and print cpu monitoring information declareProperty("SimSelectorCPUMonitoring" , m_doSelectorCPUMon ); - // refine the screen output for debugging - declareProperty("ScreenOutputPrefix" , m_screenOutputPrefix ); // The Particle/Vertex BarcodeService used in ISF to store barcode info declareProperty("BarcodeService" , m_barcodeSvc, "The Particle/Vertex BarcodeService used in ISF" ); @@ -109,46 +97,33 @@ ISF::ParticleBrokerDynamicOnReadIn::~ParticleBrokerDynamicOnReadIn() /** framework methods */ StatusCode ISF::ParticleBrokerDynamicOnReadIn::initialize() { - - // Screen output - for (size_t prl = 0; prl < m_screenOutputPrefix.size(); ++prl) m_screenEmptyPrefix += " "; - ATH_MSG_DEBUG ( m_screenOutputPrefix << "--------------------------------------------------------"); - - // retrieve the particle stack filler tool - if ( m_particleStackFiller.retrieve().isFailure() ){ - ATH_MSG_FATAL( m_screenOutputPrefix << "Could not retrieve ParticleStack Filler. Abort."); - return StatusCode::FAILURE; - } else - ATH_MSG_INFO( m_screenEmptyPrefix << "- StackFiller : " << m_particleStackFiller.typeAndName() ); + ATH_MSG_INFO("initialize() ..."); // retrieve the entry layer tool if ( m_entryLayerTool.retrieve().isFailure() ){ - ATH_MSG_FATAL( m_screenOutputPrefix << "Could not retrieve EntryLayer Tool. Abort."); + ATH_MSG_FATAL("Could not retrieve EntryLayer Tool. Abort."); return StatusCode::FAILURE; } else { - ATH_MSG_INFO( m_screenEmptyPrefix << "- EntryLayerTool : " << m_entryLayerTool.typeAndName() ); - // store a quick-access-pointer (removes GaudiOverhead) - m_entryLayerToolQuick = &(*m_entryLayerTool); + ATH_MSG_INFO( "- EntryLayerTool : " << m_entryLayerTool.typeAndName() ); } // retrieve the particle ing tool if given if ( ! m_orderingTool.empty()) { if ( m_orderingTool.retrieve().isFailure() ){ - ATH_MSG_FATAL( m_screenOutputPrefix << "Could not retrieve ParticleOrderingTool. Abort."); + ATH_MSG_FATAL("Could not retrieve ParticleOrderingTool. Abort."); return StatusCode::FAILURE; } else { - ATH_MSG_INFO( m_screenEmptyPrefix << "- Particel OrderingTool : " << m_orderingTool.typeAndName() ); - // store a quick-access-pointer (removes GaudiOverhead) - m_orderingToolQuick = &(*m_orderingTool); + ATH_MSG_INFO( "- Particel OrderingTool : " << m_orderingTool.typeAndName() ); + m_hasOrderingTool = true; } } // retrieve the geo identification decision tool if ( m_geoIDSvc.retrieve().isFailure()){ - ATH_MSG_FATAL( m_screenOutputPrefix << "Could not retrieve GeometryIdentifier Service. Abort."); + ATH_MSG_FATAL("Could not retrieve GeometryIdentifier Service. Abort."); return StatusCode::FAILURE; } else { - ATH_MSG_INFO( m_screenEmptyPrefix << "- GeoIDSvc : " + ATH_MSG_INFO( "- GeoIDSvc : " << (m_geoIDSvc.empty() ? "<not configured>" : m_geoIDSvc.typeAndName()) ); // store a quick-access-pointer (removes GaudiOverhead) m_geoIDSvcQuick = &(*m_geoIDSvc); @@ -192,7 +167,7 @@ StatusCode ISF::ParticleBrokerDynamicOnReadIn::initialize() // error when trying to retrieve the THistSvc else { // -> turn off validation output - ATH_MSG_ERROR( m_screenOutputPrefix << "Validation mode turned on but unable to retrieve THistService. Will not write out ROOT histograms/Trees."); + ATH_MSG_ERROR("Validation mode turned on but unable to retrieve THistService. Will not write out ROOT histograms/Trees."); m_validationOutput = false; } @@ -206,7 +181,7 @@ StatusCode ISF::ParticleBrokerDynamicOnReadIn::initialize() /** framework methods */ StatusCode ISF::ParticleBrokerDynamicOnReadIn::finalize() { - ATH_MSG_INFO ( m_screenOutputPrefix << "finalize() successful"); + ATH_MSG_INFO("finalize() ..."); return StatusCode::SUCCESS; } @@ -278,15 +253,9 @@ void ISF::ParticleBrokerDynamicOnReadIn::fillPosValTree( TTree *tree, /** update all SimulationSelectors in the routing chain with the given particle */ void ISF::ParticleBrokerDynamicOnReadIn::updateAllSelectors(const ISFParticle &particle) { - - // update all simSelectors with the given (new) particle - - // iterators used to loop over all sim Selectors - SimSelectorSet::iterator simSelectorIter = m_simSelectorSet.begin(); - SimSelectorSet::iterator simSelectorIterEnd = m_simSelectorSet.end(); - - for ( ; simSelectorIter != simSelectorIterEnd; ++simSelectorIter) - (*simSelectorIter)->update( particle); + for ( const auto& simSelector : m_simSelectorSet ) { + simSelector->update(particle); + } } @@ -307,14 +276,10 @@ void ISF::ParticleBrokerDynamicOnReadIn::selectAndStore( ISF::ISFParticle* p) // register the SimulatorID to the particle p->setNextSimID( selectedSimID); - // record the simulation flavor in the particle's extra barcode - storeSimulationFlavor( p ); - - // set particle order - if (m_orderingToolQuick) m_orderingToolQuick->setOrder( *p); + if (m_hasOrderingTool) m_orderingTool->setOrder(*p); - // push the particle onto the particle container - m_particles.push( p); + // store particle locally + m_particles.push(p); // no simulator could be found // -> drop particle @@ -333,19 +298,6 @@ void ISF::ParticleBrokerDynamicOnReadIn::selectAndStore( ISF::ISFParticle* p) } } - -/** store the simulation flavor of SimulationSelector that has selected the particle */ -void ISF::ParticleBrokerDynamicOnReadIn::storeSimulationFlavor( ISF::ISFParticle* p ) -{ - // m_simflavor has been identified in identifySimID() - if ( m_barcodeSvc->hasBitCalculator() ) { - Barcode::ParticleBarcode extrabc = p->getExtraBC(); - m_barcodeSvc->getBitCalculator()->SetSimulator(extrabc,m_simflavor); - p->setExtraBC( extrabc ); - } -} - - /** go through the chain of SimulationSelectors and return the SimulatoID of the first SimulationSelector that selects the particle */ ISF::SimSvcID ISF::ParticleBrokerDynamicOnReadIn::identifySimID( const ISF::ISFParticle* p) { @@ -382,39 +334,13 @@ ISF::SimSvcID ISF::ParticleBrokerDynamicOnReadIn::identifySimID( const ISF::ISFP // determine the simulator ID ISF::SimSvcID simID = selected ? (*--selectorIt)->simSvcID() : ISF::SimSvcID(ISF::fUndefinedSimID); - // reset simulation flavor -> stored in setSimulationFlavor(); - m_simflavor = ISF::UndefinedSim; - - if (selected) { - std::string simulatorType("none"); - ServiceHandle<ISimulationSvc>* hsimulator = (*selectorIt)->simulator(); - if ( hsimulator!=0 ) { - //if ( simulator.retrieve().isSuccess() ) { - //if ( (*(*--selectorIt)->simulator()) != 0 ) { - simulatorType = (*hsimulator).type(); - //} - } - std::transform(simulatorType.begin(), simulatorType.end(), simulatorType.begin(), ::tolower); - - if (simulatorType.find("fatras")!=std::string::npos) { m_simflavor = ISF::FatrasSim; } - else if (simulatorType.find("g4")!=std::string::npos) { m_simflavor = ISF::Geant4Sim; } - else if (simulatorType.find("geant")!=std::string::npos) { m_simflavor = ISF::Geant4Sim; } - else if (simulatorType.find("full")!=std::string::npos) { m_simflavor = ISF::Geant4Sim; } - else if (simulatorType.find("fastcalo")!=std::string::npos) { m_simflavor = ISF::FastCaloSim; } - else { m_simflavor = ISF::UndefinedSim; } // = 0 - - ATH_MSG_DEBUG( "simulation flavor : " << m_simflavor << " " << simulatorType ); - - } - return simID; } /** Initialize the stackSvc and the truthSvc */ -StatusCode ISF::ParticleBrokerDynamicOnReadIn::initializeEvent() +StatusCode ISF::ParticleBrokerDynamicOnReadIn::initializeEvent(ISFParticleContainer&& simParticles) { - ATH_MSG_DEBUG( m_screenOutputPrefix << "Initializing particle stack"); // fill set of simulation selectors once per job @@ -431,61 +357,34 @@ StatusCode ISF::ParticleBrokerDynamicOnReadIn::initializeEvent() } // call beginEvent() for all selectors registerd to the ParticleBroker: - // iterators used to loop over all sim Selectors - SimSelectorSet::iterator simSelectorIter = m_simSelectorSet.begin(); - SimSelectorSet::iterator simSelectorIterEnd = m_simSelectorSet.end(); - for ( ; simSelectorIter != simSelectorIterEnd; ++simSelectorIter) - (*simSelectorIter)->beginEvent(); // call beginEvent() on current selector - - // read particles from EvGen - ISFParticleContainer initContainer; - if ( m_particleStackFiller->fillStack( initContainer).isFailure() ){ - ATH_MSG_FATAL ( m_screenOutputPrefix << "Could not fill initial particle container. Abort." ); - return StatusCode::FAILURE; - } else - ATH_MSG_VERBOSE ( m_screenOutputPrefix << "Initial particle container filled, initial size: " << initContainer.size() ); + for ( const auto& simSelector : m_simSelectorSet ) { + simSelector->beginEvent(); + } // update the routing chain selectors with the particles in the initial stack - ISFParticleContainer::iterator particleIter = initContainer.begin(); - ISFParticleContainer::iterator particleIterEnd = initContainer.end(); - for ( ; particleIter != particleIterEnd; ++particleIter) { + for ( auto& particlePointer : simParticles ) { + auto& particle = *particlePointer; // identify the geoID of the particle - m_geoIDSvcQuick->identifyAndRegNextGeoID(**particleIter); + m_geoIDSvcQuick->identifyAndRegNextGeoID(particle); // the geoID at this point better makes sense :) - assertAtlasRegion( (**particleIter).nextGeoID() ); + assertAtlasRegion( particle.nextGeoID() ); // update all registered selectors (in all geoIDs) with this particle - updateAllSelectors( **particleIter); + updateAllSelectors(particle); - // inform the entry layer tool about this particle - ISF::EntryLayer layer = m_entryLayerToolQuick->registerParticle( **particleIter); + m_entryLayerTool->registerParticle(particle); + } - // if validation mode: fill the corresponding entry layer ROOT tree - if ( m_validationOutput && validEntryLayer(layer) ) { - fillPosValTree( m_t_entryLayerPos[layer], **particleIter); - } + size_t order = simParticles.size(); // FIXME: ugly hack to keep bit-wise identical output with prior FullG4 implementation :( - } + for ( auto& particlePtr: simParticles ) { + // FIXME: ugly hack to keep bit-wise identical output with prior FullG4 implementation :( + if (!m_hasOrderingTool) particlePtr->setOrder(order--); - // move the particles from the initial stack to the different geoID stacks - particleIter = initContainer.begin(); - particleIterEnd = initContainer.end(); - int iparticle=initContainer.size(); - for ( ; particleIter != particleIterEnd; ++particleIter,iparticle--) { - // - if a Selector selects a particle -> it is pushed onto the active stack - // - if it is not selected -> pushed onto the hold stack - selectAndStore( *particleIter); - if (!m_orderingToolQuick) { - (*particleIter)->setOrder(iparticle); - } + selectAndStore(particlePtr); } - // empty initial stack - // (don't delete the pointers, since they are now used in the local - // particle container: m_particles) - initContainer.clear(); - return StatusCode::SUCCESS; } @@ -511,8 +410,8 @@ void ISF::ParticleBrokerDynamicOnReadIn::push( ISFParticle *particlePtr, const I ISFParticle &particle = *particlePtr; if (parentPtr) { - Barcode::ParticleBarcode extrabc = parentPtr->getExtraBC(); - particle.setExtraBC( extrabc ); + int bcid = parentPtr->getBCID(); + particle.setBCID(bcid); } // get the particle's next geoID @@ -524,7 +423,7 @@ void ISF::ParticleBrokerDynamicOnReadIn::push( ISFParticle *particlePtr, const I geoID = m_geoIDSvcQuick->identifyAndRegNextGeoID(particle); } // inform the entry layer tool about this particle - ISF::EntryLayer layer = m_entryLayerToolQuick->registerParticle( particle ); + ISF::EntryLayer layer = m_entryLayerTool->registerParticle( particle ); // ---> if validation mode: fill the corresponding entry layer ROOT tree if ( m_validationOutput ) { @@ -587,7 +486,7 @@ const ISF::ConstISFParticleVector& ISF::ParticleBrokerDynamicOnReadIn::popVector // if this particle has a different order or the maximum size of the return vector is reached // -> don't add any more particles to the m_popParticles std::vector - if ( m_orderingToolQuick && ((curOrder != returnOrder) || (m_popParticles.size()>=maxVectorSize) ) ) break; + if ( m_hasOrderingTool && ((curOrder != returnOrder) || (m_popParticles.size()>=maxVectorSize) ) ) break; // add this particle to the, later returned, m_popParticles std::vector m_popParticles.push_back( curParticle); diff --git a/Simulation/ISF/ISF_Core/ISF_Services/src/ParticleBrokerDynamicOnReadIn.h b/Simulation/ISF/ISF_Core/ISF_Services/src/ParticleBrokerDynamicOnReadIn.h index 5755a5f58c6274381b190c166a8416ae5c12243c..4ea96f302dcff0f09898bdc51d62d69c051b3dc6 100644 --- a/Simulation/ISF/ISF_Core/ISF_Services/src/ParticleBrokerDynamicOnReadIn.h +++ b/Simulation/ISF/ISF_Core/ISF_Services/src/ParticleBrokerDynamicOnReadIn.h @@ -41,7 +41,6 @@ class TTree; namespace ISF { class IGeoIDSvc; - class IStackFiller; class IEntryLayerTool; class ISimulationSelector; @@ -70,7 +69,7 @@ namespace ISF { StatusCode finalize(); /** Initialize the particle broker */ - StatusCode initializeEvent(); + StatusCode initializeEvent(ISFParticleContainer&& simParticles); /** Finalize the event in the broker service */ virtual StatusCode finalizeEvent(); @@ -122,19 +121,12 @@ namespace ISF { SimulationSelector that selects the particle */ ISF::SimSvcID identifySimID( const ISF::ISFParticle* p); - /** store the simulation flavor of SimulationSelector that has selected the particle */ - void storeSimulationFlavor( ISF::ISFParticle* p ); - - /** AthenaTool for reading in the initial (eg. EvGen)_particle list */ - ToolHandle<IStackFiller> m_particleStackFiller; - /** AthenaTool responsible for writing Calo/Muon Entry/Exit Layer collection */ ToolHandle<IEntryLayerTool> m_entryLayerTool; - IEntryLayerTool *m_entryLayerToolQuick; //!< minimize Gaudi overhead /** AthenaTool responsible for proritizing the particles and determine their simulation order */ ToolHandle<IParticleOrderingTool> m_orderingTool; - IParticleOrderingTool *m_orderingToolQuick;//!< minimize Gaudi overhead + bool m_hasOrderingTool; /** the geo identifier service used to route the particle into the right SimulationSelector chain */ @@ -180,8 +172,6 @@ namespace ISF { int m_val_pdg; float m_val_p; float m_val_x, m_val_y, m_val_z; - - ISF::SimulationFlavor m_simflavor; }; /** Get the current stack size */ diff --git a/Simulation/ISF/ISF_Core/ISF_Services/src/TruthSvc.cxx b/Simulation/ISF/ISF_Core/ISF_Services/src/TruthSvc.cxx new file mode 100644 index 0000000000000000000000000000000000000000..20ac7172610d795241c8a84c990469db0dd5beed --- /dev/null +++ b/Simulation/ISF/ISF_Core/ISF_Services/src/TruthSvc.cxx @@ -0,0 +1,364 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/////////////////////////////////////////////////////////////////// +// TruthSvc.cxx, (c) ATLAS Detector software +/////////////////////////////////////////////////////////////////// + +// class header +#include "TruthSvc.h" +// other ISF_HepMC includes +#include "ISF_HepMC_Interfaces/ITruthStrategy.h" +// ISF includes +#include "ISF_Event/ITruthIncident.h" +// Framework +#include "GaudiKernel/ISvcLocator.h" +#include "StoreGate/StoreGateSvc.h" +#include "GaudiKernel/SystemOfUnits.h" +// Barcode +#include "BarcodeInterfaces/IBarcodeSvc.h" +// HepMC includes +#include "HepMC/SimpleVector.h" +#include "HepMC/GenParticle.h" +#include "HepMC/GenEvent.h" +#include "HepMC/GenVertex.h" +// CLHEP includes +#include "CLHEP/Geometry/Point3D.h" + +// DetectorDescription +#include "AtlasDetDescr/AtlasRegionHelper.h" + +/** Constructor **/ +ISF::TruthSvc::TruthSvc(const std::string& name,ISvcLocator* svc) : + AthService(name,svc), + m_barcodeSvc("BarcodeSvc",name), + m_geoStrategies(), + m_numStrategies(), + m_skipIfNoChildren(true), + m_skipIfNoParentBarcode(true), + m_ignoreUndefinedBarcodes(false), + m_passWholeVertex(true), + m_forceEndVtxRegionsVec(), + m_forceEndVtx(), + m_quasiStableParticlesIncluded(false), + m_secondaryParticleBcOffset(Barcode::fUndefinedBarcode), + m_myLowestVertexBC(Barcode::fUndefinedBarcode) +{ + // the barcode service (used to compute Vertex Barco des) + declareProperty("BarcodeSvc", m_barcodeSvc ); + // MCTruth writing strategies + declareProperty("SkipIfNoChildren", m_skipIfNoChildren ); + declareProperty("SkipIfNoParentBarcode", m_skipIfNoParentBarcode ); + declareProperty("IgnoreUndefinedBarcodes", m_ignoreUndefinedBarcodes ); + declareProperty("PassWholeVertices", m_passWholeVertex ); + // the truth strategies for the different AtlasDetDescr regions + declareProperty("BeamPipeTruthStrategies", m_geoStrategyHandles[AtlasDetDescr::fAtlasForward] ); + declareProperty("IDTruthStrategies", m_geoStrategyHandles[AtlasDetDescr::fAtlasID] ); + declareProperty("CaloTruthStrategies", m_geoStrategyHandles[AtlasDetDescr::fAtlasCalo] ); + declareProperty("MSTruthStrategies", m_geoStrategyHandles[AtlasDetDescr::fAtlasMS] ); + declareProperty("CavernTruthStrategies", m_geoStrategyHandles[AtlasDetDescr::fAtlasCavern] ); + // attach end-vertex if parent particle dies for the different AtlasDetDescr regions + declareProperty("ForceEndVtxInRegions", m_forceEndVtxRegionsVec ); + + declareProperty("QuasiStableParticlesIncluded", m_quasiStableParticlesIncluded); +} + +ISF::TruthSvc::~TruthSvc() +{} + + +/** Query the interfaces. */ +StatusCode ISF::TruthSvc::queryInterface(const InterfaceID& riid, void** ppvInterface) +{ + if ( IID_ITruthSvc == riid ) + *ppvInterface = (ITruthSvc*)this; + else { + // Interface is not directly available: try out a base class + return Service::queryInterface(riid, ppvInterface); + } + addRef(); + return StatusCode::SUCCESS; +} + + +/** framework methods */ +StatusCode ISF::TruthSvc::initialize() +{ + ATH_MSG_VERBOSE( "initialize()" ); + + // Screen output + ATH_MSG_DEBUG("--------------------------------------------------------"); + + // retrieve BarcodeSvc + if ( m_barcodeSvc.retrieve().isFailure() ) { + ATH_MSG_FATAL("Could not retrieve BarcodeService. Abort."); + return StatusCode::FAILURE; + } + + // retrieve the strategies for each atlas region (Athena Alg Tools) + // and setup whether we want to write end-vertices in this region whenever a truth particle dies + for ( unsigned short geoID=AtlasDetDescr::fFirstAtlasRegion; geoID<AtlasDetDescr::fNumAtlasRegions; ++geoID) { + if ( m_geoStrategyHandles[geoID].retrieve().isFailure() ) { + ATH_MSG_FATAL("Could not retrieve TruthStrategy Tool Array for SimGeoID=" + << AtlasDetDescr::AtlasRegionHelper::getName(geoID) << ". Abort."); + return StatusCode::FAILURE; + } + + // copy a pointer to the strategy instance to the local + // array of pointers (for faster access) + unsigned short curNumStrategies = m_geoStrategyHandles[geoID].size(); + m_numStrategies[geoID] = curNumStrategies; + m_geoStrategies[geoID] = new ISF::ITruthStrategy*[curNumStrategies]; + for ( unsigned short i = 0; i < curNumStrategies; ++i) { + m_geoStrategies[geoID][i] = &(*m_geoStrategyHandles[geoID][i]); + } + + // create an end-vertex for all truth particles ending in the current AtlasRegion? + bool forceEndVtx = std::find( m_forceEndVtxRegionsVec.begin(), + m_forceEndVtxRegionsVec.end(), + geoID ) != m_forceEndVtxRegionsVec.end(); + m_forceEndVtx[geoID] = forceEndVtx; + } + + ATH_MSG_VERBOSE("initialize() successful"); + return StatusCode::SUCCESS; +} + + +/** framework methods */ +StatusCode ISF::TruthSvc::finalize() +{ + ATH_MSG_VERBOSE("Finalizing ..."); + return StatusCode::SUCCESS; +} + + +/** Initialize the TruthSvc and the truthSvc */ +StatusCode ISF::TruthSvc::initializeTruthCollection() +{ + m_myLowestVertexBC = m_barcodeSvc->secondaryVertexBcOffset(); + m_secondaryParticleBcOffset = m_barcodeSvc->secondaryParticleBcOffset(); + + return StatusCode::SUCCESS; +} + + +StatusCode ISF::TruthSvc::releaseEvent() { + return StatusCode::SUCCESS; +} + + +/** Register a truth incident */ +void ISF::TruthSvc::registerTruthIncident( ISF::ITruthIncident& ti) { + + // pass whole vertex or individual child particles + ti.setPassWholeVertices(m_passWholeVertex); + + // the GeoID + AtlasDetDescr::AtlasRegion geoID = ti.geoID(); + + // check geoID assigned to the TruthIncident + if ( !validAtlasRegion(geoID) ) { + ATH_MSG_ERROR("Unable to register truth incident with unknown SimGeoID="<< geoID); + return; + } + + ATH_MSG_VERBOSE( "Registering TruthIncident for SimGeoID=" + << AtlasDetDescr::AtlasRegionHelper::getName(geoID) ); + + // number of child particles + unsigned short numSec = ti.numberOfChildren(); + if ( m_skipIfNoChildren && (numSec==0) ) { + ATH_MSG_VERBOSE( "No child particles present in the TruthIncident," + << " will not record this TruthIncident."); + return; + } + + // the parent particle -> get its barcode + Barcode::ParticleBarcode parentBC = ti.parentBarcode(); + if ( m_skipIfNoParentBarcode && (parentBC==Barcode::fUndefinedBarcode) ) { + ATH_MSG_VERBOSE( "Parent particle in TruthIncident does not have a barcode," + << " will not record this TruthIncident."); + return; + } + + // loop over registered truth strategies for given geoID + bool pass = false; + for ( unsigned short stratID=0; (!pass) && (stratID<m_numStrategies[geoID]); stratID++) { + // (*) test if given TruthIncident passes current strategy + pass = m_geoStrategies[geoID][stratID]->pass(ti); + } + + if (pass) { + // at least one truth stategy returend true + // -> record incident + recordIncidentToMCTruth( ti); + + } else { + // none of the truth strategies returned true + // -> child particles will NOT be added to the TruthEvent collection + + // attach parent particle end vertex if it gets killed by this interaction + if ( m_forceEndVtx[geoID] && !ti.parentSurvivesIncident() ) { + createGenVertexFromTruthIncident( ti); + } + + // -> assign shared barcode to all child particles (if barcode service supports it) + setSharedChildParticleBarcode( ti); + } + + return; +} + +/** Record the given truth incident to the MC Truth */ +void ISF::TruthSvc::recordIncidentToMCTruth( ISF::ITruthIncident& ti) { + + Barcode::PhysicsProcessCode processCode = ti.physicsProcessCode(); + Barcode::ParticleBarcode parentBC = ti.parentBarcode(); + + // record the GenVertex + HepMC::GenVertex *vtx = createGenVertexFromTruthIncident(ti); + + ATH_MSG_VERBOSE ( "Outgoing particles:" ); + // update parent barcode and add it to the vertex as outgoing particle + Barcode::ParticleBarcode newPrimBC = m_barcodeSvc->incrementBarcode( parentBC, processCode); + if ( newPrimBC == Barcode::fUndefinedBarcode) { + if (m_ignoreUndefinedBarcodes) { + ATH_MSG_WARNING("Unable to generate new Particle Barcode. Continuing due to 'IgnoreUndefinedBarcodes'==True"); + } else { + ATH_MSG_ERROR("Unable to generate new Particle Barcode. Aborting"); + abort(); + } + } + + HepMC::GenParticle *parentAfterIncident = ti.parentParticleAfterIncident( newPrimBC ); + if(parentAfterIncident) { + ATH_MSG_VERBOSE ( "Parent After Incident: " << *parentAfterIncident); + vtx->add_particle_out( parentAfterIncident ); + } + + // add child particles to the vertex + unsigned short numSec = ti.numberOfChildren(); + for ( unsigned short i=0; i<numSec; ++i) { + + bool writeOutChild = m_passWholeVertex || ti.childPassedFilters(i); + + if (writeOutChild) { + // generate a new barcode for the child particle + Barcode::ParticleBarcode secBC = m_barcodeSvc->newSecondary( parentBC, processCode); + if ( secBC == Barcode::fUndefinedBarcode) { + if (m_ignoreUndefinedBarcodes) + ATH_MSG_WARNING("Unable to generate new Secondary Particle Barcode. Continuing due to 'IgnoreUndefinedBarcodes'==True"); + else { + ATH_MSG_ERROR("Unable to generate new Secondary Particle Barcode. Aborting"); + abort(); + } + } + HepMC::GenParticle *p = ti.childParticle(i, secBC ); + ATH_MSG_VERBOSE ( "Writing out " << i << "th child particle: " << *p); + // add particle to vertex + vtx->add_particle_out( p); + + // Check to see if this is meant to be a "parent" vertex + if ( p && p->barcode() < m_secondaryParticleBcOffset ){ + vtx->suggest_barcode( m_myLowestVertexBC ); + ++m_myLowestVertexBC; + if (m_quasiStableParticlesIncluded){ + ATH_MSG_VERBOSE( "Found a case of low barcode (" << p->barcode() << " < " << + m_secondaryParticleBcOffset << " changing vtx barcode to " << m_myLowestVertexBC+1 ); + } else { + ATH_MSG_WARNING( "Modifying vertex barcode, but no apparent quasi-stable particle simulation enabled." ); + ATH_MSG_WARNING( "This means that you have encountered a very strange configuration. Watch out!" ); + } + } + } // <-- if write out child particle + else { + ATH_MSG_VERBOSE ( "Not writing out " << i << "th child particle." ); + } + + } // <-- loop over all child particles +} + +/** Record the given truth incident to the MC Truth */ +HepMC::GenVertex *ISF::TruthSvc::createGenVertexFromTruthIncident( ISF::ITruthIncident& ti) { + + Barcode::PhysicsProcessCode processCode = ti.physicsProcessCode(); + Barcode::ParticleBarcode parentBC = ti.parentBarcode(); + + std::vector<double> weights(1); + Barcode::ParticleBarcode primaryBC = parentBC % m_barcodeSvc->particleGenerationIncrement(); + weights[0] = static_cast<double>( primaryBC ); + + // Check for a previous end vertex on this particle. If one existed, then we should put down next to this + // a new copy of the particle. This is the agreed upon version of the quasi-stable particle truth, where + // the vertex at which we start Q-S simulation no longer conserves energy, but we keep both copies of the + // truth particles + HepMC::GenParticle *parent = ti.parentParticle(); + if (!parent) { + ATH_MSG_ERROR("Unable to write particle interaction to MC truth due to missing parent HepMC::GenParticle instance"); + abort(); + } + HepMC::GenEvent *mcEvent = parent->parent_event(); + if (!mcEvent) { + ATH_MSG_ERROR("Unable to write particle interaction to MC truth due to missing parent HepMC::GenEvent instance"); + abort(); + } + + // generate vertex + Barcode::VertexBarcode vtxbcode = m_barcodeSvc->newVertex( parentBC, processCode ); + if ( vtxbcode == Barcode::fUndefinedBarcode) { + if (m_ignoreUndefinedBarcodes) { + ATH_MSG_WARNING("Unable to generate new Truth Vertex Barcode. Continuing due to 'IgnoreUndefinedBarcodes'==True"); + } else { + ATH_MSG_ERROR("Unable to generate new Truth Vertex Barcode. Aborting"); + abort(); + } + } + int vtxID = 1000 + static_cast<int>(processCode); + HepMC::GenVertex *vtx = new HepMC::GenVertex( ti.position(), vtxID, weights ); + vtx->suggest_barcode( vtxbcode ); + + if (parent->end_vertex()){ + if(!m_quasiStableParticlesIncluded) { + ATH_MSG_WARNING("Parent particle found with an end vertex attached. This should only happen"); + ATH_MSG_WARNING("in the case of simulating quasi-stable particles. That functionality"); + ATH_MSG_WARNING("is not yet validated in ISF, so you'd better know what you're doing."); + ATH_MSG_WARNING("Will delete the old vertex and swap in the new one."); + } + + // Remove the old vertex from the event + parent->parent_event()->remove_vertex( parent->end_vertex() ); + + // Now add the new vertex to the new parent + vtx->add_particle_in( parent ); + ATH_MSG_VERBOSE ( "QS End Vertex representing process: " << processCode << ", for parent with barcode "<<parentBC<<". Creating." ); + ATH_MSG_VERBOSE ( "Parent: " << *parent); + } else { // Normal simulation + // add parent particle to vtx + vtx->add_particle_in( parent ); + ATH_MSG_VERBOSE ( "End Vertex representing process: " << processCode << ", for parent with barcode "<<parentBC<<". Creating." ); + ATH_MSG_VERBOSE ( "Parent: " << *parent); + } + + mcEvent->add_vertex( vtx ); + + return vtx; +} + +/** Set shared barcode for child particles particles */ +void ISF::TruthSvc::setSharedChildParticleBarcode( ISF::ITruthIncident& ti) { + Barcode::PhysicsProcessCode processCode = ti.physicsProcessCode(); + Barcode::ParticleBarcode parentBC = ti.parentBarcode(); + + ATH_MSG_VERBOSE ( "End Vertex representing process: " << processCode << ". TruthIncident failed cuts. Skipping."); + + // generate one new barcode for all child particles + Barcode::ParticleBarcode childBC = m_barcodeSvc->sharedChildBarcode( parentBC, processCode); + + // propagate this barcode into the TruthIncident only if + // it is a proper barcode, ie !=fUndefinedBarcode + if (childBC != Barcode::fUndefinedBarcode) { + ti.setAllChildrenBarcodes( childBC ); + } +} diff --git a/Simulation/ISF/ISF_Core/ISF_Services/src/TruthSvc.h b/Simulation/ISF/ISF_Core/ISF_Services/src/TruthSvc.h new file mode 100644 index 0000000000000000000000000000000000000000..b0541c4ff54474997d28ecaa6015db86e38d9d67 --- /dev/null +++ b/Simulation/ISF/ISF_Core/ISF_Services/src/TruthSvc.h @@ -0,0 +1,121 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/////////////////////////////////////////////////////////////////// +// TruthSvc.h, (c) ATLAS Detector software +/////////////////////////////////////////////////////////////////// + +#ifndef ISF_SERVICES_HEPMC_TRUTHSVC_H +#define ISF_SERVICES_HEPMC_TRUTHSVC_H 1 + +// STL includes +#include <string> + +// FrameWork includes +#include "GaudiKernel/ToolHandle.h" +#include "GaudiKernel/ServiceHandle.h" +#include "AthenaBaseComps/AthService.h" + +// ISF include +#include "ISF_Interfaces/ITruthSvc.h" + +// DetectorDescription +#include "AtlasDetDescr/AtlasRegion.h" + +// Barcode +#include "BarcodeEvent/Barcode.h" + +// McEventCollection +#include "GeneratorObjects/McEventCollection.h" + +// forward declarations +class StoreGateSvc; + +namespace Barcode { + class IBarcodeSvc; +} + +namespace HepMC { + class GenEvent; +} + +namespace ISF { + + class ITruthStrategy; + typedef ToolHandleArray<ITruthStrategy> TruthStrategyArray; + + /** @class TruthSvc + + HepMC based version of the ISF::ITruthSvc, + currently it takes an ITruthIncident base class + + + @author Andreas.Salzburger -at- cern.ch , Elmar.Ritsch -at- cern.ch + */ + class TruthSvc : public AthService, public ITruthSvc { + public: + + //** Constructor with parameters */ + TruthSvc( const std::string& name, ISvcLocator* pSvcLocator ); + + /** Destructor */ + virtual ~TruthSvc(); + + /** Athena algorithm's interface method initialize() */ + StatusCode initialize() override final; + /** Athena algorithm's interface method finalize() */ + StatusCode finalize() override final; + + /** Register a truth incident */ + void registerTruthIncident( ITruthIncident& truthincident) override final; + + /** Initialize the Truth Svc at the beginning of each event */ + StatusCode initializeTruthCollection() override final; + + /** Finalize the Truth Svc at the end of each event*/ + StatusCode releaseEvent() override final; + + /** Query the interfaces. **/ + StatusCode queryInterface( const InterfaceID& riid, void** ppvInterface ); + + private: + /** Record the given truth incident to the MC Truth */ + void recordIncidentToMCTruth( ITruthIncident& truthincident); + /** Record and end vertex to the MC Truth for the parent particle */ + HepMC::GenVertex *createGenVertexFromTruthIncident( ITruthIncident& truthincident); + + /** Set shared barcode for child particles */ + void setSharedChildParticleBarcode( ITruthIncident& truthincident); + + ServiceHandle<Barcode::IBarcodeSvc> m_barcodeSvc; //!< The Barcode service + + /** the truth strategie applied (as AthenaToolHandle Array) */ + TruthStrategyArray m_geoStrategyHandles[AtlasDetDescr::fNumAtlasRegions]; + /** for faster access: using an internal pointer to the actual ITruthStrategy instances */ + ITruthStrategy** m_geoStrategies[AtlasDetDescr::fNumAtlasRegions]; + unsigned short m_numStrategies[AtlasDetDescr::fNumAtlasRegions]; + + /** MCTruth steering */ + bool m_skipIfNoChildren; //!< do not record incident if numChildren==0 + bool m_skipIfNoParentBarcode; //!< do not record if parentBarcode==fUndefinedBarcode + bool m_ignoreUndefinedBarcodes;//!< do/don't abort if retrieve an undefined barcode + + bool m_storeExtraBCs; + bool m_passWholeVertex; + + std::vector<bool> m_forceEndVtxRegionsVec; //!< property containing AtlasRegions for which + // to write end-vtx + bool m_forceEndVtx[AtlasDetDescr::fNumAtlasRegions]; //!< attach end vertex to + // all parent particles if they die + + bool m_quasiStableParticlesIncluded; //!< does this job simulate quasi-stable particles. + + Barcode::ParticleBarcode m_secondaryParticleBcOffset; + Barcode::VertexBarcode m_myLowestVertexBC; + + }; +} + + +#endif //> !ISF_SERVICES_HEPMC_TRUTHSVC_H diff --git a/Simulation/ISF/ISF_Core/ISF_Services/src/components/ISF_Services_entries.cxx b/Simulation/ISF/ISF_Core/ISF_Services/src/components/ISF_Services_entries.cxx index 0ab8bfbcee77d8acfe8eb1eff066950306c449bf..5c8b6a298efec8fd1007341c6311591fc6fdd0ea 100644 --- a/Simulation/ISF/ISF_Core/ISF_Services/src/components/ISF_Services_entries.cxx +++ b/Simulation/ISF/ISF_Core/ISF_Services/src/components/ISF_Services_entries.cxx @@ -1,23 +1,29 @@ #include "GaudiKernel/DeclareFactoryEntries.h" -#include "../ParticleBrokerDynamicOnReadIn.h" -#include "../SimHitSvc.h" -#include "../ParticleKillerSimSvc.h" -#include "../ISFEnvelopeDefSvc.h" #include "../AFIIEnvelopeDefSvc.h" #include "../GeoIDSvc.h" +#include "../InputConverter.h" +#include "../ISFEnvelopeDefSvc.h" +#include "../ParticleBrokerDynamicOnReadIn.h" +#include "../ParticleKillerSimSvc.h" +#include "../SimHitSvc.h" +#include "../TruthSvc.h" -DECLARE_NAMESPACE_SERVICE_FACTORY( ISF , ParticleBrokerDynamicOnReadIn ) -DECLARE_NAMESPACE_SERVICE_FACTORY( ISF , SimHitSvc ) -DECLARE_NAMESPACE_SERVICE_FACTORY( ISF , ParticleKillerSimSvc ) -DECLARE_NAMESPACE_SERVICE_FACTORY( ISF , ISFEnvelopeDefSvc ) DECLARE_NAMESPACE_SERVICE_FACTORY( ISF , AFIIEnvelopeDefSvc ) DECLARE_NAMESPACE_SERVICE_FACTORY( ISF , GeoIDSvc ) +DECLARE_NAMESPACE_SERVICE_FACTORY( ISF , InputConverter ) +DECLARE_NAMESPACE_SERVICE_FACTORY( ISF , ISFEnvelopeDefSvc ) +DECLARE_NAMESPACE_SERVICE_FACTORY( ISF , ParticleBrokerDynamicOnReadIn ) +DECLARE_NAMESPACE_SERVICE_FACTORY( ISF , ParticleKillerSimSvc ) +DECLARE_NAMESPACE_SERVICE_FACTORY( ISF , SimHitSvc ) +DECLARE_NAMESPACE_SERVICE_FACTORY( ISF , TruthSvc ) DECLARE_FACTORY_ENTRIES( ISF_Services ) { - DECLARE_NAMESPACE_SERVICE( ISF , ParticleBrokerDynamicOnReadIn ) - DECLARE_NAMESPACE_SERVICE( ISF , SimHitSvc ) - DECLARE_NAMESPACE_SERVICE( ISF , ParticleKillerSimSvc ) - DECLARE_NAMESPACE_SERVICE( ISF , ISFEnvelopeDefSvc ) DECLARE_NAMESPACE_SERVICE( ISF , AFIIEnvelopeDefSvc ) DECLARE_NAMESPACE_SERVICE( ISF , GeoIDSvc ) + DECLARE_NAMESPACE_SERVICE( ISF , InputConverter ) + DECLARE_NAMESPACE_SERVICE( ISF , ISFEnvelopeDefSvc ) + DECLARE_NAMESPACE_SERVICE( ISF , ParticleBrokerDynamicOnReadIn ) + DECLARE_NAMESPACE_SERVICE( ISF , ParticleKillerSimSvc ) + DECLARE_NAMESPACE_SERVICE( ISF , SimHitSvc ) + DECLARE_NAMESPACE_SERVICE( ISF , TruthSvc ) } diff --git a/Simulation/ISF/ISF_Core/ISF_Services/test/ISF_Services.xml b/Simulation/ISF/ISF_Core/ISF_Services/test/ISF_Services.xml new file mode 100644 index 0000000000000000000000000000000000000000..50fbad5b5ab290662a95b59daef05b7b6e8a8a08 --- /dev/null +++ b/Simulation/ISF/ISF_Core/ISF_Services/test/ISF_Services.xml @@ -0,0 +1,15 @@ +<?xml version="1.0"?> +<atn> + <TEST name="UnitTests" type="makecheck"> + <package>Simulation/ISF/ISF_Core/ISF_Services</package> + <author>Elmar Ritsch</author> + <mailto>atlas-srl-Sim-ISF-Core</mailto> + <expectations> + <errorMessage>Athena exited abnormally</errorMessage> + <errorMessage>differ</errorMessage> + <warningMessage> # WARNING_MESSAGE : post.sh> ERROR</warningMessage> + <successMessage>check ok</successMessage> + <returnValue>0</returnValue> + </expectations> + </TEST> +</atn> diff --git a/Simulation/ISF/ISF_Core/ISF_Services/test/InputConverter_test.cxx b/Simulation/ISF/ISF_Core/ISF_Services/test/InputConverter_test.cxx new file mode 100644 index 0000000000000000000000000000000000000000..9226cee223bdb538980ad2d2663ca99d89a9a04e --- /dev/null +++ b/Simulation/ISF/ISF_Core/ISF_Services/test/InputConverter_test.cxx @@ -0,0 +1,452 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * @author Elmar Ritsch <Elmar.Ritsch@cern.ch> + * @date June, 2016 + * @brief Tests for ISF::InputConverter. + */ + +#undef NDEBUG + +// Tested service +#include "../src/InputConverter.h" + +// Framework +#include "GaudiKernel/PhysicalConstants.h" +#include "GaudiKernel/DeclareFactoryEntries.h" +#include "GaudiKernel/Bootstrap.h" +#include "GaudiKernel/IProperty.h" +#include "GaudiKernel/ISvcManager.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/IAppMgrUI.h" +#include "GaudiKernel/SmartIF.h" +#include "AthenaBaseComps/AthAlgTool.h" + +// Framework testing +#include "TestTools/initGaudi.h" + +// Google Test +#include "gtest/gtest.h" +// Google Mock +#include "gmock/gmock.h" + +// ISF +#include "ISF_Event/ISFParticle.h" +#include "ISF_HepMC_Interfaces/IGenParticleFilter.h" + +// Amg +#include "GeoPrimitives/GeoPrimitives.h" + +// HepMC +#include "HepMC/GenParticle.h" +#include "HepMC/GenVertex.h" + +// STL includes +#include <cstdlib> // quick_exit + + +namespace ISFTesting { + +// Athena Tool to emulate a GenParticleFilter +class MockFilterTool : public AthAlgTool, + public ISF::IGenParticleFilter { + + public: + MockFilterTool(const std::string& type, const std::string& name, const IInterface* parent) + : AthAlgTool(type,name,parent) + { declareInterface<ISF::IGenParticleFilter>(this); }; + + virtual ~MockFilterTool() {}; + + // mock method which will be called by tested code + MOCK_CONST_METHOD1(pass, bool(const HepMC::GenParticle&)); +}; + +DECLARE_TOOL_FACTORY( MockFilterTool ) + + +class InputConverter_test: public ::testing::Test { + + protected: + virtual void SetUp() override { + m_appMgr = Gaudi::createApplicationMgr(); + ASSERT_TRUE( m_appMgr!=nullptr ); + + m_svcLoc = m_appMgr; + ASSERT_TRUE( m_svcLoc.isValid() ); + + m_svcMgr = m_appMgr; + ASSERT_TRUE( m_svcMgr.isValid() ); + + m_propMgr = m_appMgr; + ASSERT_TRUE( m_propMgr.isValid() ); + ASSERT_TRUE( m_propMgr->setProperty( "EvtSel", "NONE" ).isSuccess() ); + ASSERT_TRUE( m_propMgr->setProperty( "JobOptionsType", "NONE" ).isSuccess() ); + + m_toolSvc = m_svcLoc->service("ToolSvc"); + ASSERT_TRUE( m_toolSvc.isValid() ); + + ASSERT_TRUE( m_appMgr->configure().isSuccess() ); + ASSERT_TRUE( m_appMgr->initialize().isSuccess() ); + + // the tested AthenaService + m_svc = m_svcLoc->service("ISF::InputConverter/InputConverter"); + ASSERT_TRUE( m_svc.isValid() ); + ASSERT_TRUE( m_svc->setProperties().isSuccess() ); + ASSERT_TRUE( m_svc->configure().isSuccess() ); + } + + virtual void TearDown() override { + // @TODO: for newer Gaudi versions (atlasoff rel 21+) + // an approach like this would be much cleaner + // than releasing the tools by hand in the individual + // test functions + //const auto tools = m_toolSvc->getTools(); + //for (auto& tool: tools) { + // ASSERT_TRUE( TearDownTool(tool).isSuccess() ); + //} + + m_svcMgr->removeService(m_svc); + ASSERT_TRUE( m_svc->finalize().isSuccess() ); + ASSERT_TRUE( m_svc->terminate().isSuccess() ); + ReleaseSmartIFComponent(m_svc); + + ASSERT_TRUE( m_appMgr->finalize().isSuccess() ); + ASSERT_TRUE( m_appMgr->terminate().isSuccess() ); + Gaudi::setInstance( static_cast<IAppMgrUI*>(nullptr)) ; + } + + MockFilterTool* SetUpMockFilterTool(const std::string& name) const { + IAlgTool* mockFilterITool = nullptr; + m_toolSvc->retrieveTool(name, mockFilterITool); + + MockFilterTool* mockFilterTool = dynamic_cast<MockFilterTool*>(mockFilterITool); + return mockFilterTool; + } + + void ReleaseSmartIFComponent(IInterface* comp) { + size_t finalRefCount = 1; // keep one reference for the SmartIF destructor + for (size_t refCount = comp->refCount(); refCount>finalRefCount; refCount--) { + comp->release(); + } + } + + // release given tool from the ToolService until it reaches a + // reference count of 1 + StatusCode TearDownTool(IAlgTool* tool) const { + for (size_t refCount = tool->refCount(); refCount>0; refCount--) { + StatusCode sc = m_toolSvc->releaseTool(tool); + if ( !sc.isSuccess() ) { + return StatusCode::FAILURE; + } + } + return StatusCode::SUCCESS; + } + + // + // accessors for private methods + // NB: This works because InputConverter_test is a friend + // of the tested InputConverter service + // + template<typename... Args> + ISF::ISFParticle* convertParticle(Args&&... args) const { + return m_svc->convertParticle(std::forward<Args>(args)...); + } + + template<typename... Args> + bool passesFilters(Args&&... args) const { + return m_svc->passesFilters(std::forward<Args>(args)...); + } + + // + // protected member variables + // + + // Core Gaudi components + IAppMgrUI* m_appMgr = nullptr; + SmartIF<ISvcLocator> m_svcLoc; + SmartIF<ISvcManager> m_svcMgr; + SmartIF<IToolSvc> m_toolSvc; + SmartIF<IProperty> m_propMgr; + + SmartIF<ISF::InputConverter> m_svc; // the tested AthenaService + +}; // InputConverter_test fixture + + +TEST_F(InputConverter_test, initialize_empty) { + ASSERT_TRUE( m_svc->initialize().isSuccess() ); +} + + +TEST_F(InputConverter_test, convertParticle_nullptr) { + ISF::ISFParticle* expected = nullptr; + int bcid = 1; + ASSERT_EQ( expected, convertParticle(nullptr, bcid) ); +} + + +TEST_F(InputConverter_test, convertParticle_without_production_vertex) { + HepMC::FourVector mom(12.3, 45.6, 78.9, 0.12); + HepMC::GenParticle* genPart = new HepMC::GenParticle(mom, + 123, // pdg + 1 // status + ); + ISF::ISFParticle* expected = nullptr; + int bcid = 99; + ASSERT_EQ( expected, convertParticle(genPart, bcid) ); + delete genPart; +} + + +TEST_F(InputConverter_test, convertParticle_using_generated_mass) { + m_svc->setProperty("UseGeneratedParticleMass", "True"); + ASSERT_TRUE( m_svc->initialize().isSuccess() ); + + HepMC::FourVector mom(12.3, 45.6, 78.9, 0.12); + // dynamic allocation necessary as particle ownership is + // handed over to a HepMC::GenVertex later + HepMC::GenParticle* genPart = new HepMC::GenParticle(mom, + 11, // pdg id (e-) + 1 // status + ); + genPart->set_generated_mass(1234.56); + genPart->suggest_barcode(9876352); + + HepMC::FourVector pos(9.8, 7.65, 4.3, 0.321); // NB: 4th component is time*c + int vtx_id = -123; + HepMC::GenVertex prodVtx(pos, vtx_id); + prodVtx.add_particle_out(genPart); + + Amg::Vector3D expectedPos(9.8, 7.65, 4.3); + Amg::Vector3D expectedMom(12.3, 45.6, 78.9); + ISF::DetRegionSvcIDPair expectedHistory(AtlasDetDescr::fUndefinedAtlasRegion, ISF::fEventGeneratorSimID); + auto expectedTruthBinding = new ISF::TruthBinding(genPart); + ISF::ISFParticle expected(expectedPos, + expectedMom, + 1234.56, + -1., // charge + 11, // pdg id + 0.321/Gaudi::Units::c_light, // time + expectedHistory, + 563, // bcid + 9876352, // barcode + expectedTruthBinding + ); + + int bcid = 563; + // call the InputConverter's private method + ISF::ISFParticle* returned = convertParticle(genPart, bcid); + ASSERT_TRUE( returned ); + + ASSERT_EQ( expected, *returned ); +} + + +TEST_F(InputConverter_test, convertParticle_using_particleDataTable_photon) { + m_svc->setProperty("UseGeneratedParticleMass", "False"); + ASSERT_TRUE( m_svc->initialize().isSuccess() ); + + HepMC::FourVector mom(12.3, 45.6, 78.9, 0.12); + // dynamic allocation necessary as particle ownership is + // handed over to a HepMC::GenVertex later + HepMC::GenParticle* genPart = new HepMC::GenParticle(mom, + 22, // pdg id (gamma) + 1 // status + ); + genPart->set_generated_mass(1234.56); // should be ignored later on + genPart->suggest_barcode(9876352); + + HepMC::FourVector pos(9.8, 7.65, 4.3, 0.321); // NB: 4th component is time*c + int vtx_id = -123; + HepMC::GenVertex prodVtx(pos, vtx_id); + prodVtx.add_particle_out(genPart); + + Amg::Vector3D expectedPos(9.8, 7.65, 4.3); + Amg::Vector3D expectedMom(12.3, 45.6, 78.9); + ISF::DetRegionSvcIDPair expectedHistory(AtlasDetDescr::fUndefinedAtlasRegion, ISF::fEventGeneratorSimID); + auto expectedTruthBinding = new ISF::TruthBinding(genPart); + ISF::ISFParticle expected(expectedPos, + expectedMom, + 0., // mass from ParticleDataTable + 0., // charge + 22, // pdg id + 0.321/Gaudi::Units::c_light, // time + expectedHistory, + 0, // bcid + 9876352, // barcode + expectedTruthBinding + ); + + int bcid = 0; + // call the InputConverter's private method + ISF::ISFParticle* returned = convertParticle(genPart, bcid); + ASSERT_TRUE( returned ); + + ASSERT_EQ( expected, *returned ); +} + + +TEST_F(InputConverter_test, convertParticle_using_particleDataTable_electron) { + m_svc->setProperty("UseGeneratedParticleMass", "False"); + ASSERT_TRUE( m_svc->initialize().isSuccess() ); + + HepMC::FourVector mom(12.3, 45.6, 78.9, 0.12); + // dynamic allocation necessary as particle ownership is + // handed over to a HepMC::GenVertex later + HepMC::GenParticle* genPart = new HepMC::GenParticle(mom, + 11, // pdg id (e-) + 1 // status + ); + genPart->set_generated_mass(1234.56); // should be ignored later on + genPart->suggest_barcode(9876352); + + HepMC::FourVector pos(9.8, 7.65, 4.3, 0.321); // NB: 4th component is time*c + int vtx_id = -123; + HepMC::GenVertex prodVtx(pos, vtx_id); + prodVtx.add_particle_out(genPart); + + Amg::Vector3D expectedPos(9.8, 7.65, 4.3); + Amg::Vector3D expectedMom(12.3, 45.6, 78.9); + ISF::DetRegionSvcIDPair expectedHistory(AtlasDetDescr::fUndefinedAtlasRegion, ISF::fEventGeneratorSimID); + auto expectedTruthBinding = new ISF::TruthBinding(genPart); + ISF::ISFParticle expected(expectedPos, + expectedMom, + 0.51099891/Gaudi::Units::MeV, // from particle + -1., // charge + 11, // pdg id + 0.321/Gaudi::Units::c_light, // time + expectedHistory, + 11, // bcid + 9876352, // barcode + expectedTruthBinding + ); + + int bcid = 11; + // call the InputConverter's private method + ISF::ISFParticle* returned = convertParticle(genPart, bcid); + std::cout << " EMASS=" << std::setprecision(20) << returned->mass() << std::endl; + ASSERT_TRUE( returned ); + + ASSERT_EQ( expected, *returned ); +} + + +TEST_F(InputConverter_test, passesFilters_empty_filters_defaultconstructed_genpart) { + ASSERT_TRUE( m_svc->initialize().isSuccess() ); + + const HepMC::GenParticle genPart{}; + ASSERT_TRUE( passesFilters(genPart) ); +} + + +TEST_F(InputConverter_test, passesFilters_empty_filters) { + ASSERT_TRUE( m_svc->initialize().isSuccess() ); + + HepMC::FourVector mom(12.3, 45.6, 78.9, 0.12); + HepMC::GenParticle genPart(mom, + 11, // pdg id (e-) + 1 // status + ); + genPart.set_generated_mass(1234.56); + genPart.suggest_barcode(9876352); + const HepMC::GenParticle constGenPart(std::move(genPart)); + + ASSERT_TRUE( passesFilters(constGenPart) ); +} + + +TEST_F(InputConverter_test, passesFilters_one_pass_filter) { + // retrieve mockable GenParticleFilter tool and point InputConverter to the same instance + MockFilterTool* filterTool = SetUpMockFilterTool("ISFTesting::MockFilterTool/DummyFilter"); + ASSERT_TRUE( filterTool ); + m_svc->setProperty("GenParticleFilters", "['ISFTesting::MockFilterTool/DummyFilter']"); + ASSERT_TRUE( m_svc->initialize().isSuccess() ); + + const HepMC::GenParticle genPart{}; + HepMC::FourVector mom(12.3, 45.6, 78.9, 0.12); + HepMC::GenParticle genPart2(mom, + 11, // pdg id (e-) + 1 // status + ); + + EXPECT_CALL(*filterTool, pass(genPart)) + .Times(1) + .WillOnce(::testing::Return(true)); + + ASSERT_TRUE( passesFilters(genPart) ); + + ASSERT_TRUE( TearDownTool(filterTool).isSuccess() ); +} + + +TEST_F(InputConverter_test, passesFilters_one_nonpass_filter) { + // retrieve mockable GenParticleFilter tool and point InputConverter to the same instance + MockFilterTool* filterTool = SetUpMockFilterTool("ISFTesting::MockFilterTool/DummyFilter"); + ASSERT_TRUE( filterTool ); + m_svc->setProperty("GenParticleFilters", "['ISFTesting::MockFilterTool/DummyFilter']"); + ASSERT_TRUE( m_svc->initialize().isSuccess() ); + + const HepMC::GenParticle genPart{}; + HepMC::FourVector mom(12.3, 45.6, 78.9, 0.12); + HepMC::GenParticle genPart2(mom, + 11, // pdg id (e-) + 1 // status + ); + + EXPECT_CALL(*filterTool, pass(genPart)) + .Times(1) + .WillOnce(::testing::Return(false)); + + ASSERT_FALSE( passesFilters(genPart) ); + + ASSERT_TRUE( TearDownTool(filterTool).isSuccess() ); +} + + +TEST_F(InputConverter_test, passesFilters_two_filters) { + // retrieve mockable GenParticleFilter tool and point InputConverter to the same instance + MockFilterTool* filterTool1 = SetUpMockFilterTool("ISFTesting::MockFilterTool/DummyFilterZ"); + MockFilterTool* filterTool2 = SetUpMockFilterTool("ISFTesting::MockFilterTool/DummyFilterY"); + ASSERT_TRUE( filterTool1 ); + ASSERT_TRUE( filterTool2 ); + m_svc->setProperty("GenParticleFilters", "['ISFTesting::MockFilterTool/DummyFilterZ', 'ISFTesting::MockFilterTool/DummyFilterY']"); + ASSERT_TRUE( m_svc->initialize().isSuccess() ); + + const HepMC::GenParticle genPart{}; + HepMC::FourVector mom(12.3, 45.6, 78.9, 0.12); + HepMC::GenParticle genPart2(mom, + 11, // pdg id (e-) + 1 // status + ); + + EXPECT_CALL(*filterTool1, pass(genPart)) + .Times(1) + .WillOnce(::testing::Return(true)); + + EXPECT_CALL(*filterTool2, pass(genPart)) + .Times(1) + .WillOnce(::testing::Return(true)); + + ASSERT_TRUE( passesFilters(genPart) ); + + // apparently it's our responsibility to reduce the reference + // counter to 0 to make sure the tools are properly destructed + ASSERT_TRUE( m_toolSvc->releaseTool(filterTool1).isSuccess() ); + ASSERT_TRUE( m_toolSvc->releaseTool(filterTool1).isSuccess() ); + ASSERT_TRUE( m_toolSvc->releaseTool(filterTool2).isSuccess() ); + ASSERT_TRUE( m_toolSvc->releaseTool(filterTool2).isSuccess() ); +} + +} // <-- namespace ISFTesting + +int main(int argc, char *argv[]) { + ::testing::InitGoogleTest( &argc, argv ); + + // gets stuck forever while trying to finalize boost crap inside SGTools: + //return RUN_ALL_TESTS(); + // skips proper finalization: + std::quick_exit( RUN_ALL_TESTS() ); +} diff --git a/Simulation/ISF/ISF_Core/ISF_Services/test/gtest_post_check.sh b/Simulation/ISF/ISF_Core/ISF_Services/test/gtest_post_check.sh new file mode 100755 index 0000000000000000000000000000000000000000..66b31db557526776de1a4fd0cddcb8ed0ed71fd7 --- /dev/null +++ b/Simulation/ISF/ISF_Core/ISF_Services/test/gtest_post_check.sh @@ -0,0 +1,20 @@ +#!/bin/bash +LOGFILE=${1} +FAILUREPATTERN='\[ FAILED \].*' +ALIVEPATTERN='\[ PASSED \].*' + +#cat ${LOGFILE} + +if ! grep -xq "$ALIVEPATTERN" ${LOGFILE} +then + echo -e "\nUnable to find gtest signature '${ALIVEPATTERN}' in test output!" + echo -e "ERROR: Tests failed!\n" + exit 1 +fi + +if grep -xq "$FAILUREPATTERN" ${LOGFILE} +then + echo -e "\nFound failure pattern '${FAILUREPATTERN}' in test output!" + echo -e "ERROR: Tests failed!\n" + exit 1 +fi