Skip to content

Particle

dexter.InitialConditions(time0: float, theta0: float, psip0: float, rho0: float, zeta0: float, mu: float)

A set of initial conditions.

The initial conditions are defined on the \((t, \theta, \psi_p, \rho, \zeta, \mu)\) space.

Example

Creating an InitialConditions set:

>>> initial = dx.InitialConditions(
...     time0=0,
...     theta0=0,
...     psip0=0.3*qfactor.psip_wall,
...     rho0=1e-5,
...     zeta0=0,
...     mu=1e-6,
... )

Parameters:

  • time0 (float) –

    The initial time.

  • theta0 (float) –

    The initial \(\theta\) angle.

  • psip0 (float) –

    The initial poloidal magnetic flux \(\psi_p\).

  • rho0 (float) –

    The initial parallel gyro radius \(\rho\).

  • zeta0 (float) –

    The initial \(\zeta\) angle.

  • mu (float) –

    The magnetic moment \(\mu\).


dexter.MappingParameters(section: PoincareSection, alpha: float, intersections: int)

Defines all the necessary parameters of a Mapping.

Example

Creating an MappingParameters:

>>> params = dx.MappingParameters(
...     section="ConstTheta",
...     alpha=0, # θ=0 interection
...     intersections=2000,
... )

Parameters:

  • section (PoincareSection) –

    The surface of section \(\Sigma\), defined by an equation \(x_i = \alpha\), where \(x_i = \theta\) or \(\zeta\).

  • alpha (float) –

    The constant that defines the surface of section (modulo \(2π\)).

  • intersections (int) –

    The number of interections to calculate.


dexter.Particle(initial_conditions: InitialConditions)

A Particle.

By taking \(\mu = 0\) and \(\rho \rightarrow 0\), the particle traces magnetic field lines.

Attributes:

  • initial_conditions (InitialConditions) –

    The initial conditions set.

  • evolution (Evolution) –

    The evolution time series of the particle's integration.

  • status (str) –

    The particle's integration status.

  • frequencies (Frequencies) –

    The particle's calculated frequencies.

  • initial_energy (float) –

    The particle's initial energy, calculated from its initial state, in Normalized Units.

  • final_energy (float) –

    The particle's final energy, calculated from its final state, in Normalized Units.

Parameters:

Example

Creating a Particle from an InitialConditions set:

>>> initial = dx.InitialConditions(
...     time0=0,
...     theta0=0,
...     psip0=0.3*qfactor.psip_wall,
...     rho0=1e-5,
...     zeta0=0,
...     mu=1e-6,
... )
>>>
>>> particle = dx.Particle(initial)

Methods:

  • integrate

    Integrates the particle, storing its evolution.

  • map

    Integrates the particle, storing its intersections with the Poincare

  • calculate_frequencies

    Calculates \(\omega_\theta\), \(\omega_\zeta\) and \(q_{kinetic}\).

dexter.Particle.integrate(qfactor: Qfactor, bfield: Bfield, currents: Currents, perturbation: Perturbation, t_eval: tuple[float, float]) -> None

Integrates the particle, storing its evolution.

Parameters:

  • qfactor (Qfactor) –

    The equilibrium's qfactor.

  • currents (Currents) –

    The equilibrium's plasma current.

  • bfield (Bfield) –

    The equilibrium's magnetic field.

  • perturbation (Perturbation) –

    The equilibrium's perturbation.

  • t_eval (tuple[float, float]) –

    The time span \((t_0, t_f)\) in which to integrate the particle, in Normalized Units.

Example
>>> particle.integrate(
...     qfactor=qfactor,
...     currents=currents,
...     bfield=bfield,
...     perturbation=perturbation,
...     t_eval=(0, 500),
... )

dexter.Particle.map(qfactor: Qfactor, currents: Currents, bfield: Bfield, perturbation: Perturbation, params: MappingParameters) -> None

Integrates the particle, storing its intersections with the Poincare surface defined by params.

Parameters:

  • qfactor (Qfactor) –

    The equilibrium's qfactor.

  • currents (Currents) –

    The equilibrium's plasma current.

  • bfield (Bfield) –

    The equilibrium's magnetic field.

  • perturbation (Perturbation) –

    The equilibrium's perturbation.

  • params (MappingParameters) –

    The parameters of the Poincare mapping.

Example
>>> params = dx.MappingParameters(
...     section="ConstTheta",
...     alpha=0, # θ=0 interection
...     intersections=100,
... )
>>>
>>> particle.map(
...     qfactor=qfactor,
...     currents=currents,
...     bfield=bfield,
...     perturbation=perturbation,
...     params=params,
... )

dexter.Particle.calculate_frequencies(qfactor: Qfactor, currents: Currents, bfield: Bfield, perturbation: Perturbation) -> None

Calculates \(\omega_\theta\), \(\omega_\zeta\) and \(q_{kinetic}\).

Note

\(\omega_\theta\) is calculated by integrating for a single period with respect to the \(\theta-\psi_p\) variables.

The orbit frequency \(\omega_\zeta\) corresponds to the bounce/transit averaged rate of toroidal precession \(\Delta\zeta / T_\omega\).

Finally, \(q_{kinetic} = \omega_\zeta / \omega_\theta\).

Tip

Avoid using values like \(\pi, 0\) for \(\theta\). The solver looks for intersections with the initial \(\theta-\psi_p\) values, but \(\pi\) and \(0\) tend to be local minima/maxima, and therefore no intersections can be detected. Use 'random' intermediate values instead.

Parameters:

  • qfactor (Qfactor) –

    The equilibrium's qfactor.

  • currents (Currents) –

    The equilibrium's plasma current.

  • bfield (Bfield) –

    The equilibrium's magnetic field.

  • perturbation (Perturbation) –

    The equilibrium's perturbation.

Example
>>> initial = dx.InitialConditions(
...     time0=0,
...     theta0=1,
...     psip0=0.8*qfactor.psip_wall,
...     rho0=1e-5,
...     zeta0=0,
...     mu=1e-6,
... )
>>>
>>> particle = dx.Particle(initial)
>>>
>>> particle.calculate_frequencies(
...     qfactor=qfactor,
...     currents=currents,
...     bfield=bfield,
...     perturbation=dx.Perturbation([]),
... )
>>> print(particle.frequencies)  # doctest: +SKIP
Frequencies {
    omega_theta: "0.0000357",
    omega_zeta: "0.0000033",
    qkinetic: "0.0911628",
}

dexter.Evolution

Stores the time series of the particle's orbit.

Not meant to be constructed. It is stored as a particle's attribute.

Attributes:

  • time (NDArray1D) –

    The time evolution

  • theta (NDArray1D) –

    The \(\theta\) time series.

  • psip (NDArray1D) –

    The \(\psi_p\) time series.

  • rho (NDArray1D) –

    The \(\rho_{||}\) time series.

  • zeta (NDArray1D) –

    The \(\zeta\) time series.

  • psi (NDArray1D) –

    The \(\psi\) time series.

  • ptheta (NDArray1D) –

    The \(P_\theta\) time series.

  • pzeta (NDArray1D) –

    The \(P_\zeta\) time series.

  • energy (NDArray1D) –

    The energy time series.

  • energy_std (float) –

    The relative standard deviation (\(\sigma/\mu\)) of the energy time series.

  • steps_taken (int) –

    The total number of steps taken to complete the integration.

  • steps_stored (int) –

    The number of points stored. This can different from the steps_taken attribute, for example when mapping a particle, in which case only the intersections are stored.

Example
>>> particle.evolution.theta # doctest: +SKIP
array([  3.14      ,   3.14293393,   3.14607403, ..., 504.04624189,
    504.05828496, 504.07118786], shape=(41270,))

dexter.Frequencies

Stores the Particle's calculated \(\omega_\theta\), \(\omega_\zeta\) and \(q_{kinetic}\).

The values are calculated from Particle.calculate_frequencies since they must be calculated in a specific order. Otherwise they are absent.