diff --git a/Detectors/FastSim/include/FastSim/G4FastSimulation.h b/Detectors/FastSim/include/FastSim/G4FastSimulation.h index 900e5e2d01ef7..3cbeacc9cd1b9 100644 --- a/Detectors/FastSim/include/FastSim/G4FastSimulation.h +++ b/Detectors/FastSim/include/FastSim/G4FastSimulation.h @@ -29,7 +29,6 @@ /// `G4.fastSimRegions` overrides the walk with an explicit space-separated list /// of media, for when a model should see less than a whole subtree. -#include "TG4RunConfiguration.h" #include "TG4VUserFastSimulation.h" #include "TG4VUserPostDetConstruction.h" @@ -53,15 +52,11 @@ class G4FastSimulation : public TG4VUserFastSimulation double mMinEnergy = 1.; }; -/// Supplies Geant4-VMC with the fast simulation models and their regions. -/// Returns nullptr when no model is configured, so nothing is set up. -class G4RunConfiguration : public TG4RunConfiguration -{ - public: - using TG4RunConfiguration::TG4RunConfiguration; - TG4VUserFastSimulation* CreateUserFastSimulation() override; - TG4VUserPostDetConstruction* CreateUserPostDetConstruction() override; -}; +/// The fast simulation for Geant4-VMC, or nullptr when `G4.fastSimModels` is empty. +TG4VUserFastSimulation* createFastSimulation(); + +/// The construction of the fast simulation regions, or nullptr when `G4.fastSimModels` is empty. +TG4VUserPostDetConstruction* createFastSimRegionConstruction(); } // namespace o2::fastsim diff --git a/Detectors/FastSim/src/G4FastSimulation.cxx b/Detectors/FastSim/src/G4FastSimulation.cxx index 6349084fdf04d..f959d2a7d958f 100644 --- a/Detectors/FastSim/src/G4FastSimulation.cxx +++ b/Detectors/FastSim/src/G4FastSimulation.cxx @@ -67,7 +67,7 @@ void G4FastSimulation::Construct() } //_____________________________________________________________________________ -TG4VUserFastSimulation* G4RunConfiguration::CreateUserFastSimulation() +TG4VUserFastSimulation* createFastSimulation() { const auto& params = o2::conf::G4Params::Instance(); auto models = split(params.fastSimModels, ','); @@ -79,12 +79,12 @@ TG4VUserFastSimulation* G4RunConfiguration::CreateUserFastSimulation() } //_____________________________________________________________________________ -TG4VUserPostDetConstruction* G4RunConfiguration::CreateUserPostDetConstruction() +TG4VUserPostDetConstruction* createFastSimRegionConstruction() { const auto& params = o2::conf::G4Params::Instance(); auto models = split(params.fastSimModels, ','); if (models.empty()) { - return TG4RunConfiguration::CreateUserPostDetConstruction(); + return nullptr; } std::vector wanted; wanted.reserve(models.size()); diff --git a/Detectors/gconfig/CMakeLists.txt b/Detectors/gconfig/CMakeLists.txt index 282fa4c9d124e..a1a2b426f2bb4 100644 --- a/Detectors/gconfig/CMakeLists.txt +++ b/Detectors/gconfig/CMakeLists.txt @@ -15,7 +15,7 @@ o2_add_library(G3Setup ) o2_add_library(G4Setup - SOURCES src/G4Config.cxx + SOURCES src/G4Config.cxx src/G4RunConfiguration.cxx src/G4LocalFieldConstruction.cxx PUBLIC_LINK_LIBRARIES MC::Geant4VMC MC::Geant4 FairRoot::Base O2::SimulationDataFormat O2::Generators O2::SimSetup O2::FastSim ) diff --git a/Detectors/gconfig/g4Config.C b/Detectors/gconfig/g4Config.C index 1907c1aa9ebcd..83a932e674e5b 100644 --- a/Detectors/gconfig/g4Config.C +++ b/Detectors/gconfig/g4Config.C @@ -65,7 +65,7 @@ R__LOAD_LIBRARY(libgeant4vmc) #include "G4ScoringManager.hh" #include "G4VScoringMesh.hh" #include -#include "FastSim/G4FastSimulation.h" +#include "SimSetup/G4RunConfiguration.h" #endif #include "commonConfig.C" @@ -119,12 +119,11 @@ void Config() LOG(fatal) << "Unsupported geometry navigation mode"; } - // o2::fastsim::G4RunConfiguration differs from TG4RunConfiguration only in - // providing the fast-simulation hook; with G4.fastSimModels empty it behaves - // identically. - auto runConfiguration = new o2::fastsim::G4RunConfiguration(geomNavStr, physicsSetup, - "stepLimiter+specialCuts", - specialStacking, mtMode); + // o2::g4config::G4RunConfiguration adds the fast-simulation hook and the local + // magnetic fields; with neither configured it behaves like TG4RunConfiguration. + auto runConfiguration = new o2::g4config::G4RunConfiguration(geomNavStr, physicsSetup, + "stepLimiter+specialCuts", + specialStacking, mtMode); if (g4Params.g4scoring) { runConfiguration->SetUseOfG4Scoring(); if (g4Params.g4fluenceweight) { diff --git a/Detectors/gconfig/g4config.in b/Detectors/gconfig/g4config.in index df9376a9dda8f..280489d754ed0 100644 --- a/Detectors/gconfig/g4config.in +++ b/Detectors/gconfig/g4config.in @@ -47,12 +47,33 @@ /process/em/transportationWithMsc Disabled # -# Adding extra lines for fixing tracking bias -# +# Field integration (O2-7198) +# a tight deltaIntersection removes the 1/pT bias from chord-to-boundary placement (ALIROOT-7121) /mcMagField/setDeltaIntersection 1.0e-05 mm -/mcMagField/setMinimumEpsilonStep 0.5e-05 -/mcMagField/setMaximumEpsilonStep 1.0e-05 +# the epsilons do not change the bias; minimumEpsilon sets the accuracy of long steps, +# which only the muon spectrometer needs (it keeps the tight value as a local field) +/mcMagField/setMinimumEpsilonStep 1.0e-04 +/mcMagField/setMaximumEpsilonStep 1.0e-03 /mcMagField/printParameters +# the muon spectrometer keeps tight epsilons as local fields (see G4LocalFieldConstruction) +/mcDet/createMagFieldParameters YOUT1 +/mcMagField/YOUT1/stepperType NystromRK4 +/mcMagField/YOUT1/setConstDistance 1 mm +/mcMagField/YOUT1/setDeltaIntersection 1.0e-05 mm +/mcMagField/YOUT1/setMinimumEpsilonStep 0.5e-05 +/mcMagField/YOUT1/setMaximumEpsilonStep 1.0e-05 +/mcDet/createMagFieldParameters DDIP +/mcMagField/DDIP/stepperType NystromRK4 +/mcMagField/DDIP/setConstDistance 1 mm +/mcMagField/DDIP/setDeltaIntersection 1.0e-05 mm +/mcMagField/DDIP/setMinimumEpsilonStep 0.5e-05 +/mcMagField/DDIP/setMaximumEpsilonStep 1.0e-05 +/mcDet/createMagFieldParameters YOUT2 +/mcMagField/YOUT2/stepperType NystromRK4 +/mcMagField/YOUT2/setConstDistance 1 mm +/mcMagField/YOUT2/setDeltaIntersection 1.0e-05 mm +/mcMagField/YOUT2/setMinimumEpsilonStep 0.5e-05 +/mcMagField/YOUT2/setMaximumEpsilonStep 1.0e-05 # Change default parameters for killing looping particles # diff --git a/Detectors/gconfig/include/SimSetup/G4LocalFieldConstruction.h b/Detectors/gconfig/include/SimSetup/G4LocalFieldConstruction.h new file mode 100644 index 0000000000000..5fa4aae245b9e --- /dev/null +++ b/Detectors/gconfig/include/SimSetup/G4LocalFieldConstruction.h @@ -0,0 +1,37 @@ +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_SIMSETUP_G4LOCALFIELDCONSTRUCTION_H_ +#define O2_SIMSETUP_G4LOCALFIELDCONSTRUCTION_H_ + +#include "TG4VUserPostDetConstruction.h" + +#include + +namespace o2::g4config +{ + +/// Gives every volume with its own field parameters (/mcDet/createMagFieldParameters ) +/// a local copy of the global field, so that the /mcMagField// settings take effect. +class G4LocalFieldConstruction : public TG4VUserPostDetConstruction +{ + public: + /// next is another construction step run first (may be nullptr); it is owned + explicit G4LocalFieldConstruction(TG4VUserPostDetConstruction* next) : mNext(next) {} + void Construct() override; + + private: + std::unique_ptr mNext; +}; + +} // namespace o2::g4config + +#endif // O2_SIMSETUP_G4LOCALFIELDCONSTRUCTION_H_ diff --git a/Detectors/gconfig/include/SimSetup/G4RunConfiguration.h b/Detectors/gconfig/include/SimSetup/G4RunConfiguration.h new file mode 100644 index 0000000000000..e2fb5b6a45991 --- /dev/null +++ b/Detectors/gconfig/include/SimSetup/G4RunConfiguration.h @@ -0,0 +1,31 @@ +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_SIMSETUP_G4RUNCONFIGURATION_H_ +#define O2_SIMSETUP_G4RUNCONFIGURATION_H_ + +#include "TG4RunConfiguration.h" + +namespace o2::g4config +{ + +/// The Geant4 VMC run configuration of O2: adds the fast simulation and the local magnetic fields. +class G4RunConfiguration : public TG4RunConfiguration +{ + public: + using TG4RunConfiguration::TG4RunConfiguration; + TG4VUserFastSimulation* CreateUserFastSimulation() override; + TG4VUserPostDetConstruction* CreateUserPostDetConstruction() override; +}; + +} // namespace o2::g4config + +#endif // O2_SIMSETUP_G4RUNCONFIGURATION_H_ diff --git a/Detectors/gconfig/src/G4LocalFieldConstruction.cxx b/Detectors/gconfig/src/G4LocalFieldConstruction.cxx new file mode 100644 index 0000000000000..4898ce53eb402 --- /dev/null +++ b/Detectors/gconfig/src/G4LocalFieldConstruction.cxx @@ -0,0 +1,87 @@ +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "SimSetup/G4LocalFieldConstruction.h" +#include "SimConfig/G4Params.h" + +#include "TG4GeometryManager.h" + +#include +#include +#include +#include +#include + +#include +#include + +namespace o2::g4config +{ + +namespace +{ +// First volume in the subtree of vol whose medium has no magnetic field (ifield = 0) +const TGeoVolume* findZeroFieldVolume(const TGeoVolume* vol, std::unordered_set& visited) +{ + if (!visited.insert(vol).second) { + return nullptr; + } + auto med = vol->GetMedium(); + if (med && !vol->IsAssembly() && med->GetParam(1) == 0) { + return vol; + } + for (int i = 0; i < vol->GetNdaughters(); ++i) { + if (auto nf = findZeroFieldVolume(vol->GetNode(i)->GetVolume(), visited)) { + return nf; + } + } + return nullptr; +} +} // namespace + +void G4LocalFieldConstruction::Construct() +{ + if (mNext) { + mNext->Construct(); + } + auto tree = G4UImanager::GetUIpointer()->GetTree()->FindCommandTree("/mcMagField/"); + auto field = TVirtualMC::GetMC()->GetMagField(); + if (!tree || !field) { + return; + } + int nattached = 0; + for (int i = 1; i <= tree->GetTreeEntry(); ++i) { + std::string path = tree->GetTree(i)->GetPathName(); // "/mcMagField//" + auto name = path.substr(12, path.size() - 13); + auto vol = gGeoManager->GetVolume(name.c_str()); + if (!vol) { + LOG(warn) << "local field: no volume " << name << "; its field parameters are unused"; + continue; + } + // Geant4 VMC forces a local field onto all daughters, which would override zero-field media + std::unordered_set visited; + if (auto nf = findZeroFieldVolume(vol, visited)) { + LOG(warn) << "local field: volume " << name << " contains the zero-field volume " << nf->GetName() << "; skipped"; + continue; + } + vol->SetField(field); + LOG(info) << "local field: volume " << name << " uses the parameters in /mcMagField/" << name << "/"; + ++nattached; + } + if (nattached > 0) { + TG4GeometryManager::Instance()->SetIsLocalField(true); + if (o2::conf::G4Params::Instance().navmode != o2::conf::EG4Nav::kTGeo) { + LOG(warn) << "local field: Geant4 VMC builds local fields only with TGeo navigation; the global field applies everywhere"; + } + } +} + +} // namespace o2::g4config diff --git a/Detectors/gconfig/src/G4RunConfiguration.cxx b/Detectors/gconfig/src/G4RunConfiguration.cxx new file mode 100644 index 0000000000000..db67cce9063ec --- /dev/null +++ b/Detectors/gconfig/src/G4RunConfiguration.cxx @@ -0,0 +1,30 @@ +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "SimSetup/G4RunConfiguration.h" +#include "SimSetup/G4LocalFieldConstruction.h" +#include "FastSim/G4FastSimulation.h" + +namespace o2::g4config +{ + +TG4VUserFastSimulation* G4RunConfiguration::CreateUserFastSimulation() +{ + return o2::fastsim::createFastSimulation(); +} + +TG4VUserPostDetConstruction* G4RunConfiguration::CreateUserPostDetConstruction() +{ + auto fastSimRegions = o2::fastsim::createFastSimRegionConstruction(); + return new G4LocalFieldConstruction(fastSimRegions ? fastSimRegions : TG4RunConfiguration::CreateUserPostDetConstruction()); +} + +} // namespace o2::g4config