Momentum and pitch grids

src/grids/momentum.jl

Public

Runes2P.MomentumGrid — Type
MomentumGrid{T}

Momentum grid in spherical coordinates (p, ξ), with p the momentum normalized to mₑc and ξ = cos θ the pitch. Cells are defined by their faces; cell centres are face midpoints.

source
Runes2P.biuniform_p_faces — Method
biuniform_p_faces(cell_count, lower_cell_count, p_min, p_separation, p_max)

Faces of a two-region uniform momentum grid: lower_cell_count cells on [p_min, p_separation] and cell_count - lower_cell_count cells on [p_separation, p_max], with the momenta in units of mₑc (DREAM PBiUniformGridGenerator).

source
Runes2P.biuniform_theta_xi_faces — Method
biuniform_theta_xi_faces(cell_count, lower_cell_count, theta_separation)

Faces of a two-region pitch grid, uniform in θ = acos(ξ): lower_cell_count cells on θ ∈ [0, theta_separation] with theta_separation in rad (near ξ = 1) and cell_count - lower_cell_count cells on [theta_separation, π], returned as ξ = cos θ faces (DREAM TYPE_BIUNIFORM_THETA, XiBiUniformThetaGridGenerator). Refines towards ξ = 1, where runaway electrons concentrate.

source
Runes2P.cell_count — Method
cell_count(grid::MomentumGrid)
cell_count(grid::KineticGrid, ir)
cell_count(grid::KineticGrid)

Number of (p, ξ) cells: of a MomentumGrid, or of the momentum grid of a KineticGrid at radius ir. Without ir, the sum over all radii, which is the length of a distribution of the kinetic grid.

source
Runes2P.momentum_cell_count — Method
momentum_cell_count(grid::MomentumGrid)
momentum_cell_count(grid::KineticGrid, ir)
momentum_cell_count(grid::KineticGrid)

Number of cells in p: of a MomentumGrid, or of the momentum grid of a KineticGrid at radius ir. Without ir, the cell counts must be the same at all radii, and an ArgumentError is thrown otherwise.

source
Runes2P.pitch_cell_count — Method
pitch_cell_count(grid::MomentumGrid)
pitch_cell_count(grid::KineticGrid, ir)
pitch_cell_count(grid::KineticGrid)

Number of cells in ξ: of a MomentumGrid, or of the momentum grid of a KineticGrid at radius ir. Without ir, the cell counts must be the same at all radii, and an ArgumentError is thrown otherwise.

source
Runes2P.tanh_p_faces — Method
tanh_p_faces(cell_count, lower_cell_count, p_min, p_separation, p_max;
             transition_cells=cell_count/20)

Faces of a smoothly stretched momentum grid: the biuniform grid of biuniform_p_faces with its spacing jump at p_separation replaced by a tanh transition over about transition_cells cells above it. In the continuous cell index x the spacing is

h(x) = h₁ + (h₂ - h₁) (1 + tanh((x - n₁ - 3w)/w))/2,   n₁ = lower_cell_count, w = transition_cells,

and face k sits at p_min + ∫₀ᵏ h, with h₁ and h₂ chosen so that face n₁ is at p_separation and the last face at p_max (the momenta in units of mₑc). The transition is centred three widths above the separation, so up to p_separation the spacing exceeds h₁ by at most 0.25% of h₂ - h₁ (the bulk keeps its resolution) and it grows over the next few w cells; the upper region needs at least 5w cells. transition_cells = 0 gives the biuniform grid exactly, and the faces approach it linearly in w. The default width, a twentieth of the cells, grows with the cell count, which keeps the grid map smooth under refinement; with a fixed width in cells the max-norm order stalls near 1.5 in the manufactured-solution test. Not available in DREAM, which has uniform, biuniform and custom momentum grids; a DREAM comparison passes these faces as a custom grid.

The biuniform grid converges at second order despite its jump: the local truncation error is O(1) at the jump cell only, and the global error stays second order (test/test_manufactured_solutions.jl). This grid keeps the truncation error second order everywhere when transition_cells grows with the cell count. Where the solution still varies above p_separation, its transition cells, finer than the biuniform grid's upper cells, make it more accurate at equal cell count: 3.5 times on the manufactured solution, 2 times on DREAM's avalanche/generateCylindrical.py with upwind, and no gain on DREAM's runaway/basic.py split at p = 0.1 with the central scheme.

source
Runes2P.uniform_p_faces — Method
uniform_p_faces(cell_count, p_min, p_max)

Faces of a uniform momentum grid with cell_count cells, from p_min to p_max in units of mₑc.

source

src/grids/pitch_overlap.jl

Public

Runes2P.PitchOverlap — Type
PitchOverlap{T}

Overlap of two pitch grids on the same interval, called the left and the right grid (the two sides of a face: the inner and the outer radius, or the lower and the upper momentum grid). The faces of both grids together cut the interval into overlap cells. Overlap cell s lies in exactly one cell of each grid, left_cells[s] and right_cells[s], and the overlap cells of a grid cell j are the contiguous range left_ranges[j] (or right_ranges[j]).

left_fractions[s] is the share of the left cell's measure that lies in overlap cell s, and right_fractions[s] the share of the right cell's. The measure of an interval is its width by default, which is the phase-space volume where 𝒱' does not depend on ξ (cylindrical geometry). measure(a, b) replaces it for a weight that varies with ξ (∫ 𝒱' dξ in toroidal geometry).

A quantity that is one number per overlap cell (a flux through the face, the content moved by a remap) and is given to both sides conserves the total: the left cell j receives Σ_s left_fractions[s] q_s over left_ranges[j] per unit of its measure, the right cell the same with its fractions.

Faces of the two grids closer than 1e-12 of the interval count as one face (the left grid's value is kept), so that faces equal up to round-off, such as cos(π/2) and 0, leave no sliver. The fractions of a cell then sum to 1 within that tolerance, and to round-off otherwise.

source
Runes2P.PitchOverlap — Method
PitchOverlap(left_xi_faces, right_xi_faces; measure=(a, b) -> b - a)
PitchOverlap(left::MomentumGrid, right::MomentumGrid; measure)

Overlap of the pitch grids with the given faces. Both must cover the same interval.

source
Runes2P.has_identical_grids — Method
has_identical_grids(overlap)

Whether the two pitch grids have the same faces, so that every overlap cell is a cell of both.

source
Runes2P.overlap_cell_count — Method
overlap_cell_count(overlap)

Number of overlap cells: between the larger of the two pitch cell counts (nested grids) and their sum minus one (no common interior face).

source
Runes2P.remap_to_left! — Method
remap_to_left!(f_left, overlap, f_right)

Conservative remap of cell averages from the right pitch grid of overlap to the left one, the reverse of remap_to_right!, with the same properties.

source
Runes2P.remap_to_right! — Method
remap_to_right!(f_right, overlap, f_left)

Conservative remap of cell averages from the left pitch grid of overlap to the right one (remap_to_left! is the reverse), for a vector over the pitch cells or a (p cells, ξ cells) matrix (each momentum cell on its own). The source is taken as constant in each of its cells, and the new cell average is the measure-weighted mean of the source over the cell:

\[f^\mathrm{right}_j = \sum_{s \in \mathtt{right\_ranges}[j]} \mathtt{right\_fractions}[s]\, f^\mathrm{left}_{\mathtt{left\_cells}[s]}.\]

The content Σ_j measure_j f_j is conserved to round-off, a constant stays a constant, the result lies between the smallest and the largest source value (so a non-negative source stays non-negative), and the remap between identical grids is a copy. First order in the cell width: a remap to another grid and back smooths the source. Allocation free. Does not add to the target, it overwrites it.

source