Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/geometry/magneticfield/include/G4QSStepper.hh

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 // G4QSStepper
 27 //
 28 // QSS Integrator Stepper
 29 
 30 // Authors: Lucio Santi, Rodrigo Castro (Univ. Buenos Aires) - 2018-2021
 31 // --------------------------------------------------------------------
 32 #ifndef QSS_Stepper_HH
 33 #define QSS_Stepper_HH 1
 34 
 35 #include "G4FieldTrack.hh"
 36 #include "G4FieldUtils.hh"
 37 #include "G4LineSection.hh"
 38 #include "G4MagIntegratorStepper.hh"
 39 #include "G4QSS2.hh"
 40 #include "G4QSS3.hh"
 41 #include "G4QSSDriver.hh"
 42 #include "G4QSSMessenger.hh"
 43 #include "G4VIntegrationDriver.hh"
 44 #include "G4qss_misc.hh"
 45 
 46 #include <cmath>
 47 #include <cassert>
 48 
 49 // Maximum allowed number of QSS substeps per integration step
 50 #define QSS_MAX_SUBSTEPS 1000
 51 
 52 template <class QSS>
 53 class G4QSStepper : public G4MagIntegratorStepper
 54 {
 55   public:
 56 
 57     G4QSStepper(G4EquationOfMotion* EqRhs,
 58                 G4int numberOfVariables = 6,
 59                 G4bool primary = true);
 60    ~G4QSStepper() override;
 61 
 62     void Stepper(const G4double y[],
 63                  const G4double dydx[],
 64                        G4double h,
 65                        G4double yout[],
 66                        G4double yerr[]) override;
 67 
 68     void Stepper(const G4double yInput[],
 69                  const G4double dydx[],
 70                        G4double hstep,
 71                        G4double yOutput[],
 72                        G4double yError[],
 73                        G4double dydxOutput[]);
 74 
 75     // For calculating the output at the tau fraction of Step
 76     //
 77     inline void SetupInterpolation() {}
 78     inline void Interpolate(G4double tau, G4double yOut[]);
 79 
 80     G4double DistChord() const override;
 81 
 82     G4int IntegratorOrder() const override { return method->order(); }
 83 
 84     void reset(const G4FieldTrack* track);
 85 
 86     void SetPrecision(G4double dq_rel, G4double dq_min);
 87       // precision parameters for QSS method
 88 
 89     static G4QSStepper<G4QSS2>* build_QSS2(G4EquationOfMotion* EqRhs,
 90                                            G4int numberOfVariables = 6,
 91                                            G4bool primary = true);
 92 
 93     static G4QSStepper<G4QSS3>* build_QSS3(G4EquationOfMotion* EqRhs,
 94                                            G4int numberOfVariables = 6,
 95                                            G4bool primary = true);
 96 
 97     inline G4EquationOfMotion* GetSpecificEquation() { return GetEquationOfMotion(); }
 98 
 99     inline const field_utils::State& GetYOut() const { return fyOut; }
100 
101     inline G4double GetLastStepLength() { return fLastStepLength; }
102 
103   private:
104 
105     G4QSStepper(QSS* method,
106                 G4EquationOfMotion* EqRhs,
107                 G4int numberOfVariables = 6,
108                 G4bool primary = true);
109 
110     void initialize_data_structs();
111     static QSS_simulator build_simulator();
112 
113     inline void update_field();
114     inline void save_substep(G4double time, G4double length);
115 
116     inline void realloc_substeps();
117     inline void get_state_from_poly(G4double* x, G4double* tx,
118                                     G4double time, G4double* state);
119 
120     inline void recompute_derivatives(int index);
121     inline void update_time();
122 
123     inline G4double get_coeff() { return fCoeff_local; }
124 
125     inline void set_coeff(G4double coeff) { fCoeff_local = coeff; }
126 
127     inline void set_charge(G4double q)
128     {
129       f_charge_c2 = q * cLight_local * cLight_local;  // 89875.5178737;
130     }
131 
132     inline G4double get_qc2() { return f_charge_c2; }
133 
134     inline void set_mg() { fMassGamma = f_mass * fGamma2; }
135 
136     inline void set_gamma2(G4double gamma2) { fGamma2 = gamma2; }
137     inline void set_velocity(G4double v) { fVelocity = v; }
138 
139     inline void velocity_to_momentum(G4double* state);
140 
141     inline void set_gamma(G4double p_sq)
142     {
143       set_gamma2(std::sqrt(p_sq / (f_mass * f_mass) + 1));
144       set_mg();
145       set_coeff(get_qc2() / fMassGamma);
146     }
147 
148   private:
149 
150     QSS_simulator simulator;
151     QSS* method;
152 
153     // State
154     //
155     G4double fLastStepLength;
156     field_utils::State fyIn, fyOut;
157 
158     G4double f_mass;
159     static constexpr G4double cLight_local = 299.792458;  // should use CLHEP
160     G4double f_charge_c2;
161     G4double fMassGamma;
162     G4double fGamma2;
163     G4double fCoeff_local;
164     G4double fVelocity;
165 };
166 
167 using G4QSStepper_QSS2 = G4QSStepper<G4QSS2>;
168 using G4QSStepper_QSS3 = G4QSStepper<G4QSS3>;
169 
170 template <class QSS>
171 inline G4QSStepper<QSS>::G4QSStepper(QSS* qss, G4EquationOfMotion* EqRhs,
172                               G4int noIntegrationVariables, G4bool)
173   : G4MagIntegratorStepper(EqRhs, noIntegrationVariables),
174     simulator(qss->getSimulator()),
175     method(qss)
176 {
177   SetIsQSS(true);  //  Replaces virtual method IsQSS
178   fLastStepLength = -1.0;
179 
180   f_mass = 0;
181   f_charge_c2 = 0;
182   fMassGamma = 0;
183   fGamma2 = 0;
184   fCoeff_local = 0;
185   fVelocity = 0;
186 
187   this->initialize_data_structs();
188   this->SetPrecision(1e-4, 1e-7);  // Default values
189 }
190 
191 template <class QSS>
192 inline G4QSStepper<QSS>::~G4QSStepper()
193 {
194   for (auto & i : simulator->SD) { free(i); }
195 
196   free(SUBSTEPS(this->simulator));
197   free(this->simulator);
198 }
199 
200 template <class QSS>
201 inline void G4QSStepper<QSS>::Stepper(const G4double yInput[],
202                                       const G4double dydx[],
203                                             G4double hstep,
204                                             G4double yOutput[],
205                                             G4double yError[],
206                                             G4double /*dydxOutput*/[])
207 {
208   Stepper(yInput, dydx, hstep, yOutput, yError);
209 }
210 
211 template <class QSS>
212 inline void G4QSStepper<QSS>::update_time()
213 {
214   auto* const sim = this->simulator;
215 
216   sim->time = sim->nextStateTime[0];
217   sim->minIndex = 0;
218 
219   if (sim->nextStateTime[1] < sim->time) {
220     sim->time = sim->nextStateTime[1];
221     sim->minIndex = 1;
222   }
223   if (sim->nextStateTime[2] < sim->time) {
224     sim->time = sim->nextStateTime[2];
225     sim->minIndex = 2;
226   }
227   if (sim->nextStateTime[3] < sim->time) {
228     sim->time = sim->nextStateTime[3];
229     sim->minIndex = 3;
230   }
231   if (sim->nextStateTime[4] < sim->time) {
232     sim->time = sim->nextStateTime[4];
233     sim->minIndex = 4;
234   }
235   if (sim->nextStateTime[5] < sim->time) {
236     sim->time = sim->nextStateTime[5];
237     sim->minIndex = 5;
238   }
239 }
240 
241 template <class QSS>
242 inline void G4QSStepper<QSS>::Stepper(const G4double yInput[],
243                                       const G4double /*DyDx*/[],
244                                             G4double max_length,
245                                             G4double yOut[],
246                                             G4double[] /*yErr[]*/)
247 {
248   G4double elapsed;
249   G4double t, prev_time = 0;
250   G4double length = 0.;
251   G4int index;
252 
253   const G4int coeffs = method->order() + 1;
254   G4double* tq = simulator->tq;
255   G4double* tx = simulator->tx;
256   G4double* dQRel = simulator->dQRel;
257   G4double* dQMin = simulator->dQMin;
258   G4double* lqu = simulator->lqu;
259   G4double* x = simulator->x;
260   G4int** SD = simulator->SD;
261   G4int cf0, infCf0;
262 
263   CUR_SUBSTEP(simulator) = 0;
264 
265   this->save_substep(0, length);
266 
267   this->update_time();
268   t = simulator->time;
269   index = simulator->minIndex;
270 
271   while (length < max_length && t < Qss_misc::INF && CUR_SUBSTEP(simulator) < QSS_MAX_SUBSTEPS) {
272     cf0 = index * coeffs;
273     elapsed = t - tx[index];
274     method->advance_time_x(cf0, elapsed);
275     tx[index] = t;
276     lqu[index] = dQRel[index] * std::fabs(x[cf0]);
277     if (lqu[index] < dQMin[index]) {
278       lqu[index] = dQMin[index];
279     }
280     method->update_quantized_state(index);
281     tq[index] = t;
282     method->next_time(index, t);
283     for (G4int i = 0; i < 3; i++) {
284       G4int j = SD[index][i];
285       elapsed = t - tx[j];
286       infCf0 = j * coeffs;
287       if (elapsed > 0) {
288         x[infCf0] = method->evaluate_x_poly(infCf0, elapsed, x);
289         tx[j] = t;
290       }
291     }
292 
293     this->update_field();
294     this->recompute_derivatives(index);
295     method->recompute_next_times(SD[index], t);
296 
297     if (t > prev_time) {
298       length += fVelocity * (t - prev_time);
299       if (length <= max_length) { this->save_substep(t, length); }
300       else { break; }
301     }
302 
303     this->update_time();
304     prev_time = t;
305     t = simulator->time;
306     index = simulator->minIndex;
307   }
308 
309   if(CUR_SUBSTEP(simulator) >= QSS_MAX_SUBSTEPS) {
310     max_length = length;
311   }
312 
313   auto* const substep = &LAST_SUBSTEP_STRUCT(simulator);
314   t = substep->start_time + (max_length - substep->len) / fVelocity;
315 
316   this->get_state_from_poly(substep->x, substep->tx, t, yOut);
317 
318   velocity_to_momentum(yOut);
319 
320   const G4int numberOfVariables = GetNumberOfVariables();
321   for (G4int i = 0; i < numberOfVariables; ++i) {
322     // Store Input and Final values, for possible use in calculating chord
323     fyIn[i] = yInput[i];
324     fyOut[i] = yOut[i];
325   }
326 
327   fLastStepLength = max_length;
328 }
329 
330 template<class QSS>
331 inline G4double G4QSStepper<QSS>::DistChord() const
332 {
333   G4double yMid[6];
334   const_cast<G4QSStepper<QSS>*>(this)->Interpolate(0.5, yMid);
335 
336   const G4ThreeVector begin = makeVector(fyIn, field_utils::Value3D::Position);
337   const G4ThreeVector end = makeVector(fyOut, field_utils::Value3D::Position);
338   const G4ThreeVector mid = makeVector(yMid, field_utils::Value3D::Position);
339 
340   return G4LineSection::Distline(mid, begin, end);
341 }
342 
343 template <class QSS>
344 inline void G4QSStepper<QSS>::Interpolate(G4double tau, G4double yOut[])
345 {
346   G4double length = tau * fLastStepLength;
347   G4int idx = 0, j = LAST_SUBSTEP(simulator);
348   G4double end_time;
349 
350   if (j >= 15) {
351     G4int i = 0, k = j;
352     idx = j >> 1;
353     while (idx < k && i < j - 1) {
354       if (length < SUBSTEP_LEN(simulator, idx)) {
355         j = idx;
356       } else if (length >= SUBSTEP_LEN(simulator, idx + 1)) {
357         i = idx;
358       } else {
359         break;
360       }
361 
362       idx = (i + j) >> 1;
363     }
364   }
365   else {
366     for (; idx < j && length >= SUBSTEP_LEN(simulator, idx + 1); idx++) {;}
367   }
368 
369   auto* const substep = &SUBSTEP_STRUCT(simulator, idx);
370   end_time = substep->start_time + (length - substep->len) / fVelocity;
371 
372   this->get_state_from_poly(substep->x, substep->tx, end_time, yOut);
373 
374   velocity_to_momentum(yOut);
375 }
376 
377 template <class QSS>
378 inline void G4QSStepper<QSS>::reset(const G4FieldTrack* track)
379 {
380   using Qss_misc::PXidx;
381   using Qss_misc::PYidx;
382   using Qss_misc::PZidx;
383   using Qss_misc::VXidx;
384   using Qss_misc::VYidx;
385   using Qss_misc::VZidx;
386 
387   G4ThreeVector pos = track->GetPosition();
388   G4ThreeVector momentum = track->GetMomentum();
389 
390   f_mass = track->GetRestMass();
391   set_charge(track->GetCharge());
392   set_gamma(momentum.mag2());
393   G4double c_mg = cLight_local / fMassGamma;
394   set_velocity(momentum.mag() * c_mg);
395 
396   method->reset_state(PXidx, pos.getX());
397   method->reset_state(PYidx, pos.getY());
398   method->reset_state(PZidx, pos.getZ());
399 
400   method->reset_state(VXidx, momentum.getX() * c_mg);
401   method->reset_state(VYidx, momentum.getY() * c_mg);
402   method->reset_state(VZidx, momentum.getZ() * c_mg);
403 
404   this->update_field();
405   method->full_definition(get_coeff());
406 
407   method->recompute_all_state_times(0);
408 
409   simulator->time = 0;
410 }
411 
412 template <class QSS>
413 inline void G4QSStepper<QSS>::SetPrecision(G4double dq_rel, G4double dq_min)
414 {
415   G4double* dQMin = simulator->dQMin;
416   G4double* dQRel = simulator->dQRel;
417   G4int n_vars = simulator->states;
418 
419   if (dq_min <= 0) { dq_min = dq_rel * 1e-3; }
420 
421   for (G4int i = 0; i < n_vars; ++i) {
422     dQRel[i] = dq_rel;
423     dQMin[i] = dq_min;
424   }
425 }
426 
427 template <class QSS>
428 inline void G4QSStepper<QSS>::initialize_data_structs()
429 {
430   auto sim = this->simulator;
431   auto states = (G4int*)calloc(Qss_misc::VAR_IDX_END, sizeof(G4int));
432 
433   sim->states = Qss_misc::VAR_IDX_END;
434   sim->it = 0.;
435 
436   for (unsigned int i = 0; i < Qss_misc::VAR_IDX_END; i++) {
437     sim->SD[i] = (G4int*)malloc(3 * sizeof(G4int));
438   }
439 
440   sim->SD[0][states[0]++] = 3;
441   sim->SD[0][states[0]++] = 4;
442   sim->SD[0][states[0]++] = 5;
443 
444   sim->SD[1][states[1]++] = 3;
445   sim->SD[1][states[1]++] = 4;
446   sim->SD[1][states[1]++] = 5;
447 
448   sim->SD[2][states[2]++] = 3;
449   sim->SD[2][states[2]++] = 4;
450   sim->SD[2][states[2]++] = 5;
451 
452   sim->SD[3][states[3]++] = 0;
453   sim->SD[3][states[3]++] = 4;
454   sim->SD[3][states[3]++] = 5;
455 
456   sim->SD[4][states[4]++] = 1;
457   sim->SD[4][states[4]++] = 3;
458   sim->SD[4][states[4]++] = 5;
459 
460   sim->SD[5][states[5]++] = 2;
461   sim->SD[5][states[5]++] = 3;
462   sim->SD[5][states[5]++] = 4;
463 
464   free(states);
465 }
466 
467 template <class QSS>
468 inline QSS_simulator G4QSStepper<QSS>::build_simulator()
469 {
470   QSS_simulator sim = (QSS_simulator)malloc(sizeof(*sim));
471   MAX_SUBSTEP(sim) = Qss_misc::MIN_SUBSTEPS;
472   SUBSTEPS(sim) = (QSSSubstep)malloc(Qss_misc::MIN_SUBSTEPS * sizeof(*SUBSTEPS(sim)));
473   return sim;
474 }
475 
476 template <class QSS>
477 inline void G4QSStepper<QSS>::recompute_derivatives(G4int index)
478 {
479   const G4int coeffs = method->order() + 1;
480   G4double e;
481   G4int idx = 0;
482 
483   e = simulator->time - simulator->tq[0];
484   if (likely(e > 0)) { method->advance_time_q(idx, e); }
485   simulator->tq[0] = simulator->time;
486 
487   idx += coeffs;
488   e = simulator->time - simulator->tq[1];
489   if (likely(e > 0)) { method->advance_time_q(idx, e); }
490   simulator->tq[1] = simulator->time;
491 
492   idx += coeffs;
493   e = simulator->time - simulator->tq[2];
494   if (likely(e > 0)) { method->advance_time_q(idx, e); }
495   simulator->tq[2] = simulator->time;
496 
497   idx += coeffs;
498   e = simulator->time - simulator->tq[3];
499   if (likely(e > 0)) { method->advance_time_q(idx, e); }
500   simulator->tq[3] = simulator->time;
501 
502   idx += coeffs;
503   e = simulator->time - simulator->tq[4];
504   if (likely(e > 0)) { method->advance_time_q(idx, e); }
505   simulator->tq[4] = simulator->time;
506 
507   idx += coeffs;
508   e = simulator->time - simulator->tq[5];
509   if (likely(e > 0)) { method->advance_time_q(idx, e); }
510   simulator->tq[5] = simulator->time;
511 
512   method->dependencies(index, get_coeff());
513 }
514 
515 template <class QSS>
516 inline void G4QSStepper<QSS>::update_field()
517 {
518   using Qss_misc::PXidx;
519   using Qss_misc::PYidx;
520   using Qss_misc::PZidx;
521 
522   const G4int order1 = method->order() + 1;
523   G4double* const _field = simulator->alg;
524   G4double* const _point = _field + order1;
525 
526   _point[PXidx] = simulator->x[PXidx];
527   _point[PYidx] = simulator->x[PYidx * order1];
528   _point[PZidx] = simulator->x[PZidx * order1];
529 
530   this->GetEquationOfMotion()->GetFieldValue(_point, _field);
531 }
532 
533 template <class QSS>
534 inline void G4QSStepper<QSS>::save_substep(G4double time, G4double length)
535 {
536   memcpy(CUR_SUBSTEP_X(simulator), simulator->x,
537     (Qss_misc::VAR_IDX_END * (Qss_misc::MAX_QSS_STEPPER_ORDER + 2)) * sizeof(G4double));
538 
539   CUR_SUBSTEP_START(simulator) = time;
540   CUR_SUBSTEP_LEN(simulator) = length;
541   CUR_SUBSTEP(simulator)++;
542 
543   if (unlikely(CUR_SUBSTEP(simulator) == MAX_SUBSTEP(simulator))) {
544     this->realloc_substeps();
545   }
546 }
547 
548 template <class QSS>
549 inline void G4QSStepper<QSS>::realloc_substeps()
550 {
551   const G4int prev_index = MAX_SUBSTEP(simulator), new_index = 2 * prev_index;
552 
553   MAX_SUBSTEP(simulator) = new_index;
554   SUBSTEPS(simulator) =
555     (QSSSubstep)realloc(SUBSTEPS(simulator), new_index * sizeof(*SUBSTEPS(simulator)));
556 }
557 
558 template <class QSS>
559 inline void G4QSStepper<QSS>::get_state_from_poly(
560   G4double* x, G4double* tx, G4double time, G4double* state)
561 {
562   unsigned int coeff_index = 0, i;
563   const unsigned int x_order = method->order(), x_order1 = x_order + 1;
564 
565   for (i = 0; i < Qss_misc::VAR_IDX_END; ++i) {
566     assert(tx[i] <= time);
567     state[i] = method->evaluate_x_poly(coeff_index, time - tx[i], x);
568     coeff_index += x_order1;
569   }
570 }
571 
572 template <class QSS>
573 inline void G4QSStepper<QSS>::velocity_to_momentum(G4double* state)
574 {
575   using Qss_misc::VXidx;
576   using Qss_misc::VYidx;
577   using Qss_misc::VZidx;
578   G4double coeff = fMassGamma / cLight_local;
579 
580   state[VXidx] *= coeff;
581   state[VYidx] *= coeff;
582   state[VZidx] *= coeff;
583 }
584 
585 #endif
586