Skip to content

Particle

dexter.InitialFlux(kind: FluxCoordinate, value: float)

Defines the flux coordinate to be used in the initial conditions of a Particle.

Parameters:

  • kind (FluxCoordinate) –

    The kind of initial flux.

  • value (float) –

    The flux' value

Example
InitialFlux definition
>>> flux0=("Toroidal", 0.1), # ψ0 = 0.1
>>> flux0=("Poloidal", 0.5), # ψp0 = 0.5

Attributes:

  • kind (FluxCoordinate) –

    The kind of initial flux (\(\psi\) or \(\psi_p\))

  • value (float) –

    The contained value, regardless of kind.

dexter.InitialFlux.kind: FluxCoordinate property

The kind of initial flux (\(\psi\) or \(\psi_p\))

dexter.InitialFlux.value: float property

The contained value, regardless of kind.

dexter.InitialConditions()

Initial Conditions set for a Particle.

The set can be in either Boozer or Mixed coordinates.

Use InitialConditions.boozer and InitialConditions.mixed class methods to construct the set.

Methods:

  • boozer

    Creates initial conditions for a Particle in Boozer coordinates.

  • mixed

    Creates initial conditions for a Particle in Mixed coordinates.

Attributes:

  • t0 (float) –

    The initial time, in Normalized Units.

  • flux0 (InitialFlux) –

    The initial \(\psi / \psi_p\), in Normalized Units.

  • theta0 (float) –

    The initial \(\theta\) angle, in Normalized Units.

  • zeta0 (float) –

    The initial \(\zeta\) angle, in Normalized Units.

  • mu0 (float) –

    The initial magnetic moment \(\mu\), in Normalized Units.

  • rho0 (float) –

    The initial parallel radius \(\rho_{||}\), in Normalized Units.

  • pzeta0 (float) –

    The initial canonical momentum \(P_\zeta\), in Normalized Units.

  • coordinate_set (CoordinateSet) –

    The kind of InitialConditions set.

dexter.InitialConditions.t0: float property

The initial time, in Normalized Units.

dexter.InitialConditions.flux0: InitialFlux property

The initial \(\psi / \psi_p\), in Normalized Units.

dexter.InitialConditions.theta0: float property

The initial \(\theta\) angle, in Normalized Units.

dexter.InitialConditions.zeta0: float property

The initial \(\zeta\) angle, in Normalized Units.

dexter.InitialConditions.mu0: float property

The initial magnetic moment \(\mu\), in Normalized Units.

dexter.InitialConditions.rho0: float property

The initial parallel radius \(\rho_{||}\), in Normalized Units.

dexter.InitialConditions.pzeta0: float property

The initial canonical momentum \(P_\zeta\), in Normalized Units.

dexter.InitialConditions.coordinate_set: CoordinateSet property

The kind of InitialConditions set.

dexter.InitialConditions.boozer(t0: float, flux0: InitialFlux, theta0: float, zeta0: float, rho0: float, mu0: float) -> InitialConditions classmethod

Creates initial conditions for a Particle in Boozer coordinates.

The initial conditions are defined on the \((t, \psi, \theta, \zeta, \rho, \mu)\) or \((t, \psi_p, \theta, \zeta, \rho, \mu)\) space, depending on the value of flux0.

Parameters:

  • t0 (float) –

    The initial time, in Normalized Units.

  • flux0 (InitialFlux) –

    The initial \(\psi / \psi_p\), in Normalized Units.

  • theta0 (float) –

    The initial \(\theta\) angle, in rads.

  • zeta0 (float) –

    The initial \(\zeta\) angle, in rads.

  • rho0 (float) –

    The initial \(\rho_{||}\), in Normalized Units.

  • mu0 (float) –

    The initial magnetic moment \(\mu\), in Normalized Units.

Example
InitialConditions definition in Boozer coordinates
>>> initial_conditions = dex.InitialConditions.boozer(
...     t0=0,
...     flux0=dex.InitialFlux("Toroidal", 0.1), # ψ0 = 0.1
...     theta0=3.14,
...     zeta0=0,
...     rho0=1e-4,
...     mu0=7e-6,
... )

dexter.InitialConditions.mixed(t0: float, flux0: InitialFlux, theta0: float, zeta0: float, pzeta0: float, mu0: float) -> InitialConditions classmethod

Creates initial conditions for a Particle in Mixed coordinates.

The initial conditions are defined on the \((t, \psi, \theta, \zeta, P\zeta, \mu)\) or \((t, \zeta, \psi_p, \theta, \zeta, P\zeta, \mu)\) space, depending on the value of flux0.

Parameters:

  • t0 (float) –

    The initial time, in Normalized Units.

  • pzeta0 (float) –

    The initial \(P_\zeta\), in Normalized Units.

  • flux0 (InitialFlux) –

    The initial \(\psi / \psi_p\), in Normalized Units.

  • theta0 (float) –

    The initial \(\theta\) angle, in rads.

  • zeta0 (float) –

    The initial \(\zeta\) angle, in rads.

  • mu0 (float) –

    The initial magnetic moment \(\mu\), in Normalized Units.

Example
InitialConditions definition in Mixed Coordinates
>>> initial_conditions = dex.InitialConditions.mixed(
...     t0=0,
...     flux0=dex.InitialFlux("Toroidal", 0.1), # ψ0 = 0.1
...     theta0=3.14,
...     zeta0=0,
...     pzeta0=-0.025,
...     mu0=7e-6,
... )

dexter.IntersectParams(intersection: Intersection, angle: float, turns: int)

Parameters for the Particle's intersect() method.

Parameters:

  • intersection (Intersection) –

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

  • angle (float) –

    The constant that defines the surface of section.

  • turns (int) –

    The number of intersections to calculate.

Example
IntersectParams definition
>>> intersect_params = dex.IntersectParams(
...     intersection = "ConstTheta",
...     angle = 3.1415,
...     turns = 100,
... )

Attributes:

dexter.IntersectParams.intersection: Intersection property

The intersection surface.

dexter.IntersectParams.angle: float property

The intersection surface's angle.

dexter.IntersectParams.turns: int property

The number of intersections to calculate.

dexter.Particle(initial_conditions: InitialConditions)

A Particle.

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

Parameters:

Example

Particle creation from a Boozer Coordinates set
>>> initial_conditions = dex.InitialConditions.boozer(
...     t0=0,
...     flux0=dex.InitialFlux("Toroidal", 0.1),
...     theta0=3.14,
...     zeta0=0,
...     rho0=1e-4,
...     mu0=7e-6,
... )
>>> particle = dex.Particle(initial_conditions)
Particle creation from a Mixed Coordinates set
>>> initial_conditions = dex.InitialConditions.mixed(
...     t0=0,
...     flux0=dex.InitialFlux("Toroidal", 0.1),
...     theta0=3.14,
...     zeta0=0,
...     pzeta0=-0.025,
...     mu0=7e-6,
... )
>>> particle = dex.Particle(initial_conditions)

Methods:

  • plot_evolution

    Plots the time evolution of an integrated Particle.

  • plot_db_drift

    Plots the magnetic field strength \(B(\psi/\psi_p, \theta)\) along the particle's orbit.

  • integrate

    Integrates the particle for a certain time interval.

  • intersect

    Integrates the particle, calculating its intersections with a constant \(\theta\) or \(\zeta\) surface.

  • close

    Integrates the particle for a certain amount of \(\theta-\psi\) periods.

  • classify

    Classifies the particle’s orbit using its position on the \((E, P_\zeta, \mu=const)\)

Attributes:

dexter.Particle.initial_conditions: InitialConditions property

The initial conditions set.

dexter.Particle.integration_status: IntegrationStatus property

The particle's integration status.

dexter.Particle.steps_taken: int property

The total number of steps taken during the integration.

This number is not necessarily the same as the number of steps stored.

dexter.Particle.steps_stored: int property

The number of steps stored in the the time series arrays.

dexter.Particle.initial_energy: float property

The particle's initial energy before the integration in Normalized Units.

dexter.Particle.final_energy: float property

The particle's final energy after the integration in Normalized Units.

dexter.Particle.energy_var: float property

The variance of energy throughout the integration.

dexter.Particle.energy_pzeta_position: EnergyPzetaPosition property

The particle's position on the \(E-P_\zeta\) plane, relative to the orbit classification curves.

See the diagram for explanation.

dexter.Particle.orbit_type: OrbitType property

The particle's orbit type.

dexter.Particle.omega_theta: float property

The particle's calculated \(\omega_\theta\)

dexter.Particle.omega_zeta: float property

The particle's calculated \(\omega_\zeta\)

dexter.Particle.qkinetic: float property

The particle's calculated \(q_{kinetic}\)

dexter.Particle.t_array: Array1 property

The times of the integration steps.

dexter.Particle.psi_array: Array1 property

The \(\psi\) time series.

dexter.Particle.psip_array: Array1 property

The \(\psi_p\) time series.

dexter.Particle.theta_array: Array1 property

The \(\theta\) time series.

dexter.Particle.zeta_array: Array1 property

The \(\zeta\) time series.

dexter.Particle.rho_array: Array1 property

The \(\rho\) time series.

dexter.Particle.mu_array: Array1 property

The \(\mu\) time series.

dexter.Particle.ptheta_array: Array1 property

The \(P_\theta\) time series.

dexter.Particle.pzeta_array: Array1 property

The \(P_\zeta\) time series.

dexter.Particle.energy_array: Array1 property

The energy time series.

dexter.Particle.plot_evolution(percentage: float = 100, downsample: bool = True, show: bool = True) -> MultiCanvas

Plots the time evolution of an integrated Particle.

Parameters:

  • percentage (float, default: 100 ) –

    The percentage of the evolution to plot. Defaults to 100.

  • downsample (bool, default: True ) –

    Whether or not to downsample the evolution arrays. This can be really helpful when plotting arrays with a lot of points, since it drastically improves both figure creation and interaction performance. Downsampling is done by increasing the [::step] just enough so that the final number of points is more than 50.000. Defaults to True

  • show (bool, default: True ) –

    Whether or not to call plt.show(). Defaults to True.

Returns:

dexter.Particle.plot_db_drift(equilibrium: Equilibrium, show: bool = True) -> MultiCanvas

Plots the magnetic field strength \(B(\psi/\psi_p, \theta)\) along the particle's orbit.

Parameters:

  • equilibrium (Equilibrium) –

    The equilibrium in which the particle was integrated.

  • show (bool, default: True ) –

    Whether or not to call plt.show(). Defaults to True.

Returns:

dexter.Particle.integrate(equilibrium: Equilibrium, teval: tuple[float, float], *, stepping_method: Optional[SteppingMethod] = 'EnergyAdaptiveStep', max_steps: Optional[int] = 1000000, first_step: Optional[float] = 0.1, safety_factor: Optional[float] = 0.9, energy_rel_tol: Optional[float] = 1e-12, energy_abs_tol: Optional[float] = 1e-14, error_rel_tol: Optional[float] = 1e-12, error_abs_tol: Optional[float] = 1e-14)

Integrates the particle for a certain time interval.

The time interval is in Normalized Units (inverse gyro-frequency).

Parameters:

  • equilibrium (Equilibrium) –

    The equilibrium in which to integrate the particle.

  • teval (tuple[float, float]) –

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

Other Parameters:

  • stepping_method (Optional[SteppingMethod]) –

    The optimal step calculation method. Defaults to "EnergyAdaptiveStep".

  • max_steps (Optional[int]) –

    The maximum amount of steps a particle can make before terminating its integration. Defaults to 1.000.000.

  • first_step (Optional[float]) –

    The initial time step for the RKF45 adaptive step method. The value is empirical. Defaults to 1e-1.

  • safety_factor (Optional[float]) –

    The safety factor of the solver. Should be less than 1.0. Defaults to 0.9.

  • energy_rel_tol (Optional[float]) –

    The relative tolerance of the energy difference in every step. Defaults to 1e-12.

  • energy_abs_tol (Optional[float]) –

    The absolute tolerance of the energy difference in every step. Defaults to 1e-14.

  • error_rel_tol (Optional[float]) –

    The relative tolerance of the local truncation error in every step. Defaults to 1e-12.

  • error_abs_tol (Optional[float]) –

    The absolute tolerance of the local truncation error in every step. Defaults to 1e-14.

Example
Particle integration
>>> # Equilibrium setup
>>> LCFS = dex.LastClosedFluxSurface(kind="Toroidal", value=0.45)
>>> equilibrium = dex.Equilibrium(
...     qfactor=dex.ParabolicQfactor(qaxis=1.1, qlast=4.1, lcfs=LCFS),
...     current=dex.LarCurrent(),
...     bfield=dex.LarBfield(),
...     perturbation=dex.Perturbation(
...         [
...             dex.CosHarmonic(epsilon=1e-3, lcfs=LCFS, m=1, n=3, phase=0),
...             dex.CosHarmonic(epsilon=1e-3, lcfs=LCFS, m=2, n=3, phase=0),
...         ]
...     )
... )
>>>
>>> # Initial conditions setup
>>> initial_conditions = dex.InitialConditions.boozer(
...     t0=0,
...     flux0=dex.InitialFlux("Toroidal", 0.1),
...     theta0=3.14,
...     zeta0=0,
...     rho0=1e-4,
...     mu0=7e-6,
... )
>>>
>>> # Particle setup and integration
>>> particle = dex.Particle(initial_conditions)
>>> particle.integrate(
...     equilibrium=equilibrium,
...     teval=(0, 1e2),
...     first_step=1e-3,
...     energy_rel_tol=1e-11,
... )

dexter.Particle.intersect(equilibrium: Equilibrium, intersect_params: IntersectParams, *, stepping_method: Optional[SteppingMethod] = 'EnergyAdaptiveStep', max_steps: Optional[int] = 1000000, first_step: Optional[float] = 0.1, safety_factor: Optional[float] = 0.9, energy_rel_tol: Optional[float] = 1e-12, energy_abs_tol: Optional[float] = 1e-14, error_rel_tol: Optional[float] = 1e-12, error_abs_tol: Optional[float] = 1e-14)

Integrates the particle, calculating its intersections with a constant \(\theta\) or \(\zeta\) surface.

Using the method described by Hénon we can force the solver to step exactly on the intersection surface.

The differences between two consecutive values of the corresponding angle variable are guaranteed to be \(2\pi \pm \epsilon\), where \(\epsilon\) a number smaller than the solver’s relative tolerance.

Parameters:

  • equilibrium (Equilibrium) –

    The equilibrium in which to integrate the particle.

  • intersect_params (IntersectParams) –

    The parameters of the integration.

Other Parameters:

  • stepping_method (Optional[SteppingMethod]) –

    The optimal step calculation method. Defaults to "EnergyAdaptiveStep".

  • max_steps (Optional[int]) –

    The maximum amount of steps a particle can make before terminating its integration. Defaults to 1.000.000.

  • first_step (Optional[float]) –

    The initial time step for the RKF45 adaptive step method. The value is empirical. Defaults to 1e-1.

  • safety_factor (Optional[float]) –

    The safety factor of the solver. Should be less than 1.0. Defaults to 0.9.

  • energy_rel_tol (Optional[float]) –

    The relative tolerance of the energy difference in every step. Defaults to 1e-12.

  • energy_abs_tol (Optional[float]) –

    The absolute tolerance of the energy difference in every step. Defaults to 1e-14.

  • error_rel_tol (Optional[float]) –

    The relative tolerance of the local truncation error in every step. Defaults to 1e-12.

  • error_abs_tol (Optional[float]) –

    The absolute tolerance of the local truncation error in every step. Defaults to 1e-14.

Example
Particle intersection integration
>>> # Equilibrium setup
>>> LCFS = dex.LastClosedFluxSurface(kind="Toroidal", value=0.45)
>>> equilibrium = dex.Equilibrium(
...     qfactor=dex.ParabolicQfactor(qaxis=1.1, qlast=4.1, lcfs=LCFS),
...     current=dex.LarCurrent(),
...     bfield=dex.LarBfield(),
...     perturbation=dex.Perturbation(
...         [
...             dex.CosHarmonic(epsilon=1e-3, lcfs=LCFS, m=1, n=3, phase=0),
...             dex.CosHarmonic(epsilon=1e-3, lcfs=LCFS, m=2, n=3, phase=0),
...         ]
...     )
... )
>>>
>>> # Initial conditions and Intersection Parameters setup
>>> initial_conditions = dex.InitialConditions.boozer(
...     t0=0,
...     flux0=dex.InitialFlux("Toroidal", 0.1),
...     theta0=3.14,
...     zeta0=0,
...     rho0=1e-4,
...     mu0=7e-6,
... )
>>> intersect_params = dex.IntersectParams(
...     intersection = "ConstTheta",
...     angle = 3.1415,
...     turns = 5,
... )
>>>
>>> # Particle setup and intersection
>>> particle = dex.Particle(initial_conditions)
>>> particle.intersect(
...     equilibrium=equilibrium,
...     intersect_params=intersect_params,
... )

dexter.Particle.close(equilibrium: Equilibrium, *, periods: Optional[int] = 1, stepping_method: Optional[SteppingMethod] = 'EnergyAdaptiveStep', max_steps: Optional[int] = 1000000, first_step: Optional[float] = 0.1, safety_factor: Optional[float] = 0.9, energy_rel_tol: Optional[float] = 1e-12, energy_abs_tol: Optional[float] = 1e-14, error_rel_tol: Optional[float] = 1e-12, error_abs_tol: Optional[float] = 1e-14)

Integrates the particle for a certain amount of \(\theta-\psi\) periods.

Parameters:

  • equilibrium (Equilibrium) –

    The equilibrium in which to integrate the particle.

  • periods (Optional[int], default: 1 ) –

    The amount of periods to integrate. Defaults to 1.

Other Parameters:

  • stepping_method (Optional[SteppingMethod]) –

    The optimal step calculation method. Defaults to "EnergyAdaptiveStep".

  • max_steps (Optional[int]) –

    The maximum amount of steps a particle can make before terminating its integration. Defaults to 1.000.000.

  • first_step (Optional[float]) –

    The initial time step for the RKF45 adaptive step method. The value is empirical. Defaults to 1e-1.

  • safety_factor (Optional[float]) –

    The safety factor of the solver. Should be less than 1.0. Defaults to 0.9.

  • energy_rel_tol (Optional[float]) –

    The relative tolerance of the energy difference in every step. Defaults to 1e-12.

  • energy_abs_tol (Optional[float]) –

    The absolute tolerance of the energy difference in every step. Defaults to 1e-14.

  • error_rel_tol (Optional[float]) –

    The relative tolerance of the local truncation error in every step. Defaults to 1e-12.

  • error_abs_tol (Optional[float]) –

    The absolute tolerance of the local truncation error in every step. Defaults to 1e-14.

Example
Particle integration
>>> # Equilibrium setup
>>> LCFS = dex.LastClosedFluxSurface(kind="Toroidal", value=0.45)
>>> equilibrium = dex.Equilibrium(
...     qfactor=dex.ParabolicQfactor(qaxis=1.1, qlast=4.1, lcfs=LCFS),
...     current=dex.LarCurrent(),
...     bfield=dex.LarBfield(),
...     perturbation=dex.Perturbation([])
... )
>>>
>>> # Initial conditions setup
>>> initial_conditions = dex.InitialConditions.boozer(
...     t0=0,
...     flux0=dex.InitialFlux("Toroidal", 0.1),
...     theta0=3.14,
...     zeta0=0,
...     rho0=1e-5,
...     mu0=7e-6,
... )
>>>
>>> # Particle setup and integration
>>> particle = dex.Particle(initial_conditions)
>>> particle.close(
...     equilibrium=equilibrium,
...     periods=4,
... )

dexter.Particle.classify(equilibrium: Equilibrium)

Classifies the particle’s orbit using its position on the \((E, P_\zeta, \mu=const)\) plane without integrating.

Parameters:

  • equilibrium (Equilibrium) –

    The equilibrium in which to integrate the particle.

Example
Particle classification
>>> # Equilibrium setup
>>> LCFS = dex.LastClosedFluxSurface(kind="Toroidal", value=0.45)
>>> equilibrium = dex.Equilibrium(
...     qfactor=dex.ParabolicQfactor(qaxis=1.1, qlast=4.1, lcfs=LCFS),
...     current=dex.LarCurrent(),
...     bfield=dex.LarBfield(),
... )
>>>
>>> # Initial conditions setup
>>> initial_conditions = dex.InitialConditions.boozer(
...     t0=0,
...     flux0=dex.InitialFlux("Toroidal", 0.1),
...     theta0=3.14,
...     zeta0=0,
...     rho0=1e-4,
...     mu0=7e-6,
... )
>>>
>>> # Particle setup and classification
>>> particle = dex.Particle(initial_conditions)
>>> particle.close(equilibrium=equilibrium)