Grids
FlowGeometries.Grids.AbstractCurvilinearGrid — Type
AbstractCurvilinearGrid{G,T} <: AbstractGrid{G,T}Curvilinear grids. Default: CurvilinearGrid.
FlowGeometries.Grids.AbstractEmbedding — Type
AbstractEmbeddingHow a grid's cell centres sit in the Euclidean space an index searches, and therefore what a physical radius means there. A type, for the reason stencils are: the conversion is applied once per query, so a runtime tag would leave it unresolved and put a branch — and a boxed radius — in the hot path.
FlowGeometries.Grids.AbstractGrid — Type
AbstractGrid{G<:AbstractGeometry, T<:AbstractFloat}Supertype for all grid architectures.
FlowGeometries.Grids.AbstractStructuredGrid — Type
AbstractStructuredGrid{G,T} <: AbstractGrid{G,T}Rectilinear grids. Default: StructuredGrid.
FlowGeometries.Grids.AbstractTopology — Type
AbstractTopologyHow a coordinate direction closes: Periodic or Bounded.
Carried in the grid's type, so isperiodic is a compile-time answer and callers can dispatch on it. The cell measure depends on it — a wrapped boundary cell has a width a bounded one does not — so it is part of what the grid is, not a flag attached to it.
FlowGeometries.Grids.AbstractUnstructuredGrid — Type
AbstractUnstructuredGrid{G,T} <: AbstractGrid{G,T}Unstructured / node grids. Default: UnstructuredGrid.
FlowGeometries.Grids.AllActive — Type
AllActive(size)The mask of a grid where every cell participates, stored as its size alone. getindex is a constant the compiler can fold, and count is length without a scan.
FlowGeometries.Grids.ArcEmbedding — Type
ArcEmbedding(R)Points on the reference sphere of radius R, where the metric is the great-circle arc. A radius has to be converted to the chord it subtends.
FlowGeometries.Grids.AxisStats — Type
AxisStatsEverything about one axis that does not depend on the query, reduced once when the grid is built: gaps, span, and whether the axis type proves constant spacing. Each of these is otherwise an O(N_d) scan — or a dynamic lookup, since the coordinate tuple is heterogeneous — for an answer that cannot change over the grid's life.
FlowGeometries.Grids.Bounded — Type
Bounded()A direction that ends: its first and last cells each have one neighbour rather than two.
FlowGeometries.Grids.CartesianEmbedding — Type
CartesianEmbedding()The coordinates themselves, replicated at the periodic images. A radius passes through unchanged.
FlowGeometries.Grids.CellListIndex — Type
CellListIndexA uniform-bin spatial index over the embedded cell centres: points are bucketed by which bin of side h they fall in, and a query visits the bins its ball can reach.
Three properties distinguish it from a tree, and all three are why it is the one that runs on a device:
- it is arrays only — bin offsets and point ids — so
Adaptmoves it like any other field; - every point lands in exactly one bin, because periodicity wraps the bin coordinate rather than replicating the point, so a query emits each cell once and needs no candidate buffer to deduplicate into. That is what lets
fold_candidatesbe a fold rather than a list; - bins are hashed into
O(n)buckets, so the memory does not depend onh. A sphere binned at 100 km would otherwise need(2R/h)³ ≈ 2×10⁶mostly empty cells, and far more ashshrinks.
Build it for the radius you intend to query at: h is that radius, so a query touches 3ᴰ bins. A much larger radius still works and costs (2⌈r/h⌉+1)ᴰ bins.
FlowGeometries.Grids.ChordEmbedding — Type
ChordEmbedding()The embedded distance already is the metric, or a lower bound on it: (λ, φ, r) on a sphere, where the metric is the 3-D chord, and geodetic coordinates on a spheroid, where the ECEF chord is at most the geodesic. A radius passes through unchanged; under-approximating means the query over-returns, which is what an index is allowed to do.
FlowGeometries.Grids.CurvilinearGrid — Type
CurvilinearGrid{T, G, N, TP, C, MA, B}Curvilinear grid whose cell-center coordinates are N-dimensional arrays (e.g. an orthogonal curvilinear mesh). coordinates holds one N-D cell-center array per direction and corners the matching cell-vertex arrays, each one larger in every direction.
At N = 2 the cell measure is computed from those corners as the exact quadrilateral area rather than by a cell-center spacing approximation. In any other dimension the measure is the caller's to supply: the corner-area kernel is a genuinely 2-D algorithm, not a 2-D special case of an N-D one.
Type parameters
T: coordinate float type.G<:AbstractGeometry{T}is tied to it (a mismatched-eltype geometry is a type error, not a silent promotion) — henceTprecedesG(Julia forbids the forward referenceG<:AbstractGeometry{T}, Tneeded to keep the{G,T}order).N: number of coordinate directions.C: tuple type shared by the center and corner coordinate arrays — a mesh's own coordinate arrays are legitimately almost always the same concrete type.MA: array type of the derivedmeasurefield — independent ofC, since it is a computed field with no reason to match the coordinate arrays' storage type.B: array type of the activemask.
FlowGeometries.Grids.CurvilinearGrid — Method
CurvilinearGrid(geometry, coords..., mask; measure=nothing, corners=nothing, …)
CurvilinearGrid(geometry, coords..., measure, mask; corners=nothing, …)Build a curvilinear grid in any number of directions from one N-D cell-center coordinate array per direction. mask is the trailing array; a measure array before it is used verbatim (common when a dataset ships its own cell areas), and may equally be given as the measure keyword.
With no measure supplied, one is computed from the cell-vertex arrays — at N = 2 only, as the exact quadrilateral cell area. Spherical cells use the exact spherical-quadrilateral area, the spherical excess of the two triangles through the cell's four corner directions (see Geometry.spherical_excess); Cartesian cells the exact planar shoelace area. That kernel is a 2-D algorithm rather than the 2-D case of an N-D one, so in any other dimension the measure must be given.
Pass corners (a tuple of arrays, each one larger than the centers in every direction) for exact cell vertices, e.g. from the source mesh's own vertex grid; otherwise they are reconstructed from the centers per direction (see _centers_to_corners), which requires at least 2 cells across.
periodic is a Bool (applied to direction 1) or an NTuple{N,Bool}. When omitted, direction-1 periodicity is auto-detected the same way as StructuredGrid (full-circle spherical longitude), and every other direction is bounded.
FlowGeometries.Grids.Periodic — Type
Periodic()A direction that wraps: the last cell's neighbour is the first, one period away.
FlowGeometries.Grids.SeparableMeasure — Type
SeparableMeasure(factors)The cell measure of a rectilinear grid, stored as its per-axis factors rather than materialized.
Every measure this package supports on such a grid is a product of one factor per axis (see _measure_factors), so the ∏ Nᵈ entries carry only ∑ Nᵈ numbers. It is a genuine AbstractArray: indexing, broadcasting and collect behave as for the dense equivalent.
sum is specialized to ∏ᵈ ∑ᵢ wᵈᵢ, which is O(∑ Nᵈ) rather than O(∏ Nᵈ).
FlowGeometries.Grids.StructuredGrid — Type
StructuredGrid{G, T, N, TP, C, AT, BT}Rectilinear N-dimensional grid, for any N: one coordinate vector per direction (coordinates), an N-D cell measure (length in 1-D, area in 2-D, volume in 3-D, the N-D measure in general), an N-D active mask, per-direction topology, and the wrap period of each periodic direction.
TP is the per-direction AbstractTopology: singletons, so no storage, and readable from the type.
C is a heterogeneous NTuple{N,AbstractVector{T}} — each axis independently keeps whatever concrete AbstractVector{T} type it was constructed with (an Axes.UniformAxis, a plain Vector, a device array, or any other subtype); there is deliberately no shared vector type forcing the axes to match. This matters beyond storage: a UniformAxis's type is a compile-time proof of constant spacing that isuniform and spacing read without touching a coordinate, and forcing the axes into a common type would destroy it. One axis can be uniform while another is stretched.
FlowGeometries.Grids.StructuredGrid — Method
StructuredGrid(geometry, axes...; mask = nothing, topology = nothing, period = nothing)
StructuredGrid(geometry, axes..., mask; topology = nothing, period = nothing)Build a rectilinear grid in any number of dimensions from one coordinate vector per direction, pre-computing the separable cell measure from the geometry.
Each axis may independently be uniform or stretched, and keeps whichever it is in its own type — see isuniform. Axes are adapted to the geometry's float type T by _to_axis, which preserves uniformity and keeps a device-resident axis on its device.
For a SphericalGeometry the directions are (λ, φ, r, …): longitude, geographic latitude, and — in 3-D and above — the absolute radius from the origin, not an offset from a reference radius. Measures are the metric elements R·Δλ, R²cosφ·Δλ·Δφ and r²cosφ·Δλ·Δφ·Δr, with further directions entering as plain widths. A CartesianGeometry measure is the product of the per-direction widths.
Keywords
mask: anN-DBoolarray of active cells. Omit it (or passnothing) for an all-active grid, which stores only its size — seeAllActive. It may also be given positionally, after the axes.topology: per-direction closure. AcceptsPeriodic/Boundedinstances, a tuple of them, aBool, or a tuple ofBools; a single value or a short tuple applies to the leading directions and the rest areBounded. When omitted, direction 1 is auto-detected — on a spherical grid a longitude axis spanning the full circle isPeriodicand a regional span is not, in either storage order — and every other direction isBounded.period: the wrap length of each periodic direction. Omit it and the axis's own closure is used:2πfor spherical longitude, andextent + one spacingfor a Cartesian direction, which is exact for a uniform axis (n·|Δ|). A nonuniform periodic Cartesian direction has no well-defined closure to infer — its seam gap is not determined by its samples — soperiodis required there determine.
FlowGeometries.Grids.UnstructuredGrid — Type
UnstructuredGrid(geometry, x, y, mask; k=6, radius=nothing, areas=nothing)Build an UnstructuredGrid with REAL neighbor adjacency, via a k-d-tree nearest-neighbor query (NearestNeighbors.jl; brute-force O(N²) doesn't scale) — either the k nearest neighbors per node (default k=6), or every neighbor within a physical radius (pass radius to switch; mutually exclusive with k). For SphericalGeometry the tree is built on the 3D Cartesian embedding of the nodes (nearest-by-chord-distance is exactly nearest-by-great-circle-distance — exact, not an approximation).
areas: supply per-node cell areas explicitly (common for a real dataset that ships its own), or leave nothing to auto-compute exact Voronoi-cell areas from a Delaunay/convex-hull tessellation (DelaunayTriangulation.jl for Cartesian, Quickhull.jl for spherical — see _voronoi_areas).
periodic/period declare a wrapping domain, and the neighbor search honors it: a node near one face finds the nodes across the opposite face as genuine neighbors. Spherical longitude wraps by default; a Cartesian box is opt-in and needs its period.
FlowGeometries.Grids.UnstructuredGrid — Type
UnstructuredGrid{T, G, V, VA, B, VI}Unstructured mesh (e.g. radial data, finite volume, or triangular mesh) where coords are 1D vectors.
Type parameters
T: coordinate float type.G<:AbstractGeometry{T}is tied to it (a mismatched-eltype geometry is a type error, not a silent promotion) — henceTprecedesG(Julia forbids the forward referenceG<:AbstractGeometry{T}, Tneeded to keep the{G,T}order), matching the same conventionCurvilinearGriduses.C: tuple type of the per-direction node-coordinate vectors (a node set's own coordinate vectors are legitimately almost always the same concrete type).VA: vector type of the derivedmeasurefield — independent ofC, since it is frequently a computed field (Voronoi tessellation) with no reason to match the coordinate vectors' storage type.B: mask storage type.VN/VP: CSR neighbor-list and offset storage types, independent of each other. Their element type is a freeInteger, so a large mesh can carryInt32indices (half the memory and bandwidth ofInt64, and the width GPU kernels want) without needing a separate grid type.
Neighbor adjacency is stored CSR-style (flat neighbor_nbrs + neighbor_ptr offsets, node t owns neighbor_ptr[t]:neighbor_ptr[t+1]-1) rather than as a vector of per-node vectors — the data is immutable after construction, so there's no reason to pay for Nnodes separately-heap-allocated Vectors (cache-unfriendly pointer-chasing, one allocation per node) when one contiguous block (two allocations total) holds the same information.
FlowGeometries.Grids.UnstructuredGrid — Method
UnstructuredGrid(geometry, coords::Tuple, measure, mask[, neighbor_nbrs, neighbor_ptr]; periodic, period)
UnstructuredGrid(geometry, x, y, measure, mask[, neighbor_nbrs, neighbor_ptr]; periodic, period)Build a node grid in any number of directions from one coordinate vector per direction and CSR adjacency. Coordinates come as a tuple; the two-direction case may pass x, y positionally.
Omitting the CSR pair gives a grid with no adjacency — every node reports zero neighbours, which is enough for scattered-point spectral methods that never query it. Real-space neighbourhood operations need adjacency: build it (e.g. through the k-d-tree constructor below) and pass it in, or query by distance with Connectivity.neighbors_within, which reads coordinates rather than edges.
periodic declares that the enclosing domain wraps in a direction, and period gives the wrap length there. A scattered point set carries no axis to infer this from, so both are explicit — except on a sphere, where longitude wraps at 2π by construction and is the default. See isperiodic and period.
FlowGeometries.Discretization.apply_stencil! — Method
apply_stencil!(out, field, grid, indices, weights, dim; order=1, active_only=true,
masked=zero, policy=BlankMasked(), backend=nothing) -> outApply a stencil table built by Discretization.axis_stencils — the mask, the wrap period and the axis all come from grid, which is what the bare (indices, weights) form cannot do.
Because the axis comes too, any mask policy works here. The bare form has no axis to rebuild a window from at a mask edge, so it accepts only BlankMasked; a caller wanting ReduceInRun on a masked grid would otherwise have to give up the table and pay its rebuild on every call.
This is the form to use in a loop over fields: the table is the same for all of them, and building it is the one part of the work that does not depend on the field.
FlowGeometries.Discretization.apply_stencil! — Method
apply_stencil!(out, field, grid, dim; order=1, nodes=order+1, active_only=true, masked=zero) -> outDiscretization.apply_stencil! with the axis, wrap period and mask taken from grid, so a periodic direction wraps and an inactive cell is honoured without restating any of it.
Only a rectilinear direction has a 1-D axis to difference along, so this is a StructuredGrid method.
FlowGeometries.Discretization.axis_stencils — Method
axis_stencils(grid, dim; order=1, nodes=order+1) -> (indices, weights)Discretization.axis_stencils for direction dim of grid, taking that direction's axis and wrap period from the grid.
The table depends only on the grid, not on any field, so a caller differencing many fields along the same direction should build it once and hand it to the (out, field, grid, indices, weights, dim) form — the (out, field, grid, dim) form above rebuilds it on every call.
FlowGeometries.Discretization.derivative! — Method
derivative!(out, field, grid, indices, weights, dim; order=1, active_only=true, masked=zero,
policy=BlankMasked(), backend=nothing) -> outDiscretization.derivative! from a table the caller holds — the same reuse as the apply_stencil! form above, for the entry point a geometry-aware caller actually uses.
FlowGeometries.Geometry.distance — Method
Geometry.distance(grid, I, J) -> T
Geometry.distance(grid::UnstructuredGrid, i, j) -> TDistance between the centres of two cells under the grid's own geometry and topology: the coordinates are resolved from the indices, reduced to the nearest image in every periodic direction, and handed to the point form of Geometry.distance.
Across a periodic seam this is the short way round — one spacing between the first and last cell of a periodic direction, not the full extent, which is what the point form on the raw coordinates would give. A bounded direction contributes its plain coordinate difference. See displacement for the offset it was taken from.
FlowGeometries.Grids._axis_stats — Method
_axis_stats(x) -> AxisStatsFlowGeometries.Grids._build_kdtree_neighbors — Method
_build_kdtree_neighbors(geometry, coords::Tuple; k=6, radius=nothing) -> (nbrs, ptr)Extension hook: build CSR neighbor adjacency via a k-d tree. Overridden by a consumer NearestNeighbors extension (load using NearestNeighbors). radius, if given, switches to an all-neighbors-within-radius query (mutually exclusive with k); radius is in the grid's physical distance units (Geometry.distance — meters for SphericalGeometry, geometry's own units for CartesianGeometry), NOT a raw chord/angle.
FlowGeometries.Grids._cell_measure — Method
_cell_measure(geometry, axes, periods)The grid's stored measure: a SeparableMeasure wherever the metric factors, and a dense array where it genuinely does not.
FlowGeometries.Grids._centers_to_corners — Method
_centers_to_corners(C) -> KReconstruct a cell-vertex array one larger in every direction from the N-D cell-center array C, by averaging the (up to 2^N) surrounding centers with a linearly-extrapolated one-cell ghost ring, so the true domain-boundary vertices land a half-cell outside the outermost centers. Used only when the caller does not supply explicit corner arrays; requires at least 2 centers across every direction.
Unlike the corner-area kernel this is dimension-generic: it is a multilinear midpoint, and the ghost ring is a per-direction linear extension of it.
FlowGeometries.Grids._curvilinear_periods — Method
_curvilinear_periods(geometry, centers, topology, period) -> NTuple{N,T}Wrap length per periodic direction, zero where bounded. Spherical longitude closes at 2π; a Cartesian direction's comes from that direction's own line of centres.
FlowGeometries.Grids._curvilinear_topology — Method
_curvilinear_topology(geometry, x, topo) -> NTuple{2,AbstractTopology}Per-direction closure. Absent a caller's choice, direction 1 is auto-detected from the first row of centres read as a longitude-like axis, as StructuredGrid does.
FlowGeometries.Grids._ghost_points — Method
_ghost_points(pts, periodic, period) -> (all_pts, nghost)Replicate the D × N point matrix once per combination of periodic image offsets, originals in the first N columns. A wrapping domain is then searched by an ordinary Euclidean query over the images.
FlowGeometries.Grids._grid_points — Method
_grid_points(grid) -> (raw, D)Cell centres as a D × n matrix, in the grid's own coordinates.
FlowGeometries.Grids._max_gap — Method
_max_gap(x) -> maximum consecutive |gap|, or 0 if length(x) < 2Largest spacing anywhere on axis x, the counterpart of _min_gap. Together they bound how far an index window must reach to cover a given physical distance.
FlowGeometries.Grids._measure_factors — Method
_measure_factors(geometry, axes, periods) -> NTuple{N,AbstractVector}Per-axis factors whose outer product is the cell measure: measure[I...] == prod(w[d][I[d]]).
Every rectilinear cell measure this package supports is separable in exactly this way — Cartesian Δx·Δy·Δz, and spherical R²cosφ·Δλ·Δφ = (Δλ) · (R²cosφ·Δφ) or r²cosφ·Δλ·Δφ·Δr = (Δλ) · (cosφ·Δφ) · (r²·Δr). Building the measure as an outer product of these factors rather than by a nested scalar loop keeps the result in whatever array type the axes use, and makes the separability available to callers that can exploit it.
Degenerate (length-1) angular axes are handled by dropping the differential that no longer exists, so a zonal transect measures arc length R·cosφ·Δλ along its circle of latitude and a meridional one measures R·Δφ — not an area formula with a placeholder substituted in.
FlowGeometries.Grids._min_gap — Method
_min_gap(x) -> minimum consecutive |gap|, or Inf if length(x) < 2Smallest spacing found anywhere on axis x. Used to build a conservative (safe, never under-covering) search-radius bound for a genuinely nonuniform axis: since real distance checks still gate what's actually included, using the smallest gap anywhere can only widen the search window, never cause a missed in-range cell.
FlowGeometries.Grids._min_image — Method
_min_image(p0, pt, prd) -> NTuplept brought to the image nearest p0, per component, for each direction with a nonzero wrap length.
For an angular coordinate the geometry's own distance is already 2π-periodic and this changes nothing (it also keeps Vincenty inside its |Δλ| ≤ π regime); for a periodic Cartesian coordinate it is what makes the seam invisible. Per-component minimum image is the global minimum for a separable metric, which the Euclidean one is.
FlowGeometries.Grids._raw_coords — Method
_raw_coords(grid, I...) -> NTuplePositional coordinate values at indices I. Internal; prefer coords.
FlowGeometries.Grids._sep_extrema — Method
_sep_extrema(f, m) -> (lo, hi)Smallest and largest f(cell) over a SeparableMeasure, from the per-axis extremes.
A product's extremes are attained with every factor at one of its own endpoints, so all 2^N endpoint combinations are formed and the best taken. That is exact for factors of ANY sign — ∏ maximum alone would be wrong the moment a factor could go negative — and it costs O(∑ Nᵈ + 2^N) against the dense O(∏ Nᵈ).
FlowGeometries.Grids._shift_set — Method
_shift_set(periodic, period)Offsets to replicate a point set by: (0,) in a non-wrapping direction, (0, -L, +L) in a wrapping one. Zero first, so the originals occupy the first block of the replicated set.
FlowGeometries.Grids._to_axis — Method
_to_axis(T, x) -> AbstractVector{T}Adapt axis input x to element type T, keeping whatever is known about its spacing and never collapsing a provably uniform axis into a plain Vector.
An axis already of element type T is kept exactly as it is, whatever type it is. A caller's own range subtype, a StepRangeLen whose TwicePrecision internals they want, a BigFloat-backed range — all pass through untouched. Nothing needs converting to get the uniform fast paths: those dispatch on Axes.spacing_trait, which is UniformSpacing() for every AbstractRange, so the caller's own range takes them.
Conversion happens only where the element type must change, and there an arbitrary range subtype cannot generically be rebuilt at a new eltype. That case becomes an Axes.UniformAxis{T}, which is also how a Float32 axis stops carrying Float64 internals. To convert deliberately rather than by side effect, call Axes.uniform_axis.
Four methods, ordered so nothing is ambiguous (a StepRangeLen{T} is both an AbstractRange and an AbstractVector{T}, so the parameterized range form is needed to break that tie):
AbstractRange{T}/AbstractVector{T}: passthrough, zero cost, type preserved.AbstractRange(wrong eltype): rebuilt asUniformAxis{T}, still uniform and nowisbits.AbstractVector(wrong eltype): copied withsimilar, so a device-resident array stays in its own storage.
FlowGeometries.Grids._voronoi_areas — Method
_voronoi_areas(geometry, x, y) -> Vector{T}Extension hook: exact per-node Voronoi-cell area from a Delaunay/convex-hull tessellation of the node coordinates. Dispatched on the geometry type (each needs a different tessellation library): overridden for CartesianGeometry by a consumer DelaunayTriangulation extension (load using DelaunayTriangulation, planar Voronoi clipped to the point set's convex hull) and for SphericalGeometry by a consumer Quickhull extension (load using Quickhull, spherical Voronoi from the dual of the 3D convex hull of the unit-sphere embedding).
FlowGeometries.Grids._wrap_lengths — Method
_wrap_lengths(grid, Val(N)) -> NTuple{N,T}Wrap length per direction, zero where the direction is bounded, so _min_image leaves those components alone.
FlowGeometries.Grids._wrap_sign — Method
_wrap_sign(x) -> ±1+1 for an ascending axis and -1 for a descending one: the sign that turns a period magnitude into the wrapped neighbour's offset in index order. Defined in Axes — it is a property of the axis alone, and the discretization layer needs the same answer.
FlowGeometries.Grids.area — Method
area(grid, I...) -> Tmeasure under its 2-D name.
FlowGeometries.Grids.axis — Method
axis(grid::AbstractStructuredGrid, d::Integer) -> AbstractVectorDirection d's coordinate axis. Only rectilinear grids have axes; this is coordinates under the name that is exact for them.
FlowGeometries.Grids.axis_stats — Method
axis_stats(grid) -> NTuple{N,AxisStats}
axis_stats(grid, d) -> AxisStatsThe cached per-axis reductions. Homogeneous whatever the axis types are, so reading one with a runtime direction index stays type-stable.
FlowGeometries.Grids.bounds — Method
bounds(grid, d) -> (lo, hi)Smallest and largest coordinate along direction d, ordered lo ≤ hi regardless of whether the direction is stored ascending or descending. These are the extreme SAMPLE positions (cell centres), not the outer cell boundaries.
FlowGeometries.Grids.cell_list — Method
cell_list(grid; ball) -> CellListIndexBuild a CellListIndex over grid's cell centres, binned at side ball — the radius you mean to query at. Needs no external package.
FlowGeometries.Grids.cell_width — Method
cell_width(grid, d, i) -> TThe coordinate width of cell i along direction d: Discretization.cell_width on that direction's axis, with the grid's own wrap period. Non-negative whichever way the axis is stored.
This is the coordinate width, not the cell measure — on a sphere measure is R²cosφ·Δλ·Δφ and this is the Δλ or Δφ in it, which measure_factors does not expose separately because it folds the metric into the factor it multiplies.
FlowGeometries.Grids.cell_widths — Method
cell_widths(grid, d) -> AbstractVectorcell_width along the whole of direction d, as Discretization.cell_widths on its axis with the grid's own wrap period. A uniform direction gets an Axes.ConstantVector, so nothing is materialized.
FlowGeometries.Grids.coordinate_names — Method
coordinate_names(grid) -> NTuple{N,Symbol}The grid's coordinate names, from its geometry: (:x, :y[, :z]) or (:λ, :φ[, :r]).
FlowGeometries.Grids.coordinates — Method
coordinates(grid) -> NTuple{N,AbstractArray}
coordinates(grid, d::Integer) -> AbstractArrayThe grid's coordinate arrays, or just direction d's. Shape depends on the grid architecture: a StructuredGrid stores one 1-D axis vector per direction, a CurvilinearGrid one N-D array per direction, an UnstructuredGrid one value per node. Direction order matches Geometry.point_names — (x, y, z) for Cartesian, (λ, φ, r) for spherical.
See also axis (the rectilinear spelling), coords (a single point).
FlowGeometries.Grids.coords! — Method
coords!(out, grid, I...) -> outWrite positional coordinates into a preallocated AbstractVector (length(out) ≥ N).
FlowGeometries.Grids.coords — Method
coords(grid, I...) -> NamedTuplePoint at indices I, as a geometry-named NamedTuple:
- Cartesian:
(x=, y=)or(x=, y=, z=) - Spherical:
(λ=, φ=)or(λ=, φ=, r=)
See also coords!, coords(::Type, grid, I...).
FlowGeometries.Grids.coords — Method
coords(::Type{S}, grid, I...) -> SConstruct the point as type S — Tuple, NTuple{N,T}, NamedTuple, Vector{T}, or SVector{N,T}/MVector{N,T} when StaticArrays is loaded. See Geometry.build_point for how S is assembled.
FlowGeometries.Grids.corner_coords — Method
corner_coords(grid::CurvilinearGrid, I...) -> NamedTuple
corner_coords(S, grid::CurvilinearGrid, I...) -> SVertex I of the cell-vertex array, named by the geometry exactly as coords names cell centers.
FlowGeometries.Grids.corners — Method
corners(grid::CurvilinearGrid) -> NTuple{N,AbstractArray}
corners(grid::CurvilinearGrid, d::Integer) -> AbstractArrayThe cell-vertex coordinate arrays — one larger than coordinates in every direction, and in the same direction order.
FlowGeometries.Grids.displacement — Function
displacement(grid, I, J) -> NTuple{N,T}
displacement(grid::UnstructuredGrid, i, j) -> NTuple{N,T}The signed per-direction coordinate offset from cell I to cell J, reduced to the nearest image in every periodic direction — the offset Geometry.distance is taken from.
A coordinate quantity rather than a metric one, which is why it lives here while the distance itself extends Geometry.distance: across a periodic seam the two cells' stored coordinates differ by nearly a full period, and this reports the short way round instead.
FlowGeometries.Grids.embed_point — Function
embed_point(grid, p) -> NTupleOne coordinate tuple through the same transform embedded_points applies to the cell centres, so a query seeded by a point searches the space the index was built in.
FlowGeometries.Grids.embedded_points — Function
embedded_points(grid) -> (pts, nghost, embedding)The cell centres in the space an index searches, the number of periodic replications they carry, and the AbstractEmbedding saying what a radius means there.
One definition, so every index searches the same space as every other and as the k-d-tree construction path — the guarantee that an indexed query and a scan return the same cells rests on it.
FlowGeometries.Grids.embedded_radius — Method
embedded_radius(embedding, r) -> TA physical radius as a radius in the embedding.
FlowGeometries.Grids.extent — Method
extent(grid, d) -> Thi - lo from bounds: the span covered by direction d's samples. Zero for a singleton direction.
FlowGeometries.Grids.fold_candidates — Function
fold_candidates(f, acc, index, grid, I, r) -> accThread acc = f(acc, k) over every cell k the index reports near cell I, without building a list. A superset of the ball, each cell exactly once; the caller's exact distance gate decides membership.
A fold rather than a returned list is the whole point: it allocates nothing and needs no per-query buffer, which is what a kernel requires and what a tree cannot offer, since a tree walk has to deduplicate the periodic images it searches over.
FlowGeometries.Grids.fold_candidates_at — Method
fold_candidates_at(f, acc, index, q, r, scratch) -> accfold_candidates around an arbitrary point q, already in the index's embedding, rather than around a cell. A cell query is this one at the cell's own centre, so there is one traversal.
scratch is a candidate buffer for an index that has to materialize one — a tree does, since it must deduplicate the periodic images it searches over. A cell list folds directly and ignores it.
FlowGeometries.Grids.has_spatial_index — Method
has_spatial_index(grid) -> BoolWhether the k-d tree behind spatial_index can be built for this grid — false until the NearestNeighbors extension is loaded. Answers "is the tree available?" without calling spatial_index speculatively and catching its error.
This is not a test for whether a grid can be indexed at all: cell_list needs no extension and is what the sweeps build.
FlowGeometries.Grids.index_within! — Method
index_within!(buffer, index, grid, I, r) -> candidate cell indices
index_within(index, grid, I, r) -> candidate cell indicesExtension hook: the cells an index reports near I, as linear indices. It must return a superset of the cells within r; the caller applies the exact distance gate, so over-returning is safe and under-returning is not.
index_within! overwrites and returns buffer, which is how a sweep over many cells avoids one heap allocation per query — nothing at all, against 480 bytes on a small ball and 6.1 KB on a 310-candidate one. index_within is the same query into a fresh vector.
FlowGeometries.Grids.isperiodic — Method
isperiodic(grid, d) -> BoolWhether coordinate direction d wraps. See topology for the type-level form and period for the wrap length.
FlowGeometries.Grids.isuniform — Method
isuniform(grid, d) -> Bool
isuniform(grid) -> BoolWhether coordinate direction d has constant spacing known from its TYPE (all directions, for the no-d form). This is the compile-time answer, so it can select a fast path by dispatch rather than by a runtime scan — see Axes.spacing_trait for the trait it reads and No code path inspects coordinate VALUES to decide this; the answer comes from the type alone.
A curvilinear or unstructured grid is never uniform: its coordinates are per-cell fields, not axes.
FlowGeometries.Grids.local_spacing — Method
local_spacing(grid, d, i) -> (h_m, h_p)The one-sided coordinate gaps around index i along direction d: Discretization.local_spacing on that direction's axis, with the wrap period taken from the grid, so a periodic seam is right without the caller supplying it.
Signed, so a descending axis reports negative gaps — see the axis-level form for why, and cell_width for the non-negative width built from them. Allocation-free, so this is the per-point form to call inside a loop assembling a finite-difference operator.
FlowGeometries.Grids.locate — Function
locate(grid, p) -> cell index
locate(grid, p; active_only=false, topology, scratch) -> cell indexThe cell of grid that p belongs to, as an NTuple of indices on a rectilinear or curvilinear grid and a node number on an UnstructuredGrid. p is a coordinate tuple in the grid's own coordinates.
On a StructuredGrid this is Discretization.locate per direction, so the answer is the cell whose faces bracket p — an O(1) lookup on a uniform axis and a bisection otherwise, with a periodic direction wrapped first. A direction p lies outside reports 0 for that direction.
Elsewhere there are no axes to bracket along and it is the nearest cell centre, which is exactly the containing cell for a node set, whose cells are the Voronoi regions of its nodes. On a curvilinear grid the two can differ where cells are strongly sheared, so read it as nearest-centre rather than point-in-quadrilateral. That form takes the keywords: topology carrying an index — cell_list — makes it a bin lookup rather than a scan, scratch is a Connectivity.ball_scratch buffer, and active_only restricts the answer to unmasked cells (false here, unlike the ball queries, since the cell a point falls in is a question about the grid rather than about the active region).
FlowGeometries.Grids.mask — Method
isactive(grid, I...) -> BoolWhether cell/node I participates (false = masked out).
FlowGeometries.Grids.maximum_spacing — Method
maximum_spacing(grid, d) -> TLargest gap between consecutive samples along direction d, the counterpart of minimum_spacing. A direction of fewer than two samples reports 0, the identity for max.
FlowGeometries.Grids.measure — Method
measure(grid, I...) -> TCell measure at index I: length in 1-D, area in 2-D, volume in 3-D, or the node's control-volume size on an unstructured grid. area is the 2-D spelling of the same quantity.
FlowGeometries.Grids.measure_array — Method
measure_array(grid) -> ArrayThe cell measure materialized densely. This is ∏ Nᵈ values — only ask for it when a dense array is genuinely required; measure already indexes and broadcasts.
FlowGeometries.Grids.measure_factors — Method
measure_factors(grid) -> NTuple{N,AbstractVector} or nothingThe grid's per-axis measure factors when it has them, else nothing. Callers that can exploit separability (a zonal mean weights by one factor only, a global integral is a product of sums) can avoid touching ∏ Nᵈ values at all.
FlowGeometries.Grids.minimum_spacing — Method
minimum_spacing(grid, d) -> TSmallest gap between consecutive samples along direction d, as a non-negative magnitude. O(1) when the direction is isuniform and O(N_d) otherwise. With maximum_spacing it bounds how far an index window must reach to cover a given physical distance, which is what a neighbourhood-by-distance query needs on a stretched axis. They are also the exact test of whether a stretched axis happens to be equally spaced: its gaps are identical when the two are equal.
A direction of fewer than two samples has no gap, and reports Inf — the identity for min.
FlowGeometries.Grids.neighbor_nbrs — Method
neighbor_nbrs(grid::UnstructuredGrid) -> AbstractVector{<:Integer}
neighbor_ptr(grid::UnstructuredGrid) -> AbstractVector{<:Integer}The CSR adjacency arrays: the flat neighbour indices, and the per-node offsets into them.
FlowGeometries.Grids.neighbors — Method
neighbors(grid::UnstructuredGrid, idx::Integer) -> AbstractVector{<:Integer}Neighbor node indices of node idx, as a zero-copy view into the CSR-flattened adjacency storage.
FlowGeometries.Grids.origin — Method
origin(grid, d) -> TThe first coordinate along direction d.
FlowGeometries.Grids.period — Method
period(grid, d) -> TWrap length of coordinate direction d, meaningful only where isperiodic holds.
FlowGeometries.Grids.periodic_flags — Method
periodic_flags(grid) -> NTuple{N,Bool}topology as one Bool per direction. Const-folds, and unlike indexing the heterogeneous topology tuple it stays type-stable under a runtime direction.
FlowGeometries.Grids.rotate — Method
rotate(grid::StructuredGrid, rot) -> CurvilinearGrid
unrotate(grid::StructuredGrid, rot) -> CurvilinearGridThe same mesh with its coordinates expressed in the other frame of Geometry.PoleRotation rot — unrotate being the usual direction, taking a rotated-pole grid's rectilinear (λ′, φ′) axes to the geographic coordinates of each cell.
The result is curvilinear because that is what it is: a rotated lat–lon mesh is logically rectangular and geometrically warped, and only its own frame's axes are separable.
Two things carry over rather than being recomputed. The cell measure is exact, because a rotation is an isometry of the sphere — recomputing it from the rotated corners would only add roundoff. The index topology is too: it is the same mesh with the same neighbours, so a direction that wrapped still wraps. Longitude remains an angle mod 2π in either frame, so the wrap length is unchanged.
FlowGeometries.Grids.size_tuple — Method
size_tuple(grid) -> NTuple{N,Int}size(grid), kept as a named function for call sites that read better spelled out.
FlowGeometries.Grids.spacing — Method
spacing(grid, d) -> TThe constant spacing of coordinate direction d, available without reading any coordinate. Signed, so a descending axis reports a negative spacing. Raises for a direction that is not isuniform — for a nonuniform one use minimum_spacing / maximum_spacing for its range of gaps, local_spacing for the gaps at one index, or cell_width / cell_widths for the width of a cell.
FlowGeometries.Grids.spatial_index — Method
spatial_index(grid) -> opaque indexExtension hook: a range-queryable spatial index over the grid's cell centres, overridden by the NearestNeighbors extension. Paired with index_within!.
FlowGeometries.Grids.topology — Method
topology(grid) -> NTuple{N,AbstractTopology}
topology(grid, d) -> AbstractTopologyThe grid's per-direction topology. Singletons, so this occupies no storage.