_mesh

_mesh#

Mesh management utilities for PSI staggered grid data.

MAS and POT3D solve their equations on staggered (Yee-type) spherical grids \((r, \theta, \varphi)\). Different physical quantities are located at different positions within each grid cell so that discrete differential operators (curl, divergence) are exactly satisfied at the discrete level. Each axis of a multi-dimensional output array is independently classified as either:

  • Main mesh — quantity sampled at the cell-center nodes.

  • Half mesh — quantity sampled at the face or edge midpoint, displaced by half a grid spacing along that axis.

Mesh codes#

A mesh code encodes the staggering of every axis in a single compact integer. Each binary bit indicates, per axis, whether the data lives on the half mesh (1) or the main mesh (0). With PSI’s Fortran column-major HDF convention the most-significant bit maps to the last numpy axis (the radial \(r\) direction), so a three-bit code reads \((r, \theta, \varphi)\) MSB → LSB:

Code

\(r\)

\(\theta\)

\(\varphi\)

Typical quantities

0b100

half

main

main

\(B_r\) (MAS)

0b010

main

half

main

\(B_\theta\) (MAS)

0b001

main

main

half

\(B_\varphi\) (MAS)

0b011

main

half

half

\(v_r\), \(J_r\) (MAS); \(B_r\) (POT3D)

0b101

half

main

half

\(v_\theta\), \(J_\theta\) (MAS); \(B_\theta\) (POT3D)

0b110

half

half

main

\(v_\varphi\), \(J_\varphi\) (MAS); \(B_\varphi\) (POT3D)

0b111

half

half

half

scalars: \(T\), \(\rho\), \(p\), …

0b000

main

main

main

all-main; result of remeshing every axis

Accepted input forms for a mesh code are described by MeshCodeType (integer, string shorthand 'main'/'half', or per-axis sequence). The memory-order convention is described by ArrayOrdering.

Public API#

Mesh

Enum with two members — MAIN and HALF — representing the two mesh positions.

MeshCodeType

Type alias for the three accepted forms of a mesh stagger specification.

ArrayOrdering

Type alias for the memory-order string ('F' or 'C') accepted by remesh_array().

remesh_array()

Shift an array from one mesh stagger to another by averaging adjacent elements along each axis that needs to move from half mesh to main mesh.

Examples#

Convert a radial magnetic-field array (half-mesh in \(r\), the last numpy axis) to the all-main mesh:

>>> import numpy as np
>>> from psi_io._mesh import remesh_array
>>> br = np.ones((128, 64, 57))   # shape (Nφ, Nθ, Nr); Nr is half-mesh size
>>> br_main = remesh_array(br, imesh=0b100, omesh='main')
>>> br_main.shape
(128, 64, 56)

Remesh a scalar quantity (all-half, 0b111) to all-main:

>>> rho = np.ones((128, 64, 57))
>>> remesh_array(rho, imesh=0b111, omesh='main').shape
(127, 63, 56)

Classes

Mesh(*values)

Enum identifying the stagger position of one array axis.

Functions

remesh_array(data, imesh[, omesh, order])

Shift an array from one mesh stagger to another.

Attributes

ArrayOrdering

Type alias for the memory-order convention accepted by remesh_array().

MeshCodeType

Type alias for mesh stagger specifications accepted by remesh_array().