Source code for struphy.propagators.push_eta
"Only particle variables are updated."
import logging
from dataclasses import dataclass
from line_profiler import profile
from struphy.io.options import OptionsBase
from struphy.models.variables import PICVariable, SPHVariable
from struphy.ode.utils import ButcherTableau
from struphy.pic.pushing import pusher_kernels
from struphy.pic.pushing.pusher import Pusher
from struphy.propagators.base import Propagator
from struphy.utils.pyccel import Pyccelkernel
logger = logging.getLogger("struphy")
[docs]
class PushEta(Propagator):
r"""For each marker :math:`p`, solves
.. math::
\frac{\textnormal d \mathbf{x}_p(t)}{\textnormal d t} = \mathbf{v}_p\,,
in logical space given by :math:`\mathbf{x} = F(\boldsymbol{\eta})`:
.. math::
\frac{\textnormal d \boldsymbol{\eta}_p(t)}{\textnormal d t} = DF^{-1}(\boldsymbol{\eta}_p(t)) \,\mathbf{v}_p\,,
for constant :math:`\mathbf{v}_p`. Available algorithms:
- Explicit RK from :class:`~struphy.ode.utils.ButcherTableau`
"""
[docs]
class Variables:
"""Container for variables advanced by :class:`PushEta`.
Attributes
----------
var : PICVariable or SPHVariable
Particle variable whose marker positions are advanced.
"""
def __init__(self):
self._var: PICVariable | SPHVariable = None
@property
def var(self) -> PICVariable | SPHVariable:
return self._var
@var.setter
def var(self, new):
assert isinstance(new, PICVariable | SPHVariable)
self._var = new
def __init__(self):
self.variables = self.Variables()
[docs]
@dataclass(repr=False)
class Options(OptionsBase):
"""Configuration options for :class:`PushEta`.
Parameters
----------
butcher : ButcherTableau, default=None
Butcher tableau used for explicit Runge-Kutta marker pushing.
If ``None``, defaults to ``ButcherTableau()``.
"""
butcher: ButcherTableau = None
def __post_init__(self):
# defaults
if self.butcher is None:
self.butcher = ButcherTableau()
@property
def options(self) -> Options:
if not hasattr(self, "_options"):
self._options = self.Options()
return self._options
@options.setter
def options(self, new):
assert isinstance(new, self.Options)
self._options = new
logger.info(f"\nNew options for propagator '{self.__class__.__name__}':\n{self._options}")
@profile
def allocate(self):
# get kernel
kernel = Pyccelkernel(pusher_kernels.push_eta_stage)
# define algorithm
butcher = self.options.butcher
# temp fix due to refactoring of ButcherTableau:
args_kernel = (
butcher.a_stage,
butcher.b,
butcher.c,
)
self._pusher = Pusher(
self.variables.var.particles,
kernel,
args_kernel,
self.domain.args_domain,
alpha_in_kernel=1.0,
n_stages=butcher.n_stages,
mpi_sort="each",
)
@profile
def __call__(self, dt):
self._pusher(dt)
# update_weights
if self.variables.var.particles.control_variate:
self.variables.var.particles.update_weights()