ATLAS Offline Software
Loading...
Searching...
No Matches
G4mplEquationSetup.cxx
Go to the documentation of this file.
1//
2// ********************************************************************
3// * License and Disclaimer *
4// * *
5// * The Geant4 software is copyright of the Copyright Holders of *
6// * the Geant4 Collaboration. It is provided under the terms and *
7// * conditions of the Geant4 Software License, included in the file *
8// * LICENSE and available at http://cern.ch/geant4/license . These *
9// * include a list of copyright holders. *
10// * *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work make any representation or warranty, express or implied, *
14// * regarding this software system or assume any liability for its *
15// * use. Please see the license in the file LICENSE and URL above *
16// * for the full disclaimer and the limitation of liability. *
17// * *
18// * This code implementation is the result of the scientific and *
19// * technical work of the GEANT4 collaboration. *
20// * By using, copying, modifying or distributing the software (or *
21// * any work based on the software) you agree to acknowledge its *
22// * use in resulting scientific publications, and indicate your *
23// * acceptance of all terms of the Geant4 Software license. *
24// ********************************************************************
25//
28//
29//
30//
31// G4mplEquationSetup is responsible for switching between two different
32// equation of motions, one for monopoles and another for the rest of the
33// particles.
34//
35// This updated version is designed to cope with:
36// - multiple G4FieldManager objects being defined in the setup
37// - many G4MagneticField objects (i.e a global and one or more local fiedls)
38// - a G4FieldManager which switches the G4Field object to which it points
39// during the simulation (e.g. to null)
40
41// =======================================================================
42// Modified: 19 May 2019, M. Bandieramonte: introduced MT mode. The class
43// was a Singleton and it was not thread-safe.
44// Added the #ifdef G4MULTITHREADED directive to handle
45// the multithreaded case. One instance of the class will be created
46// per each thread and stored in a tbb::concurrent_unordered_map that
47// is hashed with the threadID number.
48// Modified: 28 August 2013, W. Taylor: adapted for ATLAS
49// Created: 23 May 2013, J. Apostolakis
50// Adapted from G4MonopoleFieldSetup by B. Bozsogi
51// =======================================================================
52
53// class header
54#include "G4mplEquationSetup.hh"
55// package headers
56#include "G4mplEqMagElectricField.hh"
57// Geant4 headers
58#include "G4MagneticField.hh"
59#include "G4UniformMagField.hh"
60#include "G4FieldManager.hh"
61#include "G4TransportationManager.hh"
62#include "G4Mag_UsualEqRhs.hh"
63#include "G4MagIntegratorStepper.hh"
64#include "G4ChordFinder.hh"
65#include "G4MagIntegratorDriver.hh"
66#include "G4AtlasRK4.hh" // Used for non-magnetic particles
67#include "G4ClassicalRK4.hh" // Used for monopoles
68// NOTE:
69// Only Steppers which can integrate over any number of variables can be used
70// to integrate the equation of motion of a monopole.
71// The following cannot be used:
72// Helix... - these integrate over 6 variables only; also assume helix as 'base'
73// AtlasRK4, NystromRK4 - these have the equation of motion embedded inside
74#include "G4SystemOfUnits.hh"
75#include "G4UniformMagField.hh"
76
77#ifdef G4MULTITHREADED
78G4mplEquationSetup::ESThreadMap_t G4mplEquationSetup::m_ESThreadMap;
79#endif
80
81//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
82
83G4mplEquationSetup::G4mplEquationSetup():
84 fMinStep(0.01*CLHEP::mm), // minimal step of 1 mm is default
85 fVerbose(false)
86{
87 if( fVerbose )
88 G4cout << "!!! G4mplEquationSetup constructor" << G4endl;
89}
90
91//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
92
93G4mplEquationSetup* G4mplEquationSetup::GetInstance()
94{
95#ifdef G4MULTITHREADED
96 auto es = getES();
97 if (!es) //nullpointer if it is not found
98 return setES();
99 else return es;
100#else
101 //Standard implementation of a Singleton Pattern
102 static G4mplEquationSetup instance;
103 return &instance;
104#endif
105
106}
107
108//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
109
110G4mplEquationSetup::~G4mplEquationSetup()
111{
112 if( fVerbose )
113 G4cout << "!!! G4mplEquationSetup destructor" << G4endl;
114}
115
116//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
117
118#ifdef G4MULTITHREADED
119 G4mplEquationSetup* G4mplEquationSetup::getES()
120 {
121 // Get current thread-ID
122 const auto tid = std::this_thread::get_id();
123 auto esPair = m_ESThreadMap.find(tid);
124 if(esPair == m_ESThreadMap.end())
125 return nullptr; //if not found return null pointer
126 else return esPair->second;
127 }
128
129//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
130
131 G4mplEquationSetup* G4mplEquationSetup::setES()
132 {
133 G4mplEquationSetup* instance = new G4mplEquationSetup;
134 const auto tid = std::this_thread::get_id();
135 auto inserted = m_ESThreadMap.insert( std::make_pair(tid, instance)).first;
136 return (G4mplEquationSetup*) inserted->second;
137 }
138#endif
139
140//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
141
142// The ownership model of the current implementation is the following:
143// An instance of G4mplEquationSetup owns
144// - the equation fMonopoleEquation
145// - the stepper fMonopoleStepper
146// - the chord-finder fChordFinder
147// They are transiently associated with the current FieldManager during the
148// 'stepping' loop of the one monopole track.
149
150// InitialiseForField must be called either
151// - at the start of the simulation (when the global field manager has been assigned, or else
152// - at the start of tracking of the first monopole track (and never later than this!)
153
154void
155G4mplEquationSetup::InitialiseForField(G4FieldManager* fieldManager )
156{
157 if (fieldManager == nullptr) {
158 return;
159 }
160
161 // Store the 'original ChordFinder of the volume - to enable us to restore it,
162 // when either we
163 // i. enter a volume with a different field manager or
164 // ii. have finished tracking the current track. Fix: J.A. 27/10/2022
165 fOriginalChordFinder = fieldManager->GetChordFinder();
166 fCurrentFieldManager = fieldManager;
167 // How to ensure that two/multiple calls do not overwrite it?
168 // Consider whether it can be null
169
170 const G4MagneticField* magField = dynamic_cast<const G4MagneticField*>(fieldManager->GetDetectorField());
171 G4MagneticField* magFieldNC ATLAS_THREAD_SAFE = const_cast<G4MagneticField*>(magField);
172
173 CreateStepperToChordFinder(magFieldNC);
174}
175
176//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
177
178void
179G4mplEquationSetup::CreateStepperToChordFinder(G4MagneticField* magFieldNC)
180{
181 if(magFieldNC == nullptr)
182 {
183 static G4ThreadLocal G4UniformMagField nullField( G4ThreeVector(0.0, 0.0, 0.0));
184 magFieldNC= &nullField;
185 }
186
187 fMonopoleEquation = std::make_unique<G4mplEqMagElectricField>(magFieldNC);
188
189 fMonopoleStepper = std::make_unique< G4ClassicalRK4>( fMonopoleEquation.get(), 8 ); // for time information..
190
191 if ( !fMonopoleStepper )
192 {
193 G4ExceptionDescription ermsg;
194 ermsg << "The creation of a stepper for Monopoles failed - trying to use G4ClassicalRK4";
195 G4Exception("G4mplEquationSetup::InitialiseForField",
196 "FailureToCreateObject", FatalException, ermsg);
197 }
198
199 auto integrDriver = new G4MagInt_Driver( fMinStep, fMonopoleStepper.get(),
200 // cppcheck-suppress nullPointerRedundantCheck; false positive
201 fMonopoleStepper->GetNumberOfVariables() );
202 fMonopoleChordFinder = std::make_unique<G4ChordFinder>( integrDriver );
203}
204
205//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
206
207// This method must be called before
208
209void G4mplEquationSetup::SwitchStepperAndChordFinder(G4bool useMonopoleEq,
210 G4FieldManager* fieldManager)
211{
212 // For the existing version to work, InitialiseForField must be called
213 // - for *this* field manager (not another) before this call
214 // - potentially after a change of 'field' object in this field manager (tbc)
215 const G4MagneticField* magField = dynamic_cast<const G4MagneticField*>(fieldManager->GetDetectorField());
216 G4MagneticField* magFieldNC ATLAS_THREAD_SAFE = const_cast<G4MagneticField*>(magField); // fieldManager only allow const access despite being non-const
217
218 // New code is needed to cope with the following cases:
219 // - a different field manager is encountered (i.e. a local one or second local one)
220 // - the 'field' object to which the G4FieldManager is pointing was changed
221
222 if ( magFieldNC )
223 {
224 // First check whether the field in equation of motion has changed!
225 CheckAndUpdateField( magFieldNC );
226
227 if (useMonopoleEq) {
228 fieldManager->SetChordFinder( fMonopoleChordFinder.get() );
229 } else {
230 fieldManager->SetChordFinder( fOriginalChordFinder );
231 }
232 }
233}
234
235//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
236
237void G4mplEquationSetup::ResetIntegration(G4FieldManager* fieldManager)
238// Restore the original ChordFinder to either
239// - allow non-monopole tracks to work seamlessly
240// - prepare for move of monopole to volume/region with different fieldManager
241{
242 if( fieldManager != fCurrentFieldManager){
243 G4ExceptionDescription ermsg;
244 ermsg << "This method expects to be called with the chordfinder it knows"
245 << " yet its is called with " << fieldManager
246 << " and expected " << fCurrentFieldManager << G4endl;
247 G4Exception("G4mplEquationSetup::ResetIntegration",
248 "InvalidState", FatalException, ermsg);
249 }
250
251 if( fCurrentFieldManager ) {
252 fCurrentFieldManager->SetChordFinder(fOriginalChordFinder);
253
254 if ( fVerbose )
255 G4cout << " G4mplEquationSetup: Reset Chord-Finder to original one (for pure electric charge): "
256 << fOriginalChordFinder << G4endl;
257
258 fOriginalChordFinder = nullptr; // Now Forget it!
259 fCurrentFieldManager = nullptr;
260 }
261 // Since these objects referred to the outgoing field manager, clean them up!
262}
263
264//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
265
266void G4mplEquationSetup::CheckAndUpdateField( G4MagneticField* magFieldNC )
267// Ensure that the field of this fieldManager is the one in the equation - else update it to be so.
268{
269 if( magFieldNC != fMonopoleEquation->GetFieldObj() )
270 {
271 // fMonopoleEquation->SetFieldObj( magFieldNC ); // Dangerous method -- but types are both G4MagneticField
272 // A cleaner version will call again Initialise ...
273 CreateStepperToChordFinder(magFieldNC);
274 }
275}
276
std::map< std::string, double > instance
#define ATLAS_THREAD_SAFE