43 constexpr G4double inv_STEPFAC1 = 1.0 / STEPFAC1;
44 constexpr G4double inv_STEPFAC4 = 1.0 / STEPFAC4;
49 : fnvar(nvar), m_eps_rel(eps_rel), m_midpoint(equation,nvar), m_max_dt(max_dt)
53 for(
G4int i = 0; i < m_k_max + 1; ++i)
55 m_interval_sequence[i] = 2 * (i + 1);
58 m_cost[i] = m_interval_sequence[i];
62 m_cost[i] = m_cost[i-1] + m_interval_sequence[i];
64 for(
G4int k = 0; k < i; ++k)
67 /
static_cast<G4double>(m_interval_sequence[k]);
68 m_coeff[i][k] = 1.0 / (r * r - 1.0);
105 for(
G4int k = 0; k <= m_current_k_opt+1; ++k)
109 m_midpoint.
SetSteps(m_interval_sequence[k]);
112 m_midpoint.
DoStep(in, dxdt, out, dt);
117 m_midpoint.
DoStep(in, dxdt, m_table[k-1], dt);
120 for (
G4int i = 0; i < fnvar; ++i)
122 m_err[i] = out[i] - m_table[0][i];
126 h_opt[k] = calc_h_opt(dt, error, k);
127 work[k] =
static_cast<G4double>(m_cost[k]) / h_opt[k];
129 if( (k == m_current_k_opt-1) || m_first)
135 if( (work[k] < KFAC2 * work[k-1]) || (m_current_k_opt <= 2) )
138 m_current_k_opt = std::min(m_k_max - 1 , std::max(2 , k + 1));
140 new_h *=
static_cast<G4double>(m_cost[k + 1])
145 m_current_k_opt = std::min(m_k_max - 1, std::max(2, k));
150 if(should_reject(error , k) && !m_first)
157 if(k == m_current_k_opt)
163 if(work[k-1] < KFAC2 * work[k])
165 m_current_k_opt = std::max( 2 , m_current_k_opt-1 );
166 new_h = h_opt[m_current_k_opt];
168 else if( (work[k] < KFAC2 * work[k-1]) && !m_last_step_rejected )
170 m_current_k_opt = std::min(m_k_max - 1, m_current_k_opt + 1);
172 new_h *=
static_cast<G4double>(m_cost[m_current_k_opt])
177 new_h = h_opt[m_current_k_opt];
181 if(should_reject(error, k))
184 new_h = h_opt[m_current_k_opt];
188 if(k == m_current_k_opt + 1)
193 if(work[k-2] < KFAC2 * work[k-1])
195 m_current_k_opt = std::max(2, m_current_k_opt - 1);
197 if((work[k] < KFAC2 * work[m_current_k_opt]) && !m_last_step_rejected)
199 m_current_k_opt = std::min(m_k_max - 1 , k);
201 new_h = h_opt[m_current_k_opt];
206 new_h = h_opt[m_current_k_opt];
218 if(!m_last_step_rejected || new_h < dt)
221 new_h = std::min(m_max_dt, new_h);
226 m_last_step_rejected = reject;
235 m_last_step_rejected =
false;
238void G4BulirschStoer::extrapolate(std::size_t k ,
G4double xest[])
243 for(std::size_t j = k - 1 ; j > 0; --j)
245 for (
G4int i = 0; i < fnvar; ++i)
247 m_table[j-1][i] = m_table[j][i] * (1. + m_coeff[k][j])
248 - m_table[j-1][i] * m_coeff[k][j];
251 for (
G4int i = 0; i < fnvar; ++i)
253 xest[i] = m_table[0][i] * (1. + m_coeff[k][0]) - xest[i] * m_coeff[k][0];
258G4BulirschStoer::calc_h_opt(
G4double h ,
G4double error , std::size_t k)
const
262 const G4double expo = 1.0 / (2 * k + 1);
263 const G4double facmin = std::pow(STEPFAC3, expo);
273 fac = STEPFAC2 * std::pow(error * inv_STEPFAC1 , -expo);
274 fac = std::max(facmin * inv_STEPFAC4, std::min( facminInv, fac));
290 if( (work[k-1] < KFAC1 * work[k]) || (k == m_k_max) )
292 m_current_k_opt = (
G4int)k - 1;
293 dt = h_opt[ m_current_k_opt ];
296 if( (work[k] < KFAC2 * work[k-1])
297 || m_last_step_rejected || (k == m_k_max-1) )
299 m_current_k_opt = (
G4int)k;
300 dt = h_opt[m_current_k_opt];
304 m_current_k_opt = (
G4int)k + 1;
305 dt = h_opt[m_current_k_opt - 1] * m_cost[m_current_k_opt]
306 / m_cost[m_current_k_opt - 1];
311G4bool G4BulirschStoer::in_convergence_window(
G4int k)
const
313 if( (k == m_current_k_opt - 1) && !m_last_step_rejected )
317 return (k == m_current_k_opt) || (k == m_current_k_opt + 1);
323 if(k == m_current_k_opt - 1)
325 const auto d =
G4double(m_interval_sequence[m_current_k_opt]
326 * m_interval_sequence[m_current_k_opt+1]);
327 const auto e =
G4double(m_interval_sequence[0]);
330 return error * e2 * e2 > d * d;
332 if(k == m_current_k_opt)
334 const auto d =
G4double(m_interval_sequence[m_current_k_opt]);
335 const auto e =
G4double(m_interval_sequence[0]);
336 return error * e * e > d * d;
G4BulirschStoer(G4EquationOfMotion *equation, G4int nvar, G4double eps_rel, G4double max_dt=DBL_MAX)
step_result try_step(const G4double in[], const G4double dxdt[], G4double &t, G4double out[], G4double &dt)
void SetSteps(G4int steps)
void DoStep(const G4double yIn[], const G4double dydxIn[], G4double yOut[], G4double hstep) const
G4double relativeError(const G4double y[], const G4double yerr[], G4double hstep, G4double errorTolerance)