Geant4 11.4.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// Implementation of the G4FieldSetup class
27//
28// Author: Ivana Hrivnacova (IJClab, Orsay), 2024.
29// --------------------------------------------------------------------
30
31#include "G4FieldSetup.hh"
33
34#include "G4Exception.hh"
35#include "G4LogicalVolume.hh"
36#include "G4SystemOfUnits.hh"
37
41#include "G4CashKarpRKF45.hh"
42#include "G4ChordFinder.hh"
43#include "G4ClassicalRK4.hh"
44#include "G4ConstRK4.hh"
45#include "G4DoLoMcPriRK34.hh"
46#include "G4DormandPrince745.hh"
50#include "G4EqEMFieldWithEDM.hh"
54#include "G4ExplicitEuler.hh"
56#include "G4FieldManager.hh"
58#include "G4HelixHeum.hh"
61#include "G4HelixSimpleRunge.hh"
62#include "G4ImplicitEuler.hh"
63#include "G4MagneticField.hh"
64#include "G4MagErrorStepper.hh"
67#include "G4Mag_EqRhs.hh"
68#include "G4Mag_SpinEqRhs.hh"
69#include "G4Mag_UsualEqRhs.hh"
70#include "G4NystromRK4.hh"
71#include "G4RK547FEq1.hh"
72#include "G4RK547FEq2.hh"
73#include "G4RK547FEq3.hh"
74#include "G4RKG3_Stepper.hh"
75#include "G4SimpleHeum.hh"
76#include "G4SimpleRunge.hh"
77#include "G4TsitourasRK45.hh"
79
80
81//_____________________________________________________________________________
83 G4Field* field, G4LogicalVolume* lv)
84 : fParameters(parameters), fG4Field(field), fLogicalVolume(lv)
85{
86 // Standard constructor
87
88 fMessenger = new G4FieldSetupMessenger(this);
89
90 // Get or create field manager
91 if (fLogicalVolume == nullptr)
92 {
93 // global field
95 }
96 else
97 {
98 // local field
99 fFieldManager = new G4FieldManager();
100 G4bool overwriteDaughtersField = true;
101 // TO DO: this parameter should be made optional for users
102 fLogicalVolume->SetFieldManager(fFieldManager, overwriteDaughtersField);
103 }
104}
105
106//_____________________________________________________________________________
108{
109 // Destructor
110 delete fG4Field;
111 delete fChordFinder;
112 delete fStepper;
113}
114
115//
116// private methods
117//
118
119//_____________________________________________________________________________
120G4Field* G4FieldSetup::CreateCachedField(
121 const G4FieldParameters& parameters, G4Field* field)
122{
123 // Create cached magnetic field if const distance is set > 0.
124 // and field is of G4MagneticField.
125 // Return the input field otherwise.
126
127 if (parameters.GetConstDistance() > 0.)
128 {
129 auto magField = dynamic_cast<G4MagneticField*>(field);
130 if (magField == nullptr)
131 {
133 "G4FieldSetup::CreateCachedField:", "GeomFieldParameters0001",
134 JustWarning, "Incompatible field type.");
135 return field;
136 }
137 return new G4CachedMagneticField(magField, parameters.GetConstDistance());
138 }
139
140 return field;
141}
142
143//_____________________________________________________________________________
144G4EquationOfMotion* G4FieldSetup::CreateEquation(G4EquationType equation)
145{
146 // Set the equation of motion of a particle in a field
147
148 // magnetic fields
149 G4MagneticField* magField = nullptr;
150 if (equation == kEqMagnetic || equation == kEqMagneticWithSpin)
151 {
152 magField = dynamic_cast<G4MagneticField*>(fG4Field);
153 if (magField == nullptr)
154 {
156 "G4FieldSetup::CreateEquation:", "GeomFieldParameters0001",
157 FatalErrorInArgument, "Incompatible field and equation.\n"
158 "The field type must be set explicitly for other than magnetic field.");
159 return nullptr;
160 }
161 }
162
163 // electromagnetic fields
164 G4ElectroMagneticField* elMagField = nullptr;
165 if (equation >= kEqElectroMagnetic && equation <= kEqEMfieldWithEDM)
166 {
167 elMagField = dynamic_cast<G4ElectroMagneticField*>(fG4Field);
168 if (elMagField == nullptr)
169 {
171 "G4FieldSetup::CreateEquation:", "GeomFieldParameters0001",
172 FatalErrorInArgument, "Incompatible field and equation.\n"
173 "The field type must be set explicitly for other than magnetic field.");
174 return nullptr;
175 }
176 }
177
178 // electromagnetic fields
179 switch (equation)
180 {
181 case kEqMagnetic:
182 return new G4Mag_UsualEqRhs(magField);
183 break;
184
186 return new G4Mag_SpinEqRhs(magField);
187 break;
188
190 return new G4EqMagElectricField(elMagField);
191 break;
192
194 return new G4EqEMFieldWithSpin(elMagField);
195 break;
196
198 return new G4EqEMFieldWithEDM(elMagField);
199 break;
200
201 // other fields
202 case kEqGravity:
203 case kEqMonopole:
204 case kEqReplate:
206 "G4FieldSetup::CreateEquation:", "GeomFieldParameters0001",
207 FatalErrorInArgument, "Limitation: Equation not supported in G4FieldBuilder.\n"
208 "Only magnetic and electromagnetic field can be constructed with G4FieldBuilder.");
209 return nullptr;
210 break;
211 case kUserEquation:
212 // nothing to be done
213 return nullptr;
214 break;
215 }
216
218 "G4FieldSetup::CreateEquation:", "GeomFieldParameters0001",
219 FatalErrorInArgument, "Unknown equation type.");
220 return nullptr;
221}
222
223//_____________________________________________________________________________
224G4MagIntegratorStepper* G4FieldSetup::CreateStepper(
225 G4EquationOfMotion* equation, G4StepperType stepper)
226{
227 // Set the integrator of particle's equation of motion
228
229 // Check steppers which require equation of motion of G4Mag_EqRhs type
230 auto eqRhs = dynamic_cast<G4Mag_EqRhs*>(equation);
231 if ((eqRhs == nullptr) && (stepper > kTsitourasRK45))
232 {
234 "G4FieldSetup::CreateStepper:", "GeomFieldParameters0001",
236 "The stepper type requires equation of motion of G4Mag_EqRhs type.");
237 return nullptr;
238 }
239
240 switch (stepper)
241 {
243 return new G4BogackiShampine23(equation);
244 break;
245
247 return new G4BogackiShampine45(equation);
248 break;
249
250 case kCashKarpRKF45:
251 return new G4CashKarpRKF45(equation);
252 break;
253
254 case kClassicalRK4:
255 return new G4ClassicalRK4(equation);
256 break;
257
258 case kDoLoMcPriRK34:
259 return new G4DoLoMcPriRK34(equation);
260 break;
261
263 return new G4DormandPrince745(equation);
264 break;
265
267 return new G4DormandPrinceRK56(equation);
268 break;
269
271 return new G4DormandPrinceRK78(equation);
272 break;
273
274 case kExplicitEuler:
275 return new G4ExplicitEuler(equation);
276 break;
277
278 case kImplicitEuler:
279 return new G4ImplicitEuler(equation);
280 break;
281
282 case kSimpleHeum:
283 return new G4SimpleHeum(equation);
284 break;
285
286 case kSimpleRunge:
287 return new G4SimpleRunge(equation);
288 break;
289
290 case kTsitourasRK45:
291 return new G4TsitourasRK45(equation);
292 break;
293
294 case kConstRK4:
295 return new G4ConstRK4(eqRhs);
296 break;
297
299 return new G4ExactHelixStepper(eqRhs);
300 break;
301
303 return new G4HelixExplicitEuler(eqRhs);
304 break;
305
306 case kHelixHeum:
307 return new G4HelixHeum(eqRhs);
308 break;
309
311 return new G4HelixImplicitEuler(eqRhs);
312 break;
313
315 return new G4HelixMixedStepper(eqRhs);
316 break;
317
319 return new G4HelixSimpleRunge(eqRhs);
320 break;
321
322 case kNystromRK4:
323 return new G4NystromRK4(eqRhs);
324 break;
325
326 case kRKG3Stepper:
327 return new G4RKG3_Stepper(eqRhs);
328 break;
329 case kUserStepper:
330 // nothing to be done
331 return nullptr;
332 break;
333
334 // templated steppers
335 case kTCashKarpRKF45:
338 case kQSStepper:
340 "G4FieldSetup::CreateStepper:", "GeomFieldParameters0001",
341 FatalErrorInArgument, "Limitation: Templated steppers not supported in G4FieldBuilder");
342 return nullptr;
343 break;
344
345 default:
347 "G4FieldSetup::CreateStepper:", "GeomFieldParameters0001",
348 FatalErrorInArgument, "Incorrect stepper type.");
349 return nullptr;
350 }
351}
352
353//_____________________________________________________________________________
354G4VIntegrationDriver* G4FieldSetup::CreateFSALStepperAndDriver(
355 G4EquationOfMotion* equation, G4StepperType stepperType, G4double minStep)
356{
357 // Set the FSAL integrator of particle's equation of motion
358
359 switch (stepperType)
360 {
361 case kRK547FEq1:
362 return new G4FSALIntegrationDriver<G4RK547FEq1>(
363 minStep, new G4RK547FEq1(equation));
364
365 case kRK547FEq2:
366 return new G4FSALIntegrationDriver<G4RK547FEq2>(
367 minStep, new G4RK547FEq2(equation));
368
369 case kRK547FEq3:
370 return new G4FSALIntegrationDriver<G4RK547FEq3>(
371 minStep, new G4RK547FEq3(equation));
372
373 default:
375 "G4FieldSetup::CreateFSALStepperAndDriver", "GeomFieldParameters0001",
376 FatalErrorInArgument, "Incorrect stepper type.");
377 return nullptr;
378 }
379}
380
381//_____________________________________________________________________________
382void G4FieldSetup::CreateCachedField()
383{
384 // Create cached field (if ConstDistance is set)
385 fG4Field = CreateCachedField(fParameters, fG4Field);
386}
387
388//_____________________________________________________________________________
389void G4FieldSetup::CreateStepper()
390{
391 // Create equation of motion (or get the user one if defined)
392 if (fParameters.GetEquationType() == kUserEquation)
393 {
394 fEquation = fParameters.GetUserEquationOfMotion();
395 }
396 else
397 {
398 delete fEquation;
399 fEquation = nullptr;
400 fEquation = CreateEquation(fParameters.GetEquationType());
401 }
402 fEquation->SetFieldObj(fG4Field);
403
404 // Create stepper (or get the user one if defined)
405 if (fParameters.GetStepperType() == kUserStepper)
406 {
407 // User stepper
408 fStepper = fParameters.GetUserStepper();
409 }
410 else if (fParameters.GetStepperType() >= kRK547FEq1)
411 {
412 // FSAL stepper
413 delete fDriver;
414 delete fStepper;
415 fDriver = nullptr;
416 fStepper = nullptr;
417 fDriver = CreateFSALStepperAndDriver(
418 fEquation, fParameters.GetStepperType(), fParameters.GetMinimumStep());
419 if (fDriver != nullptr)
420 {
421 fStepper = fDriver->GetStepper();
422 }
423 }
424 else
425 {
426 // Normal stepper
427 delete fStepper;
428 fStepper = nullptr;
429 fStepper = CreateStepper(fEquation, fParameters.GetStepperType());
430 }
431}
432
433//_____________________________________________________________________________
434void G4FieldSetup::CreateChordFinder()
435{
436 // Chord finder
437 if (fParameters.GetFieldType() == kMagnetic)
438 {
439 if (fDriver != nullptr)
440 {
441 fChordFinder = new G4ChordFinder(fDriver);
442 }
443 else
444 {
445 // Chord finder
446 fChordFinder = new G4ChordFinder(static_cast<G4MagneticField*>(fG4Field),
447 fParameters.GetMinimumStep(), fStepper);
448 }
449 fChordFinder->SetDeltaChord(fParameters.GetDeltaChord());
450 }
451 else if (fParameters.GetFieldType() == kElectroMagnetic)
452 {
453 auto intDriver = new G4MagInt_Driver(
454 fParameters.GetMinimumStep(), fStepper, fStepper->GetNumberOfVariables());
455 if (intDriver != nullptr)
456 {
457 // Chord finder
458 fChordFinder = new G4ChordFinder(intDriver);
459 }
460 }
461}
462
463//_____________________________________________________________________________
464void G4FieldSetup::UpdateFieldManager()
465{
466 fFieldManager->SetChordFinder(fChordFinder);
467 fFieldManager->SetDetectorField(fG4Field);
468
469 fFieldManager->SetMinimumEpsilonStep(fParameters.GetMinimumEpsilonStep());
470 fFieldManager->SetMaximumEpsilonStep(fParameters.GetMaximumEpsilonStep());
471 fFieldManager->SetDeltaOneStep(fParameters.GetDeltaOneStep());
472 fFieldManager->SetDeltaIntersection(fParameters.GetDeltaIntersection());
473}
474
475//
476// public methods
477//
478
479//_____________________________________________________________________________
481{
482 // First clean up previous state.
483 delete fChordFinder;
484 fChordFinder = nullptr;
485
486 if (fG4Field == nullptr)
487 {
488 delete fEquation;
489 delete fDriver;
490 delete fStepper;
491 delete fChordFinder;
492 fEquation = nullptr;
493 fDriver = nullptr;
494 fStepper = nullptr;
495 fChordFinder = nullptr;
496 fFieldManager->SetChordFinder(fChordFinder);
497 fFieldManager->SetDetectorField(fG4Field);
498 }
499}
500
501//_____________________________________________________________________________
503{
504 // Update field with new field parameters
505
506 Clear();
507 if (fG4Field == nullptr)
508 {
509 // No further update needed
510 return;
511 }
512
513 CreateCachedField();
514 CreateStepper();
515 CreateChordFinder();
516 UpdateFieldManager();
517}
518
519//_____________________________________________________________________________
520void G4FieldSetup::PrintInfo(G4int verboseLevel, const G4String& about)
521{
522 if (verboseLevel == 0) { return; }
523
524 auto fieldType = G4FieldParameters::FieldTypeName(fParameters.GetFieldType());
525 auto isCachedMagneticField = (fParameters.GetConstDistance() > 0.);
526 if (fLogicalVolume == nullptr)
527 {
528 fieldType = "Global";
529 }
530 else
531 {
532 fieldType = "Local (in ";
533 fieldType.append(fLogicalVolume->GetName());
534 fieldType.append(")");
535 }
536 if (isCachedMagneticField)
537 {
538 fieldType.append(" cached");
539 }
540
541 G4cout << fieldType << " field " << about << " with stepper ";
542 G4cout << G4FieldParameters::StepperTypeName(fParameters.GetStepperType())
543 << G4endl;
544
545 if (verboseLevel > 1)
546 {
547 fParameters.PrintParameters();
548 }
549}
@ JustWarning
@ FatalErrorInArgument
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
G4EquationType
G4EquationType defines the types of equations of motion of a particle in a field in Geant4.
@ kEqMagneticWithSpin
@ kUserEquation
User defined equation of motion.
@ kEqEMfieldWithSpin
@ kEqMagnetic
@ kEqGravity
@ kEqReplate
@ kEqMonopole
@ kEqElectroMagnetic
@ kEqEMfieldWithEDM
@ kElectroMagnetic
electromagnetic field
@ kMagnetic
magnetic field
G4StepperType
G4StepperType defines the available integrator of particle's equation of motion in Geant4.
@ kRKG3Stepper
G4RKG3_Stepper.
@ kRK547FEq2
G4RK547FEq2.
@ kHelixSimpleRunge
G4HelixSimpleRunge.
@ kNystromRK4
G4NystromRK4.
@ kDormandPrince745
G4DormandPrince745.
@ kCashKarpRKF45
G4CashKarpRKF45.
@ kDormandPrinceRK78
G4DormandPrinceRK78.
@ kQSStepper
G4QSStepper.
@ kSimpleRunge
G4SimpleRunge.
@ kHelixImplicitEuler
G4HelixImplicitEuler.
@ kConstRK4
G4ConstRK4.
@ kUserStepper
User defined stepper.
@ kDoLoMcPriRK34
G4DoLoMcPriRK34.
@ kSimpleHeum
G4SimpleHeum.
@ kHelixHeum
G4HelixHeum.
@ kHelixExplicitEuler
G4HelixExplicitEuler.
@ kDormandPrinceRK56
G4DormandPrinceRK56.
@ kTDormandPrince45
G4TDormandPrince45.
@ kTsitourasRK45
G4TsitourasRK45.
@ kImplicitEuler
G4ImplicitEuler.
@ kExactHelixStepper
G4ExactHelixStepper.
@ kHelixMixedStepper
G4HelixMixedStepper.
@ kBogackiShampine45
G4BogackiShampine45.
@ kExplicitEuler
G4ExplicitEuler.
@ kTCashKarpRKF45
G4TCashKarpRKF45.
@ kRK547FEq1
G4RK547FEq1.
@ kRK547FEq3
G4RK547FEq3.
@ kBogackiShampine23
G4BogackiShampine23.
@ kClassicalRK4
G4ClassicalRK4.
@ kTMagErrorStepper
G4TMagErrorStepper.
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
G4EquationOfMotion is the abstract base class for the right hand size of the equation of motion of a ...
G4FieldManager is a manager (store) for a pointer to the Field subclass that describes the field of a...
static G4FieldManager * GetGlobalFieldManager()
G4FieldParameters defines the type of equation of motion of a particle in a field and the integration...
G4double GetConstDistance() const
static G4String StepperTypeName(G4StepperType stepper)
static G4String FieldTypeName(G4FieldType field)
G4FieldSetupMessenger is a messenger class that defines commands for G4FieldSetup.
G4FieldSetup()=delete
void PrintInfo(G4int verboseLevel, const G4String &about="created")
G4Field is the abstract class for any kind of field. It allows any kind of field (vector,...
Definition G4Field.hh:67
G4LogicalVolume represents a leaf node or unpositioned subtree in the geometry hierarchy....
G4MagIntegratorStepper is an abstract base class for integrator of particle's equation of motion,...