Meshes
Aether.Meshes.Mesh — Type
struct Mesh{FT, C<:Aether.Meshes.AbstractCoordinates, Arch, Comm, BG}Mesh(architecture, FT = Float64; size, extent = nothing,
x1 = nothing, x2 = nothing, x3 = nothing,
cells_per_block = size, nghost = 2,
coordinates = CartesianCoordinates(),
communicator = nothing)Host-side mesh: domain geometry and its decomposition into equal-size blocks. Geometry and decomposition only — no field arrays, no time, no physics. Never passed to kernels whole; kernels receive block_geometry plus the index packs.
Keyword arguments:
size: global interior cell counts(nx1, nx2, nx3). Singleton directions (nx == 1) must be trailing: 1D runs use x1, 2D runs use x1–x2.extent: domain lengths(L1, L2, L3), giving bounds[0, L]per direction. Mutually exclusive withx1/x2/x3.x1,x2,x3: explicit(min, max)bounds per direction. All three are required whenextentis not given, singleton directions included (a 2D run still has an x3 thickness).cells_per_block: interior cells per block; must dividesizeevenly, be at leastmax(nghost, 2)in active directions (a smaller block cannot serve its neighbor's ghost layer), and be1in singleton directions. Defaults tosize(a single block).nghost: ghost cells per side in active directions (≥ 1).coordinates: the coordinate system (CartesianCoordinates).communicator:nothingfor a serial run (the default; the single process owns every block), or anMPI.Comm(with MPI.jl loaded) to distribute the blocks over its ranks. Works on CPU and GPU architectures alike.
Blocks are identified by their global id gid ∈ 1:nblocks1*nblocks2*nblocks3, assigned in Z-order (Morton order) of the logical locations (lx1, lx2, lx3) — zorder, realized by block_index / block_location. The Z-ordered gid list is dealt to ranks in contiguous slices (distribute_blocks); every rank computes the same global tables deterministically, so construction needs no communication. Each rank stores geometry only for its owned_gids, and the kernel-facing block slot is mb = gid - first(owned_gids) + 1.
Block bounds are computed from the global domain ends with face_position, so neighboring blocks share bitwise-identical face coordinates, and the cell spacings are bitwise-identical across blocks.
architecture::Any: architecture the mesh's device data lives oncoordinates::Aether.Meshes.AbstractCoordinates: coordinate system, dispatched on by every geometry accessorcommunicator::Any:nothingfor serial runs, theMPI.Commfor distributed runsrank::Int64: this process's rank in the communicator (0 for serial)nranks::Int64: number of ranks in the communicator (1 for serial)indices::Aether.Meshes.GridIndices: global-domain cell counts and nominal index ranges (no global array exists)block_indices::Aether.Meshes.GridIndices: per-block cell counts and index ranges; identical for every blockx1min::Any: lower x1 domain boundx1max::Any: upper x1 domain boundx2min::Any: lower x2 domain boundx2max::Any: upper x2 domain boundx3min::Any: lower x3 domain boundx3max::Any: upper x3 domain boundnblocks1::Int64: number of blocks along x1nblocks2::Int64: number of blocks along x2nblocks3::Int64: number of blocks along x3block_locations::Vector{Tuple{Int64, Int64, Int64}}: host table: logical location(lx1, lx2, lx3)of every block, Z-ordered by gidblock_ranks::Vector{Int64}: host table: owning rank of every block, indexed by gidowned_gids::UnitRange{Int64}: gids of the blocks owned by this rank (a contiguous Z-order slice)nblocks::Int64: number of blocks owned by this rank — the kernel-facing block countblock_geometry::Any: device vector ofBlockGeometryfor the owned blocks, indexed by slotmbin kernels
using Aether
Mesh(CPU(); size = (8, 8, 8), extent = (1, 1, 1), cells_per_block = (4, 8, 8))
# output
Mesh{Float64} on CPU()
├── coordinates: CartesianCoordinates()
├── domain: [0.0, 1.0] × [0.0, 1.0] × [0.0, 1.0]
├── cells: 8 × 8 × 8 interior, nghost = 2
└── blocks: 2 × 1 × 1 = 2 of 4 × 8 × 8 cellsAether.Meshes.CartesianCoordinates — Type
struct CartesianCoordinates <: Aether.Meshes.AbstractCoordinatesCartesianCoordinates()Uniform Cartesian coordinates. All geometry accessors fold to compile-time constant expressions of the cell spacings.
using Aether
CartesianCoordinates()
# output
CartesianCoordinates()Aether.Meshes.CylindricalCoordinates — Type
struct CylindricalCoordinates <: Aether.Meshes.AbstractCoordinatesCylindricalCoordinates()Uniform cylindrical coordinates $(R, \varphi, z)$ in the slots $(x_1, x_2, x_3)$: x1 is the cylindrical radius R ≥ 0, x2 the azimuth φ, x3 the height z. Spacings are uniform in each coordinate; the metric lives entirely in the geometry accessors — the x1-face area is R dφ dz, the cell volume is ½(R₊² - R₋²) dφ dz, the x2-edge length is R dφ, and the cell center is the volume-weighted radius. Hydrodynamics and MHD alike: the curvilinear momentum source terms are attached automatically by Simulation, and constrained transport carries the metric through its edge lengths and face areas.
using Aether
CylindricalCoordinates()
# output
CylindricalCoordinates()Aether.Meshes.SphericalPolarCoordinates — Type
struct SphericalPolarCoordinates <: Aether.Meshes.AbstractCoordinatesSphericalPolarCoordinates()Uniform spherical-polar coordinates $(r, \theta, \varphi)$ in the slots $(x_1, x_2, x_3)$: x1 is the spherical radius r ≥ 0, x2 the polar angle θ ∈ [0, π], x3 the azimuth φ. Spacings are uniform in each coordinate; the metric lives entirely in the geometry accessors — the x1-face area is r² sinθ dθ dφ, the cell volume is ⅓(r₊³ - r₋³)(cosθ₋ - cosθ₊) dφ, the x3-edge length is r sinθ dφ, and the cell center is the volume-weighted radius and polar angle. Hydrodynamics and MHD alike: the curvilinear momentum source terms are attached automatically by Simulation, and constrained transport carries the metric through its edge lengths and face areas. A domain reaching the polar axis (θ = 0, π) takes PolarBC on the corresponding x2 face — connectivity through the pole for general flows and fields — on a full periodic azimuth or an axisymmetric (nx3 = 1) mesh.
using Aether
SphericalPolarCoordinates()
# output
SphericalPolarCoordinates()Aether.Meshes.x1v — Function
x1v(
_::CartesianCoordinates,
i,
geometry::Aether.Meshes.BlockGeometry,
indices::Aether.Meshes.GridIndices
) -> Any
Position of the center of cell i in the block described by geometry — center_position applied to the block bounds. indices must be the mesh's block_indices.
using Aether
mesh = Mesh(CPU(); size = (4, 1, 1), extent = (1, 1, 1))
geometry = mesh.block_geometry[1]
Meshes.x1v(CartesianCoordinates(), mesh.block_indices.is, geometry, mesh.block_indices)
# output
0.125Aether.Meshes.x2v — Function
x2v(
_::CartesianCoordinates,
j,
geometry::Aether.Meshes.BlockGeometry,
indices::Aether.Meshes.GridIndices
) -> Any
Position of the center of cell j in x2; see x1v.
Aether.Meshes.x3v — Function
x3v(
_::CartesianCoordinates,
k,
geometry::Aether.Meshes.BlockGeometry,
indices::Aether.Meshes.GridIndices
) -> Any
Position of the center of cell k in x3; see x1v.
Aether.Meshes.cell_volume — Function
cell_volume(
_::CartesianCoordinates,
i,
j,
k,
geometry::Aether.Meshes.BlockGeometry,
indices::Aether.Meshes.GridIndices
) -> Any
Volume of cell (i, j, k). Uniform Cartesian: dx1 * dx2 * dx3.
using Aether
mesh = Mesh(CPU(); size = (4, 1, 1), extent = (1, 1, 1))
geometry = mesh.block_geometry[1]
Meshes.cell_volume(CartesianCoordinates(), mesh.block_indices.is, 1, 1, geometry, mesh.block_indices)
# output
0.25