Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/geometry/magneticfield/src/G4FieldSetup.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

  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"
 36 #include "G4FieldSetupMessenger.hh"
 37 
 38 #include "G4Exception.hh"
 39 #include "G4LogicalVolume.hh"
 40 #include "G4SystemOfUnits.hh"
 41 
 42 #include "G4BogackiShampine23.hh"
 43 #include "G4BogackiShampine45.hh"
 44 #include "G4CachedMagneticField.hh"
 45 #include "G4CashKarpRKF45.hh"
 46 #include "G4ChordFinder.hh"
 47 #include "G4ClassicalRK4.hh"
 48 #include "G4ConstRK4.hh"
 49 #include "G4DormandPrince745.hh"
 50 #include "G4DormandPrinceRK56.hh"
 51 #include "G4DormandPrinceRK78.hh"
 52 #include "G4ElectroMagneticField.hh"
 53 #include "G4EqEMFieldWithEDM.hh"
 54 #include "G4EqEMFieldWithSpin.hh"
 55 #include "G4EqMagElectricField.hh"
 56 #include "G4ExactHelixStepper.hh"
 57 #include "G4ExplicitEuler.hh"
 58 #include "G4FSALIntegrationDriver.hh"
 59 #include "G4FieldManager.hh"
 60 #include "G4HelixExplicitEuler.hh"
 61 #include "G4HelixHeum.hh"
 62 #include "G4HelixImplicitEuler.hh"
 63 #include "G4HelixMixedStepper.hh"
 64 #include "G4HelixSimpleRunge.hh"
 65 #include "G4ImplicitEuler.hh"
 66 #include "G4MagneticField.hh"
 67 #include "G4MagErrorStepper.hh"
 68 #include "G4MagHelicalStepper.hh"
 69 #include "G4MagIntegratorDriver.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"
 81 #include "G4VIntegrationDriver.hh"
 82 
 83 
 84 //_____________________________________________________________________________
 85 G4FieldSetup::G4FieldSetup(const G4FieldParameters& parameters,
 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
 96     fFieldManager = G4FieldManager::GetGlobalFieldManager();
 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 //_____________________________________________________________________________
108 G4FieldSetup::~G4FieldSetup()
109 {
110   // Destructor
111   delete fG4Field;
112   delete fChordFinder;
113   delete fStepper;
114 }
115 
116 //
117 // private methods
118 //
119 
120 //_____________________________________________________________________________
121 G4Field* 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) {
131       G4Exception(
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 //_____________________________________________________________________________
143 G4EquationOfMotion* 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) {
152       G4Exception(
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) {
165       G4Exception(
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 
179     case kEqMagneticWithSpin:
180       return new G4Mag_SpinEqRhs(magField);
181       break;
182 
183     case kEqElectroMagnetic:
184       return new G4EqMagElectricField(elMagField);
185       break;
186 
187     case kEqEMfieldWithSpin:
188       return new G4EqEMFieldWithSpin(elMagField);
189       break;
190 
191     case kEqEMfieldWithEDM:
192       return new G4EqEMFieldWithEDM(elMagField);
193       break;
194     case kUserEquation:
195       // nothing to be done
196       return nullptr;
197       break;
198   }
199 
200   G4Exception(
201     "G4FieldSetup::CreateEquation:", "GeomFieldParameters0001",
202     FatalErrorInArgument, "Unknown equation type.");
203   return nullptr;
204 }
205 
206 //_____________________________________________________________________________
207 G4MagIntegratorStepper* 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)) {
215     G4Exception(
216       "G4FieldSetup::CreateStepper:", "GeomFieldParameters0001",
217       FatalErrorInArgument, 
218       "The stepper type requires equation of motion of G4Mag_EqRhs type.");
219     return nullptr;
220   }
221 
222   switch (stepper) {
223     case kBogackiShampine23:
224       return new G4BogackiShampine23(equation);
225       break;
226 
227     case kBogackiShampine45:
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 
239     case kDormandPrince745:
240       return new G4DormandPrince745(equation);
241       break;
242 
243     case kDormandPrinceRK56:
244       return new G4DormandPrinceRK56(equation);
245       break;
246 
247     case kDormandPrinceRK78:
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 
275     case kExactHelixStepper:
276       return new G4ExactHelixStepper(eqRhs);
277       break;
278 
279     case kHelixExplicitEuler:
280       return new G4HelixExplicitEuler(eqRhs);
281       break;
282 
283     case kHelixHeum:
284       return new G4HelixHeum(eqRhs);
285       break;
286 
287     case kHelixImplicitEuler:
288       return new G4HelixImplicitEuler(eqRhs);
289       break;
290 
291     case kHelixMixedStepper:
292       return new G4HelixMixedStepper(eqRhs);
293       break;
294 
295     case kHelixSimpleRunge:
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:
311       G4Exception(
312         "G4FieldSetup::CreateStepper:", "GeomFieldParameters0001",
313         FatalErrorInArgument, "Incorrect stepper type.");
314       return nullptr;
315   }
316 }
317 
318 //_____________________________________________________________________________
319 G4VIntegrationDriver* 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:
338       G4Exception(
339         "G4FieldSetup::CreateFSALStepperAndDriver", "GeomFieldParameters0001",
340         FatalErrorInArgument, "Incorrect stepper type.");
341       return nullptr;
342   }
343 }
344 
345 //_____________________________________________________________________________
346 void G4FieldSetup::CreateCachedField()
347 {
348   // Create cached field (if ConstDistance is set)
349   fG4Field = CreateCachedField(fParameters, fG4Field);
350 }
351 
352 //_____________________________________________________________________________
353 void 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 //_____________________________________________________________________________
398 void 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 //_____________________________________________________________________________
429 void 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 //_____________________________________________________________________________
450 void G4FieldSetup::Clear()
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 //_____________________________________________________________________________
472 void G4FieldSetup::Update()
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 //_____________________________________________________________________________
489 void 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 ";
508   G4cout << G4FieldParameters::StepperTypeName(
509               fParameters.GetStepperType())
510          << G4endl;
511 
512   if (verboseLevel > 1) {
513     fParameters.PrintParameters();
514   }
515 }
516