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),
50 m_last_step_rejected(false), m_first(true), m_dt_last(0.0), m_max_dt(max_dt)
54 for(
G4int i = 0; i < m_k_max + 1; ++i)
56 m_interval_sequence[i] = 2 * (i + 1);
59 m_cost[i] = m_interval_sequence[i];
63 m_cost[i] = m_cost[i-1] + m_interval_sequence[i];
65 for(
G4int k = 0; k < i; ++k)
68 /
static_cast<G4double>(m_interval_sequence[k]);
69 m_coeff[i][k] = 1.0 / (r * r - 1.0);
106 for(
G4int k = 0; k <= m_current_k_opt+1; ++k)
110 m_midpoint.
SetSteps(m_interval_sequence[k]);
113 m_midpoint.
DoStep(in, dxdt, out, dt);
118 m_midpoint.
DoStep(in, dxdt, m_table[k-1], dt);
121 for (
G4int i = 0; i < fnvar; ++i)
123 m_err[i] = out[i] - m_table[0][i];
127 h_opt[k] = calc_h_opt(dt, error, k);
128 work[k] =
static_cast<G4double>(m_cost[k]) / h_opt[k];
130 if( (k == m_current_k_opt-1) || m_first)
136 if( (work[k] < KFAC2 * work[k-1]) || (m_current_k_opt <= 2) )
139 m_current_k_opt = std::min(m_k_max - 1 , std::max(2 , k + 1));
141 new_h *=
static_cast<G4double>(m_cost[k + 1])
146 m_current_k_opt = std::min(m_k_max - 1, std::max(2, k));
151 else if(should_reject(error , k) && !m_first)
158 if(k == m_current_k_opt)
164 if(work[k-1] < KFAC2 * work[k])
166 m_current_k_opt = std::max( 2 , m_current_k_opt-1 );
167 new_h = h_opt[m_current_k_opt];
169 else if( (work[k] < KFAC2 * work[k-1]) && !m_last_step_rejected )
171 m_current_k_opt = std::min(m_k_max - 1, m_current_k_opt + 1);
173 new_h *=
static_cast<G4double>(m_cost[m_current_k_opt])
178 new_h = h_opt[m_current_k_opt];
182 else if(should_reject(error, k))
185 new_h = h_opt[m_current_k_opt];
189 if(k == m_current_k_opt + 1)
194 if(work[k-2] < KFAC2 * work[k-1])
196 m_current_k_opt = std::max(2, m_current_k_opt - 1);
198 if((work[k] < KFAC2 * work[m_current_k_opt]) && !m_last_step_rejected)
200 m_current_k_opt = std::min(m_k_max - 1 , k);
202 new_h = h_opt[m_current_k_opt];
207 new_h = h_opt[m_current_k_opt];
219 if(!m_last_step_rejected || new_h < dt)
222 new_h = std::min(m_max_dt, new_h);
227 m_last_step_rejected = reject;
236 m_last_step_rejected =
false;
239void G4BulirschStoer::extrapolate(std::size_t k ,
G4double xest[])
244 for(std::size_t j = k - 1 ; j > 0; --j)
246 for (
G4int i = 0; i < fnvar; ++i)
248 m_table[j-1][i] = m_table[j][i] * (1. + m_coeff[k][j])
249 - m_table[j-1][i] * m_coeff[k][j];
252 for (
G4int i = 0; i < fnvar; ++i)
254 xest[i] = m_table[0][i] * (1. + m_coeff[k][0]) - xest[i] * m_coeff[k][0];
259G4BulirschStoer::calc_h_opt(
G4double h ,
G4double error , std::size_t k)
const
263 const G4double expo = 1.0 / (2 * k + 1);
264 const G4double facmin = std::pow(STEPFAC3, expo);
274 fac = STEPFAC2 * std::pow(error * inv_STEPFAC1 , -expo);
275 fac = std::max(facmin * inv_STEPFAC4, std::min( facminInv, fac));
291 if( (work[k-1] < KFAC1 * work[k]) || (k == m_k_max) )
293 m_current_k_opt = (
G4int)k - 1;
294 dt = h_opt[ m_current_k_opt ];
297 else if( (work[k] < KFAC2 * work[k-1])
298 || m_last_step_rejected || (k == m_k_max-1) )
300 m_current_k_opt = (
G4int)k;
301 dt = h_opt[m_current_k_opt];
305 m_current_k_opt = (
G4int)k + 1;
306 dt = h_opt[m_current_k_opt - 1] * m_cost[m_current_k_opt]
307 / m_cost[m_current_k_opt - 1];
312G4bool G4BulirschStoer::in_convergence_window(
G4int k)
const
314 if( (k == m_current_k_opt - 1) && !m_last_step_rejected )
318 return (k == m_current_k_opt) || (k == m_current_k_opt + 1);
324 if(k == m_current_k_opt - 1)
327 * m_interval_sequence[m_current_k_opt+1]);
331 return error * e2 * e2 > d * d;
333 else if(k == m_current_k_opt)
337 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)