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 delete fMonopoleEquation;
116 delete fMonopoleStepper;
117
118 delete fMonopoleChordFinder;
119 // JA: Is protection below still needed ?
120 // WJT: Avoid segmentation violation in G4FieldManager destructor
121}
122
123//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
124
125#ifdef G4MULTITHREADED
126 G4mplEquationSetup* G4mplEquationSetup::getES()
127 {
128 // Get current thread-ID
129 const auto tid = std::this_thread::get_id();
130 auto esPair = m_ESThreadMap.find(tid);
131 if(esPair == m_ESThreadMap.end())
132 return nullptr; //if not found return null pointer
133 else return esPair->second;
134 }
135
136//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
137
138 G4mplEquationSetup* G4mplEquationSetup::setES()
139 {
140 G4mplEquationSetup* instance = new G4mplEquationSetup;
141 const auto tid = std::this_thread::get_id();
142 auto inserted = m_ESThreadMap.insert( std::make_pair(tid, instance)).first;
143 return (G4mplEquationSetup*) inserted->second;
144 }
145#endif
146
147//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
148
149// The ownership model of the current implementation is the following:
150// An instance of G4mplEquationSetup owns
151// - the equation fMonopoleEquation
152// - the stepper fMonopoleStepper
153// - the chord-finder fChordFinder
154// They are transiently associated with the current FieldManager during the
155// 'stepping' loop of the one monopole track.
156
157// InitialiseForField must be called either
158// - at the start of the simulation (when the global field manager has been assigned, or else
159// - at the start of tracking of the first monopole track (and never later than this!)
160
161void
162G4mplEquationSetup::InitialiseForField(G4FieldManager* fieldManager )
163{
164 if (fieldManager == nullptr) {
165 return;
166 }
167
168 // Store the 'original ChordFinder of the volume - to enable us to restore it,
169 // when either we
170 // i. enter a volume with a different field manager or
171 // ii. have finished tracking the current track. Fix: J.A. 27/10/2022
172 fOriginalChordFinder = fieldManager->GetChordFinder();
173 fCurrentFieldManager = fieldManager;
174 // How to ensure that two/multiple calls do not overwrite it?
175 // Consider whether it can be null
176
177 const G4MagneticField* magField = dynamic_cast<const G4MagneticField*>(fieldManager->GetDetectorField());
178 G4MagneticField* magFieldNC ATLAS_THREAD_SAFE = const_cast<G4MagneticField*>(magField);
179
180 CreateStepperToChordFinder(magFieldNC);
181}
182
183//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
184
185void
186G4mplEquationSetup::CreateStepperToChordFinder(G4MagneticField* magFieldNC)
187{
188 if(magFieldNC == nullptr)
189 {
190 static G4ThreadLocal G4UniformMagField nullField( G4ThreeVector(0.0, 0.0, 0.0));
191 magFieldNC= &nullField;
192 }
193
194 delete fMonopoleEquation;
195 fMonopoleEquation = new G4mplEqMagElectricField(magFieldNC);
196
197 delete fMonopoleStepper;
198 fMonopoleStepper = new G4ClassicalRK4( fMonopoleEquation, 8 ); // for time information..
199
200 if ( !fMonopoleStepper )
201 {
202 G4ExceptionDescription ermsg;
203 ermsg << "The creation of a stepper for Monopoles failed - trying to use G4ClassicalRK4";
204 G4Exception("G4mplEquationSetup::InitialiseForField",
205 "FailureToCreateObject", FatalException, ermsg);
206 }
207
208 delete fMonopoleChordFinder;
209
210 auto integrDriver = new G4MagInt_Driver( fMinStep, fMonopoleStepper,
211 // cppcheck-suppress nullPointerRedundantCheck; false positive
212 fMonopoleStepper->GetNumberOfVariables() );
213 fMonopoleChordFinder = new G4ChordFinder( integrDriver );
214}
215
216//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
217
218// This method must be called before
219
220void G4mplEquationSetup::SwitchStepperAndChordFinder(G4bool useMonopoleEq,
221 G4FieldManager* fieldManager)
222{
223 // For the existing version to work, InitialiseForField must be called
224 // - for *this* field manager (not another) before this call
225 // - potentially after a change of 'field' object in this field manager (tbc)
226 const G4MagneticField* magField = dynamic_cast<const G4MagneticField*>(fieldManager->GetDetectorField());
227 G4MagneticField* magFieldNC ATLAS_THREAD_SAFE = const_cast<G4MagneticField*>(magField); // fieldManager only allow const access despite being non-const
228
229 // New code is needed to cope with the following cases:
230 // - a different field manager is encountered (i.e. a local one or second local one)
231 // - the 'field' object to which the G4FieldManager is pointing was changed
232
233 if ( magFieldNC )
234 {
235 // First check whether the field in equation of motion has changed!
236 CheckAndUpdateField( magFieldNC );
237
238 if (useMonopoleEq) {
239 fieldManager->SetChordFinder( fMonopoleChordFinder );
240 } else {
241 fieldManager->SetChordFinder( fOriginalChordFinder );
242 }
243 }
244}
245
246//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
247
248void G4mplEquationSetup::ResetIntegration(G4FieldManager* fieldManager)
249// Restore the original ChordFinder to either
250// - allow non-monopole tracks to work seamlessly
251// - prepare for move of monopole to volume/region with different fieldManager
252{
253 if( fieldManager != fCurrentFieldManager){
254 G4ExceptionDescription ermsg;
255 ermsg << "This method expects to be called with the chordfinder it knows"
256 << " yet its is called with " << fieldManager
257 << " and expected " << fCurrentFieldManager << G4endl;
258 G4Exception("G4mplEquationSetup::ResetIntegration",
259 "InvalidState", FatalException, ermsg);
260 }
261
262 if( fCurrentFieldManager ) {
263 fCurrentFieldManager->SetChordFinder(fOriginalChordFinder);
264
265 if ( fVerbose )
266 G4cout << " G4mplEquationSetup: Reset Chord-Finder to original one (for pure electric charge): "
267 << fOriginalChordFinder << G4endl;
268
269 fOriginalChordFinder = nullptr; // Now Forget it!
270 fCurrentFieldManager = nullptr;
271 }
272 // Since these objects referred to the outgoing field manager, clean them up!
273 delete fMonopoleEquation; fMonopoleEquation= nullptr;
274 delete fMonopoleStepper; fMonopoleStepper= nullptr;
275 delete fMonopoleChordFinder; fMonopoleChordFinder= nullptr;
276}
277
278//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
279
280void G4mplEquationSetup::CheckAndUpdateField( G4MagneticField* magFieldNC )
281// Ensure that the field of this fieldManager is the one in the equation - else update it to be so.
282{
283 if( magFieldNC != fMonopoleEquation->GetFieldObj() )
284 {
285 // fMonopoleEquation->SetFieldObj( magFieldNC ); // Dangerous method -- but types are both G4MagneticField
286 // A cleaner version will call again Initialise ...
287 CreateStepperToChordFinder(magFieldNC);
288 }
289}
290
std::map< std::string, double > instance
#define ATLAS_THREAD_SAFE