60 if( qss_order < 2 || qss_order > 3 )
63 err_msg <<
"-G4QSStepper/c-tor: qss_order= " << qss_order <<
" is not either 2 or 3 ";
69 if( qss_order != messenger->GetQssOrder() )
74 if( qss_order != messenger->GetQssOrder() )
76 static std::atomic<G4int> change_of_order= 0;
79 if( change_of_order == 1 )
86 err_msg <<
"G4QSSStepper: Trying to change order of QSS stepper(s) for "
87 << change_of_order <<
" th time -- Maximum allowed is 1 time. "
88 <<
" Requesting order = " << qss_order
89 <<
" whereas current (static) value = " << messenger->GetQssOrder()
97 fCharge_c2 = fCharge * ( 1.0 / (CLHEP::c_light*CLHEP::c_light) );
98 G4double momentum[3]= { 0.0, 0.0, 0.0 };
100 std::fill_n( fYout, 12, 0.0 );
108 G4double momentum2 = momentum[0]*momentum[0] + momentum[1]*momentum[1] + momentum[2]*momentum[2];
109 fGamma = std::sqrt(momentum2/(fRestMass*fRestMass) + 1);
110 G4double mass_times_gamma = fRestMass * fGamma;
111 fMassOverC = mass_times_gamma * (1.0 / CLHEP::c_light);
112 fInv_mass_over_c = CLHEP::c_light * (1.0 / mass_times_gamma);
113 fCoeff = fCharge_c2 / mass_times_gamma;
125 if (fCurrent_track !=
nullptr)
127 fCharge = fCurrent_track->GetCharge();
128 fCharge_c2 = fCharge * CLHEP::c_squared;
137 fVelocity = std::sqrt(velocity_vector[0]*velocity_vector[0] + velocity_vector[1]*velocity_vector[1] + velocity_vector[2]*velocity_vector[2] );
139 std::copy_n( y, 3, ¤t_substep.state_x[DERIVATIVE_0][POSITION_IDX] );
140 std::copy_n( velocity_vector, 3, ¤t_substep.state_x[DERIVATIVE_0][VELOCITY_IDX] );
142 std::copy_n( ¤t_substep.state_x[DERIVATIVE_0][0], 6, ¤t_substep.state_q[DERIVATIVE_0][0] );
144 for (
G4int i = 1; i < qss_order; ++i)
152 current_substep.t = 0;
153 current_substep.extrapolation_method = qss_order;
158 dq_vector[i] = std::fmax(dqmin[
INDEX_TYPE(i)], dqrel[
INDEX_TYPE(i)] * std::fabs(current_substep.state_x[DERIVATIVE_0][i]));
173 a = current_substep.state_x[DERIVATIVE_2][index]/2;
174 b = current_substep.state_x[DERIVATIVE_1][index] - current_substep.state_q[DERIVATIVE_1][index] ;
175 c = current_substep.state_x[DERIVATIVE_0][index] - current_substep.state_q[DERIVATIVE_0][index];
178 if (qss_order == 3 && current_substep.state_x[DERIVATIVE_3][index] != 0.0)
181 h = current_substep.state_x[DERIVATIVE_3][index]/6;
182 a -= current_substep.state_q[DERIVATIVE_2][index]/2;
184 G4double q_cube = fCharge*fCharge*fCharge;
187 if (a == 0 && b == 0 && c == 0)
189 delta_sync_t = cbrt(std::fabs(dq/h));
197 G4double qLocal = (a * a - 3 * b) * (1.0 / 9.0);
198 G4double r_base = (2*a*a*a - 9*a*b + 27*c)*(1.0/54.0);
200 G4double sqrt_q = std::sqrt(qLocal);
201 G4double sqrt_q_cube = std::sqrt(q_cube);
209 G4double theta = std::acos(r/sqrt_q_cube);
210 G4double t1 = -2*sqrt_q*std::cos((1./3.)*theta) - a_over_3;
211 G4double t2 = -2*sqrt_q*std::cos((1./3.)*(theta+2*CLHEP::pi)) - a_over_3;
212 G4double t3 = -2*sqrt_q*std::cos((1./3.)*(theta-2*CLHEP::pi)) - a_over_3;
215 if (t > 0) { delta_sync_t = std::fmin(delta_sync_t,t); }
221 G4double A = -copysign(1,r) * cbrt(std::fabs(r) + std::sqrt(r*r - q_cube));
224 if (t1 > 0) {delta_sync_t = std::fmin(delta_sync_t,t1);}
231 else if (qss_order == 1 || a == 0)
234 if (b == 0) { delta_sync_t = INFTY; }
237 else if ( (b > 0) == (dq > c) ) { delta_sync_t = (dq-c)/b; }
238 else { delta_sync_t = (-dq-c)/b; }
247 if ((a > 0) == (dq > c)) {delta_sync_t = std::sqrt((dq-c)/a);}
248 else {delta_sync_t = std::sqrt((-dq-c)/a);}
255 G4double discriminator_base = b*b - a4*c;
256 G4double discriminator_difference = a4*dq;
257 G4double discriminator_1 = discriminator_base + discriminator_difference;
258 G4double discriminator_2 = discriminator_base - discriminator_difference;
259 G4double fixed_solution_part = -b/a2;
262 for(
G4double discriminator : {discriminator_1, discriminator_2})
264 if (discriminator < 0) {
continue; }
265 G4double variable_solution_part = std::sqrt(discriminator)/std::fabs(a2);
266 G4double t_local = fixed_solution_part - variable_solution_part;
270 t_local = fixed_solution_part + variable_solution_part;
272 if (t_local > 0) { delta_sync_t = std::fmin(delta_sync_t,t_local); }
277 current_substep.sync_t[index] = current_substep.state_tx[index] + delta_sync_t;
296 fFinal_t = h/fVelocity;
297 fFinal_t = std::fmin(fFinal_t,INFTY);
299 while (t < fFinal_t && t < INFTY && substeps.current_substep_index < QSS_MAX_SUBSTEPS)
301 substeps.save_substep(¤t_substep);
305 t = current_substep.sync_t[sync_index];
306 t = std::fmin(t,fFinal_t);
307 current_substep.t = t;
314 current_substep.state_q[DERIVATIVE_0][sync_index] = current_substep.state_x[DERIVATIVE_0][sync_index];
315 current_substep.state_q[DERIVATIVE_1][sync_index] = current_substep.state_x[DERIVATIVE_1][sync_index];
316 current_substep.state_q[DERIVATIVE_2][sync_index] = current_substep.state_x[DERIVATIVE_2][sync_index];
318 current_substep.state_tq[sync_index] = current_substep.state_tx[sync_index];
320 dq_vector[sync_index] = std::fmax(dqmin[
INDEX_TYPE(sync_index)], dqrel[
INDEX_TYPE(sync_index)] * std::fabs(current_substep.state_x[DERIVATIVE_0][sync_index]));
334 G4double &tIndex = current_substep.state_tx[sync_index];
338 if(sync_index < VELOCITY_IDX && ! fField_changed) {
continue; }
350 if (sync_index < VELOCITY_IDX)
352 for (
G4int i = VELOCITY_IDX; i < 6; ++i)
363 G4int indexDep1 = (sync_index + 2)%VELOCITY_IDX + VELOCITY_IDX;
364 G4int indexDep2 = (sync_index + 1)%VELOCITY_IDX + VELOCITY_IDX;
365 G4int index_class = sync_index - VELOCITY_IDX;
367 for (
G4int i : {indexDep1, indexDep2, index_class})
375 if(substeps.current_substep_index >= QSS_MAX_SUBSTEPS)
377 fFinal_t = current_substep.t;
384 memcpy(yout, ¤t_substep.state_x[DERIVATIVE_0],
sizeof(
QSStateVector));
396 G4double target_t = current_substep.t * tau;
398 G4double t = current_substep.t * tau;;
400 if (substeps.current_substep_index < 20)
402 while(i < substeps.current_substep_index && substeps._substeps[i+1].t <= target_t )
410 G4int high_i = substeps.current_substep_index;
412 G4int idx = high_i >> 1;
413 while(low_i < high_i-1)
415 if(target_t < substeps._substeps[idx].t)
423 idx = (low_i+high_i) >> 1;