diff --git a/MagneticField/MagFieldConditions/MagFieldConditions/AtlasFieldCacheCondObj.h b/MagneticField/MagFieldConditions/MagFieldConditions/AtlasFieldCacheCondObj.h index 74bb2636e4f066175c9fa8cefa2f00cb895524d6..f0a75517d5ff6a306631e65d2059a343da05773a 100644 --- a/MagneticField/MagFieldConditions/MagFieldConditions/AtlasFieldCacheCondObj.h +++ b/MagneticField/MagFieldConditions/MagFieldConditions/AtlasFieldCacheCondObj.h @@ -28,11 +28,14 @@ public: inline void getInitializedCache (MagField::AtlasFieldCache& cache) const; /** access to solenoid field scale factor */ - double solenoidFieldScaleFactor() const { return m_solFieldScale; } ; + double solenoidFieldScaleFactor() const { return m_solFieldScale; } /** access to toroid field scale factor */ - double toriodFieldScaleFactor() const { return m_torFieldScale; } ; + double toriodFieldScaleFactor() const { return m_torFieldScale; } + /** access to non-owning AtlasFieldMap*/ + const MagField::AtlasFieldMap* fieldMap() const { return m_fieldMap; } + /** set values for field scale and service to be able to build the cache **/ bool initialize(double solFieldScale, double torFieldScale, const MagField::AtlasFieldMap* fieldMap); diff --git a/Simulation/G4Atlas/G4AtlasServices/CMakeLists.txt b/Simulation/G4Atlas/G4AtlasServices/CMakeLists.txt index 2d735a12d06a67ac253d5e95567b77b5be823ce9..83078840efae523467702f9a4d99d013788525fa 100644 --- a/Simulation/G4Atlas/G4AtlasServices/CMakeLists.txt +++ b/Simulation/G4Atlas/G4AtlasServices/CMakeLists.txt @@ -10,13 +10,15 @@ find_package( CLHEP ) find_package( Geant4 ) find_package( TBB ) find_package( XercesC ) - +find_package( ROOT COMPONENTS Core Tree MathCore Hist RIO pthread ) # Component(s) in the package: atlas_add_component( G4AtlasServices src/*.cxx src/components/*.cxx - INCLUDE_DIRS ${GEANT4_INCLUDE_DIRS} ${XERCESC_INCLUDE_DIRS} ${CLHEP_INCLUDE_DIRS} ${TBB_INCLUDE_DIRS} - LINK_LIBRARIES ${GEANT4_LIBRARIES} ${XERCESC_LIBRARIES} ${CLHEP_LIBRARIES} ${TBB_LIBRARIES} GaudiKernel AthenaBaseComps G4AtlasInterfaces G4AtlasToolsLib G4PhysicsLists MagFieldInterfaces) + INCLUDE_DIRS ${GEANT4_INCLUDE_DIRS} ${XERCESC_INCLUDE_DIRS} ${CLHEP_INCLUDE_DIRS} ${TBB_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${GEANT4_LIBRARIES} ${XERCESC_LIBRARIES} ${CLHEP_LIBRARIES} ${TBB_LIBRARIES} ${ROOT_LIBRARIES} + GaudiKernel AthenaBaseComps + G4AtlasInterfaces G4AtlasToolsLib G4PhysicsLists PathResolver MagFieldElements MagFieldInterfaces) #test G4AtlasFieldServices atlas_add_test( G4AtlasFieldServices_test diff --git a/Simulation/G4Atlas/G4AtlasServices/python/G4AtlasFieldServices.py b/Simulation/G4Atlas/G4AtlasServices/python/G4AtlasFieldServices.py index 8dcbf5aba462fd46d61cb5531dc723161e234454..9a4ca5784b3f93a44a59bdd154e8a3ad83b81b29 100644 --- a/Simulation/G4Atlas/G4AtlasServices/python/G4AtlasFieldServices.py +++ b/Simulation/G4Atlas/G4AtlasServices/python/G4AtlasFieldServices.py @@ -3,7 +3,6 @@ from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator from AthenaConfiguration.ComponentFactory import CompFactory StandardFieldSvc=CompFactory.StandardFieldSvc -from MagFieldServices.MagFieldServicesConfig import MagneticFieldSvcCfg #to prevent unit tests failing when just running over simulation import os if "AthSimulation_DIR" not in os.environ: @@ -12,26 +11,15 @@ if "AthSimulation_DIR" not in os.environ: def StandardFieldSvcCfg(ConfigFlags,name="StandardField", **kwargs): result = ComponentAccumulator() - #setup the field and add the magneticfield service - acc = MagneticFieldSvcCfg(ConfigFlags) - result.merge(acc) - - kwargs.setdefault("MagneticFieldSvc", result.getService("AtlasFieldSvc")) # TODO This should probably be based on simFlags.MagneticField? - #kwargs.setdefault("FieldOn", True) - result.addService(StandardFieldSvc(name, **kwargs)) return result def ForwardFieldSvcCfg(ConfigFlags, name="ForwardField", **kwargs): result = ComponentAccumulator() - #setup the field and add the magneticfield service - acc = MagneticFieldSvcCfg(ConfigFlags) - result.merge(acc) - - #FIXME Once it exists this version should use the new MagField Service defined in ForwardRegionMgField - kwargs.setdefault("MagneticFieldSvc", result.getService("AtlasFieldSvc")) - #kwargs.setdefault("FieldOn", True) + # #FIXME Once it exists this version should use the new MagField Service defined in ForwardRegionMgField + # kwargs.setdefault("MagneticFieldSvc", result.getService("AtlasFieldSvc")) + # #kwargs.setdefault("FieldOn", True) result.addService(StandardFieldSvc(name, **kwargs)) return result @@ -44,6 +32,7 @@ def Q1FwdG4FieldSvcCfg(ConfigFlags, name='Q1FwdG4FieldSvc', **kwargs): MQXA_DataFile = "MQXA_NOMINAL.dat")) kwargs.setdefault("MagneticFieldSvc", result.getService("Q1")) + kwargs.setdefault("UseMagFieldSvc", True) result.addService(StandardFieldSvc(name, **kwargs)) return result def Q2FwdG4FieldSvcCfg(ConfigFlags, name='Q2FwdG4FieldSvc', **kwargs): @@ -53,6 +42,7 @@ def Q2FwdG4FieldSvcCfg(ConfigFlags, name='Q2FwdG4FieldSvc', **kwargs): Magnet = 1, # FIXME find a better way to do this. MQXA_DataFile = "MQXA_NOMINAL.dat")) kwargs.setdefault("MagneticFieldSvc", result.getService("Q2")) + kwargs.setdefault("UseMagFieldSvc", True) result.addService(StandardFieldSvc(name, **kwargs)) return result def Q3FwdG4FieldSvcCfg(ConfigFlags, name='Q3FwdG4FieldSvc', **kwargs): @@ -62,6 +52,7 @@ def Q3FwdG4FieldSvcCfg(ConfigFlags, name='Q3FwdG4FieldSvc', **kwargs): Magnet = 2, # FIXME find a better way to do this. MQXA_DataFile = "MQXA_NOMINAL.dat")) kwargs.setdefault("MagneticFieldSvc", result.getService("Q3")) + kwargs.setdefault("UseMagFieldSvc", True) result.addService(StandardFieldSvc(name, **kwargs)) return result def D1FwdG4FieldSvcCfg(ConfigFlags, name='D1FwdG4FieldSvc', **kwargs): @@ -70,6 +61,7 @@ def D1FwdG4FieldSvcCfg(ConfigFlags, name='D1FwdG4FieldSvc', **kwargs): Magnet = 3))# FIXME find a better way to do this. kwargs.setdefault("MagneticFieldSvc", result.getService("D1")) + kwargs.setdefault("UseMagFieldSvc", True) result.addService(StandardFieldSvc(name, **kwargs)) return result def D2FwdG4FieldSvcCfg(ConfigFlags, name='D2FwdG4FieldSvc', **kwargs): @@ -78,6 +70,7 @@ def D2FwdG4FieldSvcCfg(ConfigFlags, name='D2FwdG4FieldSvc', **kwargs): result.addService( MagField__ForwardRegionFieldSvc("D2", Magnet = 4))# FIXME find a better way to do this. kwargs.setdefault("MagneticFieldSvc", result.getService("D2")) + kwargs.setdefault("UseMagFieldSvc", True) result.addService(StandardFieldSvc(name, **kwargs)) return result def Q4FwdG4FieldSvcCfg(ConfigFlags, name='Q4FwdG4FieldSvc', **kwargs): @@ -85,6 +78,7 @@ def Q4FwdG4FieldSvcCfg(ConfigFlags, name='Q4FwdG4FieldSvc', **kwargs): result.addService( MagField__ForwardRegionFieldSvc("Q4", Magnet = 5))# FIXME find a better way to do this. kwargs.setdefault("MagneticFieldSvc", result.getService("Q4")) + kwargs.setdefault("UseMagFieldSvc", True) result.addService(StandardFieldSvc(name, **kwargs)) return result def Q5FwdG4FieldSvcCfg(ConfigFlags, name='Q5FwdG4FieldSvc', **kwargs): @@ -92,6 +86,7 @@ def Q5FwdG4FieldSvcCfg(ConfigFlags, name='Q5FwdG4FieldSvc', **kwargs): result.addService( MagField__ForwardRegionFieldSvc("Q5", Magnet = 6))# FIXME find a better way to do this. kwargs.setdefault("MagneticFieldSvc", result.getService("Q5")) + kwargs.setdefault("UseMagFieldSvc", True) result.addService(StandardFieldSvc(name, **kwargs)) return result def Q6FwdG4FieldSvcCfg(ConfigFlags, name='Q6FwdG4FieldSvc', **kwargs): @@ -99,6 +94,7 @@ def Q6FwdG4FieldSvcCfg(ConfigFlags, name='Q6FwdG4FieldSvc', **kwargs): result.addService( MagField__ForwardRegionFieldSvc("Q6", Magnet = 7))# FIXME find a better way to do this. kwargs.setdefault("MagneticFieldSvc", result.getService("Q6")) + kwargs.setdefault("UseMagFieldSvc", True) result.addService(StandardFieldSvc(name, **kwargs)) return result def Q7FwdG4FieldSvcCfg(ConfigFlags, name='Q7FwdG4FieldSvc', **kwargs): @@ -106,6 +102,7 @@ def Q7FwdG4FieldSvcCfg(ConfigFlags, name='Q7FwdG4FieldSvc', **kwargs): result.addService( MagField__ForwardRegionFieldSvc("Q7", Magnet = 8))# FIXME find a better way to do this. kwargs.setdefault("MagneticFieldSvc", result.getService("Q7")) + kwargs.setdefault("UseMagFieldSvc", True) result.addService(StandardFieldSvc(name, **kwargs)) return result def Q1HKickFwdG4FieldSvcCfg(ConfigFlags, name='Q1HKickFwdG4FieldSvc', **kwargs): @@ -113,6 +110,7 @@ def Q1HKickFwdG4FieldSvcCfg(ConfigFlags, name='Q1HKickFwdG4FieldSvc', **kwargs): result.addService( MagField__ForwardRegionFieldSvc("Q1HKick", Magnet = 9))# FIXME find a better way to do this. kwargs.setdefault("MagneticFieldSvc", result.getService("Q1HKick")) + kwargs.setdefault("UseMagFieldSvc", True) result.addService(StandardFieldSvc(name, **kwargs)) return result def Q1VKickFwdG4FieldSvcCfg(ConfigFlags, name='Q1VKickFwdG4FieldSvc', **kwargs): #note is lower case "v" in ForwardRegionMgFieldConfig.py @@ -120,6 +118,7 @@ def Q1VKickFwdG4FieldSvcCfg(ConfigFlags, name='Q1VKickFwdG4FieldSvc', **kwargs): result.addService( MagField__ForwardRegionFieldSvc("Q1VKick", Magnet = 10))# FIXME find a better way to do this. kwargs.setdefault("MagneticFieldSvc", result.getService("Q1VKick")) + kwargs.setdefault("UseMagFieldSvc", True) result.addService(StandardFieldSvc(name, **kwargs)) return result def Q2HKickFwdG4FieldSvcCfg(ConfigFlags, name='Q2HKickFwdG4FieldSvc', **kwargs): @@ -127,6 +126,7 @@ def Q2HKickFwdG4FieldSvcCfg(ConfigFlags, name='Q2HKickFwdG4FieldSvc', **kwargs): result.addService( MagField__ForwardRegionFieldSvc("Q2HKick", Magnet = 11))# FIXME find a better way to do this. kwargs.setdefault("MagneticFieldSvc", result.getService("Q2HKick")) + kwargs.setdefault("UseMagFieldSvc", True) result.addService(StandardFieldSvc(name, **kwargs)) return result def Q2VKickFwdG4FieldSvcCfg(ConfigFlags, name='Q2VKickFwdG4FieldSvc', **kwargs): @@ -134,6 +134,7 @@ def Q2VKickFwdG4FieldSvcCfg(ConfigFlags, name='Q2VKickFwdG4FieldSvc', **kwargs): result.addService( MagField__ForwardRegionFieldSvc("Q2VKick", Magnet = 12))# FIXME find a better way to do this. kwargs.setdefault("MagneticFieldSvc", result.getService("Q2VKick")) + kwargs.setdefault("UseMagFieldSvc", True) result.addService(StandardFieldSvc(name, **kwargs)) return result def Q3HKickFwdG4FieldSvcCfg(ConfigFlags, name='Q3HKickFwdG4FieldSvc', **kwargs): @@ -141,6 +142,7 @@ def Q3HKickFwdG4FieldSvcCfg(ConfigFlags, name='Q3HKickFwdG4FieldSvc', **kwargs): result.addService( MagField__ForwardRegionFieldSvc("Q3HKick", Magnet = 13))# FIXME find a better way to do this. kwargs.setdefault("MagneticFieldSvc", result.getService("Q3HKick")) + kwargs.setdefault("UseMagFieldSvc", True) result.addService(StandardFieldSvc(name, **kwargs)) return result def Q3VKickFwdG4FieldSvcCfg(ConfigFlags, name='Q3VKickFwdG4FieldSvc', **kwargs): @@ -148,6 +150,7 @@ def Q3VKickFwdG4FieldSvcCfg(ConfigFlags, name='Q3VKickFwdG4FieldSvc', **kwargs): result.addService( MagField__ForwardRegionFieldSvc("Q3VKick", Magnet = 14))# FIXME find a better way to do this. kwargs.setdefault("MagneticFieldSvc", result.getService("Q3VKick")) + kwargs.setdefault("UseMagFieldSvc", True) result.addService(StandardFieldSvc(name, **kwargs)) return result def Q4VKickAFwdG4FieldSvcCfg(ConfigFlags, name='Q4VKickAFwdG4FieldSvc', **kwargs): @@ -155,6 +158,7 @@ def Q4VKickAFwdG4FieldSvcCfg(ConfigFlags, name='Q4VKickAFwdG4FieldSvc', **kwargs result.addService( MagField__ForwardRegionFieldSvc("Q4VKickA", Magnet = 15))# FIXME find a better way to do this. kwargs.setdefault("MagneticFieldSvc", result.getService("Q4VKickA")) + kwargs.setdefault("UseMagFieldSvc", True) result.addService(StandardFieldSvc(name, **kwargs)) return result def Q4HKickFwdG4FieldSvcCfg(ConfigFlags, name='Q4HKickFwdG4FieldSvc', **kwargs): @@ -162,6 +166,7 @@ def Q4HKickFwdG4FieldSvcCfg(ConfigFlags, name='Q4HKickFwdG4FieldSvc', **kwargs): result.addService( MagField__ForwardRegionFieldSvc("Q4HKick", Magnet = 16))# FIXME find a better way to do this. kwargs.setdefault("MagneticFieldSvc", result.getService("Q4HKick")) + kwargs.setdefault("UseMagFieldSvc", True) result.addService(StandardFieldSvc(name, **kwargs)) return result def Q4VKickBFwdG4FieldSvcCfg(ConfigFlags, name='Q4VKickBFwdG4FieldSvc', **kwargs): @@ -169,6 +174,7 @@ def Q4VKickBFwdG4FieldSvcCfg(ConfigFlags, name='Q4VKickBFwdG4FieldSvc', **kwargs result.addService( MagField__ForwardRegionFieldSvc("Q4VKickB", Magnet = 17))# FIXME find a better way to do this. kwargs.setdefault("MagneticFieldSvc", result.getService("Q4VKickB")) + kwargs.setdefault("UseMagFieldSvc", True) result.addService(StandardFieldSvc(name, **kwargs)) return result def Q5HKickFwdG4FieldSvcCfg(ConfigFlags, name='Q5HKickFwdG4FieldSvc', **kwargs): @@ -176,6 +182,7 @@ def Q5HKickFwdG4FieldSvcCfg(ConfigFlags, name='Q5HKickFwdG4FieldSvc', **kwargs): result.addService( MagField__ForwardRegionFieldSvc("Q5HKick", Magnet = 18))# FIXME find a better way to do this. kwargs.setdefault("MagneticFieldSvc", result.getService("Q5HKick")) + kwargs.setdefault("UseMagFieldSvc", True) result.addService(StandardFieldSvc(name, **kwargs)) return result def Q6VKickFwdG4FieldSvcCfg(ConfigFlags, name='Q6VKickFwdG4FieldSvc', **kwargs): @@ -183,5 +190,6 @@ def Q6VKickFwdG4FieldSvcCfg(ConfigFlags, name='Q6VKickFwdG4FieldSvc', **kwargs): result.addService( MagField__ForwardRegionFieldSvc("Q6VKick", Magnet = 19))# FIXME find a better way to do this. kwargs.setdefault("MagneticFieldSvc", result.getService("Q6VKick")) + kwargs.setdefault("UseMagFieldSvc", True) result.addService(StandardFieldSvc(name, **kwargs)) return result diff --git a/Simulation/G4Atlas/G4AtlasServices/python/G4AtlasServicesConfig.py b/Simulation/G4Atlas/G4AtlasServices/python/G4AtlasServicesConfig.py index 70df4efe8a08039e1dfad5eeb877c8c5992d1b26..27b66102a8ba9fdafecdb5f6e61cc70d3b509bb2 100644 --- a/Simulation/G4Atlas/G4AtlasServices/python/G4AtlasServicesConfig.py +++ b/Simulation/G4Atlas/G4AtlasServices/python/G4AtlasServicesConfig.py @@ -161,76 +161,97 @@ def getTB_RegionCreatorList(): ######################################################################### def getStandardFieldSvc(name="StandardField", **kwargs): - import MagFieldServices.SetupField # noqa: F401 - kwargs.setdefault("MagneticFieldSvc", "AtlasFieldSvc") # TODO This should probably be based on simFlags.MagneticField? #kwargs.setdefault("FieldOn", True) return CfgMgr.StandardFieldSvc(name, **kwargs) def getForwardFieldSvc(name="ForwardField", **kwargs): #FIXME Once it exists this version should use the new MagField Service defined in ForwardRegionMgField - kwargs.setdefault("MagneticFieldSvc", "AtlasFieldSvc") + # kwargs.setdefault("MagneticFieldSvc", "AtlasFieldSvc") + kwargs.setdefault("MagneticFieldSvc", "ForwardRegionFieldSvc") #kwargs.setdefault("FieldOn", True) + # Must switch on the use of a field svc to be able to have StandardFieldSvc use ForwardRegionFieldSvc + kwargs.setdefault("UseMagFieldSvc", True) return CfgMgr.StandardFieldSvc(name, **kwargs) def getQ1FwdG4FieldSvc(name='Q1FwdG4FieldSvc', **kwargs): kwargs.setdefault("MagneticFieldSvc", "Q1") + kwargs.setdefault("UseMagFieldSvc", True) return CfgMgr.StandardFieldSvc(name, **kwargs) def getQ2FwdG4FieldSvc(name='Q2FwdG4FieldSvc', **kwargs): kwargs.setdefault("MagneticFieldSvc", "Q2") + kwargs.setdefault("UseMagFieldSvc", True) return CfgMgr.StandardFieldSvc(name, **kwargs) def getQ3FwdG4FieldSvc(name='Q3FwdG4FieldSvc', **kwargs): kwargs.setdefault("MagneticFieldSvc", "Q3") + kwargs.setdefault("UseMagFieldSvc", True) return CfgMgr.StandardFieldSvc(name, **kwargs) def getD1FwdG4FieldSvc(name='D1FwdG4FieldSvc', **kwargs): kwargs.setdefault("MagneticFieldSvc", "D1") + kwargs.setdefault("UseMagFieldSvc", True) return CfgMgr.StandardFieldSvc(name, **kwargs) def getD2FwdG4FieldSvc(name='D2FwdG4FieldSvc', **kwargs): kwargs.setdefault("MagneticFieldSvc", "D2") + kwargs.setdefault("UseMagFieldSvc", True) return CfgMgr.StandardFieldSvc(name, **kwargs) def getQ4FwdG4FieldSvc(name='Q4FwdG4FieldSvc', **kwargs): kwargs.setdefault("MagneticFieldSvc", "Q4") + kwargs.setdefault("UseMagFieldSvc", True) return CfgMgr.StandardFieldSvc(name, **kwargs) def getQ5FwdG4FieldSvc(name='Q5FwdG4FieldSvc', **kwargs): kwargs.setdefault("MagneticFieldSvc", "Q5") + kwargs.setdefault("UseMagFieldSvc", True) return CfgMgr.StandardFieldSvc(name, **kwargs) def getQ6FwdG4FieldSvc(name='Q6FwdG4FieldSvc', **kwargs): kwargs.setdefault("MagneticFieldSvc", "Q6") + kwargs.setdefault("UseMagFieldSvc", True) return CfgMgr.StandardFieldSvc(name, **kwargs) def getQ7FwdG4FieldSvc(name='Q7FwdG4FieldSvc', **kwargs): kwargs.setdefault("MagneticFieldSvc", "Q7") + kwargs.setdefault("UseMagFieldSvc", True) return CfgMgr.StandardFieldSvc(name, **kwargs) def getQ1HKickFwdG4FieldSvc(name='Q1HKickFwdG4FieldSvc', **kwargs): kwargs.setdefault("MagneticFieldSvc", "Q1HKick") + kwargs.setdefault("UseMagFieldSvc", True) return CfgMgr.StandardFieldSvc(name, **kwargs) def getQ1VKickFwdG4FieldSvc(name='Q1VKickFwdG4FieldSvc', **kwargs): kwargs.setdefault("MagneticFieldSvc", "Q1VKick") + kwargs.setdefault("UseMagFieldSvc", True) return CfgMgr.StandardFieldSvc(name, **kwargs) def getQ2HKickFwdG4FieldSvc(name='Q2HKickFwdG4FieldSvc', **kwargs): kwargs.setdefault("MagneticFieldSvc", "Q2HKick") + kwargs.setdefault("UseMagFieldSvc", True) return CfgMgr.StandardFieldSvc(name, **kwargs) def getQ2VKickFwdG4FieldSvc(name='Q2VKickFwdG4FieldSvc', **kwargs): kwargs.setdefault("MagneticFieldSvc", "Q2VKick") + kwargs.setdefault("UseMagFieldSvc", True) return CfgMgr.StandardFieldSvc(name, **kwargs) def getQ3HKickFwdG4FieldSvc(name='Q3HKickFwdG4FieldSvc', **kwargs): kwargs.setdefault("MagneticFieldSvc", "Q3HKick") + kwargs.setdefault("UseMagFieldSvc", True) return CfgMgr.StandardFieldSvc(name, **kwargs) def getQ3VKickFwdG4FieldSvc(name='Q3VKickFwdG4FieldSvc', **kwargs): kwargs.setdefault("MagneticFieldSvc", "Q3VKick") + kwargs.setdefault("UseMagFieldSvc", True) return CfgMgr.StandardFieldSvc(name, **kwargs) def getQ4VKickAFwdG4FieldSvc(name='Q4VKickAFwdG4FieldSvc', **kwargs): kwargs.setdefault("MagneticFieldSvc", "Q4VKickA") + kwargs.setdefault("UseMagFieldSvc", True) return CfgMgr.StandardFieldSvc(name, **kwargs) def getQ4HKickFwdG4FieldSvc(name='Q4HKickFwdG4FieldSvc', **kwargs): kwargs.setdefault("MagneticFieldSvc", "Q4HKick") + kwargs.setdefault("UseMagFieldSvc", True) return CfgMgr.StandardFieldSvc(name, **kwargs) def getQ4VKickBFwdG4FieldSvc(name='Q4VKickBFwdG4FieldSvc', **kwargs): kwargs.setdefault("MagneticFieldSvc", "Q4VKickB") + kwargs.setdefault("UseMagFieldSvc", True) return CfgMgr.StandardFieldSvc(name, **kwargs) def getQ5HKickFwdG4FieldSvc(name='Q5HKickFwdG4FieldSvc', **kwargs): kwargs.setdefault("MagneticFieldSvc", "Q5HKick") + kwargs.setdefault("UseMagFieldSvc", True) return CfgMgr.StandardFieldSvc(name, **kwargs) def getQ6VKickFwdG4FieldSvc(name='Q6VKickFwdG4FieldSvc', **kwargs): kwargs.setdefault("MagneticFieldSvc", "Q6VKick") + kwargs.setdefault("UseMagFieldSvc", True) return CfgMgr.StandardFieldSvc(name, **kwargs) def getATLAS_FieldMgrList(): diff --git a/Simulation/G4Atlas/G4AtlasServices/src/StandardFieldSvc.cxx b/Simulation/G4Atlas/G4AtlasServices/src/StandardFieldSvc.cxx index 2d237afd057fe2fc8f84edeb96640b50a8b32ccc..a4f533e3410e85e4a1fd7279c7d5ae434bcf48ea 100644 --- a/Simulation/G4Atlas/G4AtlasServices/src/StandardFieldSvc.cxx +++ b/Simulation/G4Atlas/G4AtlasServices/src/StandardFieldSvc.cxx @@ -1,24 +1,30 @@ /* - Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration */ #include "StandardFieldSvc.h" +#include "GaudiKernel/ThreadLocalContext.h" +#include "StoreGate/ReadCondHandle.h" + +// Field map +#include "MagFieldElements/AtlasFieldMap.h" + +// PathResolver +#include "PathResolver/PathResolver.h" + +// ROOT +#include "TFile.h" +#include "TTree.h" -//----------------------------------------------------------------------------- -// Constructor for the AtlasField G4 field object -//----------------------------------------------------------------------------- -AtlasField::AtlasField(MagField::IMagFieldSvc* m) - : m_magFieldSvc(m) -{} //----------------------------------------------------------------------------- // Constructor for the StandardFieldSvc //----------------------------------------------------------------------------- StandardFieldSvc::StandardFieldSvc(const std::string& name, ISvcLocator* pSvcLocator) - : G4MagFieldSvcBase(name, pSvcLocator) -{ -} + : G4MagFieldSvcBase(name, pSvcLocator) +{} + //----------------------------------------------------------------------------- // Initialize the service @@ -26,7 +32,18 @@ StandardFieldSvc::StandardFieldSvc(const std::string& name, StatusCode StandardFieldSvc::initialize() { ATH_MSG_INFO( "Initializing " << name() ); - ATH_CHECK( m_magFieldSvc.retrieve() ); + + // Either initialize the field map - used for solenoid and toroid, or the field service for the forward field + if (m_useMagFieldSvc) { + ATH_CHECK( m_magFieldSvc.retrieve() ); + ATH_MSG_INFO( "initialize: using field service " << m_magFieldSvc.name() ); + } + else { + // Create field map + ATH_CHECK( createFieldMap() ); + ATH_MSG_INFO( "initialize: using created map for field cache "); + } + return StatusCode::SUCCESS; } @@ -36,5 +53,91 @@ StatusCode StandardFieldSvc::initialize() G4MagneticField* StandardFieldSvc::makeField() { ATH_MSG_INFO( "StandardFieldSvc::makeField" ); - return new AtlasField( &*m_magFieldSvc ); + + AtlasField* af{nullptr}; + + // Either initialize the field map - used for solenoid and toroid, or the field service for the forward field + if (m_useMagFieldSvc) { + af = new AtlasField( &*m_magFieldSvc ); + } + else { + af = new AtlasField(m_fieldMap.get()); + } + + return (af); +} + + +//----------------------------------------------------------------------------- +// Create field map +//----------------------------------------------------------------------------- +StatusCode StandardFieldSvc::createFieldMap() +{ + ATH_MSG_INFO( "StandardFieldSvc::createFieldMap" ); + + + // Select map file according to the value of the currents which indicate which map is 'on' + + // determine the map to load + std::string mapFile; + if ( solenoidOn() && toroidOn() ) mapFile = m_fullMapFilename; + else if ( solenoidOn() ) mapFile = m_soleMapFilename; + else if ( toroidOn() ) mapFile = m_toroMapFilename; + else { + // all magnets OFF. no need to read map + return StatusCode::SUCCESS; + } + + ATH_MSG_INFO ( "StandardFieldSvc::createFieldMap: Set map currents from FieldSvc: solenoid/toroid " + << m_mapSoleCurrent << "," << m_mapToroCurrent); + ATH_MSG_INFO ( "StandardFieldSvc::createFieldMap: Use map file " << mapFile); + + + // find the path to the map file + std::string resolvedMapFile = PathResolver::find_file( mapFile.c_str(), "DATAPATH" ); + if ( resolvedMapFile.empty() ) { + ATH_MSG_ERROR( "StandardFieldSvc::createFieldMap: Field map file " << mapFile << " not found" ); + return StatusCode::FAILURE; + } + // Do checks and extract root file to initialize the map + if ( resolvedMapFile.find(".root") == std::string::npos ) { + ATH_MSG_ERROR("StandardFieldSvc::createFieldMap: input file name '" << resolvedMapFile << "' does not end with .root"); + return StatusCode::FAILURE; + } + + std::unique_ptr<TFile> rootfile = std::make_unique<TFile>(resolvedMapFile.c_str(), "OLD"); + if ( ! rootfile.get() ) { + ATH_MSG_ERROR("StandardFieldSvc::createFieldMap: failed to open " << resolvedMapFile); + return StatusCode::FAILURE; + } + if ( !rootfile->cd() ) { + // could not make it current directory + ATH_MSG_ERROR("StandardFieldSvc::createFieldMap: unable to cd() into the ROOT field map TFile"); + rootfile->Close(); + return StatusCode::FAILURE; + } + // open the tree + TTree* tree = (TTree*)rootfile->Get("BFieldMap"); + if ( tree == nullptr ) { + // no tree + ATH_MSG_ERROR("StandardFieldSvc::createFieldMap: TTree 'BFieldMap' does not exist in ROOT field map"); + rootfile->Close(); + return StatusCode::FAILURE; + } + + // create map + m_fieldMap = std::make_unique<MagField::AtlasFieldMap>(); + + // initialize map + if (!m_fieldMap->initializeMap( rootfile.get(), m_mapSoleCurrent, m_mapToroCurrent )) { + // failed to initialize the map + ATH_MSG_ERROR("StandardFieldSvc::createFieldMap: unable to initialize the map for AtlasFieldMap for file " << resolvedMapFile); + rootfile->Close(); + return StatusCode::FAILURE; + } + + rootfile->Close(); + + ATH_MSG_INFO( "StandardFieldSvc::createFieldMap: Initialized the field map from " << resolvedMapFile ); + return StatusCode::SUCCESS; } diff --git a/Simulation/G4Atlas/G4AtlasServices/src/StandardFieldSvc.h b/Simulation/G4Atlas/G4AtlasServices/src/StandardFieldSvc.h index 03a08adf7233da5180e21af9af5e4837f57a813d..871f5af51d015094711d1ae668b45b71d4c3ee09 100644 --- a/Simulation/G4Atlas/G4AtlasServices/src/StandardFieldSvc.h +++ b/Simulation/G4Atlas/G4AtlasServices/src/StandardFieldSvc.h @@ -18,38 +18,122 @@ // Base classes #include "G4MagFieldSvcBase.h" +// MagField cache +#include "MagFieldElements/AtlasFieldCache.h" + +// forward declarations +namespace MagField { + class AtlasFieldMap; +} + +/** + * The ATLASFieldCacheTLSWrapper + * is needed due to the current threading model in simulation. + * + * In general clients need a MagField::AtlasFieldCache + * returning the magnetic field values + * for a specific position. + * + * The MagField::AtlasFieldCache refer to a specific "cell" and might + * need to be filled or updated when the position changes. + * In the other hand subsequent calls more often + * than not re-use the info from the same "cell". + * One can look at MagFieldElements for more details. + * + * Ideally objects would be passed by/be local to the caller. + * Actually this is what happens in offline/online + * where we moved completely to Condition Objects. + * i.e AtlasFieldCacheCondObj. + * + * But this is not yet possible in simulation. + * So we need to wrap things in a way that mimics + * the relevant TLS behaviour of the to be removed ATLAS Svc. + * + * The end result is that for now the ATLASFieldCacheTLSWrapper + * is to be used instead of AtlasFieldCacheCondObj in simulation. + * + * It has similar payload. + * The major difference is that when we use the + * condition Object each user of the magnetic field + * ends up with its own local MagField::AtlasFieldCache so there is + * no need for synchronisation. + * + * In the other hand here we provide thread-specific + * MagField::AtlasFieldCache (s) to allow for the TLS + * scheme needed by the simulation. + * + */ +struct ATLASFieldCacheTLSWrapper +{ +private: + MagField::AtlasFieldCache createCache() const + { + return MagField::AtlasFieldCache(solFieldScale, torFieldScale, fieldMap); + } + +public: + ///Sclae for solenoid + double solFieldScale{ 1 }; + ///Scale for toroid + double torFieldScale{ 1 }; + ///Not owning ptr + const MagField::AtlasFieldMap* fieldMap{ nullptr }; + + /// Method setting up the TLS + /// and returning ref to + /// the TLS MagField::AtlasFieldCache + MagField::AtlasFieldCache& getTLSCache() const + { + static thread_local MagField::AtlasFieldCache fieldCache = createCache(); + return fieldCache; + } + + /// getField method, forwarding to the TLS object + void getField(const double* point, double* field) const + { + MagField::AtlasFieldCache& fieldCache = getTLSCache(); + fieldCache.getField(point, field); + } +}; /// @class AtlasField -/// @brief G4 wrapper around the main ATLAS magnetic field service. -/// -/// @todo TODO this should probably be put in a good namespace. -/// +/// @brief G4 wrapper around the main ATLAS magnetic field cache or field svc for forward field. class AtlasField : public G4MagneticField { public: - + /// Construct the field object from conditions object + AtlasField(const MagField::AtlasFieldMap* fieldMap) { + m_fieldCache.fieldMap = fieldMap; + } /// Construct the field object from the IMagFieldSvc - AtlasField(MagField::IMagFieldSvc* m); + AtlasField(MagField::IMagFieldSvc* m) : + m_magFieldSvc(m) + {} + + + MagField::AtlasFieldCache& fieldCache() { return m_fieldCache.getTLSCache(); } /// Implementation of G4 method to retrieve field value void GetFieldValue(const double *point, double *field) const { - m_magFieldSvc->getField(point, field); + if (m_magFieldSvc) m_magFieldSvc->getField(point, field); + else m_fieldCache.getField(point, field); } private: + /// Field cache TLS Wrapper + ATLASFieldCacheTLSWrapper m_fieldCache{}; /// Pointer to the magnetic field service. /// We use a raw pointer here to avoid ServiceHandle overhead. - MagField::IMagFieldSvc* m_magFieldSvc{}; + MagField::IMagFieldSvc* m_magFieldSvc{nullptr}; + }; /// @class StandardFieldSvc /// @brief Athena service for constructing the AtlasField object /// -/// @todo TODO this should probably be put in a good namespace. -/// class StandardFieldSvc final : public G4MagFieldSvcBase { public: @@ -63,15 +147,51 @@ class StandardFieldSvc final : public G4MagFieldSvcBase StatusCode initialize() override final; protected: - /// Create/retrieve the AtlasField object G4MagneticField* makeField() override final; private: - /// Handle to the ATLAS magnetic field service - ServiceHandle<MagField::IMagFieldSvc> m_magFieldSvc{this, "MagneticFieldSvc", "MagField::AtlasFieldSvc/AtlasFieldSvc"}; - + // There are two options for the magnetic field: + // + // 1) For solenoid and toroid, this has moved to use AtlasFieldCache and here we must create and + // same the field map + // 2) For the forward quadrupole fields, we preserve the access to the magnetic field service + // + // The boolean flag UseMagFieldSvc is now used to differentiate between the two cases (default is false) + // + + // flag to use magnet field service + Gaudi::Property<bool> m_useMagFieldSvc {this, + "UseMagFieldSvc", false, "Use magnetic field service - Should ONLY be used for ForwardRegionFieldSvc"}; + + /// Handle to the the Forward ATLAS magnetic field service + ServiceHandle<MagField::IMagFieldSvc> m_magFieldSvc {this, "MagneticFieldSvc", ""}; + + StatusCode createFieldMap(); + + // properties taken from AtlasFieldMapCondAlg + bool solenoidOn() { return (m_mapSoleCurrent > 0.0); } + bool toroidOn() { return (m_mapToroCurrent > 0.0); } + + /// map file names + Gaudi::Property<std::string> m_fullMapFilename {this, + "FullMapFile", "MagneticFieldMaps/bfieldmap_7730_20400_14m.root", + "File storing the full magnetic field map"}; + Gaudi::Property<std::string> m_soleMapFilename {this, + "SoleMapFile", "MagneticFieldMaps/bfieldmap_7730_0_14m.root", + "File storing the solenoid-only magnetic field map"}; + Gaudi::Property<std::string> m_toroMapFilename {this, + "ToroMapFile", "MagneticFieldMaps/bfieldmap_0_20400_14m.root", + "File storing the toroid-only magnetic field map"}; + /// nominal current for the maps + Gaudi::Property<double> m_mapSoleCurrent {this, + "MapSoleCurrent", 7730., "Nominal solenoid current (A)"}; + Gaudi::Property<double> m_mapToroCurrent {this, + "MapToroCurrent", 20400., "Nominal toroid current (A)"}; + + // field map held locally in svc - in Athena, this would go into a conditions object + std::unique_ptr<MagField::AtlasFieldMap> m_fieldMap; }; #endif // G4ATLASSERVICES_StandardFieldSvc_H