fesomp

fesomp: A Python library for working with FESOM2 unstructured ocean model data.

class fesomp.Mesh[source]

Bases: object

Represents a FESOM2 unstructured mesh.

This class holds the core mesh data including node coordinates, element connectivity, and vertical structure. Topology, geometry, and spatial indexing are lazily computed on first access.

lon

Longitude of nodes in degrees, shape (n2d,).

Type:

np.ndarray

lat

Latitude of nodes in degrees, shape (n2d,).

Type:

np.ndarray

triangles

Triangle connectivity, shape (nelem, 3), 0-indexed.

Type:

np.ndarray

nlev

Number of vertical levels.

Type:

int

depth_levels

Depth at each level interface, shape (nlev,).

Type:

np.ndarray

depth_layers

Depth at layer centers, shape (nlev-1,).

Type:

np.ndarray

node_levels

Number of active levels at each node, shape (n2d,).

Type:

np.ndarray

elem_levels

Number of active levels at each element, shape (nelem,).

Type:

np.ndarray

node_bottom_depth

Bottom depth at each node, shape (n2d,).

Type:

np.ndarray

elem_bottom_depth

Bottom depth at each element, shape (nelem,).

Type:

np.ndarray

lon: ndarray
lat: ndarray
triangles: ndarray
nlev: int
depth_levels: ndarray
depth_layers: ndarray
node_levels: ndarray
elem_levels: ndarray
node_bottom_depth: ndarray
elem_bottom_depth: ndarray
__post_init__()[source]

Validate mesh data and ensure correct dtypes.

Return type:

None

property n2d: int

Number of 2D nodes.

property nelem: int

Number of triangular elements.

property topology: Topology

Get mesh topology (edges, neighbors, etc.).

Computed lazily on first access if not pre-loaded from NetCDF.

property geometry: Geometry

Get mesh geometry (areas, gradients, etc.).

Computed lazily on first access if not pre-loaded from NetCDF.

property spatial_index: SpatialIndex

Get spatial index for efficient point queries.

Built lazily on first access.

property lon_elem: ndarray

Longitude of element (triangle) centers in degrees.

Computed lazily on first access. Handles cyclic triangles that cross the dateline correctly.

property lat_elem: ndarray

Latitude of element (triangle) centers in degrees.

Computed lazily on first access.

find_nearest(lon, lat, k=1)[source]

Find the k nearest nodes to a given point.

Parameters:
  • lon (float) – Longitude in degrees.

  • lat (float) – Latitude in degrees.

  • k (int, optional) – Number of nearest neighbors to return.

Returns:

Indices of the k nearest nodes.

Return type:

np.ndarray

find_in_radius(lon, lat, radius_km)[source]

Find all nodes within a given radius of a point.

Parameters:
  • lon (float) – Longitude in degrees.

  • lat (float) – Latitude in degrees.

  • radius_km (float) – Search radius in kilometers.

Returns:

Indices of nodes within the radius.

Return type:

np.ndarray

subset_by_bbox(lon_min, lon_max, lat_min, lat_max)[source]

Find all nodes within a bounding box.

Parameters:
  • lon_min (float) – Longitude bounds in degrees.

  • lon_max (float) – Longitude bounds in degrees.

  • lat_min (float) – Latitude bounds in degrees.

  • lat_max (float) – Latitude bounds in degrees.

Returns:

Indices of nodes within the bounding box.

Return type:

np.ndarray

get_triangulation(mask_cyclic=True)[source]

Create a matplotlib Triangulation object for plotting.

Parameters:

mask_cyclic (bool, optional) – If True (default), mask triangles that cross the dateline to prevent ugly lines spanning the globe.

Returns:

Triangulation object ready for use with triplot, tripcolor, etc.

Return type:

matplotlib.tri.Triangulation

Example

>>> tri = mesh.get_triangulation()
>>> plt.triplot(tri, 'b-', linewidth=0.2)
__init__(lon, lat, triangles, nlev, depth_levels, depth_layers, node_levels, elem_levels, node_bottom_depth, elem_bottom_depth, _preloaded_topology=None, _preloaded_geometry=None, _topology=None, _geometry=None, _spatial_index=None, _lon_elem=None, _lat_elem=None)
Parameters:
Return type:

None

fesomp.load_mesh(path)[source]

Load a FESOM2 mesh from a file or directory.

Automatically detects the format based on the path: - If path is a .nc file: loads from NetCDF - If path is a directory: loads from ASCII files

Parameters:

path (str or Path) – Path to the mesh file (NetCDF) or directory (ASCII).

Returns:

The loaded mesh object.

Return type:

Mesh

Raises:
fesomp.plot(data, lon, lat, *, box=None, res=(360, 180), interp='nn', influence=80000, interpolator=None, cmap=None, levels=None, ptype='cf', mapproj='pc', figsize=(10, 6), rowscol=(1, 1), titles=None, units=None, colorbar=True, coastlines=True, land=False, gridlines=False, ax=None, fig=None)[source]

Plot unstructured data on a map.

Data is interpolated to a regular grid and plotted with cartopy.

Parameters:
  • data (np.ndarray or list of np.ndarray) – Data to plot. Can be a single array (npoints,) or a list of arrays for multiple subplots.

  • lon (np.ndarray) – Longitudes of data points in degrees.

  • lat (np.ndarray) – Latitudes of data points in degrees.

  • box (tuple, optional) – Bounding box (lon_min, lon_max, lat_min, lat_max). Default depends on projection: - ‘np’: (-180, 180, 60, 90) - ‘sp’: (-180, 180, -90, -60) - others: (-180, 180, -90, 90)

  • res (tuple) – Interpolation resolution (nlon, nlat). Default is (360, 180).

  • interp (str) – Interpolation method: ‘nn’ (nearest neighbor), ‘idw’, or ‘linear’.

  • influence (float) – Radius of influence for interpolation in meters. Default is 80000.

  • interpolator (RegridInterpolator, optional) – Pre-computed interpolator for caching. Speeds up repeated plots.

  • cmap (str, optional) – Colormap name. Default is ‘RdBu_r’.

  • levels (tuple or list, optional) – Contour levels. Can be (min, max, nlevels) or explicit list. Default is auto from data.

  • ptype (str) – Plot type: ‘cf’ (contourf) or ‘pcm’ (pcolormesh).

  • mapproj (str) – Map projection: ‘pc’ (Plate Carree), ‘rob’ (Robinson), ‘merc’ (Mercator), ‘np’ (North Polar), ‘sp’ (South Polar).

  • figsize (tuple) – Figure size in inches.

  • rowscol (tuple) – Subplot layout (nrows, ncols).

  • titles (str or list) – Title(s) for subplot(s).

  • units (str, optional) – Units label for colorbar.

  • colorbar (bool) – Whether to show colorbar. Default is True.

  • coastlines (bool) – Whether to draw coastlines. Default is True.

  • land (bool) – Whether to fill land areas. Default is False.

  • gridlines (bool) – Whether to draw gridlines. Default is False.

  • ax (matplotlib.axes.Axes, optional) – Existing axes to plot on (for single plot).

  • fig (matplotlib.figure.Figure, optional) – Existing figure to use.

Return type:

tuple[Figure, ndarray, RegridInterpolator]

Returns:

  • fig (matplotlib.figure.Figure) – The figure object.

  • axes (np.ndarray) – Array of axes objects.

  • interpolator (RegridInterpolator) – The interpolator used (can be reused for subsequent plots).

Example

>>> # Simple plot
>>> fig, axes, interp = fesomp.plot(temp, mesh.lon, mesh.lat)
>>>
>>> # Multiple subplots with cached interpolator
>>> fig, axes, interp = fesomp.plot(
...     [temp_surface, temp_100m, temp_500m],
...     mesh.lon, mesh.lat,
...     rowscol=(1, 3),
...     titles=['Surface', '100m', '500m'],
...     interpolator=interp,  # reuse from previous
... )
fesomp.regrid(data, lon, lat, box=(-180, 180, -90, 90), res=(360, 180), method='nn', influence=80000, fill_value=nan, interpolator=None)[source]

Interpolate unstructured data to a regular grid.

Parameters:
  • data (np.ndarray) – Data values at unstructured points, shape (npoints,).

  • lon (np.ndarray) – Longitudes of data points in degrees, shape (npoints,).

  • lat (np.ndarray) – Latitudes of data points in degrees, shape (npoints,).

  • box (tuple) – Bounding box as (lon_min, lon_max, lat_min, lat_max). Default is global (-180, 180, -90, 90).

  • res (tuple) – Output resolution as (nlon, nlat). Default is (360, 180).

  • method (str) – Interpolation method: - ‘nn’: Nearest neighbor (fast, default) - ‘idw’: Inverse distance weighting - ‘linear’: Linear interpolation (scipy griddata)

  • influence (float) – Radius of influence in meters. Points outside this radius from any source point will be set to fill_value. Default is 80000 (80 km).

  • fill_value (float) – Value for grid points with no data. Default is NaN.

  • interpolator (RegridInterpolator, optional) – Pre-computed interpolator for caching. If provided, lon, lat, box, res, method, and influence are ignored.

Return type:

tuple[ndarray, ndarray, ndarray]

Returns:

  • data_reg (np.ndarray) – Interpolated data on regular grid, shape (nlat, nlon).

  • lon_reg (np.ndarray) – 1D array of output longitudes.

  • lat_reg (np.ndarray) – 1D array of output latitudes.

Example

>>> # Simple one-off interpolation
>>> data_reg, lon_reg, lat_reg = regrid(temp, mesh.lon, mesh.lat)
>>>
>>> # With caching for multiple variables
>>> interp = RegridInterpolator(mesh.lon, mesh.lat)
>>> temp_reg, lon_reg, lat_reg = regrid(temp, mesh.lon, mesh.lat, interpolator=interp)
>>> salt_reg, _, _ = regrid(salt, mesh.lon, mesh.lat, interpolator=interp)
class fesomp.RegridInterpolator[source]

Bases: object

Cached interpolator for regridding unstructured data.

This class pre-computes and caches the KDTree and interpolation indices/weights, allowing fast repeated interpolation of different variables on the same grid.

Parameters:
  • lon (np.ndarray) – Longitudes of source points in degrees.

  • lat (np.ndarray) – Latitudes of source points in degrees.

  • box (tuple) – Target bounding box as (lon_min, lon_max, lat_min, lat_max).

  • res (tuple) – Target resolution as (nlon, nlat).

  • method (str) – Interpolation method: ‘nn’, ‘idw’, or ‘linear’.

  • influence (float) – Radius of influence in meters.

  • k (int) – Number of neighbors for IDW interpolation.

Example

>>> # Create interpolator once
>>> interp = RegridInterpolator(mesh.lon, mesh.lat, box=(-180, 180, -90, 90))
>>>
>>> # Use many times for different variables
>>> temp_reg, lon_reg, lat_reg = interp(ds['temp'].values)
>>> salt_reg, _, _ = interp(ds['salt'].values)
lon: ndarray
lat: ndarray
box: tuple[float, float, float, float] = (-180, 180, -90, 90)
res: tuple[int, int] = (360, 180)
method: Literal['nn', 'idw', 'linear'] = 'nn'
influence: float = 80000
k: int = 10
__post_init__()[source]

Build KDTree and compute interpolation indices.

__call__(data, fill_value=nan)[source]

Interpolate data to regular grid.

Parameters:
  • data (np.ndarray) – Data values at source points, shape (npoints,).

  • fill_value (float) – Value for points outside influence radius.

Return type:

tuple[ndarray, ndarray, ndarray]

Returns:

  • data_reg (np.ndarray) – Interpolated data, shape (nlat, nlon).

  • lon_reg (np.ndarray) – 1D array of output longitudes.

  • lat_reg (np.ndarray) – 1D array of output latitudes.

__init__(lon, lat, box=(-180, 180, -90, 90), res=(360, 180), method='nn', influence=80000, k=10)
Parameters:
Return type:

None

fesomp.transect(data, mesh, start, end, *, depth=None, npoints=100, method='nn', influence=80000, fill_value=nan, interpolator=None, ax=None, fig=None, figsize=(12, 5), cmap=None, levels=None, ptype='cf', title=None, xlabel=None, ylabel=None, units=None, colorbar=True, distance_units='km', depth_limits=None, invert_yaxis=True)[source]

Interpolate and plot a vertical transect through 3D ocean data.

This is a convenience function combining interpolate_transect and plot_transect. Automatically detects: - Horizontal location: nodes (n2d points) vs elements (nelem points) - Vertical coordinate: levels (interfaces) vs layers (centers)

Parameters:
  • data (np.ndarray) – Data values at unstructured points: - Shape (nlev, n2d) for data on nodes - Shape (nlev, nelem) for data on elements Can be defined on either levels (interfaces) or layers (centers).

  • mesh (Mesh) – The mesh object containing lon, lat, and depth information.

  • start (tuple) – Starting point of transect as (lon, lat) in degrees.

  • end (tuple) – Ending point of transect as (lon, lat) in degrees.

  • depth (np.ndarray, optional) – Depth coordinates in meters. If not provided, automatically selects mesh.depth_levels or mesh.depth_layers based on data shape.

  • npoints (int) – Number of points along the transect. Default is 100.

  • method (str) – Interpolation method: ‘nn’, ‘idw’, or ‘linear’.

  • influence (float) – Radius of influence in meters. Default is 80000 (80 km).

  • fill_value (float) – Value for transect points with no data. Default is NaN.

  • interpolator (TransectInterpolator, optional) – Pre-computed interpolator for caching.

  • ax (matplotlib.axes.Axes, optional) – Existing axes to plot on.

  • fig (matplotlib.figure.Figure, optional) – Existing figure to use.

  • figsize (tuple) – Figure size in inches if creating new figure.

  • cmap (str, optional) – Colormap name. Default is ‘RdBu_r’.

  • levels (tuple or list, optional) – Contour levels. Can be (min, max, nlevels) or explicit list.

  • ptype (str) – Plot type: ‘cf’ (contourf) or ‘pcm’ (pcolormesh).

  • title (str, optional) – Plot title.

  • xlabel (str, optional) – X-axis label.

  • ylabel (str, optional) – Y-axis label.

  • units (str, optional) – Units string for colorbar label.

  • colorbar (bool) – Whether to show colorbar. Default is True.

  • distance_units (str) – Units for distance axis: ‘m’ or ‘km’. Default is ‘km’.

  • depth_limits (tuple, optional) – Depth range to display as (min_depth, max_depth).

  • invert_yaxis (bool) – Whether to invert y-axis. Default is True.

Return type:

tuple[Figure, Axes, TransectInterpolator]

Returns:

  • fig (matplotlib.figure.Figure) – The figure object.

  • ax (matplotlib.axes.Axes) – The axes object.

  • interpolator (TransectInterpolator) – The interpolator used (can be reused).

Example

>>> # Plot temperature transect (data on layers)
>>> fig, ax, interp = fesomp.transect(
...     temp_3d,  # shape (nlev-1, n2d) - on layers
...     mesh,
...     start=(-30, -60), end=(-30, 60),
...     title="Temperature along 30W",
...     units="degC",
...     depth_limits=(0, 1000),
... )
>>>
>>> # Reuse interpolator for salinity
>>> fig2, ax2, _ = fesomp.transect(
...     salt_3d, mesh,
...     start=(-30, -60), end=(-30, 60),
...     interpolator=interp,
...     title="Salinity along 30W",
... )
fesomp.interpolate_transect(data, lon, lat, start, end, *, npoints=100, method='nn', influence=80000, fill_value=nan, interpolator=None)[source]

Interpolate unstructured data along a great circle transect.

Parameters:
  • data (np.ndarray) – Data values at unstructured points: - Shape (n2d,) for surface data - Shape (nlev, n2d) for 3D data

  • lon (np.ndarray) – Longitudes of data points in degrees.

  • lat (np.ndarray) – Latitudes of data points in degrees.

  • start (tuple) – Starting point of transect as (lon, lat) in degrees.

  • end (tuple) – Ending point of transect as (lon, lat) in degrees.

  • npoints (int) – Number of points along the transect. Default is 100.

  • method (str) – Interpolation method: - ‘nn’: Nearest neighbor (fast, default) - ‘idw’: Inverse distance weighting - ‘linear’: Linear interpolation (scipy griddata)

  • influence (float) – Radius of influence in meters. Default is 80000 (80 km).

  • fill_value (float) – Value for transect points with no data. Default is NaN.

  • interpolator (TransectInterpolator, optional) – Pre-computed interpolator for caching.

Return type:

tuple[ndarray, ndarray, TransectInterpolator]

Returns:

  • data_transect (np.ndarray) – Interpolated data along transect: - Shape (npoints,) if input was 1D - Shape (nlev, npoints) if input was 2D

  • transect_distance (np.ndarray) – Distance from start along transect in meters.

  • interpolator (TransectInterpolator) – The interpolator used (can be reused).

Example

>>> # 3D ocean data transect
>>> temp_t, dist, interp = interpolate_transect(
...     temp_3d,  # shape (nlev, n2d)
...     mesh.lon, mesh.lat,
...     start=(-30, -60), end=(-30, 60),
... )
>>> # temp_t has shape (nlev, npoints)
fesomp.plot_transect(data, distance, depth, *, ax=None, fig=None, figsize=(12, 5), cmap=None, levels=None, ptype='cf', title=None, xlabel=None, ylabel=None, units=None, colorbar=True, distance_units='km', depth_limits=None, invert_yaxis=True)[source]

Plot a vertical transect as a 2D cross-section.

Parameters:
  • data (np.ndarray) – Data values along transect, shape (nlev, npoints).

  • distance (np.ndarray) – Distance along transect in meters, shape (npoints,).

  • depth (np.ndarray) – Depth levels in meters (positive downward), shape (nlev,).

  • ax (matplotlib.axes.Axes, optional) – Existing axes to plot on.

  • fig (matplotlib.figure.Figure, optional) – Existing figure to use.

  • figsize (tuple) – Figure size in inches if creating new figure.

  • cmap (str, optional) – Colormap name. Default is ‘RdBu_r’.

  • levels (tuple or list, optional) – Contour levels. Can be (min, max, nlevels) or explicit list. Default is auto from data.

  • ptype (str) – Plot type: ‘cf’ (contourf) or ‘pcm’ (pcolormesh).

  • title (str, optional) – Plot title.

  • xlabel (str, optional) – X-axis label. Default is ‘Distance (km)’ or ‘Distance (m)’.

  • ylabel (str, optional) – Y-axis label. Default is ‘Depth (m)’.

  • units (str, optional) – Units string for colorbar label.

  • colorbar (bool) – Whether to show colorbar. Default is True.

  • distance_units (str) – Units for distance axis: ‘m’ or ‘km’. Default is ‘km’.

  • depth_limits (tuple, optional) – Depth range to display as (min_depth, max_depth).

  • invert_yaxis (bool) – Whether to invert y-axis (so depth increases downward). Default is True.

Return type:

tuple[Figure, Axes]

Returns:

  • fig (matplotlib.figure.Figure) – The figure object.

  • ax (matplotlib.axes.Axes) – The axes object.

Example

>>> fig, ax = plot_transect(
...     temp_transect,  # shape (nlev, npoints)
...     transect_distance,
...     mesh.depth_levels,
...     title="Temperature",
...     units="degC",
... )
class fesomp.TransectInterpolator[source]

Bases: object

Cached interpolator for extracting vertical transects from unstructured 3D data.

This class pre-computes the KDTree and interpolation indices/weights, allowing fast repeated interpolation of different variables along the same transect.

Parameters:
  • lon (np.ndarray) – Longitudes of source points in degrees, shape (n2d,).

  • lat (np.ndarray) – Latitudes of source points in degrees, shape (n2d,).

  • start (tuple) – Starting point of transect as (lon, lat) in degrees.

  • end (tuple) – Ending point of transect as (lon, lat) in degrees.

  • npoints (int) – Number of points along the transect.

  • method (str) – Interpolation method: ‘nn’, ‘idw’, or ‘linear’.

  • influence (float) – Radius of influence in meters.

  • k (int) – Number of neighbors for IDW interpolation.

transect_lon

Longitudes of transect points.

Type:

np.ndarray

transect_lat

Latitudes of transect points.

Type:

np.ndarray

transect_distance

Distances from start along transect in meters.

Type:

np.ndarray

Example

>>> # Create interpolator once
>>> interp = TransectInterpolator(
...     mesh.lon, mesh.lat,
...     start=(-30, -60), end=(-30, 60),
...     npoints=100,
... )
>>>
>>> # Use for different 3D variables - data shape: (nlev, n2d)
>>> temp_transect = interp(temp_3d)  # Returns (nlev, npoints)
>>> salt_transect = interp(salt_3d)
lon: ndarray
lat: ndarray
start: tuple[float, float]
end: tuple[float, float]
npoints: int = 100
method: Literal['nn', 'idw', 'linear'] = 'nn'
influence: float = 80000
k: int = 10
transect_lon: ndarray
transect_lat: ndarray
transect_distance: ndarray
__post_init__()[source]

Build KDTree and compute interpolation indices.

__call__(data, fill_value=nan)[source]

Interpolate data along the transect.

Parameters:
  • data (np.ndarray) – Data values at source points. Can be: - 1D array of shape (n2d,) for surface data - 2D array of shape (nlev, n2d) for 3D data

  • fill_value (float) – Value for points outside influence radius.

Returns:

data_transect – Interpolated data along transect: - Shape (npoints,) if input was 1D - Shape (nlev, npoints) if input was 2D

Return type:

np.ndarray

get_coordinates()[source]

Get transect coordinates.

Return type:

tuple[ndarray, ndarray, ndarray]

Returns:

  • lon (np.ndarray) – Longitudes along transect.

  • lat (np.ndarray) – Latitudes along transect.

  • distance (np.ndarray) – Distance from start in meters.

__init__(lon, lat, start, end, npoints=100, method='nn', influence=80000, k=10)
Parameters:
Return type:

None

fesomp.great_circle_path(start, end, npoints=100)[source]

Compute points along a great circle path between two points.

Uses spherical linear interpolation (slerp) on a unit sphere for accurate great circle computation.

Parameters:
  • start (tuple) – Starting point as (lon, lat) in degrees.

  • end (tuple) – Ending point as (lon, lat) in degrees.

  • npoints (int) – Number of points along the path (including endpoints).

Return type:

tuple[ndarray, ndarray, ndarray]

Returns:

  • lon (np.ndarray) – Longitudes along the path in degrees, shape (npoints,).

  • lat (np.ndarray) – Latitudes along the path in degrees, shape (npoints,).

  • distance (np.ndarray) – Distance from start in meters, shape (npoints,).

Example

>>> lon, lat, dist = great_circle_path((0, 0), (90, 0), npoints=10)
>>> print(f"Total distance: {dist[-1] / 1000:.0f} km")
fesomp.great_circle_distance(start, end)[source]

Compute great circle distance between two points.

Parameters:
  • start (tuple) – Starting point as (lon, lat) in degrees.

  • end (tuple) – Ending point as (lon, lat) in degrees.

Returns:

distance – Distance in meters.

Return type:

float

Top-level Functions

Mesh Loading

fesomp.load_mesh(path)[source]

Load a FESOM2 mesh from a file or directory.

Automatically detects the format based on the path: - If path is a .nc file: loads from NetCDF - If path is a directory: loads from ASCII files

Parameters:

path (str or Path) – Path to the mesh file (NetCDF) or directory (ASCII).

Returns:

The loaded mesh object.

Return type:

Mesh

Raises:

Plotting

fesomp.plot(data, lon, lat, *, box=None, res=(360, 180), interp='nn', influence=80000, interpolator=None, cmap=None, levels=None, ptype='cf', mapproj='pc', figsize=(10, 6), rowscol=(1, 1), titles=None, units=None, colorbar=True, coastlines=True, land=False, gridlines=False, ax=None, fig=None)[source]

Plot unstructured data on a map.

Data is interpolated to a regular grid and plotted with cartopy.

Parameters:
  • data (np.ndarray or list of np.ndarray) – Data to plot. Can be a single array (npoints,) or a list of arrays for multiple subplots.

  • lon (np.ndarray) – Longitudes of data points in degrees.

  • lat (np.ndarray) – Latitudes of data points in degrees.

  • box (tuple, optional) – Bounding box (lon_min, lon_max, lat_min, lat_max). Default depends on projection: - ‘np’: (-180, 180, 60, 90) - ‘sp’: (-180, 180, -90, -60) - others: (-180, 180, -90, 90)

  • res (tuple) – Interpolation resolution (nlon, nlat). Default is (360, 180).

  • interp (str) – Interpolation method: ‘nn’ (nearest neighbor), ‘idw’, or ‘linear’.

  • influence (float) – Radius of influence for interpolation in meters. Default is 80000.

  • interpolator (RegridInterpolator, optional) – Pre-computed interpolator for caching. Speeds up repeated plots.

  • cmap (str, optional) – Colormap name. Default is ‘RdBu_r’.

  • levels (tuple or list, optional) – Contour levels. Can be (min, max, nlevels) or explicit list. Default is auto from data.

  • ptype (str) – Plot type: ‘cf’ (contourf) or ‘pcm’ (pcolormesh).

  • mapproj (str) – Map projection: ‘pc’ (Plate Carree), ‘rob’ (Robinson), ‘merc’ (Mercator), ‘np’ (North Polar), ‘sp’ (South Polar).

  • figsize (tuple) – Figure size in inches.

  • rowscol (tuple) – Subplot layout (nrows, ncols).

  • titles (str or list) – Title(s) for subplot(s).

  • units (str, optional) – Units label for colorbar.

  • colorbar (bool) – Whether to show colorbar. Default is True.

  • coastlines (bool) – Whether to draw coastlines. Default is True.

  • land (bool) – Whether to fill land areas. Default is False.

  • gridlines (bool) – Whether to draw gridlines. Default is False.

  • ax (matplotlib.axes.Axes, optional) – Existing axes to plot on (for single plot).

  • fig (matplotlib.figure.Figure, optional) – Existing figure to use.

Return type:

tuple[Figure, ndarray, RegridInterpolator]

Returns:

  • fig (matplotlib.figure.Figure) – The figure object.

  • axes (np.ndarray) – Array of axes objects.

  • interpolator (RegridInterpolator) – The interpolator used (can be reused for subsequent plots).

Example

>>> # Simple plot
>>> fig, axes, interp = fesomp.plot(temp, mesh.lon, mesh.lat)
>>>
>>> # Multiple subplots with cached interpolator
>>> fig, axes, interp = fesomp.plot(
...     [temp_surface, temp_100m, temp_500m],
...     mesh.lon, mesh.lat,
...     rowscol=(1, 3),
...     titles=['Surface', '100m', '500m'],
...     interpolator=interp,  # reuse from previous
... )
fesomp.regrid(data, lon, lat, box=(-180, 180, -90, 90), res=(360, 180), method='nn', influence=80000, fill_value=nan, interpolator=None)[source]

Interpolate unstructured data to a regular grid.

Parameters:
  • data (np.ndarray) – Data values at unstructured points, shape (npoints,).

  • lon (np.ndarray) – Longitudes of data points in degrees, shape (npoints,).

  • lat (np.ndarray) – Latitudes of data points in degrees, shape (npoints,).

  • box (tuple) – Bounding box as (lon_min, lon_max, lat_min, lat_max). Default is global (-180, 180, -90, 90).

  • res (tuple) – Output resolution as (nlon, nlat). Default is (360, 180).

  • method (str) – Interpolation method: - ‘nn’: Nearest neighbor (fast, default) - ‘idw’: Inverse distance weighting - ‘linear’: Linear interpolation (scipy griddata)

  • influence (float) – Radius of influence in meters. Points outside this radius from any source point will be set to fill_value. Default is 80000 (80 km).

  • fill_value (float) – Value for grid points with no data. Default is NaN.

  • interpolator (RegridInterpolator, optional) – Pre-computed interpolator for caching. If provided, lon, lat, box, res, method, and influence are ignored.

Return type:

tuple[ndarray, ndarray, ndarray]

Returns:

  • data_reg (np.ndarray) – Interpolated data on regular grid, shape (nlat, nlon).

  • lon_reg (np.ndarray) – 1D array of output longitudes.

  • lat_reg (np.ndarray) – 1D array of output latitudes.

Example

>>> # Simple one-off interpolation
>>> data_reg, lon_reg, lat_reg = regrid(temp, mesh.lon, mesh.lat)
>>>
>>> # With caching for multiple variables
>>> interp = RegridInterpolator(mesh.lon, mesh.lat)
>>> temp_reg, lon_reg, lat_reg = regrid(temp, mesh.lon, mesh.lat, interpolator=interp)
>>> salt_reg, _, _ = regrid(salt, mesh.lon, mesh.lat, interpolator=interp)
fesomp.transect(data, mesh, start, end, *, depth=None, npoints=100, method='nn', influence=80000, fill_value=nan, interpolator=None, ax=None, fig=None, figsize=(12, 5), cmap=None, levels=None, ptype='cf', title=None, xlabel=None, ylabel=None, units=None, colorbar=True, distance_units='km', depth_limits=None, invert_yaxis=True)[source]

Interpolate and plot a vertical transect through 3D ocean data.

This is a convenience function combining interpolate_transect and plot_transect. Automatically detects: - Horizontal location: nodes (n2d points) vs elements (nelem points) - Vertical coordinate: levels (interfaces) vs layers (centers)

Parameters:
  • data (np.ndarray) – Data values at unstructured points: - Shape (nlev, n2d) for data on nodes - Shape (nlev, nelem) for data on elements Can be defined on either levels (interfaces) or layers (centers).

  • mesh (Mesh) – The mesh object containing lon, lat, and depth information.

  • start (tuple) – Starting point of transect as (lon, lat) in degrees.

  • end (tuple) – Ending point of transect as (lon, lat) in degrees.

  • depth (np.ndarray, optional) – Depth coordinates in meters. If not provided, automatically selects mesh.depth_levels or mesh.depth_layers based on data shape.

  • npoints (int) – Number of points along the transect. Default is 100.

  • method (str) – Interpolation method: ‘nn’, ‘idw’, or ‘linear’.

  • influence (float) – Radius of influence in meters. Default is 80000 (80 km).

  • fill_value (float) – Value for transect points with no data. Default is NaN.

  • interpolator (TransectInterpolator, optional) – Pre-computed interpolator for caching.

  • ax (matplotlib.axes.Axes, optional) – Existing axes to plot on.

  • fig (matplotlib.figure.Figure, optional) – Existing figure to use.

  • figsize (tuple) – Figure size in inches if creating new figure.

  • cmap (str, optional) – Colormap name. Default is ‘RdBu_r’.

  • levels (tuple or list, optional) – Contour levels. Can be (min, max, nlevels) or explicit list.

  • ptype (str) – Plot type: ‘cf’ (contourf) or ‘pcm’ (pcolormesh).

  • title (str, optional) – Plot title.

  • xlabel (str, optional) – X-axis label.

  • ylabel (str, optional) – Y-axis label.

  • units (str, optional) – Units string for colorbar label.

  • colorbar (bool) – Whether to show colorbar. Default is True.

  • distance_units (str) – Units for distance axis: ‘m’ or ‘km’. Default is ‘km’.

  • depth_limits (tuple, optional) – Depth range to display as (min_depth, max_depth).

  • invert_yaxis (bool) – Whether to invert y-axis. Default is True.

Return type:

tuple[Figure, Axes, TransectInterpolator]

Returns:

  • fig (matplotlib.figure.Figure) – The figure object.

  • ax (matplotlib.axes.Axes) – The axes object.

  • interpolator (TransectInterpolator) – The interpolator used (can be reused).

Example

>>> # Plot temperature transect (data on layers)
>>> fig, ax, interp = fesomp.transect(
...     temp_3d,  # shape (nlev-1, n2d) - on layers
...     mesh,
...     start=(-30, -60), end=(-30, 60),
...     title="Temperature along 30W",
...     units="degC",
...     depth_limits=(0, 1000),
... )
>>>
>>> # Reuse interpolator for salinity
>>> fig2, ax2, _ = fesomp.transect(
...     salt_3d, mesh,
...     start=(-30, -60), end=(-30, 60),
...     interpolator=interp,
...     title="Salinity along 30W",
... )
fesomp.plot_transect(data, distance, depth, *, ax=None, fig=None, figsize=(12, 5), cmap=None, levels=None, ptype='cf', title=None, xlabel=None, ylabel=None, units=None, colorbar=True, distance_units='km', depth_limits=None, invert_yaxis=True)[source]

Plot a vertical transect as a 2D cross-section.

Parameters:
  • data (np.ndarray) – Data values along transect, shape (nlev, npoints).

  • distance (np.ndarray) – Distance along transect in meters, shape (npoints,).

  • depth (np.ndarray) – Depth levels in meters (positive downward), shape (nlev,).

  • ax (matplotlib.axes.Axes, optional) – Existing axes to plot on.

  • fig (matplotlib.figure.Figure, optional) – Existing figure to use.

  • figsize (tuple) – Figure size in inches if creating new figure.

  • cmap (str, optional) – Colormap name. Default is ‘RdBu_r’.

  • levels (tuple or list, optional) – Contour levels. Can be (min, max, nlevels) or explicit list. Default is auto from data.

  • ptype (str) – Plot type: ‘cf’ (contourf) or ‘pcm’ (pcolormesh).

  • title (str, optional) – Plot title.

  • xlabel (str, optional) – X-axis label. Default is ‘Distance (km)’ or ‘Distance (m)’.

  • ylabel (str, optional) – Y-axis label. Default is ‘Depth (m)’.

  • units (str, optional) – Units string for colorbar label.

  • colorbar (bool) – Whether to show colorbar. Default is True.

  • distance_units (str) – Units for distance axis: ‘m’ or ‘km’. Default is ‘km’.

  • depth_limits (tuple, optional) – Depth range to display as (min_depth, max_depth).

  • invert_yaxis (bool) – Whether to invert y-axis (so depth increases downward). Default is True.

Return type:

tuple[Figure, Axes]

Returns:

  • fig (matplotlib.figure.Figure) – The figure object.

  • ax (matplotlib.axes.Axes) – The axes object.

Example

>>> fig, ax = plot_transect(
...     temp_transect,  # shape (nlev, npoints)
...     transect_distance,
...     mesh.depth_levels,
...     title="Temperature",
...     units="degC",
... )
fesomp.interpolate_transect(data, lon, lat, start, end, *, npoints=100, method='nn', influence=80000, fill_value=nan, interpolator=None)[source]

Interpolate unstructured data along a great circle transect.

Parameters:
  • data (np.ndarray) – Data values at unstructured points: - Shape (n2d,) for surface data - Shape (nlev, n2d) for 3D data

  • lon (np.ndarray) – Longitudes of data points in degrees.

  • lat (np.ndarray) – Latitudes of data points in degrees.

  • start (tuple) – Starting point of transect as (lon, lat) in degrees.

  • end (tuple) – Ending point of transect as (lon, lat) in degrees.

  • npoints (int) – Number of points along the transect. Default is 100.

  • method (str) – Interpolation method: - ‘nn’: Nearest neighbor (fast, default) - ‘idw’: Inverse distance weighting - ‘linear’: Linear interpolation (scipy griddata)

  • influence (float) – Radius of influence in meters. Default is 80000 (80 km).

  • fill_value (float) – Value for transect points with no data. Default is NaN.

  • interpolator (TransectInterpolator, optional) – Pre-computed interpolator for caching.

Return type:

tuple[ndarray, ndarray, TransectInterpolator]

Returns:

  • data_transect (np.ndarray) – Interpolated data along transect: - Shape (npoints,) if input was 1D - Shape (nlev, npoints) if input was 2D

  • transect_distance (np.ndarray) – Distance from start along transect in meters.

  • interpolator (TransectInterpolator) – The interpolator used (can be reused).

Example

>>> # 3D ocean data transect
>>> temp_t, dist, interp = interpolate_transect(
...     temp_3d,  # shape (nlev, n2d)
...     mesh.lon, mesh.lat,
...     start=(-30, -60), end=(-30, 60),
... )
>>> # temp_t has shape (nlev, npoints)

Geometry

fesomp.great_circle_path(start, end, npoints=100)[source]

Compute points along a great circle path between two points.

Uses spherical linear interpolation (slerp) on a unit sphere for accurate great circle computation.

Parameters:
  • start (tuple) – Starting point as (lon, lat) in degrees.

  • end (tuple) – Ending point as (lon, lat) in degrees.

  • npoints (int) – Number of points along the path (including endpoints).

Return type:

tuple[ndarray, ndarray, ndarray]

Returns:

  • lon (np.ndarray) – Longitudes along the path in degrees, shape (npoints,).

  • lat (np.ndarray) – Latitudes along the path in degrees, shape (npoints,).

  • distance (np.ndarray) – Distance from start in meters, shape (npoints,).

Example

>>> lon, lat, dist = great_circle_path((0, 0), (90, 0), npoints=10)
>>> print(f"Total distance: {dist[-1] / 1000:.0f} km")
fesomp.great_circle_distance(start, end)[source]

Compute great circle distance between two points.

Parameters:
  • start (tuple) – Starting point as (lon, lat) in degrees.

  • end (tuple) – Ending point as (lon, lat) in degrees.

Returns:

distance – Distance in meters.

Return type:

float

Classes

class fesomp.Mesh[source]

Bases: object

Represents a FESOM2 unstructured mesh.

This class holds the core mesh data including node coordinates, element connectivity, and vertical structure. Topology, geometry, and spatial indexing are lazily computed on first access.

lon

Longitude of nodes in degrees, shape (n2d,).

Type:

np.ndarray

lat

Latitude of nodes in degrees, shape (n2d,).

Type:

np.ndarray

triangles

Triangle connectivity, shape (nelem, 3), 0-indexed.

Type:

np.ndarray

nlev

Number of vertical levels.

Type:

int

depth_levels

Depth at each level interface, shape (nlev,).

Type:

np.ndarray

depth_layers

Depth at layer centers, shape (nlev-1,).

Type:

np.ndarray

node_levels

Number of active levels at each node, shape (n2d,).

Type:

np.ndarray

elem_levels

Number of active levels at each element, shape (nelem,).

Type:

np.ndarray

node_bottom_depth

Bottom depth at each node, shape (n2d,).

Type:

np.ndarray

elem_bottom_depth

Bottom depth at each element, shape (nelem,).

Type:

np.ndarray

lon: ndarray
lat: ndarray
triangles: ndarray
nlev: int
depth_levels: ndarray
depth_layers: ndarray
node_levels: ndarray
elem_levels: ndarray
node_bottom_depth: ndarray
elem_bottom_depth: ndarray
__post_init__()[source]

Validate mesh data and ensure correct dtypes.

Return type:

None

property n2d: int

Number of 2D nodes.

property nelem: int

Number of triangular elements.

property topology: Topology

Get mesh topology (edges, neighbors, etc.).

Computed lazily on first access if not pre-loaded from NetCDF.

property geometry: Geometry

Get mesh geometry (areas, gradients, etc.).

Computed lazily on first access if not pre-loaded from NetCDF.

property spatial_index: SpatialIndex

Get spatial index for efficient point queries.

Built lazily on first access.

property lon_elem: ndarray

Longitude of element (triangle) centers in degrees.

Computed lazily on first access. Handles cyclic triangles that cross the dateline correctly.

property lat_elem: ndarray

Latitude of element (triangle) centers in degrees.

Computed lazily on first access.

find_nearest(lon, lat, k=1)[source]

Find the k nearest nodes to a given point.

Parameters:
  • lon (float) – Longitude in degrees.

  • lat (float) – Latitude in degrees.

  • k (int, optional) – Number of nearest neighbors to return.

Returns:

Indices of the k nearest nodes.

Return type:

np.ndarray

find_in_radius(lon, lat, radius_km)[source]

Find all nodes within a given radius of a point.

Parameters:
  • lon (float) – Longitude in degrees.

  • lat (float) – Latitude in degrees.

  • radius_km (float) – Search radius in kilometers.

Returns:

Indices of nodes within the radius.

Return type:

np.ndarray

subset_by_bbox(lon_min, lon_max, lat_min, lat_max)[source]

Find all nodes within a bounding box.

Parameters:
  • lon_min (float) – Longitude bounds in degrees.

  • lon_max (float) – Longitude bounds in degrees.

  • lat_min (float) – Latitude bounds in degrees.

  • lat_max (float) – Latitude bounds in degrees.

Returns:

Indices of nodes within the bounding box.

Return type:

np.ndarray

get_triangulation(mask_cyclic=True)[source]

Create a matplotlib Triangulation object for plotting.

Parameters:

mask_cyclic (bool, optional) – If True (default), mask triangles that cross the dateline to prevent ugly lines spanning the globe.

Returns:

Triangulation object ready for use with triplot, tripcolor, etc.

Return type:

matplotlib.tri.Triangulation

Example

>>> tri = mesh.get_triangulation()
>>> plt.triplot(tri, 'b-', linewidth=0.2)
__init__(lon, lat, triangles, nlev, depth_levels, depth_layers, node_levels, elem_levels, node_bottom_depth, elem_bottom_depth, _preloaded_topology=None, _preloaded_geometry=None, _topology=None, _geometry=None, _spatial_index=None, _lon_elem=None, _lat_elem=None)
Parameters:
Return type:

None

class fesomp.RegridInterpolator[source]

Bases: object

Cached interpolator for regridding unstructured data.

This class pre-computes and caches the KDTree and interpolation indices/weights, allowing fast repeated interpolation of different variables on the same grid.

Parameters:
  • lon (np.ndarray) – Longitudes of source points in degrees.

  • lat (np.ndarray) – Latitudes of source points in degrees.

  • box (tuple) – Target bounding box as (lon_min, lon_max, lat_min, lat_max).

  • res (tuple) – Target resolution as (nlon, nlat).

  • method (str) – Interpolation method: ‘nn’, ‘idw’, or ‘linear’.

  • influence (float) – Radius of influence in meters.

  • k (int) – Number of neighbors for IDW interpolation.

Example

>>> # Create interpolator once
>>> interp = RegridInterpolator(mesh.lon, mesh.lat, box=(-180, 180, -90, 90))
>>>
>>> # Use many times for different variables
>>> temp_reg, lon_reg, lat_reg = interp(ds['temp'].values)
>>> salt_reg, _, _ = interp(ds['salt'].values)
lon: ndarray
lat: ndarray
box: tuple[float, float, float, float] = (-180, 180, -90, 90)
res: tuple[int, int] = (360, 180)
method: Literal['nn', 'idw', 'linear'] = 'nn'
influence: float = 80000
k: int = 10
__post_init__()[source]

Build KDTree and compute interpolation indices.

__call__(data, fill_value=nan)[source]

Interpolate data to regular grid.

Parameters:
  • data (np.ndarray) – Data values at source points, shape (npoints,).

  • fill_value (float) – Value for points outside influence radius.

Return type:

tuple[ndarray, ndarray, ndarray]

Returns:

  • data_reg (np.ndarray) – Interpolated data, shape (nlat, nlon).

  • lon_reg (np.ndarray) – 1D array of output longitudes.

  • lat_reg (np.ndarray) – 1D array of output latitudes.

__init__(lon, lat, box=(-180, 180, -90, 90), res=(360, 180), method='nn', influence=80000, k=10)
Parameters:
Return type:

None

class fesomp.TransectInterpolator[source]

Bases: object

Cached interpolator for extracting vertical transects from unstructured 3D data.

This class pre-computes the KDTree and interpolation indices/weights, allowing fast repeated interpolation of different variables along the same transect.

Parameters:
  • lon (np.ndarray) – Longitudes of source points in degrees, shape (n2d,).

  • lat (np.ndarray) – Latitudes of source points in degrees, shape (n2d,).

  • start (tuple) – Starting point of transect as (lon, lat) in degrees.

  • end (tuple) – Ending point of transect as (lon, lat) in degrees.

  • npoints (int) – Number of points along the transect.

  • method (str) – Interpolation method: ‘nn’, ‘idw’, or ‘linear’.

  • influence (float) – Radius of influence in meters.

  • k (int) – Number of neighbors for IDW interpolation.

transect_lon

Longitudes of transect points.

Type:

np.ndarray

transect_lat

Latitudes of transect points.

Type:

np.ndarray

transect_distance

Distances from start along transect in meters.

Type:

np.ndarray

Example

>>> # Create interpolator once
>>> interp = TransectInterpolator(
...     mesh.lon, mesh.lat,
...     start=(-30, -60), end=(-30, 60),
...     npoints=100,
... )
>>>
>>> # Use for different 3D variables - data shape: (nlev, n2d)
>>> temp_transect = interp(temp_3d)  # Returns (nlev, npoints)
>>> salt_transect = interp(salt_3d)
lon: ndarray
lat: ndarray
start: tuple[float, float]
end: tuple[float, float]
npoints: int = 100
method: Literal['nn', 'idw', 'linear'] = 'nn'
influence: float = 80000
k: int = 10
transect_lon: ndarray
transect_lat: ndarray
transect_distance: ndarray
__post_init__()[source]

Build KDTree and compute interpolation indices.

__call__(data, fill_value=nan)[source]

Interpolate data along the transect.

Parameters:
  • data (np.ndarray) – Data values at source points. Can be: - 1D array of shape (n2d,) for surface data - 2D array of shape (nlev, n2d) for 3D data

  • fill_value (float) – Value for points outside influence radius.

Returns:

data_transect – Interpolated data along transect: - Shape (npoints,) if input was 1D - Shape (nlev, npoints) if input was 2D

Return type:

np.ndarray

get_coordinates()[source]

Get transect coordinates.

Return type:

tuple[ndarray, ndarray, ndarray]

Returns:

  • lon (np.ndarray) – Longitudes along transect.

  • lat (np.ndarray) – Latitudes along transect.

  • distance (np.ndarray) – Distance from start in meters.

__init__(lon, lat, start, end, npoints=100, method='nn', influence=80000, k=10)
Parameters:
Return type:

None