lattice_qcd_rs/integrator/
symplectic_euler_rayon.rs

1//! Basic symplectic Euler integrator using [`Rayon`](https://docs.rs/rayon/1.5.1/rayon/).
2
3use std::vec::Vec;
4
5use na::SVector;
6#[cfg(feature = "serde-serialize")]
7use serde::{Deserialize, Serialize};
8
9use super::{
10    super::{
11        field::{EField, LinkMatrix, Su3Adjoint},
12        lattice::LatticeCyclic,
13        simulation::{
14            LatticeState, LatticeStateWithEField, LatticeStateWithEFieldNew, SimulationStateLeap,
15            SimulationStateSynchronous,
16        },
17        thread::run_pool_parallel_rayon,
18        Real,
19    },
20    integrate_efield, integrate_link, CMatrix3, SymplecticIntegrator,
21};
22
23/// Basic symplectic Euler integrator using Rayon.
24///
25/// It is slightly faster than [`super::SymplecticEuler`] but use slightly more memory.
26/// # Example
27/// ```
28/// # use std::error::Error;
29/// #
30/// # fn main() -> Result<(), Box<dyn Error>> {
31/// use lattice_qcd_rs::integrator::{SymplecticEulerRayon, SymplecticIntegrator};
32/// use lattice_qcd_rs::simulation::{
33///     LatticeStateDefault, LatticeStateEFSyncDefault, LatticeStateWithEField,
34/// };
35/// use rand::SeedableRng;
36///
37/// let mut rng = rand::rngs::StdRng::seed_from_u64(0); // change with your seed
38/// let state1 = LatticeStateEFSyncDefault::new_random_e_state(
39///     LatticeStateDefault::<3>::new_determinist(1_f64, 2_f64, 4, &mut rng)?,
40///     &mut rng,
41/// );
42/// let integrator = SymplecticEulerRayon::default();
43/// let state2 = integrator.integrate_symplectic(&state1, 0.000_001_f64)?;
44/// let h = state1.hamiltonian_total();
45/// let h2 = state2.hamiltonian_total();
46/// println!("The error on the Hamiltonian is {}", h - h2);
47/// #     Ok(())
48/// # }
49/// ```
50#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
51#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
52pub struct SymplecticEulerRayon;
53
54impl SymplecticEulerRayon {
55    /// Create a new SymplecticEulerRayon
56    pub const fn new() -> Self {
57        Self {}
58    }
59
60    /// Get all the integrated links
61    /// # Panics
62    /// panics if the lattice has fewer link than link_matrix has or it has fewer point than e_field has.
63    /// In debug panic if the lattice has not the same number link as link_matrix
64    /// or not the same number of point as e_field.
65    fn link_matrix_integrate<State, const D: usize>(
66        link_matrix: &LinkMatrix,
67        e_field: &EField<D>,
68        lattice: &LatticeCyclic<D>,
69        delta_t: Real,
70    ) -> Vec<CMatrix3>
71    where
72        State: LatticeStateWithEField<D>,
73    {
74        run_pool_parallel_rayon(
75            lattice.get_links(),
76            &(link_matrix, e_field, lattice),
77            |link, (link_matrix, e_field, lattice)| {
78                integrate_link::<State, D>(link, link_matrix, e_field, lattice, delta_t)
79            },
80        )
81    }
82
83    /// Get all the integrated e field
84    /// # Panics
85    /// panics if the lattice has fewer link than link_matrix has or it has fewer point than e_field has.
86    /// In debug panic if the lattice has not the same number link as link_matrix
87    /// or not the same number of point as e_field.
88    fn e_field_integrate<State, const D: usize>(
89        link_matrix: &LinkMatrix,
90        e_field: &EField<D>,
91        lattice: &LatticeCyclic<D>,
92        delta_t: Real,
93    ) -> Vec<SVector<Su3Adjoint, D>>
94    where
95        State: LatticeStateWithEField<D>,
96    {
97        run_pool_parallel_rayon(
98            lattice.get_points(),
99            &(link_matrix, e_field, lattice),
100            |point, (link_matrix, e_field, lattice)| {
101                integrate_efield::<State, D>(point, link_matrix, e_field, lattice, delta_t)
102            },
103        )
104    }
105}
106
107impl Default for SymplecticEulerRayon {
108    /// Identical to [`SymplecticEulerRayon::new`].
109    fn default() -> Self {
110        Self::new()
111    }
112}
113
114impl std::fmt::Display for SymplecticEulerRayon {
115    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
116        write!(f, "Euler integrator using rayon")
117    }
118}
119
120impl<State, const D: usize> SymplecticIntegrator<State, SimulationStateLeap<State, D>, D>
121    for SymplecticEulerRayon
122where
123    State: SimulationStateSynchronous<D> + LatticeStateWithEField<D> + LatticeStateWithEFieldNew<D>,
124{
125    type Error = State::Error;
126
127    fn integrate_sync_sync(&self, l: &State, delta_t: Real) -> Result<State, Self::Error> {
128        let link_matrix = Self::link_matrix_integrate::<State, D>(
129            l.link_matrix(),
130            l.e_field(),
131            l.lattice(),
132            delta_t,
133        );
134        let e_field =
135            Self::e_field_integrate::<State, D>(l.link_matrix(), l.e_field(), l.lattice(), delta_t);
136
137        State::new(
138            l.lattice().clone(),
139            l.beta(),
140            EField::new(e_field),
141            LinkMatrix::new(link_matrix),
142            l.t() + 1,
143        )
144    }
145
146    fn integrate_leap_leap(
147        &self,
148        l: &SimulationStateLeap<State, D>,
149        delta_t: Real,
150    ) -> Result<SimulationStateLeap<State, D>, Self::Error> {
151        let link_matrix = LinkMatrix::new(Self::link_matrix_integrate::<State, D>(
152            l.link_matrix(),
153            l.e_field(),
154            l.lattice(),
155            delta_t,
156        ));
157
158        let e_field = EField::new(Self::e_field_integrate::<State, D>(
159            &link_matrix,
160            l.e_field(),
161            l.lattice(),
162            delta_t,
163        ));
164        SimulationStateLeap::<State, D>::new(
165            l.lattice().clone(),
166            l.beta(),
167            e_field,
168            link_matrix,
169            l.t() + 1,
170        )
171    }
172
173    fn integrate_sync_leap(
174        &self,
175        l: &State,
176        delta_t: Real,
177    ) -> Result<SimulationStateLeap<State, D>, Self::Error> {
178        let e_field = Self::e_field_integrate::<State, D>(
179            l.link_matrix(),
180            l.e_field(),
181            l.lattice(),
182            delta_t / 2_f64,
183        );
184
185        // we do not advance the time counter
186        SimulationStateLeap::<State, D>::new(
187            l.lattice().clone(),
188            l.beta(),
189            EField::new(e_field),
190            l.link_matrix().clone(),
191            l.t(),
192        )
193    }
194
195    fn integrate_leap_sync(
196        &self,
197        l: &SimulationStateLeap<State, D>,
198        delta_t: Real,
199    ) -> Result<State, Self::Error> {
200        let link_matrix = LinkMatrix::new(Self::link_matrix_integrate::<State, D>(
201            l.link_matrix(),
202            l.e_field(),
203            l.lattice(),
204            delta_t,
205        ));
206        // we advance the counter by one
207        let e_field = EField::new(Self::e_field_integrate::<State, D>(
208            &link_matrix,
209            l.e_field(),
210            l.lattice(),
211            delta_t / 2_f64,
212        ));
213        State::new(
214            l.lattice().clone(),
215            l.beta(),
216            e_field,
217            link_matrix,
218            l.t() + 1,
219        )
220    }
221
222    fn integrate_symplectic(&self, l: &State, delta_t: Real) -> Result<State, Self::Error> {
223        // override for optimization.
224        // This remove a clone operation.
225
226        let e_field_half = EField::new(Self::e_field_integrate::<State, D>(
227            l.link_matrix(),
228            l.e_field(),
229            l.lattice(),
230            delta_t / 2_f64,
231        ));
232        let link_matrix = LinkMatrix::new(Self::link_matrix_integrate::<State, D>(
233            l.link_matrix(),
234            &e_field_half,
235            l.lattice(),
236            delta_t,
237        ));
238        let e_field = EField::new(Self::e_field_integrate::<State, D>(
239            &link_matrix,
240            &e_field_half,
241            l.lattice(),
242            delta_t / 2_f64,
243        ));
244
245        State::new(
246            l.lattice().clone(),
247            l.beta(),
248            e_field,
249            link_matrix,
250            l.t() + 1,
251        )
252    }
253}