Particle propagators#

Only particle variables are updated.

class struphy.propagators.propagators_markers.PushEta[source]#

Bases: Propagator

For each marker \(p\), solves

\[\frac{\textnormal d \mathbf x_p(t)}{\textnormal d t} = \mathbf v_p\,,\]

for constant \(\mathbf v_p\) in logical space given by \(\mathbf x = F(\boldsymbol \eta)\):

\[\frac{\textnormal d \boldsymbol \eta_p(t)}{\textnormal d t} = DF^{-1}(\boldsymbol \eta_p(t)) \,\mathbf v_p\,.\]

Available algorithms:

class Variables[source]#

Bases: object

property var: PICVariable | SPHVariable#
class Options(butcher: struphy.ode.utils.ButcherTableau = None)[source]#

Bases: object

butcher: ButcherTableau = None#
allocate()[source]#

Allocate all data/objects of the instance.

class struphy.propagators.propagators_markers.PushVxB[source]#

Bases: Propagator

For each marker \(p\), solves

\[\frac{\textnormal d \mathbf v_p(t)}{\textnormal d t} = \frac{1}{\varepsilon} \, \mathbf v_p(t) \times (\mathbf B + \mathbf B_{\text{add}}) \,,\]

where \(\varepsilon = 1/(\hat\Omega_c \hat t)\) is a constant scaling factor, and for rotation vector \(\mathbf B\) and optional, additional fixed rotation vector \(\mathbf B_{\text{add}}\), both given as a 2-form:

\[\mathbf B = \frac{DF\, \hat{\mathbf B}^2}{\sqrt g}\,.\]

Available algorithms: analytic, implicit.

class Variables[source]#

Bases: object

property ions: PICVariable | SPHVariable#
class Options(algo: Literal['analytic', 'implicit'] = 'analytic', b2_var: struphy.models.variables.FEECVariable = None)[source]#

Bases: object

OptsAlgo#

alias of Literal[‘analytic’, ‘implicit’]

algo: Literal['analytic', 'implicit'] = 'analytic'#
b2_var: FEECVariable = None#
allocate()[source]#

Allocate all data/objects of the instance.

class struphy.propagators.propagators_markers.PushVinEfield[source]#

Bases: Propagator

Push the velocities according to

\[\frac{\text{d} \mathbf{v}_p}{\text{d} t} = \frac{1}{\varepsilon} \, \mathbf{E}(\mathbf{x}_p) \,,\]

where \(\varepsilon \in \mathbb R\) is a constant. In logical coordinates, given by \(\mathbf x = F(\boldsymbol \eta)\):

\[\frac{\text{d} \mathbf{v}_p}{\text{d} t} = \frac{1}{\varepsilon} \, DF^{-\top} \hat{\mathbf E}^1(\boldsymbol \eta_p) \,,\]

which is solved analytically. \(\mathbf E\) can optionally be defined through a potential, \(\mathbf E = - \nabla \phi\).

class Variables[source]#

Bases: object

property var: PICVariable | SPHVariable#
class Options(e_field: struphy.models.variables.FEECVariable | tuple[Callable] = None, phi: struphy.models.variables.FEECVariable | Callable = None)[source]#

Bases: object

e_field: FEECVariable | tuple[Callable] = None#
phi: FEECVariable | Callable = None#
allocate()[source]#

Allocate all data/objects of the instance.

class struphy.propagators.propagators_markers.PushEtaPC[source]#

Bases: Propagator

For each marker \(p\), solves

\[\frac{\textnormal d \mathbf x_p(t)}{\textnormal d t} = \mathbf v_p + \mathbf U (\mathbf x_p(t))\,,\]

for constant \(\mathbf v_p\) and \(\mathbf U\) in logical space given by \(\mathbf x = F(\boldsymbol \eta)\):

\[\frac{\textnormal d \boldsymbol \eta_p(t)}{\textnormal d t} = DF^{-1}(\boldsymbol \eta_p(t)) \,\mathbf v_p + \textnormal{vec}(\hat{\mathbf U}) \,,\]

where

\[\textnormal{vec}( \hat{\mathbf U}^{1}) = G^{-1}\hat{\mathbf U}^{1}\,,\qquad \textnormal{vec}( \hat{\mathbf U}^{2}) = \frac{\hat{\mathbf U}^{2}}{\sqrt g}\,, \qquad \textnormal{vec}( \hat{\mathbf U}) = \hat{\mathbf U}\,.\]

Available algorithms:

  • rk4 (4th order, default)

  • forward_euler (1st order)

  • heun2 (2nd order)

  • rk2 (2nd order)

  • heun3 (3rd order)

class Variables[source]#

Bases: object

property var: PICVariable | SPHVariable#
class Options(butcher: struphy.ode.utils.ButcherTableau = None, use_perp_model: bool = True, u_tilde: struphy.models.variables.FEECVariable = None, u_space: Literal['Hcurl', 'Hdiv', 'H1vec'] = 'Hdiv')[source]#

Bases: object

butcher: ButcherTableau = None#
use_perp_model: bool = True#
u_tilde: FEECVariable = None#
u_space: Literal['Hcurl', 'Hdiv', 'H1vec'] = 'Hdiv'#
allocate()[source]#

Allocate all data/objects of the instance.

class struphy.propagators.propagators_markers.PushGuidingCenterBxEstar[source]#

Bases: Propagator

For each marker \(p\), solves

\[\frac{\textnormal d \mathbf X_p(t)}{\textnormal d t} = \frac{\mathbf E^* \times \mathbf b_0}{B_\parallel^*} (\mathbf X_p(t)) \,,\]

where

\[\mathbf E^* = -\nabla \phi - \varepsilon \mu_p \nabla |\mathbf B|\,,\qquad \mathbf B^* = \mathbf B + \varepsilon v_\parallel \nabla \times \mathbf b_0\,,\qquad B^*_\parallel = \mathbf B^* \cdot \mathbf b_0\,,\]

where \(\mathbf B = \mathbf B_0 + \tilde{\mathbf B}\) can be the full magnetic field (equilibrium + perturbation). The electric potential phi and/or the magnetic perturbation b_tilde can be ignored by passing None. In logical space this is given by \(\mathbf X = F(\boldsymbol \eta)\):

\[\frac{\textnormal d \boldsymbol \eta_p(t)}{\textnormal d t} = \frac{\hat{\mathbf E}^{*1} \times \hat{\mathbf b}^1_0}{\sqrt g\,\hat B_\parallel^{*}} (\boldsymbol \eta_p(t)) \,.\]

Available algorithms:

class Variables[source]#

Bases: object

property ions: PICVariable#
class Options(phi: struphy.models.variables.FEECVariable = None, evaluate_e_field: bool = False, b_tilde: struphy.models.variables.FEECVariable = None, algo: Literal['discrete_gradient_2nd_order', 'discrete_gradient_1st_order', 'discrete_gradient_1st_order_newton', 'explicit'] = 'discrete_gradient_1st_order', butcher: struphy.ode.utils.ButcherTableau = None, maxiter: int = 20, tol: float = 1e-07, mpi_sort: Literal['each', 'last', None] = 'each', verbose: bool = False)[source]#

Bases: object

OptsAlgo#

alias of Literal[‘discrete_gradient_2nd_order’, ‘discrete_gradient_1st_order’, ‘discrete_gradient_1st_order_newton’, ‘explicit’]

phi: FEECVariable = None#
evaluate_e_field: bool = False#
b_tilde: FEECVariable = None#
algo: Literal['discrete_gradient_2nd_order', 'discrete_gradient_1st_order', 'discrete_gradient_1st_order_newton', 'explicit'] = 'discrete_gradient_1st_order'#
butcher: ButcherTableau = None#
maxiter: int = 20#
tol: float = 1e-07#
mpi_sort: Literal['each', 'last', None] = 'each'#
verbose: bool = False#
allocate()[source]#

Allocate all data/objects of the instance.

class struphy.propagators.propagators_markers.PushGuidingCenterParallel[source]#

Bases: Propagator

For each marker \(p\), solves

\[\begin{split}\left\{ \begin{aligned} \frac{\textnormal d \mathbf X_p(t)}{\textnormal d t} &= v_{\parallel,p}(t) \frac{\mathbf B^*}{B^*_\parallel}(\mathbf X_p(t)) \,, \\ \frac{\textnormal d v_{\parallel,p}(t)}{\textnormal d t} &= \frac{1}{\varepsilon} \frac{\mathbf B^*}{B^*_\parallel} \cdot \mathbf E^* (\mathbf X_p(t)) \,, \end{aligned} \right.\end{split}\]

where

\[\mathbf E^* = -\nabla \phi - \varepsilon \mu_p \nabla |\mathbf B|\,,\qquad \mathbf B^* = \mathbf B + \varepsilon v_\parallel \nabla \times \mathbf b_0\,,\qquad B^*_\parallel = \mathbf B^* \cdot \mathbf b_0\,,\]

where \(\mathbf B = \mathbf B_0 + \tilde{\mathbf B}\) can be the full magnetic field (equilibrium + perturbation). The electric potential phi and/or the magnetic perturbation b_tilde can be ignored by passing None. In logical space this is given by \(\mathbf X = F(\boldsymbol \eta)\):

\[\begin{split}\left\{ \begin{aligned} \frac{\textnormal d \boldsymbol \eta_p(t)}{\textnormal d t} &= v_{\parallel,p}(t) \frac{\hat{\mathbf B}^{*2}}{\hat B^{*3}_\parallel}(\boldsymbol \eta_p(t)) \,, \\ \frac{\textnormal d v_{\parallel,p}(t)}{\textnormal d t} &= \frac{1}{\varepsilon} \frac{\hat{\mathbf B}^{*2}}{\hat B^{*3}_\parallel} \cdot \hat{\mathbf E}^{*1} (\boldsymbol \eta_p(t)) \,. \end{aligned} \right.\end{split}\]

Available algorithms:

class Variables[source]#

Bases: object

property ions: PICVariable#
class Options(phi: struphy.models.variables.FEECVariable = None, evaluate_e_field: bool = False, b_tilde: struphy.models.variables.FEECVariable = None, algo: Literal['discrete_gradient_2nd_order', 'discrete_gradient_1st_order', 'discrete_gradient_1st_order_newton', 'explicit'] = 'discrete_gradient_1st_order', butcher: struphy.ode.utils.ButcherTableau = None, maxiter: int = 20, tol: float = 1e-07, mpi_sort: Literal['each', 'last', None] = 'each', verbose: bool = False)[source]#

Bases: object

OptsAlgo#

alias of Literal[‘discrete_gradient_2nd_order’, ‘discrete_gradient_1st_order’, ‘discrete_gradient_1st_order_newton’, ‘explicit’]

phi: FEECVariable = None#
evaluate_e_field: bool = False#
b_tilde: FEECVariable = None#
algo: Literal['discrete_gradient_2nd_order', 'discrete_gradient_1st_order', 'discrete_gradient_1st_order_newton', 'explicit'] = 'discrete_gradient_1st_order'#
butcher: ButcherTableau = None#
maxiter: int = 20#
tol: float = 1e-07#
mpi_sort: Literal['each', 'last', None] = 'each'#
verbose: bool = False#
allocate()[source]#

Allocate all data/objects of the instance.

class struphy.propagators.propagators_markers.PushDeterministicDiffusion[source]#

Bases: Propagator

For each marker \(p\), solves

\[\frac{\textnormal d \mathbf x_p(t)}{\textnormal d t} = - D \, \frac{\nabla u}{ u}\mathbf (\mathbf x_p(t))\,,\]

in logical space given by \(\mathbf x = F(\boldsymbol \eta)\):

\[\frac{\textnormal d \boldsymbol \eta_p(t)}{\textnormal d t} = - G\, D \, \frac{\nabla \Pi^0_{L^2}u_h}{\Pi^0_{L^2} u_h}\mathbf (\boldsymbol \eta_p(t))\,, \qquad [\Pi^0_{L^2, ijk} u_h](\boldsymbol \eta_p) = \frac 1N \sum_{p} w_p \boldsymbol \Lambda^0_{ijk}(\boldsymbol \eta_p)\,,\]

where \(D>0\) is a positive diffusion coefficient.

Available algorithms:

class Variables[source]#

Bases: object

property var: PICVariable#
class Options(butcher: struphy.ode.utils.ButcherTableau = None, bc_type: tuple = ('periodic', 'periodic', 'periodic'), diff_coeff: float = 1.0)[source]#

Bases: object

butcher: ButcherTableau = None#
bc_type: tuple = ('periodic', 'periodic', 'periodic')#
diff_coeff: float = 1.0#
allocate()[source]#

Allocate all data/objects of the instance.

class struphy.propagators.propagators_markers.PushRandomDiffusion[source]#

Bases: Propagator

For each marker \(p\), solves

\[\textnormal d \mathbf x_p(t) = \sqrt{2 D} \, \textnormal d \mathbf B_{t}\,,\]

where \(D>0\) is a positive diffusion coefficient and \(\textnormal d \mathbf B_{t}\) is a Wiener process,

\[\mathbf B_{t + \Delta t} - \mathbf B_{t} = \sqrt{\Delta t} \,\mathcal N(0;1)\,,\]

with \(\mathcal N(0;1)\) denoting the standard normal distribution with mean zero and variance one.

Available algorithms:

  • forward_euler (1st order)

class Variables[source]#

Bases: object

property var: PICVariable#
class Options(butcher: struphy.ode.utils.ButcherTableau = None, bc_type: tuple = ('periodic', 'periodic', 'periodic'), diff_coeff: float = 1.0)[source]#

Bases: object

butcher: ButcherTableau = None#
bc_type: tuple = ('periodic', 'periodic', 'periodic')#
diff_coeff: float = 1.0#
allocate()[source]#

Allocate all data/objects of the instance.

class struphy.propagators.propagators_markers.PushVinSPHpressure[source]#

Bases: Propagator

For each marker \(p\), solves

\[\frac{\textnormal d \mathbf v_p(t)}{\textnormal d t} = \kappa_p \sum_{i=1}^N w_i \left( \frac{1}{\rho^{N,h}(\boldsymbol \eta_p)} + \frac{1}{\rho^{N,h}(\boldsymbol \eta_i)} \right) DF^{-\top}\nabla W_h(\boldsymbol \eta_p - \boldsymbol \eta_i) \,,\]

where \(DF^{-\top}\) denotes the inverse transpose Jacobian, and with the smoothed density

\[\rho^{N,h}(\boldsymbol \eta) = \frac 1N \sum_{j=1}^N w_j \, W_h(\boldsymbol \eta - \boldsymbol \eta_j)\,,\]

where \(W_h(\boldsymbol \eta)\) is a smoothing kernel from sph_smoothing_kernels. Time stepping:

class Variables[source]#

Bases: object

property fluid: SPHVariable#
class Options(kernel_type: Literal['trigonometric_1d', 'gaussian_1d', 'linear_1d', 'trigonometric_2d', 'gaussian_2d', 'linear_2d', 'trigonometric_3d', 'gaussian_3d', 'linear_isotropic_3d', 'linear_3d'] = 'gaussian_2d', kernel_width: tuple = None, algo: Literal['forward_euler'] = 'forward_euler', gravity: tuple = (0.0, 0.0, 0.0), thermodynamics: Literal['isothermal', 'polytropic'] = 'isothermal')[source]#

Bases: object

OptsAlgo#

alias of Literal[‘forward_euler’]

OptsThermo#

alias of Literal[‘isothermal’, ‘polytropic’]

kernel_type: Literal['trigonometric_1d', 'gaussian_1d', 'linear_1d', 'trigonometric_2d', 'gaussian_2d', 'linear_2d', 'trigonometric_3d', 'gaussian_3d', 'linear_isotropic_3d', 'linear_3d'] = 'gaussian_2d'#
kernel_width: tuple = None#
algo: Literal['forward_euler'] = 'forward_euler'#
gravity: tuple = (0.0, 0.0, 0.0)#
thermodynamics: Literal['isothermal', 'polytropic'] = 'isothermal'#
allocate()[source]#

Allocate all data/objects of the instance.

class struphy.propagators.propagators_markers.PushVinViscousPotential2D(particles: ParticlesSPH, *, kernel_type: str = 'gaussian_2d', kernel_width: tuple | None = None, algo: str = 'forward_euler')[source]#

Bases: Propagator

For each marker \(p\), solves

\[\frac{\textnormal d \mathbf v_p(t)}{\textnormal d t} = \kappa_p \sum_{i=1}^N w_i \left( \frac{1}{\rho^{N,h}(\boldsymbol \eta_p)} + \frac{1}{\rho^{N,h}(\boldsymbol \eta_i)} \right) DF^{-\top}\nabla W_h(\boldsymbol \eta_p - \boldsymbol \eta_i) \,,\]

where \(DF^{-\top}\) denotes the inverse transpose Jacobian, and with the smoothed density

\[\rho^{N,h}(\boldsymbol \eta) = \frac 1N \sum_{j=1}^N w_j \, W_h(\boldsymbol \eta - \boldsymbol \eta_j)\,,\]

where \(W_h(\boldsymbol \eta)\) is a smoothing kernel from sph_smoothing_kernels. Time stepping:

class struphy.propagators.propagators_markers.PushVinViscousPotential3D(particles: ParticlesSPH, *, kernel_type: str = 'gaussian_3d', kernel_width: tuple | None = None, algo: str = 'forward_euler')[source]#

Bases: Propagator

For each marker \(p\), solves

\[\frac{\textnormal d \mathbf v_p(t)}{\textnormal d t} = \kappa_p \sum_{i=1}^N w_i \left( \frac{1}{\rho^{N,h}(\boldsymbol \eta_p)} + \frac{1}{\rho^{N,h}(\boldsymbol \eta_i)} \right) DF^{-\top}\nabla W_h(\boldsymbol \eta_p - \boldsymbol \eta_i) \,,\]

where \(DF^{-\top}\) denotes the inverse transpose Jacobian, and with the smoothed density

\[\rho^{N,h}(\boldsymbol \eta) = \frac 1N \sum_{j=1}^N w_j \, W_h(\boldsymbol \eta - \boldsymbol \eta_j)\,,\]

where \(W_h(\boldsymbol \eta)\) is a smoothing kernel from sph_smoothing_kernels. Time stepping: