Skip to content

Queue

dexter.Queue(initial_conditions: QueueInitialConditions)

A collection of multiple Particles, constructed from a QueueInitialConditions.

Example
Queue Instantiation
>>> num = 100
>>> psit0s = np.linspace(0, 0.15, num)
>>> initial_conditions = dex.QueueInitialConditions.Boozer(
...     t0=np.zeros(num),
...     flux0=dex.MagneticFluxArray.Toroidal(psit0s),
...     theta0=np.zeros(num),
...     zeta0=np.zeros(num),
...     rho0=np.full(num, 1e-5),
...     mu0=np.full(num, 1e-6),
... )
>>>
>>> # Queue setup and integration
>>> queue = dex.Queue(initial_conditions)

Attributes:

  • initial_conditions (QueueInitialConditions) –

    The Queue's initial conditions

  • routines (list[Routine]) –

    The routines Queue has run

  • energy_array (Array1) –

    A 1D array with the particle's energies.

  • energy_var_array –

    A 1D array with the particle's energy variances.

  • omega_theta_array (Array1) –

    A 1D array with the particle's $\omega_\theta$.

  • omega_zeta_array (Array1) –

    A 1D array with the particle's $\omega_\zeta$.

  • qkinetic_array (Array1) –

    A 1D array with the particle's $q_{kin}$.

Note

In arrays containing particle quantities, the particles are visited in order of instantiation.

FromParticles(particles: Collection[Particle]) -> Queue classmethod

Creates a Queue from a collection of Particles, copying all their attributes.

The particles do not have to be initialized, but they must be defined on the same coordinate set (boozer/mixed).

integrate(machine: Machine, teval: tuple[float, float], solver_params: SolverParams | None = None)

Integrates the particles for a specific time interval.

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

Parameters:

  • machine (Machine) –

    The machine in which to integrate the particles.

  • teval (tuple[float, float]) –

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

  • solver_params (SolverParams | None, default: None ) –

    The parameters passed to the solver.

Example
Queue integration
>>> # Machine setup
>>> LCFS = dex.MagneticFlux.Toroidal(0.45)
>>> machine = dex.Machine(
...     qfactor=dex.ParabolicQfactor(qaxis=1.1, qlast=4.1, lcfs=LCFS),
...     current=dex.LarCurrent(),
...     bfield=dex.LarBfield(),
...     perturbation=dex.Perturbation(
...         [
...             dex.FluteMode(epsilon=1e-3, lcfs=LCFS, m=1, n=3, phase=0),
...             dex.FluteMode(epsilon=1e-3, lcfs=LCFS, m=2, n=3, phase=0),
...         ]
...     )
... )
>>>
>>> # Initial conditions setup
>>> num = 10
>>> psit0s = dex.MagneticFluxArray.Toroidal(np.linspace(0, machine.psit_last.value, num))
>>> initial_conditions = dex.QueueInitialConditions.Boozer(
...     t0=np.zeros(num),
...     flux0=psit0s,
...     theta0=np.zeros(num),
...     zeta0=np.zeros(num),
...     rho0=np.full(num, 1e-5),
...     mu0=np.full(num, 1e-6),
... )
>>>
>>> # Queue setup and integration
>>> queue = dex.Queue(initial_conditions)
>>>
>>> solver_params = dex.SolverParams(
...     method=dex.SteppingMethod.EnergyAdaptiveStep(rel_tol=1e-7, abs_tol=1e-9),
...     max_steps=100_000,
... )
>>> queue.integrate(machine, teval=(0, 1e2), solver_params=solver_params)

intersect(machine: Machine, intersect_params: IntersectParams, solver_params: SolverParams | None = None)

Integrates the particles, calculating their 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:

  • machine (Machine) –

    The machine in which to integrate the particles.

  • intersect_params (IntersectParams) –

    The intersection parameters.

  • solver_params (SolverParams | None, default: None ) –

    The parameters passed to the solver.

Example
Queue intersection integration
>>> # Machine setup
>>> LCFS = dex.MagneticFlux.Toroidal(0.45)
>>> machine = dex.Machine(
...     qfactor=dex.ParabolicQfactor(qaxis=1.1, qlast=4.1, lcfs=LCFS),
...     current=dex.LarCurrent(),
...     bfield=dex.LarBfield(),
...     perturbation=dex.Perturbation(
...         [
...             dex.FluteMode(epsilon=1e-3, lcfs=LCFS, m=1, n=3, phase=0),
...             dex.FluteMode(epsilon=1e-3, lcfs=LCFS, m=2, n=3, phase=0),
...         ]
...     )
... )
>>>
>>> # Initial conditions and Intersection Parameters setup
>>> num = 10
>>> psit0s = dex.MagneticFluxArray.Toroidal(np.linspace(0, machine.psit_last.value, num))
>>> initial_conditions = dex.QueueInitialConditions.Boozer(
...     t0=np.zeros(num),
...     flux0=psit0s,
...     theta0=np.zeros(num),
...     zeta0=np.zeros(num),
...     rho0=np.full(num, 1e-6),
...     mu0=np.full(num, 1e-4),
... )
>>>
>>> # Queue setup and integration
>>> queue = dex.Queue(initial_conditions)
>>>
>>> intersect_params = dex.IntersectParams("ConstZeta", angle=3.1415, turns=5)
>>> queue.intersect(machine, intersect_params)

close(machine: Machine, periods: int = 1, discard_arrays: bool = True, solver_params: SolverParams | None = None)

Integrates the particles for a certain amount of $\theta-\psi$ periods.

Parameters:

  • machine (Machine) –

    The machine in which to integrate the particles.

  • periods (int, default: 1 ) –

    The amount of periods to integrate.

  • discard_arrays (bool, default: True ) –

    Whether or not to discard the integration timeseries after the routine is finished. Quantities such as $q_{kin}$ are still calculated.

  • solver_params (SolverParams | None, default: None ) –

    The parameters passed to the solver.

Example
Queue orbit closing
>>> # Machine setup
>>> LCFS = dex.MagneticFlux.Toroidal(0.45)
>>> machine = dex.Machine(
...     qfactor=dex.ParabolicQfactor(qaxis=1.1, qlast=4.1, lcfs=LCFS),
...     current=dex.LarCurrent(),
...     bfield=dex.LarBfield(),
... )
>>>
>>> # Initial conditions and Intersection Parameters setup
>>> num = 10
>>> psit0s = dex.MagneticFluxArray.Toroidal(np.linspace(0, machine.psit_last.value, num))
>>> initial_conditions = dex.QueueInitialConditions.Boozer(
...     t0=np.zeros(num),
...     flux0=psit0s,
...     theta0=np.zeros(num),
...     zeta0=np.zeros(num),
...     rho0=np.full(num, 1e-5),
...     mu0=np.full(num, 1e-6),
... )
>>>
>>> # Queue setup and integration
>>> queue = dex.Queue(initial_conditions)
>>> queue.close(machine)

classify(machine: Machine)

Classifies the particles’ orbit using their position on the $(E, P_\zeta, \mu=const)$ plane without integrating.

Note

This method follows R. B. White's rules for classifying orbits. it only works for up-down symmetric equilibria with radial electric field.

See the "$E-P_\zeta$ Positions" section on the Diagrams tab for explanation.

Parameters:

  • machine (Machine) –

    The machine in which to classify the particles.

Example
Queue classification
>>> # Machine setup
>>> LCFS = dex.MagneticFlux.Toroidal(0.45)
>>> machine = dex.Machine(
...     qfactor=dex.ParabolicQfactor(qaxis=1.1, qlast=4.1, lcfs=LCFS),
...     current=dex.LarCurrent(),
...     bfield=dex.LarBfield(),
... )
>>>
>>> # Initial conditions and Intersection Parameters setup
>>> num = 10
>>> psit0s = dex.MagneticFluxArray.Toroidal(np.linspace(0, machine.psit_last.value, num))
>>> initial_conditions = dex.QueueInitialConditions.Boozer(
...     t0=np.zeros(num),
...     flux0=psit0s,
...     theta0=np.zeros(num),
...     zeta0=np.zeros(num),
...     rho0=np.full(num, 1e-5),
...     mu0=np.full(num, 1e-6),
... )
>>>
>>> # Queue setup and integration
>>> queue = dex.Queue(initial_conditions)
>>> queue.classify(machine)

particles() -> list[Particle]

Returns a list with all the contained objects.

Note that calling this method copies all particles.

retain_pzeta(start: float, end: float) -> None

Iterates through self's particles, keeping only the ones with an initial $P_\zeta$ within the given span, discarding the rest.

The span must be in Normalized Units.

Parameters:

  • start (float) –

    The $P_\zeta$ starting value.

  • end (float) –

    The $P_\zeta$ ending value.

retain_energy(start: float, end: float) -> None

Iterates through self's particles, keeping only the ones with an initial energy within the given span, discarding the rest.

The span must be in Normalized Units.

Parameters:

  • start (float) –

    The energy starting value.

  • end (float) –

    The energy ending value.

retain_energy_pzeta_positions(positions: Iterable[EnergyPzetaPosition])

Iterates through self’s particles, keeping only the ones with an EnergyPzetaPosition that matches an element of positions.

Parameters:

retain_orbit_types(orbit_types: Iterable[OrbitType])

Iterates through self’s particles, keeping only the ones with an OrbitType that matches an element of orbit_types.

Parameters:

__getitem__(index: int) -> Particle

Returns a copy of the index-th particle.

__len__() -> int

Returns the particle count.

plot_qkinetic_pzeta(machine: Machine, **kwargs: Any)

Wrapper around dexter.plot_qkinetic_pzeta.

Parameters:

plot_qkinetic_energy(machine: Machine, **kwargs: Any)

Wrapper around dexter.plot_qkinetic_energy.

Parameters:

plot_pzeta_poincare(machine: Machine, intersect_params: IntersectParams, **kwargs: Any)

Wrapper around dexter.plot_pzeta_poincare.

Parameters:

plot_rz_poincare(machine: Machine, intersect_params: IntersectParams, **kwargs: Any)

Wrapper around dexter.plot_rz_poincare.

Parameters: