For MOLE 2.0, we are exploring implementing structs to store key information about the grid and boundary conditions. This simplifies calls to the operators, but also simplifies request by the user.
Many of the grid objects are generated automatically, based on an initial call to the grid. The grid struct stores all given and derived information for the operators. Below is a sample of what the grid struct could be. It is a work in progress.
MOLE Grid Struct Reference (MATLAB/Octave)
1. Overview
The grid struct is the central data object passed to all MOLE mimetic operators
(grad, div, lap, curl, nodal, addScalarBC, interpol). It bundles
everything an operator needs to know about the physical domain: how many cells
exist in each direction, how large each cell is, where nodes/faces/cell-centers
sit in physical space, and what type of boundary treatment is expected. (It is expected that interpol will fill in fields in the grid struct, like facesToNode, NodesToFaces, etc.).
Two public functions build and validate the struct:
grid = makeGrid('m', 64, 'n', 64, 'dx', 1/64, 'dy', 1/64, 'bc', bc)
grid = validateGrid(grid) % explicit re-validation / enrichment (fill-in-missing)
makeGrid accepts either name-value pairs or a partially filled struct and
always calls validateGrid before returning. validateGrid infers missing
metadata fields, normalises boundary coefficients, and populates all coordinate
arrays. Callers should treat the returned struct as immutable: operators read
from it but never write to it.
2. Core Fields
2.1 dim — dimensionality
| Value |
Meaning |
1 |
1-D problem (x only) |
2 |
2-D problem (x, y) |
3 |
3-D problem (x, y, z) |
Inferred automatically from whichever size fields are present:
o or dz present → dim = 3
n or dy present → dim = 2
- otherwise →
dim = 1
2.2 type — grid topology
| Value |
Meaning |
'uniform' |
Constant spacing (dx/dy/dz scalars); no periodic axes |
'periodic' |
Constant spacing; one or more axes are periodic (set by bc?) |
'curvilinear' |
Physical coordinates supplied by the caller as node arrays |
Inferred automatically:
X, Y, or Z fields present at struct root → 'curvilinear'
x, y, or z fields (lowercase) present → 'nonuniform' (reserved, not yet active)
- otherwise →
'uniform' or 'periodic' depending on boundary coefficients
2.3 Cell counts: m, n, o
| Field |
Axis |
Required for |
m |
x |
1-D, 2-D, 3-D |
n |
y |
2-D, 3-D |
o |
z |
3-D |
These are cell counts, not node counts. A grid with m cells in x has
m+1 nodes along x.
For curvilinear grids, m/n/o must equal the node-array dimension minus one:
nodes.X must be (m+1) × (n+1) for 2-D, (m+1) × (n+1) × (o+1) for 3-D.
2.4 Cell spacings: dx, dy, dz
Scalar values give the uniform physical spacing between adjacent nodes along
each axis. Infered if passed x,y,z grid values. Required for uniform and periodic grids; not used for
curvilinear grids (physical distances are encoded in the node coordinate
arrays instead).
2.5 bc — boundary condition sub-struct
The bc sub-struct encodes Robin boundary coefficients and periodicity flags.
See the companion Boundary Conditions Reference document for full details.
The fields relevant to the grid struct itself are:
bc.isPeriodic — logical vector (1×1 for 1-D, 2×1 for 2-D, 3×1 for 3-D).
Each element is true if the corresponding axis wraps around. Used by
validateGrid to set grid.type = 'periodic'.
3. Coordinate Arrays
After validateGrid, the struct contains three sub-structs holding physical
coordinates for every point class in the staggered mimetic grid:
| Sub-struct |
Point class |
Role |
nodes |
Grid corners |
Where physical boundaries and node values live |
faces |
Cell-face midpoints |
Where flux (vector field) unknowns live |
centers |
Cell interiors |
Where scalar (potential) unknowns live |
All arrays use ndgrid layout: the first index varies in x, the second in y,
the third in z. This is the opposite of MATLAB's default meshgrid convention.
3.1 One-dimensional grid
| Field |
Size |
Description |
nodes.X |
(m+1) × 1 |
0, dx, 2·dx, …, m·dx |
faces.X |
(m+1) × 1 |
Identical to nodes.X (in 1-D, face midpoints coincide with nodes) |
centers.X |
(m+2) × 1 |
0, 0.5·dx, 1.5·dx, …, (m−0.5)·dx, m·dx |
The centers array has two ghost entries: the first element (0) and the
last element (m·dx) mirror the domain boundary. This is required so that
the mimetic boundary condition operator can augment the interior matrix rows
with boundary data without resizing.
3.2 Two-dimensional grid
Face arrays are split by normal direction — u faces are perpendicular to x
(x-normal), v faces are perpendicular to y (y-normal).
| Field |
Size |
Description |
nodes.X, nodes.Y |
(m+1) × (n+1) |
ndgrid of node positions |
centers.X, centers.Y |
(m+2) × (n+2) |
ndgrid with ghost padding on all sides |
faces.u.X, faces.u.Y |
(m+1) × n |
x-normal face midpoints |
faces.v.X, faces.v.Y |
m × (n+1) |
y-normal face midpoints |
u-face coordinate ranges (uniform):
faces.u.X = 0, dx, 2·dx, …, m·dx (m+1 values — same as node x-positions)
faces.u.Y = 0.5·dy, 1.5·dy, …, (n−0.5)·dy (n values — face centers between node rows)
v-face coordinate ranges (uniform):
faces.v.X = 0.5·dx, 1.5·dx, …, (m−0.5)·dx (m values)
faces.v.Y = 0, dy, 2·dy, …, n·dy (n+1 values — same as node y-positions)
3.3 Three-dimensional grid
Face arrays split into three components: u (x-normal), v (y-normal),
w (z-normal).
| Field |
Size |
Description |
nodes.X/Y/Z |
(m+1) × (n+1) × (o+1) |
ndgrid of node positions |
centers.X/Y/Z |
(m+2) × (n+2) × (o+2) |
ghost-padded ndgrid |
faces.u.X/Y/Z |
(m+1) × n × o |
x-normal faces |
faces.v.X/Y/Z |
m × (n+1) × o |
y-normal faces |
faces.w.X/Y/Z |
m × n × (o+1) |
z-normal faces |
The pattern is consistent: the face component named after a direction (u→x,
v→y, w→z) has a full node count in that direction and cell-center count in
the other two directions.
4. Curvilinear Grids
For non-uniform physical domains the caller constructs a partially filled
struct, populates the node coordinate arrays, then passes it to validateGrid:
g = struct();
g.m = m - 1; % cell count = node count - 1
g.n = n - 1;
g.type = 'curvilinear';
g.nodes.X = X'; % (m+1) × (n+1) node array, transposed to ndgrid layout
g.nodes.Y = Y';
g = validateGrid(g);
4.1 What the caller must supply
| Dimension |
Required fields |
| 2-D |
m, n, type='curvilinear', nodes.X, nodes.Y |
| 3-D |
m, n, o, type='curvilinear', nodes.X, nodes.Y, nodes.Z |
Node arrays must be exact size (m+1) × (n+1) (2-D) or
(m+1) × (n+1) × (o+1) (3-D) in ndgrid layout (x-index first).
validateGrid throws validateGrid:SizeMismatch if the sizes are wrong, and
validateGrid:CurvilinearMissingNodes if the arrays are absent.
4.2 What validateGrid derives
All coordinate arrays are computed by averaging the caller-supplied node
positions. No dx/dy/dz is computed or stored; physical distances are
implicit in the node positions themselves.
u-faces (x-normal): average of adjacent nodes along the n-direction (column pairs):
faces.u.X(:, j) = 0.5 * (nodes.X(:, j) + nodes.X(:, j+1)) for j = 1…n
faces.u.Y(:, j) = 0.5 * (nodes.Y(:, j) + nodes.Y(:, j+1))
Size: (m+1) × n.
v-faces (y-normal): average of adjacent nodes along the m-direction (row pairs):
faces.v.X(i, :) = 0.5 * (nodes.X(i, :) + nodes.X(i+1, :)) for i = 1…m
faces.v.Y(i, :) = 0.5 * (nodes.Y(i, :) + nodes.Y(i+1, :))
Size: m × (n+1).
Cell centers: bilinear average of the four surrounding corner nodes:
centers.X(i, j) = 0.25 * (nodes.X(i,j) + nodes.X(i+1,j) + nodes.X(i,j+1) + nodes.X(i+1,j+1))
centers.Y(i, j) = 0.25 * (nodes.Y(i,j) + nodes.Y(i+1,j) + nodes.Y(i,j+1) + nodes.Y(i+1,j+1))
Size: m × n.
For 3-D curvilinear, the same edge-midpoint and trilinear-average rules
apply in all three axis directions. The node arrays are
(m+1) × (n+1) × (o+1) and the derived face/center arrays follow the same
naming and sizing conventions as the uniform 3-D case above.
4.3 Layout note for operator internals
Curvilinear operators (gradCurv_impl, divCurv_impl, nodalCurv_impl)
internally need meshgrid layout for the Jacobian computation. They
transpose or permute the ndgrid arrays on entry:
X = grid.nodes.X'; % 2-D: (n+1)×(m+1) meshgrid
X = permute(grid.nodes.X, [2,1,3]); % 3-D: (n+1)×(m+1)×(o+1)
This conversion is the operator's responsibility, not the grid struct's.
The struct always stores coordinates in ndgrid layout.
5. Quick-Reference Table
| Field |
1-D |
2-D |
3-D |
Curvilinear |
Notes |
dim |
1 |
2 |
3 |
2 or 3 |
Auto-inferred |
type |
str |
str |
str |
'curvilinear' |
'uniform'/'periodic'/'curvilinear' |
m |
scalar |
scalar |
scalar |
scalar |
Cell count in x |
n |
— |
scalar |
scalar |
scalar |
Cell count in y |
o |
— |
— |
scalar |
scalar |
Cell count in z |
dx |
scalar |
scalar |
scalar |
— |
x cell spacing |
dy |
— |
scalar |
scalar |
— |
y cell spacing |
dz |
— |
— |
scalar |
— |
z cell spacing |
nodes.X |
(m+1)×1 |
(m+1)×(n+1) |
(m+1)×(n+1)×(o+1) |
same (user-supplied) |
ndgrid layout |
nodes.Y |
— |
(m+1)×(n+1) |
(m+1)×(n+1)×(o+1) |
same (user-supplied) |
|
nodes.Z |
— |
— |
(m+1)×(n+1)×(o+1) |
same (user-supplied) |
|
centers.X |
(m+2)×1 |
(m+2)×(n+2) |
(m+2)×(n+2)×(o+2) |
m×n or m×n×o |
Staggered grid for MOLE scalars |
centers.Y |
— |
(m+2)×(n+2) |
(m+2)×(n+2)×(o+2) |
m×n or m×n×o |
|
centers.Z |
— |
— |
(m+2)×(n+2)×(o+2) |
m×n×o |
|
faces.X |
(m+1)×1 |
— |
— |
— |
1-D only; equals nodes.X |
faces.u.X |
— |
(m+1)×n |
(m+1)×n×o |
(m+1)×n |
x-normal faces |
faces.u.Y |
— |
(m+1)×n |
(m+1)×n×o |
(m+1)×n |
|
faces.u.Z |
— |
— |
(m+1)×n×o |
— |
3-D only |
faces.v.X |
— |
m×(n+1) |
m×(n+1)×o |
m×(n+1) |
y-normal faces |
faces.v.Y |
— |
m×(n+1) |
m×(n+1)×o |
m×(n+1) |
|
faces.v.Z |
— |
— |
m×(n+1)×o |
— |
3-D only |
faces.w.X |
— |
— |
m×n×(o+1) |
— |
z-normal faces |
faces.w.Y |
— |
— |
m×n×(o+1) |
— |
|
faces.w.Z |
— |
— |
m×n×(o+1) |
— |
|
bc.isPeriodic |
1×1 |
2×1 |
3×1 |
— |
One flag per axis |
Keep-open request
For MOLE 2.0, we are exploring implementing structs to store key information about the grid and boundary conditions. This simplifies calls to the operators, but also simplifies request by the user.
Many of the grid objects are generated automatically, based on an initial call to the grid. The grid struct stores all given and derived information for the operators. Below is a sample of what the grid struct could be. It is a work in progress.
MOLE Grid Struct Reference (MATLAB/Octave)
1. Overview
The grid struct is the central data object passed to all MOLE mimetic operators
(
grad,div,lap,curl,nodal,addScalarBC,interpol). It bundleseverything an operator needs to know about the physical domain: how many cells
exist in each direction, how large each cell is, where nodes/faces/cell-centers
sit in physical space, and what type of boundary treatment is expected. (It is expected that interpol will fill in fields in the grid struct, like facesToNode, NodesToFaces, etc.).
Two public functions build and validate the struct:
makeGridaccepts either name-value pairs or a partially filled struct andalways calls
validateGridbefore returning.validateGridinfers missingmetadata fields, normalises boundary coefficients, and populates all coordinate
arrays. Callers should treat the returned struct as immutable: operators read
from it but never write to it.
2. Core Fields
2.1
dim— dimensionality123Inferred automatically from whichever size fields are present:
oordzpresent →dim = 3nordypresent →dim = 2dim = 12.2
type— grid topology'uniform'dx/dy/dzscalars); no periodic axes'periodic''curvilinear'Inferred automatically:
X,Y, orZfields present at struct root →'curvilinear'x,y, orzfields (lowercase) present →'nonuniform'(reserved, not yet active)'uniform'or'periodic'depending on boundary coefficients2.3 Cell counts:
m,n,omnoThese are cell counts, not node counts. A grid with
mcells in x hasm+1nodes along x.For curvilinear grids,
m/n/omust equal the node-array dimension minus one:nodes.Xmust be(m+1) × (n+1)for 2-D,(m+1) × (n+1) × (o+1)for 3-D.2.4 Cell spacings:
dx,dy,dzScalar values give the uniform physical spacing between adjacent nodes along
each axis. Infered if passed x,y,z grid values. Required for uniform and periodic grids; not used for
curvilinear grids (physical distances are encoded in the node coordinate
arrays instead).
2.5
bc— boundary condition sub-structThe
bcsub-struct encodes Robin boundary coefficients and periodicity flags.See the companion Boundary Conditions Reference document for full details.
The fields relevant to the grid struct itself are:
bc.isPeriodic— logical vector (1×1for 1-D,2×1for 2-D,3×1for 3-D).Each element is
trueif the corresponding axis wraps around. Used byvalidateGridto setgrid.type = 'periodic'.3. Coordinate Arrays
After
validateGrid, the struct contains three sub-structs holding physicalcoordinates for every point class in the staggered mimetic grid:
nodesfacescentersAll arrays use ndgrid layout: the first index varies in x, the second in y,
the third in z. This is the opposite of MATLAB's default
meshgridconvention.3.1 One-dimensional grid
nodes.X(m+1) × 10, dx, 2·dx, …, m·dxfaces.X(m+1) × 1nodes.X(in 1-D, face midpoints coincide with nodes)centers.X(m+2) × 10, 0.5·dx, 1.5·dx, …, (m−0.5)·dx, m·dxThe centers array has two ghost entries: the first element (
0) and thelast element (
m·dx) mirror the domain boundary. This is required so thatthe mimetic boundary condition operator can augment the interior matrix rows
with boundary data without resizing.
3.2 Two-dimensional grid
Face arrays are split by normal direction —
ufaces are perpendicular to x(x-normal),
vfaces are perpendicular to y (y-normal).nodes.X,nodes.Y(m+1) × (n+1)centers.X,centers.Y(m+2) × (n+2)faces.u.X,faces.u.Y(m+1) × nfaces.v.X,faces.v.Ym × (n+1)u-face coordinate ranges (uniform):
v-face coordinate ranges (uniform):
3.3 Three-dimensional grid
Face arrays split into three components:
u(x-normal),v(y-normal),w(z-normal).nodes.X/Y/Z(m+1) × (n+1) × (o+1)centers.X/Y/Z(m+2) × (n+2) × (o+2)faces.u.X/Y/Z(m+1) × n × ofaces.v.X/Y/Zm × (n+1) × ofaces.w.X/Y/Zm × n × (o+1)The pattern is consistent: the face component named after a direction (
u→x,v→y,w→z) has a full node count in that direction and cell-center count inthe other two directions.
4. Curvilinear Grids
For non-uniform physical domains the caller constructs a partially filled
struct, populates the node coordinate arrays, then passes it to
validateGrid:4.1 What the caller must supply
m,n,type='curvilinear',nodes.X,nodes.Ym,n,o,type='curvilinear',nodes.X,nodes.Y,nodes.ZNode arrays must be exact size
(m+1) × (n+1)(2-D) or(m+1) × (n+1) × (o+1)(3-D) in ndgrid layout (x-index first).validateGridthrowsvalidateGrid:SizeMismatchif the sizes are wrong, andvalidateGrid:CurvilinearMissingNodesif the arrays are absent.4.2 What
validateGridderivesAll coordinate arrays are computed by averaging the caller-supplied node
positions. No
dx/dy/dzis computed or stored; physical distances areimplicit in the node positions themselves.
u-faces (x-normal): average of adjacent nodes along the n-direction (column pairs):
Size:
(m+1) × n.v-faces (y-normal): average of adjacent nodes along the m-direction (row pairs):
Size:
m × (n+1).Cell centers: bilinear average of the four surrounding corner nodes:
Size:
m × n.For 3-D curvilinear, the same edge-midpoint and trilinear-average rules
apply in all three axis directions. The node arrays are
(m+1) × (n+1) × (o+1)and the derived face/center arrays follow the samenaming and sizing conventions as the uniform 3-D case above.
4.3 Layout note for operator internals
Curvilinear operators (
gradCurv_impl,divCurv_impl,nodalCurv_impl)internally need meshgrid layout for the Jacobian computation. They
transpose or permute the ndgrid arrays on entry:
This conversion is the operator's responsibility, not the grid struct's.
The struct always stores coordinates in ndgrid layout.
5. Quick-Reference Table
dimtype'curvilinear''uniform'/'periodic'/'curvilinear'mnodxdydznodes.X(m+1)×1(m+1)×(n+1)(m+1)×(n+1)×(o+1)nodes.Y(m+1)×(n+1)(m+1)×(n+1)×(o+1)nodes.Z(m+1)×(n+1)×(o+1)centers.X(m+2)×1(m+2)×(n+2)(m+2)×(n+2)×(o+2)m×norm×n×ocenters.Y(m+2)×(n+2)(m+2)×(n+2)×(o+2)m×norm×n×ocenters.Z(m+2)×(n+2)×(o+2)m×n×ofaces.X(m+1)×1nodes.Xfaces.u.X(m+1)×n(m+1)×n×o(m+1)×nfaces.u.Y(m+1)×n(m+1)×n×o(m+1)×nfaces.u.Z(m+1)×n×ofaces.v.Xm×(n+1)m×(n+1)×om×(n+1)faces.v.Ym×(n+1)m×(n+1)×om×(n+1)faces.v.Zm×(n+1)×ofaces.w.Xm×n×(o+1)faces.w.Ym×n×(o+1)faces.w.Zm×n×(o+1)bc.isPeriodic1×12×13×1Keep-open request
keep-open.