Grid types
Met.3D represents atmospheric data as grids. All grid types share a common abstract
interface, but differ in how they store and compute vertical coordinates.
This page describes the class hierarchy, the shared MStructuredGrid API, and the
specialisations for each vertical coordinate system.
Source code: src/data/abstractgrid.h, src/data/structuredgrid.h,
src/radar/radargrid.h.
Class hierarchy
MAbstractGrid (abstract interface; holds level type)
├── MStructuredGrid (regular lon/lat horizontal grid; flat data array)
│ ├── MRegularLonLatLnPGrid (log-pressure levels)
│ ├── MRegularLonLatStructuredPressureGrid (pressure levels)
│ ├── MRegularLonLatGrid (2-D surface field, SINGLE_LEVEL)
│ ├── MLonLatHybridSigmaPressureGrid (model levels, hybrid σ-p)
│ └── MLonLatAuxiliaryPressureGrid (arbitrary 3-D pressure field)
└── MRadarGrid (radar volume scans; elevation / azimuth / range)
All grid objects also inherit MWeatherPredictionMetaData, which carries the
NWP metadata attached to the field (variable name, init time, valid time, ensemble
member, data source ID).
Grid objects have potentially a huge memory footprint and should therefore be owned and managed by the memory manager (see Memory management). Pipeline modules producing grids as data items are automatically memory managed. Try to avoid creating non-memory managed grids as much as possible.
Vertical level types
The MVerticalLevelType enum (src/data/abstractgrid.h) identifies the vertical
coordinate system of a grid. It is the primary discriminator used throughout the
pipeline and the actor system:
Enum value |
Meaning |
|---|---|
|
2-D surface field (no vertical dimension). |
|
Constant pressure levels (e.g. 850, 500, 200 hPa). |
|
Levels uniformly spaced in log(pressure) space. |
|
Model levels in hybrid sigma-pressure coordinates (ECMWF IFS, ICON, COSMO). |
|
Levels whose pressure is stored in a separate 3-D auxiliary field. |
|
2-D PV surface (special case for isentropic/PV-level data). Deprecated. |
|
Level types that do not fit any other category. |
|
Radar elevation angles; used by |
|
Placeholder for an empty/null grid. |
The enum value is stored in every grid object and exposed via
MAbstractGrid::getLevelType().
The MStructuredGrid API
MStructuredGrid is the base class for all non-radar grids. It provides a unified
API so that code working with atmospheric fields does not need to know the concrete
grid type.
Dimensions and coordinate arrays
unsigned int getNumLevels() const; // k dimension (vertical)
unsigned int getNumLats() const; // j dimension
unsigned int getNumLons() const; // i dimension
const double* getLevels() const; // vertical coordinate values
const double* getLats() const; // latitude values [degrees]
const double* getLons() const; // longitude values [degrees]
What levels[k] means depends on the concrete subclass (pressure in hPa,
log(pressure), hybrid level index, etc.).
Data access
Data is stored in a flat float array; level (k) is the slowest-varying
dimension, longitude (i) the fastest:
float getValue(unsigned int k, unsigned int j, unsigned int i) const;
void setValue(unsigned int k, unsigned int j, unsigned int i, float v);
// Convenience: direct linear index
float getValue(unsigned int n) const;
void setValue(unsigned int n, float v);
// Raw pointer (e.g. for GPU upload)
const float* getData() const;
Pressure queries
The virtual pressure methods are the main abstraction point. Each subclass overrides them to implement its own coordinate formula:
// Pressure at grid point (k, j, i), in hPa.
virtual float getPressure(unsigned int k, unsigned int j, unsigned int i) const;
// Pressure at the cell interfaces (used for mass-weighted integrals, etc.)
virtual float getBottomInterfacePressure(unsigned int k, unsigned int j, unsigned int i);
virtual float getTopInterfacePressure (unsigned int k, unsigned int j, unsigned int i);
// Pressure range of the whole data volume.
virtual float getTopDataVolumePressure_hPa (bool useCachedValue = true) const;
virtual float getBottomDataVolumePressure_hPa(bool useCachedValue = true) const;
Interpolation
MStructuredGrid provides a family of interpolation methods. The key vertical
piece that subclasses must implement is interpolateGridColumnToPressure();
the public interpolateValue() calls it internally after resolving the horizontal
position:
// Full trilinear interpolation to (lon, lat, p_hPa).
float interpolateValue(float lon, float lat, float p_hPa);
// Bilinear interpolation on a single level k.
float interpolateValueOnLevel(float lon, float lat, unsigned int k) const;
// Sample all levels at (lon, lat) in one pass — more efficient than
// calling interpolateValueOnLevel() nlevs times.
bool interpolateValuesInVerticalColumn(float lon, float lat, float* out);
// Extract a vertical profile as (value, pressure) pairs.
QVector<QVector2D> extractVerticalProfile(float lon, float lat);
Level search
// Find level k such that p_hPa lies between level k and k+1.
virtual int findLevel(unsigned int j, unsigned int i, float p_hPa);
// Find the level whose pressure is closest to p_hPa.
int findClosestLevel(unsigned int j, unsigned int i, float p_hPa);
Methods subclasses must override
To create a new MStructuredGrid subclass, implement:
getPressure(k, j, i): the core pressure formula.interpolateGridColumnToPressure(j, i, p_hPa): vertical interpolation for a single (j, i) column.levelPressureAtLonLat_hPa(lon, lat, k): pressure on level k at a geographic position (needed forextractVerticalProfile).findLevel(j, i, p_hPa): binary search or similar.getTopDataVolumePressure_hPa()/getBottomDataVolumePressure_hPa().
Concrete MStructuredGrid subclasses
MRegularLonLatStructuredPressureGrid
Level type: PRESSURE_LEVELS_3D
Standard pressure level data (e.g. ECMWF ERA5 on pressure levels, NCEP reanalysis).
levels[k] stores pressure directly in hPa, with index 0 typically at the top
(lowest pressure).
Pressure formula: p(k, j, i) = levels[k]
Additionally provides getPressureTexCoordTexture1D(), a 1-D GPU texture that maps
normalised log(pressure) to the texture coordinate of the data volume. This is used
by the volume raycaster for efficient pressure-to-texture-space lookups.
MRegularLonLatLnPGrid
Level type: LOG_PRESSURE_LEVELS_3D
Like the pressure level grid, but levels are uniformly spaced in log(pressure) space.
levels[k] stores ln(p) in hPa.
Pressure formula: p(k, j, i) = exp(levels[k])
Vertical interpolation is linear in ln(p), which matches the typical vertical structure of atmospheric variables and avoids compression artefacts near the surface.
MRegularLonLatGrid
Level type: SINGLE_LEVEL
2-D surface field. Internally nlevs = 1, but the class provides dedicated 2-D
index helpers:
float getValue(unsigned int j, unsigned int i) const;
void setValue(unsigned int j, unsigned int i, float v);
Typical uses: surface pressure, 2-metre temperature, precipitation, boundary layer height, geopotential at the surface.
MLonLatHybridSigmaPressureGrid
Level type: HYBRID_SIGMA_PRESSURE_3D
Model-level data from NWP models that use hybrid sigma-pressure vertical coordinates (e.g., ECMWF IFS). The pressure at a grid point depends on the surface pressure at that column:
where \(a_k\) (in hPa) and \(b_k\) (dimensionless) are the hybrid coefficients
for level k, and \(p_\text{sfc}\) is a companion MRegularLonLatGrid held in
the surfacePressure member.
Cell interface pressures use a separate set of half-level coefficients
\(a^i_k\) / \(b^i_k\), computed from the level-centre coefficients by
computeInterfaceCoefficients().
Because pressure varies horizontally, vertical interpolation cannot use a simple
1-D lookup. interpolateGridColumnToPressure() performs a binary search within
each column. For GPU rendering, getPressureTexCoordTexture2D() provides a 2-D
texture (one row per lat/lon column) mapping normalised pressure to texture coordinates.
Key accessors:
float getPressure(unsigned int k, unsigned int j, unsigned int i) const;
MDataLease<MRegularLonLatGrid> getSurfacePressureGrid() const;
float getSurfacePressure(unsigned int j, unsigned int i) const;
double* getAkCoeffs() const; // array of nlevs values, in hPa
double* getBkCoeffs() const; // array of nlevs values, dimensionless
MLonLatAuxiliaryPressureGrid
Level type: AUXILIARY_PRESSURE_3D
The most flexible grid type. Pressure at every grid point is read from a separate 3-D pressure field of the same grid size:
p(k, j, i) = auxPressureField_hPa->getValue(k, j, i)
This is used for any level type that cannot be expressed with a simple formula, for example output that has already been interpolated to arbitrary 3-D coordinates, or data on isentropic (potential temperature) surfaces.
A special self-referential mode exists for the case where the grid itself is the
pressure field (i.e. the variable being stored is pressure). In that case
markAsSelfReferential() is called and getPressureGrid() returns this.
Key accessors:
MDataView<MLonLatAuxiliaryPressureGrid> getPressureGrid();
void exchangeAuxiliaryPressureGrid(MDataLease<MLonLatAuxiliaryPressureGrid> newField);
bool isSelfReferential() const;
Vertical interpolation requires a binary search within each (j, i) column of the auxiliary pressure field, since pressure values are arbitrary.
Radar grid
MRadarGrid (src/radar/radargrid.h) represents weather radar volume scans.
It does not derive from MStructuredGrid because its geometry is fundamentally
different: data is organised by elevation angle, azimuth ray, and range bin rather
than by latitude, longitude, and vertical levels.
Structure of a radar volume
A volume scan consists of several elevation angles (typically 5-18). Each elevation
is a MRadarElevation object containing:
elevationAngle: antenna tilt in degrees above horizontal.nrays: number of azimuth rays in this scan.nbins: number of range bins per ray.binDistance,rangeStart: spacing and offset to the first bin, in metres.rayAngles: per-ray azimuth angles (degrees).data: flatQVector<float>of sizenrays * nbins.cartesianCoordinates: pre-computed 3-D positions for each data point.
The radar station position (lon, lat, height) is stored on the MRadarGrid object
itself.
Data access
// Value at a specific elevation / ray / bin index.
float getValue(int elIdx, int rayIdx, int binIdx) const;
// Number of elevations, rays and bins in a given elevation.
int getNumberOfElevations() const;
int getNrays(unsigned int elIdx) const;
int getNbins (unsigned int elIdx) const;
Coordinate transformations
Because radar data lives in spherical coordinates centred on the antenna, the class provides methods to convert between radar and geographic space:
// Radar (elevation angle °, azimuth °, range m) → geographic (lon °, lat °, height m)
QVector3D radToLonLatMetreFromValues(float elev, float azimuth, float range) const;
// Radar → pressure coordinates (lon °, lat °, p hPa)
QVector3D radToLonLatPressure_hPa_FromValues(float elev, float azimuth, float range);
interpolateValue(lon, lat, p_hPa) performs the inverse transformation to find the
radar bin closest to a given geographic position.
Horizontal section extraction
For 2-D cross-sections at a given height (in metres),
calculateHorizontalRadarSection() extracts the relevant data points and their
lon/lat coordinates, which can then be passed to the GPU as textures via
getHSecLonLatTexture() / getHSecDataTexture().