1use std::sync::Arc;
17
18use super::super::{
19 advecator::Advector,
20 integrator::{StepProducts, StepTimings, TimeIntegrator},
21 phasespace::PhaseSpaceRepr,
22 progress::{StepPhase, StepProgress},
23 solver::PoissonSolver,
24 types::*,
25};
26use super::helpers;
27use crate::CausticError;
28
29const S1: f64 = 1.1746881100325735;
31const S2: f64 = -1.349_376_220_065_147;
33
34const YOSHIDA_W1: f64 = 1.3512071919596578;
36const YOSHIDA_W0: f64 = -1.7024143839193153;
38
39pub struct Rkn6Splitting {
45 pub g: f64,
47 last_timings: StepTimings,
49 progress: Option<Arc<StepProgress>>,
51}
52
53impl Rkn6Splitting {
54 pub fn new(g: f64) -> Self {
56 Self {
57 g,
58 last_timings: StepTimings::default(),
59 progress: None,
60 }
61 }
62
63 #[inline]
65 fn rkn6_drift(
66 repr: &mut dyn PhaseSpaceRepr,
67 advector: &dyn Advector,
68 coeff: f64,
69 timings: &mut StepTimings,
70 progress: &Option<Arc<StepProgress>>,
71 phase: StepPhase,
72 sub: u8,
73 ) {
74 helpers::report_phase!(progress, phase, sub, 19);
75 let _s = tracing::info_span!("rkn6_drift").entered();
76 helpers::time_ms!(timings, drift_ms, advector.drift(repr, coeff));
77 }
78
79 #[inline]
81 #[allow(clippy::too_many_arguments)]
82 fn rkn6_kick(
83 g: f64,
84 repr: &mut dyn PhaseSpaceRepr,
85 solver: &dyn PoissonSolver,
86 advector: &dyn Advector,
87 coeff: f64,
88 timings: &mut StepTimings,
89 progress: &Option<Arc<StepProgress>>,
90 sub: u8,
91 ) {
92 helpers::report_phase!(progress, StepPhase::Kick, sub, 19);
93 let _s = tracing::info_span!("rkn6_kick").entered();
94 let (_density, _potential, accel) =
95 helpers::time_ms!(timings, poisson_ms, helpers::solve_poisson(repr, solver, g));
96 helpers::time_ms!(timings, kick_ms, advector.kick(repr, &accel, coeff));
97 }
98
99 #[allow(clippy::too_many_arguments)]
103 fn yoshida_step(
104 &self,
105 repr: &mut dyn PhaseSpaceRepr,
106 solver: &dyn PoissonSolver,
107 advector: &dyn Advector,
108 dt: f64,
109 timings: &mut StepTimings,
110 progress: &Option<Arc<StepProgress>>,
111 base_sub: u8,
112 total_sub: u8,
113 ) {
114 helpers::report_phase!(progress, StepPhase::DriftHalf1, base_sub, total_sub);
116 {
117 let _s = tracing::info_span!("rkn6_drift").entered();
118 helpers::time_ms!(
119 timings,
120 drift_ms,
121 advector.drift(repr, YOSHIDA_W1 * dt / 2.0)
122 );
123 }
124
125 helpers::report_phase!(progress, StepPhase::Kick, base_sub + 1, total_sub);
127 {
128 let _s = tracing::info_span!("rkn6_kick").entered();
129 let (_density, _potential, accel) = helpers::time_ms!(
130 timings,
131 poisson_ms,
132 helpers::solve_poisson(repr, solver, self.g)
133 );
134 helpers::time_ms!(
135 timings,
136 kick_ms,
137 advector.kick(repr, &accel, YOSHIDA_W1 * dt)
138 );
139 }
140
141 helpers::report_phase!(progress, StepPhase::DriftHalf2, base_sub + 2, total_sub);
143 {
144 let _s = tracing::info_span!("rkn6_drift").entered();
145 helpers::time_ms!(
146 timings,
147 drift_ms,
148 advector.drift(repr, (YOSHIDA_W1 + YOSHIDA_W0) * dt / 2.0)
149 );
150 }
151
152 helpers::report_phase!(progress, StepPhase::Kick, base_sub + 3, total_sub);
154 {
155 let _s = tracing::info_span!("rkn6_kick").entered();
156 let (_density, _potential, accel) = helpers::time_ms!(
157 timings,
158 poisson_ms,
159 helpers::solve_poisson(repr, solver, self.g)
160 );
161 helpers::time_ms!(
162 timings,
163 kick_ms,
164 advector.kick(repr, &accel, YOSHIDA_W0 * dt)
165 );
166 }
167
168 helpers::report_phase!(progress, StepPhase::DriftHalf1, base_sub + 4, total_sub);
170 {
171 let _s = tracing::info_span!("rkn6_drift").entered();
172 helpers::time_ms!(
173 timings,
174 drift_ms,
175 advector.drift(repr, (YOSHIDA_W0 + YOSHIDA_W1) * dt / 2.0)
176 );
177 }
178
179 helpers::report_phase!(progress, StepPhase::Kick, base_sub + 5, total_sub);
181 {
182 let _s = tracing::info_span!("rkn6_kick").entered();
183 let (_density, _potential, accel) = helpers::time_ms!(
184 timings,
185 poisson_ms,
186 helpers::solve_poisson(repr, solver, self.g)
187 );
188 helpers::time_ms!(
189 timings,
190 kick_ms,
191 advector.kick(repr, &accel, YOSHIDA_W1 * dt)
192 );
193 }
194
195 helpers::report_phase!(progress, StepPhase::DriftHalf2, base_sub + 6, total_sub);
197 {
198 let _s = tracing::info_span!("rkn6_drift").entered();
199 helpers::time_ms!(
200 timings,
201 drift_ms,
202 advector.drift(repr, YOSHIDA_W1 * dt / 2.0)
203 );
204 }
205 }
206}
207
208impl TimeIntegrator for Rkn6Splitting {
209 fn advance(
210 &mut self,
211 repr: &mut dyn PhaseSpaceRepr,
212 solver: &dyn PoissonSolver,
213 advector: &dyn Advector,
214 dt: f64,
215 ) -> Result<StepProducts, CausticError> {
216 let _span = tracing::info_span!("rkn6_advance").entered();
217 let mut timings = StepTimings::default();
218 let g = self.g;
219 let progress = self.progress.clone();
220
221 if let Some(ref p) = progress {
222 p.start_step();
223 }
224
225 let s1dt = S1 * dt;
232 let s2dt = S2 * dt;
233
234 let d_half_w1_s1 = YOSHIDA_W1 * s1dt / 2.0;
236 let d_half_w01_s1 = (YOSHIDA_W1 + YOSHIDA_W0) * s1dt / 2.0;
237 let d_half_w01_s2 = (YOSHIDA_W1 + YOSHIDA_W0) * s2dt / 2.0;
238 let d_seam = YOSHIDA_W1 * (S1 + S2) * dt / 2.0;
240
241 let k_w1_s1 = YOSHIDA_W1 * s1dt;
243 let k_w0_s1 = YOSHIDA_W0 * s1dt;
244 let k_w1_s2 = YOSHIDA_W1 * s2dt;
245 let k_w0_s2 = YOSHIDA_W0 * s2dt;
246
247 Self::rkn6_drift(
249 repr,
250 advector,
251 d_half_w1_s1,
252 &mut timings,
253 &progress,
254 StepPhase::DriftHalf1,
255 0,
256 );
257 Self::rkn6_kick(
258 g,
259 repr,
260 solver,
261 advector,
262 k_w1_s1,
263 &mut timings,
264 &progress,
265 1,
266 );
267 Self::rkn6_drift(
268 repr,
269 advector,
270 d_half_w01_s1,
271 &mut timings,
272 &progress,
273 StepPhase::DriftHalf2,
274 2,
275 );
276 Self::rkn6_kick(
277 g,
278 repr,
279 solver,
280 advector,
281 k_w0_s1,
282 &mut timings,
283 &progress,
284 3,
285 );
286 Self::rkn6_drift(
287 repr,
288 advector,
289 d_half_w01_s1,
290 &mut timings,
291 &progress,
292 StepPhase::DriftHalf1,
293 4,
294 );
295 Self::rkn6_kick(
296 g,
297 repr,
298 solver,
299 advector,
300 k_w1_s1,
301 &mut timings,
302 &progress,
303 5,
304 );
305
306 Self::rkn6_drift(
308 repr,
309 advector,
310 d_seam,
311 &mut timings,
312 &progress,
313 StepPhase::DriftHalf2,
314 6,
315 );
316
317 Self::rkn6_kick(
319 g,
320 repr,
321 solver,
322 advector,
323 k_w1_s2,
324 &mut timings,
325 &progress,
326 7,
327 );
328 Self::rkn6_drift(
329 repr,
330 advector,
331 d_half_w01_s2,
332 &mut timings,
333 &progress,
334 StepPhase::DriftHalf1,
335 8,
336 );
337 Self::rkn6_kick(
338 g,
339 repr,
340 solver,
341 advector,
342 k_w0_s2,
343 &mut timings,
344 &progress,
345 9,
346 );
347 Self::rkn6_drift(
348 repr,
349 advector,
350 d_half_w01_s2,
351 &mut timings,
352 &progress,
353 StepPhase::DriftHalf2,
354 10,
355 );
356 Self::rkn6_kick(
357 g,
358 repr,
359 solver,
360 advector,
361 k_w1_s2,
362 &mut timings,
363 &progress,
364 11,
365 );
366
367 Self::rkn6_drift(
369 repr,
370 advector,
371 d_seam,
372 &mut timings,
373 &progress,
374 StepPhase::DriftHalf1,
375 12,
376 );
377
378 Self::rkn6_kick(
380 g,
381 repr,
382 solver,
383 advector,
384 k_w1_s1,
385 &mut timings,
386 &progress,
387 13,
388 );
389 Self::rkn6_drift(
390 repr,
391 advector,
392 d_half_w01_s1,
393 &mut timings,
394 &progress,
395 StepPhase::DriftHalf2,
396 14,
397 );
398 Self::rkn6_kick(
399 g,
400 repr,
401 solver,
402 advector,
403 k_w0_s1,
404 &mut timings,
405 &progress,
406 15,
407 );
408 Self::rkn6_drift(
409 repr,
410 advector,
411 d_half_w01_s1,
412 &mut timings,
413 &progress,
414 StepPhase::DriftHalf1,
415 16,
416 );
417 Self::rkn6_kick(
418 g,
419 repr,
420 solver,
421 advector,
422 k_w1_s1,
423 &mut timings,
424 &progress,
425 17,
426 );
427 Self::rkn6_drift(
428 repr,
429 advector,
430 d_half_w1_s1,
431 &mut timings,
432 &progress,
433 StepPhase::DriftHalf2,
434 18,
435 );
436
437 helpers::report_phase!(progress, StepPhase::StepComplete, 19, 19);
438
439 let (density, potential, acceleration) = helpers::time_ms!(
441 timings,
442 density_ms,
443 helpers::solve_poisson(repr, solver, self.g)
444 );
445
446 self.last_timings = timings;
447
448 Ok(StepProducts {
449 density,
450 potential,
451 acceleration,
452 })
453 }
454
455 fn max_dt(&self, repr: &dyn PhaseSpaceRepr, cfl_factor: f64) -> f64 {
456 helpers::dynamical_timestep(repr, self.g, cfl_factor)
457 }
458
459 fn last_step_timings(&self) -> Option<&StepTimings> {
460 Some(&self.last_timings)
461 }
462
463 fn set_progress(&mut self, progress: Arc<StepProgress>) {
464 self.progress = Some(progress);
465 }
466}