Geant4 11.3.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4FieldSetup.cc
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
26/// \file G4FieldSetup.cxx
27/// \brief Implementation of the G4FieldSetup class
28///
29/// This code was initially developed in Geant4 VMC package
30/// (https://github.com/vmc-project)
31/// and adapted to Geant4.
32///
33/// \author I. Hrivnacova; IJCLab, Orsay
34
35#include "G4FieldSetup.hh"
37
38#include "G4Exception.hh"
39#include "G4LogicalVolume.hh"
40#include "G4SystemOfUnits.hh"
41
45#include "G4CashKarpRKF45.hh"
46#include "G4ChordFinder.hh"
47#include "G4ClassicalRK4.hh"
48#include "G4ConstRK4.hh"
49#include "G4DormandPrince745.hh"
53#include "G4EqEMFieldWithEDM.hh"
57#include "G4ExplicitEuler.hh"
59#include "G4FieldManager.hh"
61#include "G4HelixHeum.hh"
64#include "G4HelixSimpleRunge.hh"
65#include "G4ImplicitEuler.hh"
66#include "G4MagneticField.hh"
67#include "G4MagErrorStepper.hh"
70#include "G4Mag_EqRhs.hh"
71#include "G4Mag_SpinEqRhs.hh"
72#include "G4Mag_UsualEqRhs.hh"
73#include "G4NystromRK4.hh"
74#include "G4RK547FEq1.hh"
75#include "G4RK547FEq2.hh"
76#include "G4RK547FEq3.hh"
77#include "G4RKG3_Stepper.hh"
78#include "G4SimpleHeum.hh"
79#include "G4SimpleRunge.hh"
80#include "G4TsitourasRK45.hh"
82
83
84//_____________________________________________________________________________
86 G4Field* field, G4LogicalVolume* lv)
87 : fParameters(parameters), fG4Field(field), fLogicalVolume(lv)
88{
89 // Standard constructor
90
91 fMessenger = new G4FieldSetupMessenger(this);
92
93 // Get or create field manager
94 if (fLogicalVolume == nullptr) {
95 // global field
97 }
98 else {
99 // local field
100 fFieldManager = new G4FieldManager();
101 G4bool overwriteDaughtersField = true;
102 // TO DO: this parameter should be made optional for users
103 fLogicalVolume->SetFieldManager(fFieldManager, overwriteDaughtersField);
104 }
105}
106
107//_____________________________________________________________________________
109{
110 // Destructor
111 delete fG4Field;
112 delete fChordFinder;
113 delete fStepper;
114}
115
116//
117// private methods
118//
119
120//_____________________________________________________________________________
121G4Field* G4FieldSetup::CreateCachedField(
122 const G4FieldParameters& parameters, G4Field* field)
123{
124// Create cached magnetic field if const distance is set > 0.
125// and field is of G4MagneticField.
126// Return the input field otherwise.
127
128 if (parameters.GetConstDistance() > 0.) {
129 auto magField = dynamic_cast<G4MagneticField*>(field);
130 if (magField == nullptr) {
132 "G4FieldSetup::CreateCachedField:", "GeomFieldParameters0001",
133 JustWarning, "Incompatible field type.");
134 return field;
135 }
136 return new G4CachedMagneticField(magField, parameters.GetConstDistance());
137 }
138
139 return field;
140}
141
142//_____________________________________________________________________________
143G4EquationOfMotion* G4FieldSetup::CreateEquation(G4EquationType equation)
144{
145 // Set the equation of motion of a particle in a field
146
147 // magnetic fields
148 G4MagneticField* magField = nullptr;
149 if (equation == kEqMagnetic || equation == kEqMagneticWithSpin) {
150 magField = dynamic_cast<G4MagneticField*>(fG4Field);
151 if (magField == nullptr) {
153 "G4FieldSetup::CreateEquation:", "GeomFieldParameters0001",
154 FatalErrorInArgument, "Incompatible field and equation.\n"
155 "The field type must be set explicitly for other than magnetic field.");
156 return nullptr;
157 }
158 }
159
160 // electromagnetic fields
161 G4ElectroMagneticField* elMagField = nullptr;
162 if (equation >= kEqElectroMagnetic && equation <= kEqEMfieldWithEDM) {
163 elMagField = dynamic_cast<G4ElectroMagneticField*>(fG4Field);
164 if (elMagField == nullptr) {
166 "G4FieldSetup::CreateEquation:", "GeomFieldParameters0001",
167 FatalErrorInArgument, "Incompatible field and equation.\n"
168 "The field type must be set explicitly for other than magnetic field.");
169 return nullptr;
170 }
171 }
172
173 // electromagnetic fields
174 switch (equation) {
175 case kEqMagnetic:
176 return new G4Mag_UsualEqRhs(magField);
177 break;
178
180 return new G4Mag_SpinEqRhs(magField);
181 break;
182
184 return new G4EqMagElectricField(elMagField);
185 break;
186
188 return new G4EqEMFieldWithSpin(elMagField);
189 break;
190
192 return new G4EqEMFieldWithEDM(elMagField);
193 break;
194 case kUserEquation:
195 // nothing to be done
196 return nullptr;
197 break;
198 }
199
201 "G4FieldSetup::CreateEquation:", "GeomFieldParameters0001",
202 FatalErrorInArgument, "Unknown equation type.");
203 return nullptr;
204}
205
206//_____________________________________________________________________________
207G4MagIntegratorStepper* G4FieldSetup::CreateStepper(
208 G4EquationOfMotion* equation, G4StepperType stepper)
209{
210 // Set the integrator of particle's equation of motion
211
212 // Check steppers which require equation of motion of G4Mag_EqRhs type
213 auto eqRhs = dynamic_cast<G4Mag_EqRhs*>(equation);
214 if ((eqRhs == nullptr) && (stepper > kTsitourasRK45)) {
216 "G4FieldSetup::CreateStepper:", "GeomFieldParameters0001",
218 "The stepper type requires equation of motion of G4Mag_EqRhs type.");
219 return nullptr;
220 }
221
222 switch (stepper) {
224 return new G4BogackiShampine23(equation);
225 break;
226
228 return new G4BogackiShampine45(equation);
229 break;
230
231 case kCashKarpRKF45:
232 return new G4CashKarpRKF45(equation);
233 break;
234
235 case kClassicalRK4:
236 return new G4ClassicalRK4(equation);
237 break;
238
240 return new G4DormandPrince745(equation);
241 break;
242
244 return new G4DormandPrinceRK56(equation);
245 break;
246
248 return new G4DormandPrinceRK78(equation);
249 break;
250
251 case kExplicitEuler:
252 return new G4ExplicitEuler(equation);
253 break;
254
255 case kImplicitEuler:
256 return new G4ImplicitEuler(equation);
257 break;
258
259 case kSimpleHeum:
260 return new G4SimpleHeum(equation);
261 break;
262
263 case kSimpleRunge:
264 return new G4SimpleRunge(equation);
265 break;
266
267 case kTsitourasRK45:
268 return new G4TsitourasRK45(equation);
269 break;
270
271 case kConstRK4:
272 return new G4ConstRK4(eqRhs);
273 break;
274
276 return new G4ExactHelixStepper(eqRhs);
277 break;
278
280 return new G4HelixExplicitEuler(eqRhs);
281 break;
282
283 case kHelixHeum:
284 return new G4HelixHeum(eqRhs);
285 break;
286
288 return new G4HelixImplicitEuler(eqRhs);
289 break;
290
292 return new G4HelixMixedStepper(eqRhs);
293 break;
294
296 return new G4HelixSimpleRunge(eqRhs);
297 break;
298
299 case kNystromRK4:
300 return new G4NystromRK4(eqRhs);
301 break;
302
303 case kRKG3Stepper:
304 return new G4RKG3_Stepper(eqRhs);
305 break;
306 case kUserStepper:
307 // nothing to be done
308 return nullptr;
309 break;
310 default:
312 "G4FieldSetup::CreateStepper:", "GeomFieldParameters0001",
313 FatalErrorInArgument, "Incorrect stepper type.");
314 return nullptr;
315 }
316}
317
318//_____________________________________________________________________________
319G4VIntegrationDriver* G4FieldSetup::CreateFSALStepperAndDriver(
320 G4EquationOfMotion* equation, G4StepperType stepperType, G4double minStep)
321{
322 // Set the FSAL integrator of particle's equation of motion
323
324 switch (stepperType) {
325 case kRK547FEq1:
326 return new G4FSALIntegrationDriver<G4RK547FEq1>(
327 minStep, new G4RK547FEq1(equation));
328
329 case kRK547FEq2:
330 return new G4FSALIntegrationDriver<G4RK547FEq2>(
331 minStep, new G4RK547FEq2(equation));
332
333 case kRK547FEq3:
334 return new G4FSALIntegrationDriver<G4RK547FEq3>(
335 minStep, new G4RK547FEq3(equation));
336
337 default:
339 "G4FieldSetup::CreateFSALStepperAndDriver", "GeomFieldParameters0001",
340 FatalErrorInArgument, "Incorrect stepper type.");
341 return nullptr;
342 }
343}
344
345//_____________________________________________________________________________
346void G4FieldSetup::CreateCachedField()
347{
348 // Create cached field (if ConstDistance is set)
349 fG4Field = CreateCachedField(fParameters, fG4Field);
350}
351
352//_____________________________________________________________________________
353void G4FieldSetup::CreateStepper()
354{
355 // Create equation of motion (or get the user one if defined)
356 if (fParameters.GetEquationType() == kUserEquation) {
357 fEquation = fParameters.GetUserEquationOfMotion();
358 // G4cout << "user equation: " << fEquation << G4endl;
359 }
360 else {
361 delete fEquation;
362 fEquation = nullptr;
363 fEquation = CreateEquation(fParameters.GetEquationType());
364 // G4cout << "created equation: " << fEquation << G4endl;
365 }
366 fEquation->SetFieldObj(fG4Field);
367
368 // Create stepper (or get the user one if defined)
369 if (fParameters.GetStepperType() == kUserStepper) {
370 // User stepper
371 fStepper = fParameters.GetUserStepper();
372 // G4cout << "user stepper: " << fStepper << G4endl;
373 }
374 else if (fParameters.GetStepperType() >= kRK547FEq1) {
375 // FSAL stepper
376 delete fDriver;
377 delete fStepper;
378 fDriver = nullptr;
379 fStepper = nullptr;
380 fDriver = CreateFSALStepperAndDriver(
381 fEquation, fParameters.GetStepperType(), fParameters.GetMinimumStep());
382 // G4cout << "FSAL driver: " << fDriver << G4endl;
383 if (fDriver) {
384 fStepper = fDriver->GetStepper();
385 // G4cout << "FSAL stepper: " << fStepper << G4endl;
386 }
387 }
388 else {
389 // Normal stepper
390 delete fStepper;
391 fStepper = nullptr;
392 fStepper = CreateStepper(fEquation, fParameters.GetStepperType());
393 // G4cout << "stepper: " << fStepper << G4endl;
394 }
395}
396
397//_____________________________________________________________________________
398void G4FieldSetup::CreateChordFinder()
399{
400 // Chord finder
401 if (fParameters.GetFieldType() == kMagnetic) {
402 if (fDriver) {
403 fChordFinder = new G4ChordFinder(fDriver);
404 // G4cout << "chord finder from existing driver: " << fDriver << G4endl;
405 }
406 else {
407 // Chord finder
408 fChordFinder = new G4ChordFinder(static_cast<G4MagneticField*>(fG4Field),
409 fParameters.GetMinimumStep(), fStepper);
410 // G4cout << "chord finder from parameters: " << fChordFinder
411 // << " minStep: " << fParameters.GetMinimumStep() << G4endl;
412 }
413 fChordFinder->SetDeltaChord(fParameters.GetDeltaChord());
414 // G4cout << "set delta chord: " << fParameters.GetDeltaChord() << G4endl;
415 }
416 else if (fParameters.GetFieldType() == kElectroMagnetic) {
417 G4MagInt_Driver* intDriver = new G4MagInt_Driver(
418 fParameters.GetMinimumStep(), fStepper, fStepper->GetNumberOfVariables());
419 // G4cout << "kElectroMagnetic: intDriver " << intDriver << G4endl;
420 if (intDriver) {
421 // Chord finder
422 fChordFinder = new G4ChordFinder(intDriver);
423 // G4cout << "chord finder from intDriver " << fChordFinder << G4endl;
424 }
425 }
426}
427
428//_____________________________________________________________________________
429void G4FieldSetup::UpdateFieldManager()
430{
431 fFieldManager->SetChordFinder(fChordFinder);
432 fFieldManager->SetDetectorField(fG4Field);
433
434 // G4cout << "Go to set other parameters: "
435 // << "minEpsilon: " << fParameters.GetMinimumEpsilonStep() << ", "
436 // << "maxEpsilon: " << fParameters.GetMaximumEpsilonStep() << ", "
437 // << "deltaOneStep: " << fParameters.GetDeltaOneStep() << ", "
438 // << "deltaIntersection: " << fParameters.GetDeltaIntersection() << G4endl;
439 fFieldManager->SetMinimumEpsilonStep(fParameters.GetMinimumEpsilonStep());
440 fFieldManager->SetMaximumEpsilonStep(fParameters.GetMaximumEpsilonStep());
441 fFieldManager->SetDeltaOneStep(fParameters.GetDeltaOneStep());
442 fFieldManager->SetDeltaIntersection(fParameters.GetDeltaIntersection());
443}
444
445//
446// public methods
447//
448
449//_____________________________________________________________________________
451{
452 // First clean up previous state.
453 delete fChordFinder;
454 fChordFinder = nullptr;
455
456 if (fG4Field == nullptr) {
457 // G4cout << "fG4Field == nullptr: go to clean-up " << G4endl;
458 delete fEquation;
459 delete fDriver;
460 delete fStepper;
461 delete fChordFinder;
462 fEquation = nullptr;
463 fDriver = nullptr;
464 fStepper = nullptr;
465 fChordFinder = nullptr;
466 fFieldManager->SetChordFinder(fChordFinder);
467 fFieldManager->SetDetectorField(fG4Field);
468 }
469}
470
471//_____________________________________________________________________________
473{
474 // Update field with new field parameters
475
476 Clear();
477 if (fG4Field == nullptr) {
478 // No further update needed
479 return;
480 }
481
482 CreateCachedField();
483 CreateStepper();
484 CreateChordFinder();
485 UpdateFieldManager();
486}
487
488//_____________________________________________________________________________
489void G4FieldSetup::PrintInfo(G4int verboseLevel, const G4String about)
490{
491 if (verboseLevel == 0) return;
492
493 auto fieldType = G4FieldParameters::FieldTypeName(fParameters.GetFieldType());
494 auto isCachedMagneticField = (fParameters.GetConstDistance() > 0.);
495 if (fLogicalVolume == nullptr) {
496 fieldType = "Global";
497 }
498 else {
499 fieldType = "Local (in ";
500 fieldType.append(fLogicalVolume->GetName());
501 fieldType.append(")");
502 }
503 if (isCachedMagneticField) {
504 fieldType.append(" cached");
505 }
506
507 G4cout << fieldType << " field " << about << " with stepper ";
509 fParameters.GetStepperType())
510 << G4endl;
511
512 if (verboseLevel > 1) {
513 fParameters.PrintParameters();
514 }
515}
@ JustWarning
@ FatalErrorInArgument
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
G4EquationType
@ kEqMagneticWithSpin
@ kUserEquation
User defined equation of motion.
@ kEqEMfieldWithSpin
@ kEqMagnetic
@ kEqElectroMagnetic
@ kEqEMfieldWithEDM
@ kElectroMagnetic
electromagnetic field
@ kMagnetic
magnetic field
G4StepperType
@ kRKG3Stepper
G4RKG3_Stepper.
@ kRK547FEq2
G4RK547FEq2.
@ kHelixSimpleRunge
G4HelixSimpleRunge.
@ kNystromRK4
G4NystromRK4.
@ kDormandPrince745
G4DormandPrince745.
@ kCashKarpRKF45
G4CashKarpRKF45.
@ kDormandPrinceRK78
G4DormandPrinceRK78.
@ kSimpleRunge
G4SimpleRunge.
@ kHelixImplicitEuler
G4HelixImplicitEuler.
@ kConstRK4
G4ConstRK4.
@ kUserStepper
User defined stepper.
@ kSimpleHeum
G4SimpleHeum.
@ kHelixHeum
G4HelixHeum.
@ kHelixExplicitEuler
G4HelixExplicitEuler.
@ kDormandPrinceRK56
G4DormandPrinceRK56.
@ kTsitourasRK45
G4TsitourasRK45.
@ kImplicitEuler
G4ImplicitEuler.
@ kExactHelixStepper
G4ExactHelixStepper.
@ kHelixMixedStepper
G4HelixMixedStepper.
@ kBogackiShampine45
G4BogackiShampine45.
@ kExplicitEuler
G4ExplicitEuler.
@ kRK547FEq1
G4RK547FEq1.
@ kRK547FEq3
G4RK547FEq3.
@ kBogackiShampine23
G4BogackiShampine23.
@ kClassicalRK4
G4ClassicalRK4.
double G4double
Definition G4Types.hh:83
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
#define G4endl
Definition G4ios.hh:67
G4GLOB_DLL std::ostream G4cout
static G4FieldManager * GetGlobalFieldManager()
The magnetic field parameters.
G4double GetConstDistance() const
Get the distance within which the field is considered constant.
static G4String StepperTypeName(G4StepperType stepper)
Return the stepper type as a string.
static G4String FieldTypeName(G4FieldType field)
Return the field type as a string.
Messenger class that defines commands for G4FieldSetup.
G4FieldSetup(const G4FieldParameters &parameters, G4Field *field, G4LogicalVolume *lv=nullptr)
Standard constructor.
void Clear()
Clear previously created setup.
~G4FieldSetup()
Destructor.
void PrintInfo(G4int verboseLevel, const G4String about="created")
Print information.
void Update()
Update field setup with new field parameters.