Gyrokinetic Guiding Centre Dynamics in 4D
GyroKinetics4d integrates the characteristics of the gyrokinetic Vlasov equation with a volume-preserving splitting method, rather than with the symplectic or variational methods used by the other models in this package.
It follows the notes A volume preserving particle pusher for gyrokinetic PIC codes.
The characteristics
With gyrocentre phasespace variables $Z = (R, V_{\parallel}, \mu, \theta)$, the single-particle Lagrangian of a species of mass $m$ and charge $q$ is
\[L (Z, \dot{Z}) = q \, A^{\star} \cdot \dot{R} + \frac{m}{q} \, \mu \, \dot{\theta} - H ,\]
with the generalised vector potential and its curl
\[A^{\star} (R, V_{\parallel}) = A_{0} + \frac{m V_{\parallel}}{q} \, b_{0} , \qquad B^{\star} = \nabla \times A^{\star} , \qquad B^{\star}_{\parallel} = b_{0} \cdot B^{\star} .\]
$\theta$ is ignorable and $\mu$ invariant, so the dynamics reduces to the four variables $(R, V_{\parallel})$. The Euler-Lagrange equations give
\[\begin{aligned} \dfrac{dR}{dt} &= \dfrac{1}{B^{\star}_{\parallel}} \bigg[ \dfrac{1}{m} \dfrac{\partial H}{\partial V_{\parallel}} B^{\star} - \dfrac{1}{q} \nabla H \times b_{0} \bigg] , \\ \dfrac{dV_{\parallel}}{dt} &= - \dfrac{1}{B^{\star}_{\parallel}} \, \dfrac{1}{m} \, \nabla H \cdot B^{\star} . \end{aligned}\]
This is the same system the 4D guiding centre model integrates.
Rescaled time
The phasespace volume element is $dZ = B^{\star}_{\parallel} \, dR \, dV_{\parallel} \, d\mu \, d\theta$, so it is $B^{\star}_{\parallel} f$ rather than $f$ that is transported in the flat measure. Introducing $\tilde{f} = B^{\star}_{\parallel} f$ clears the denominator above and leaves
\[\begin{aligned} \dfrac{dR}{ds} &= \dfrac{1}{m} \dfrac{\partial H}{\partial V_{\parallel}} B^{\star} - \dfrac{1}{q} \nabla H \times b_{0} , & \dfrac{dV_{\parallel}}{ds} &= - \dfrac{1}{m} \nabla H \cdot B^{\star} , \end{aligned}\]
which is what this module integrates.
The right-hand side is the guiding centre vector field multiplied by $B^{\star}_{\parallel}$, so the independent variable $s$ is related to the physical time by
\[dt = B^{\star}_{\parallel} \, ds .\]
For the supplied ITER-like equilibrium $B^{\star}_{\parallel} \approx 2 \times 10^{2}$, so one unit of $s$ is some two hundred units of physical time and the default time step is scaled to match. A step chosen for the 4D guiding centre model would be a factor of $B^{\star}_{\parallel}$ too large here.
Because $B^{\star}_{\parallel}$ depends on $(R, V_{\parallel})$, the relation between $s$ and $t$ is not linear along an orbit; recovering the physical time requires integrating $dt/ds = B^{\star}_{\parallel}$ alongside. The orbits are unaffected, which is all a PIC pusher needs.
The expressions above are written in the flat measure of a cartesian chart, where the phasespace Jacobian is $B^{\star}_{\parallel}$. In a general chart it is the Liouville density $\sqrt{\det \Omega} = J \, B^{\star}_{\parallel}$, which is what ωabs computes and what the implemented $dt = \omega_{abs} \, ds$ uses. Its magnitude is therefore chart-dependent — the three charts of the small tokamak give 0.9511, 0.9986 and 0.0499 for a common B*∥ = 0.9511 — while its sign is not: it is a measure density and positive in every chart. Getting that sign wrong reverses the orbit, which is what happened before each module applied its chart's orientation(); see Findings and ωabs.
The point of the rescaling is that the new right-hand side is divergence-free,
\[\nabla \cdot \bigg( B^{\star}_{\parallel} \dfrac{dR}{dt} \bigg) + \dfrac{\partial}{\partial V_{\parallel}} \bigg( B^{\star}_{\parallel} \dfrac{dV_{\parallel}}{dt} \bigg) = 0 ,\]
so its flow preserves phasespace volume, and a suitable discretisation can preserve it exactly.
Potentials and splitting
Defining the two vector potentials
\[\beta = \frac{1}{m} \frac{\partial H}{\partial V_{\parallel}} A^{\star} , \qquad \gamma = \frac{1}{m} A^{\star} \times \nabla H ,\]
the equations of motion take the manifestly divergence-free form
\[\begin{aligned} \dfrac{dR}{ds} &= \dfrac{\partial \gamma}{\partial V_{\parallel}} + \nabla \times \beta , & \dfrac{dV_{\parallel}}{ds} &= - \nabla \cdot \gamma . \end{aligned}\]
For the equilibrium Hamiltonian $H_{0} = \tfrac{1}{2} m V_{\parallel}^{2} + \mu B_{0}$, which is what is implemented here, these reduce to
\[\beta_{0} = V_{\parallel} A^{\star} , \qquad \gamma_{0} = \frac{\mu}{m} A^{\star} \times \nabla B_{0} .\]
This form splits into six subsystems,
\[\begin{aligned} \dot{R}_{1} &= + \partial_{2} \beta_{3} , & \dot{R}_{1} &= - \partial_{3} \beta_{2} , & \dot{R}_{2} &= + \partial_{3} \beta_{1} , \\ \dot{R}_{2} &= - \partial_{1} \beta_{3} , & \dot{R}_{3} &= + \partial_{1} \beta_{2} , & \dot{R}_{3} &= - \partial_{2} \beta_{1} , \end{aligned}\]
\[\begin{aligned} \dot{R}_{i} &= + \partial_{V_{\parallel}} \gamma_{i} , & \dot{V}_{\parallel} &= - \partial_{i} \gamma_{i} , & i &= 1, 2, 3 , \end{aligned}\]
each freezing two of the four variables and symplectic in the remaining two. Applying a symplectic integrator to each subsystem preserves the volume of that subsystem exactly, so any composition of them is volume preserving; a symmetric composition of second-order methods gives a second-order volume-preserving scheme.
The full field is odeproblem, the splitting sodeproblem.
Noncanonical Hamiltonian structure
The same equations can be written as $\dot{z} = \mathcal{J}(z) \nabla H$ with the Poisson matrix
\[\mathcal{J} = \begin{pmatrix} 0 & - b_{3}/q & + b_{2}/q & + B^{\star}_{1}/m \\ + b_{3}/q & 0 & - b_{1}/q & + B^{\star}_{2}/m \\ - b_{2}/q & + b_{1}/q & 0 & + B^{\star}_{3}/m \\ - B^{\star}_{1}/m & - B^{\star}_{2}/m & - B^{\star}_{3}/m & 0 \end{pmatrix} ,\]
where $\mathcal{J} / B^{\star}_{\parallel}$ is the inverse of the symplectic matrix of the guiding centre model. This structure is not used by the integrators here — it is the volume-preserving splitting above that the module implements — but ω provides the corresponding two-form.
Usage
using GeometricIntegrators
using ChargedParticleDynamics.GyroKinetics4d.GuidingCenter4dSolovevIterXpoint
# volume-preserving Strang composition of the six subsystems
problem = sodeproblem(initial_conditions_deeply_passing())
solution = integrate(problem, Composition(Tuple(Gauss(1) for _ in 1:6), Strang()))
# or the full vector field
problem = odeproblem(initial_conditions_deeply_passing())
solution = integrate(problem, Gauss(2))Status
The vector field is verified against the 4D guiding centre model: the two agree to machine precision after multiplication by $B^{\star}_{\parallel}$, the six subsystems sum exactly to the full field, and the Strang composition holds the determinant of the one-step map at $1$ for every step size tested, while a first-order method's volume error grows linearly with the step.
Two limitations are worth recording:
- Only the equilibrium Hamiltonian $H_{0}$ is implemented. The notes also give the zero Larmor radius Hamiltonian, with the $\phi$, $A_{\parallel}$ and $\langle \tilde{A}_{\parallel} \rangle^{2}$ terms; those are absent here, as they are from the 4D guiding centre model (see the Model Audit).
- Only the ITER-like Solov'ev equilibrium with X-point is provided, where the other model families cover a dozen equilibria each.
The coordinate transformation of coordinate_transformations.jl is not applied by the problem constructors, and is retained only as a utility: it is a preconditioner for the nonlinear solver rather than a change of variables in the model, so it belongs inside an integrator. No such integrator exists yet; see TODO.md in the repository root for the design.
Equilibria
ChargedParticleDynamics.GyroKinetics4d — Module
The characteristics of the gyrokinetic Vlasov equation, in the rescaled time of the volume-preserving formulation with $dt = B^{\star}_{\parallel} \, ds$.
The same physics as GuidingCenter4d, written so that the right-hand side is divergence-free and admits an exactly volume-preserving splitting. See the Gyrokinetic Guiding Centre Dynamics in 4D page.
Each equilibrium is its own module, and each one includes the same gc_common.jl, gc_equations.jl and coordinate_transformations.jl, so the model's functions below are documented once, under GuidingCenter4dTokamakSmallCylindrical, and hold verbatim for all eight. What differs between them is the chart, the equilibrium parameters and the rescaled default time step, which is what these docstrings record:
ChargedParticleDynamics.GyroKinetics4d.GuidingCenter4dTokamakSmallCartesian — Module
Small axisymmetric tokamak equilibrium, in cartesian coordinates.
The gyrokinetic counterpart of GuidingCenter4d.TokamakSmallCartesian, sharing its initial conditions. The independent variable is the rescaled time $s$, with $dt = B^{\star}_{\parallel} \, ds$; here $B^{\star}_{\parallel} \approx 0.95$ at the deeply passing initial condition, so the rescaling is close to a no-op and the defaults nearly match the 4D guiding centre's.
ChargedParticleDynamics.GyroKinetics4d.GuidingCenter4dTokamakSmallToroidal — Module
Small axisymmetric tokamak equilibrium, in toroidal coordinates $(r, \theta, \varphi)$.
The gyrokinetic counterpart of GuidingCenter4d.TokamakSmallToroidal, sharing its initial conditions. The independent variable is the rescaled time $s$, with $dt = B^{\star}_{\parallel} \, ds$ and $B^{\star}_{\parallel} \approx 5 \times 10^{-2}$ at the deeply passing initial condition — the smallest of the shipped equilibria, so the rescaled step is correspondingly the largest.
ChargedParticleDynamics.GyroKinetics4d.GuidingCenter4dTokamakMediumCartesian — Module
Medium-size axisymmetric tokamak equilibrium, in cartesian coordinates, with major radius $R_{0} = 2$, magnetic field $B_{0} = 5$ and safety factor $q_{0} = 2$.
The gyrokinetic counterpart of GuidingCenter4d.TokamakMediumCartesian, sharing its initial conditions. The independent variable is the rescaled time $s$, with $dt = B^{\star}_{\parallel} \, ds$ and $B^{\star}_{\parallel} \approx 3.8$ at the deeply passing initial condition.
Like its 4D guiding centre counterpart this module defines no toroidal_momentum: the third coordinate is $z$ rather than an angle, so $\vartheta_{3}$ is not a conserved momentum here.
ChargedParticleDynamics.GyroKinetics4d.GuidingCenter4dTokamakMediumCylindrical — Module
Medium-size axisymmetric tokamak equilibrium, in cylindrical coordinates $(R, Z, \varphi)$, with major radius $R_{0} = 2$, magnetic field $B_{0} = 5$ and safety factor $q_{0} = 2$.
The gyrokinetic counterpart of GuidingCenter4d.TokamakMediumCylindrical, sharing its initial conditions. The independent variable is the rescaled time $s$, with $dt = B^{\star}_{\parallel} \, ds$ and $B^{\star}_{\parallel} \approx 11$ at the deeply passing initial condition.
ChargedParticleDynamics.GyroKinetics4d.GuidingCenter4dTokamakIterCylindrical — Module
ITER-size axisymmetric tokamak equilibrium, in cylindrical coordinates $(R, Z, \varphi)$.
The gyrokinetic counterpart of GuidingCenter4d.TokamakIterCylindrical, sharing its initial conditions. The independent variable is the rescaled time $s$, with $dt = B^{\star}_{\parallel} \, ds$ and $B^{\star}_{\parallel} \approx 36$ at the deeply passing initial condition.
ChargedParticleDynamics.GyroKinetics4d.GuidingCenter4dSolovevIter — Module
Analytic ITER-like Solov'ev equilibrium, in cylindrical coordinates $(R, Z, \varphi)$.
The gyrokinetic counterpart of GuidingCenter4d.SolovevIter, sharing its initial conditions. Its independent variable is the rescaled time $s$, with $dt = B^{\star}_{\parallel} \, ds$; here $B^{\star}_{\parallel} \approx 2 \times 10^{2}$ at the deeply passing initial condition, so the defaults below are the 4D guiding centre's divided by that.
ChargedParticleDynamics.GyroKinetics4d.GuidingCenter4dSolovevIterXpoint — Module
Analytic ITER-like Solov'ev equilibrium with X-point.
Module
ChargedParticleDynamics.GyroKinetics4d.GuidingCenter4dTokamakSmallCylindrical — Module
Small axisymmetric tokamak equilibrium, in cylindrical coordinates $(R, Z, \varphi)$.
The gyrokinetic counterpart of GuidingCenter4d.TokamakSmallCylindrical, sharing its initial conditions. The independent variable is the rescaled time $s$, with $dt = B^{\star}_{\parallel} \, ds$; here $B^{\star}_{\parallel} \approx 1.0$ at the deeply passing initial condition, so the rescaling is close to a no-op.
ChargedParticleDynamics.GyroKinetics4d.GuidingCenter4dTokamakSmallCylindrical.compute_energy — Method
compute_energy(sol)The Hamiltonian along the solution, as a DataSeries.
ChargedParticleDynamics.GyroKinetics4d.GuidingCenter4dTokamakSmallCylindrical.compute_energy_error — Method
compute_energy_error(sol)Like every compute_*_error here, this forwards to GeometricSolutions.compute_invariant_error and so returns two series, not one: the invariant itself and its relative error. Destructure it — h, e = compute_energy_error(sol) — rather than passing the result somewhere a single series is expected.
ChargedParticleDynamics.GyroKinetics4d.GuidingCenter4dTokamakSmallCylindrical.compute_toroidal_momentum — Method
compute_toroidal_momentum(sol)The canonical toroidal momentum ϑ₃ along the solution, as a DataSeries. It is conserved in an axisymmetric equilibrium.
ChargedParticleDynamics.GyroKinetics4d.GuidingCenter4dTokamakSmallCylindrical.compute_toroidal_momentum_error — Method
compute_toroidal_momentum_error(sol)Returns a (value, error) pair; see compute_energy_error.
ChargedParticleDynamics.GyroKinetics4d.GuidingCenter4dTokamakSmallCylindrical.default_parameters — Method
The magnetic moment μ of the default initial condition, shared with the 4D guiding centre module of the same equilibrium.
ChargedParticleDynamics.GyroKinetics4d.GuidingCenter4dTokamakSmallCylindrical.hamiltonian — Method
The equilibrium guiding centre Hamiltonian,
\[H_{0} = \tfrac{1}{2} u^{2} + \mu \vert B \vert + \varphi ,\]
matching GuidingCenter4d. The notes this module follows give the zero Larmor radius Hamiltonian $H^{\mathrm{zlr}}$, which carries $A_{\parallel}$ and $\langle \tilde{A}_{\parallel} \rangle^{2}$ terms on top of this and would change $β$ and $γ$ as well; only $H_{0}$ is implemented. See TODO.md.
ChargedParticleDynamics.GyroKinetics4d.GuidingCenter4dTokamakSmallCylindrical.odeproblem — Function
odeproblem(qᵢ; kwargs...)
odeproblem(ics::NamedTuple; kwargs...)The gyrokinetic guiding centre characteristics in the rescaled time of the volume-preserving formulation,
\[\begin{aligned} \dfrac{d R}{d s} &= \sigma \left( \dfrac{\partial \gamma}{\partial u} + \nabla \times \beta \right) , & \dfrac{d u}{d s} &= - \sigma \, \nabla \cdot \gamma , \end{aligned}\]
with the vector potentials $\beta$ and $\gamma$ of β and γ and $\sigma =$ orientation() the sign of det(DF) for this module's chart.
The independent variable is not the physical time: the right-hand side is the guiding centre vector field multiplied by $\omega_{abs}$, so $dt = \omega_{abs} \, ds$. One unit of $s$ therefore covers $\omega_{abs} \approx 204$ units of physical time for the supplied ITER-like equilibrium, and the default time step is scaled accordingly.
That factor is the phasespace Jacobian $\omega_{abs} = J \, B^{\star}_{\parallel}$, absorbed into the distribution function as $\tilde{f} = \omega_{abs} f$. What it buys is that the right-hand side is then divergence-free, which is what makes the splitting of sodeproblem volume preserving. It is positive in every chart — see ωabs for why $\sigma$ is needed to make it so, and what went wrong while it was not — so $s$ always runs with $t$.
The second form takes the named tuple that every initial_conditions_* of this module returns, whose params carry that condition's own magnetic moment μ.
ChargedParticleDynamics.GyroKinetics4d.GuidingCenter4dTokamakSmallCylindrical.sodeproblem — Function
sodeproblem(qᵢ; kwargs...)
sodeproblem(ics::NamedTuple; kwargs...)The same characteristics as odeproblem, split into the six subsystems
\[\begin{aligned} \dot{R}_{1} &= + \partial_{2} \beta_{3} , & \dot{R}_{1} &= - \partial_{3} \beta_{2} , & \dot{R}_{2} &= + \partial_{3} \beta_{1} , \\ \dot{R}_{2} &= - \partial_{1} \beta_{3} , & \dot{R}_{3} &= + \partial_{1} \beta_{2} , & \dot{R}_{3} &= - \partial_{2} \beta_{1} , \end{aligned}\]
\[\begin{aligned} \dot{R}_{i} &= + \partial_{u} \gamma_{i} , & \dot{u} &= - \partial_{i} \gamma_{i} , & i &= 1,2,3 , \end{aligned}\]
each of which freezes two of the four variables and is symplectic in the remaining two. Composing symplectic integrators for the subsystems therefore preserves phasespace volume exactly; a symmetric composition of second-order methods gives a second-order volume-preserving scheme.
ChargedParticleDynamics.GyroKinetics4d.GuidingCenter4dTokamakSmallCylindrical.transform_q_to_q̃! — Method
transform_q_to_q̃(t, q, params)
transform_q_to_q̃!(q̃, t, q, params)Uniform rescaling of the state by the reference value $\omega_{0}$ of $B^{\star}_{\parallel}$ carried in params, $\tilde{q} = \omega_{0} \, q$, and its inverse transform_q̃_to_q!.
These are utilities, kept because a coordinate-transforming integrator was once written against them. The problem constructors work in the untransformed state $q = (R, u)$.
The notes this module follows write the rescaled characteristics as $\tilde{R} = B^{\star}_{\parallel} R$, $\tilde{V}_{\parallel} = B^{\star}_{\parallel} V_{\parallel}$, which reads like a change of variables but is not one: what the derivation actually does is absorb the phasespace Jacobian into the distribution function, $\tilde{f} = B^{\star}_{\parallel} f$, leaving the same trajectories traversed in the reparametrised time $dt = B^{\star}_{\parallel} \, ds$. That factor is already carried by the vector field v; rescaling the state on top of it describes a different system.
Note also that $B^{\star}_{\parallel}$ is a function of $(R, u)$, so freezing it at the initial condition — which is what params.ω₀ is — would in any case not reproduce the substitution above.
ChargedParticleDynamics.GyroKinetics4d.GuidingCenter4dTokamakSmallCylindrical.transform_q̃_to_q! — Method
transform_q̃_to_q(t, q̃, params)
transform_q̃_to_q!(q, t, q̃, params)Inverse of transform_q_to_q̃!.
ChargedParticleDynamics.GyroKinetics4d.GuidingCenter4dTokamakSmallCylindrical.v — Method
v(v, t, q, params)The gyrokinetic guiding centre vector field in the rescaled time,
\[\dfrac{dR}{ds} = \sigma \left( \dfrac{\partial \gamma}{\partial u} + \nabla \times \beta \right) , \qquad \dfrac{du}{ds} = - \sigma \, \nabla \cdot \gamma ,\]
built from the potentials β and γ, with $\sigma =$ orientation() the sign of det(DF) for this module's chart, as ElectromagneticFields generates it. The $\nabla \times$ above is the coordinate curl, which carries det(DF); $\sigma$ restores the orientation, so the bracket is the properly oriented curl and the field is the guiding centre one multiplied by the phasespace Jacobian $\omega_{abs} = J \, B^{\star}_{\parallel} > 0$. The independent variable is therefore related to the physical time by $dt = \omega_{abs} \, ds$, with $s$ running with $t$ in every chart. See ωabs for why the sign is not optional.
$\sigma$ does not disturb the structure: negating a divergence-free field leaves it divergence-free, so the splitting is volume preserving exactly as before.
The sub-fields v₁ … v₆ are the six subsystems this splits into; they sum to v.
ChargedParticleDynamics.GyroKinetics4d.GuidingCenter4dTokamakSmallCylindrical.β — Method
β(β, t, q, params)The first of the two vector potentials of the volume-preserving formulation,
\[\beta = \frac{1}{m} \frac{\partial H}{\partial u} A^{\star} ,\]
which reduces to $\beta = u \, A^{\star}$ for the equilibrium Hamiltonian implemented here. Together with γ it writes the equations of motion in the manifestly divergence-free form $\dot{R} = \partial_{u} \gamma + \nabla \times \beta$, $\dot{u} = - \nabla \cdot \gamma$.
ChargedParticleDynamics.GyroKinetics4d.GuidingCenter4dTokamakSmallCylindrical.γ — Method
γ(γ, t, q, params)The second vector potential of the volume-preserving formulation,
\[\gamma = \frac{1}{m} A^{\star} \times \nabla H ,\]
which reduces to $\gamma = (\mu/m) \, A^{\star} \times \nabla B_{0}$ for the equilibrium Hamiltonian implemented here. See β.
ChargedParticleDynamics.GyroKinetics4d.GuidingCenter4dTokamakSmallCylindrical.ωabs — Function
ωabs(t, q, params)The factor by which this module's vector field is rescaled relative to the 4D guiding centre one, $v_{gk} = \omega_{abs} \, v_{gc}$, so that the independent variable is the rescaled time with $dt = \omega_{abs} \, ds$. It is the phasespace Jacobian $\sqrt{\det \Omega} = J \, B^{\star}_{\parallel}$: the contraction $\omega \cdot \partial\vartheta/\partial u$ of the curl of the one-form against $b$, taken with the chart's orientation so that it is positive in every chart.
ω₁ = ∂₂ϑ₃ - ∂₃ϑ₂ is the coordinate curl, which is det(DF) times the contravariant one — the signed Jacobian, not the volume element J. The bare contraction is therefore det(DF) · B*∥ = orientation() · J · B*∥, and in the four left-handed charts of ElectromagneticFields — the cylindrical, the two toroidal and every Solovev* other than SolovevSymmetric — it comes out negative while the physical $B^{\star}_{\parallel}$ is positive. Multiplying by orientation() recovers the Liouville density √det Ω = |Pf(Ω)|, which is non-negative by construction — as the name of this function says it should be.
orientation() is generated into this module by the @code call at its top, alongside J, DF and the metric: ElectromagneticFields 0.7.1 emits the sign its own generator already reads to build det DF. It is the one generated function taking no arguments, since the handedness of a chart depends on neither t nor q. Nothing here declares it — asking the field for its own orientation is what keeps the two from drifting apart.
That sign is not free to drop. The factor is the phasespace Jacobian, absorbed into the distribution function as f̃ = ωabs f; a distribution rescaled by a negative number is not one. Carried into the vector field, it made the model chart-dependent: the small tokamak's cartesian chart circulated the particle one way round the torus and its cylindrical chart the other, for the same physical initial condition. test/gyro_kinetics_4d_tests.jl asserts that it no longer does.
The magnitude stays chart-dependent through J, which is correct for a density and is why the three charts of the small tokamak give 0.9511, 0.9986 and 0.0499 for the same B*∥ = 0.9511. Only the sign was wrong.
orientation() multiplies here and in v and nowhere else. ω, Ω, β and γ stay the plain coordinate objects they are — Ω = dϑ in particular must not be touched — so the identity v_gk = ωabs · v_gc holds exactly with both factors oriented.
Until ElectromagneticFields 0.7.0 none of this was visible: b was itself reversed in exactly those charts, so the two sign errors cancelled and the bare contraction came out positive everywhere.