Coastline Steps and Tasks

This section of the Developer’s guide covers the code for the coastline extraction workflow. The Coastline tasks section describes the user-facing aspects of the workflow such as the conventions, algorithms, and config options.

The polaris.tasks.mesh.spherical.unified.coastline module provides a raster-first coastline workflow on latitude-longitude grids. It computes the full coastline at the finest supported resolution (0.03125°) and remaps the results to coarser resolutions rather than repeating the expensive computation at each resolution tier.

Available tasks

The helper polaris.tasks.mesh.spherical.unified.coastline.add_coastline_tasks() registers one standalone task for each supported latitude-longitude target grid:

  • mesh/spherical/unified/coastline/0.03125_degree/task

  • mesh/spherical/unified/coastline/0.06250_degree/task

  • mesh/spherical/unified/coastline/0.12500_degree/task

  • mesh/spherical/unified/coastline/0.25000_degree/task

Each task is an instance of polaris.tasks.mesh.spherical.unified.coastline.LatLonCoastlineTask.

add_coastline_tasks iterates over LAT_LON_TARGET_GRID_RESOLUTIONS in sorted (ascending) order so that the finest-resolution task is registered first. This ensures the shared polaris.tasks.mesh.spherical.unified.coastline.ComputeCoastlineStep is created before coarser tasks retrieve it via component.get_or_create_shared_step.

Task structure and shared steps

LatLonCoastlineTask has a uniform structure at all resolutions:

  1. Calls polaris.tasks.mesh.spherical.unified.coastline.get_unified_mesh_coastline_steps() with resolution, cached=False, and include_viz=True. That factory obtains the shared topography-combine step from e3sm/init internally, always creates or retrieves the shared polaris.tasks.mesh.spherical.unified.coastline.ComputeCoastlineStep at the finest supported resolution (0.03125°), and for coarser-resolution tasks additionally creates a polaris.tasks.mesh.spherical.unified.coastline.RemapCoastlineStep.

  2. Sets the shared coastline.cfg and adds all returned steps, using the dict keys returned by the factory as symlink names in the task workdir.

Finest resolution (0.03125°)

The task workdir contains symlinks to:

  • combine_topo_lat_lon_0.03125_degree — the shared topography-combine step at 0.03125°

  • coastline_final — the shared ComputeCoastlineStep

  • viz_coastline — the shared VizCoastlineStep

Coarser resolutions (0.06250°, 0.12500°, 0.25000°)

The task workdir contains:

  • combine_topo_lat_lon_0.03125_degree — the same shared topography-combine step at 0.03125° (the finest combine step is always used by ComputeCoastlineStep regardless of which task instantiates it)

  • coastline_compute — the shared ComputeCoastlineStep at 0.03125°

  • coastline_final — a RemapCoastlineStep at the task’s resolution

  • viz_coastline — a VizCoastlineStep for the remapped output

The ComputeCoastlineStep is created once (by the finest-resolution task) and shared via component.get_or_create_shared_step. Coarser tasks retrieve the existing instance; the combine_topo_step argument passed by a coarser task has no effect once the step has already been created.

Implementation map

ComputeCoastlineStep (0.03125°)

ComputeCoastlineStep.run() reads coastline.cfg, opens topography.nc, and dispatches the numerical work to polaris.tasks.mesh.spherical.unified.coastline.compute.build_coastline_datasets(). That helper operates on (lat, lon) NumPy arrays and, for each convention:

  • builds a candidate ocean mask from base_elevation, ice_mask, and grounded_mask;

  • calls _flood_fill_ocean to retain only the connected ocean;

  • calls _coastline_edges to derive the raster edge diagnostics used for coastline sampling; and

  • calls _signed_distance_from_mask to compute the signed-distance field.

The results are assembled by _build_single_coastline_dataset into one raster dataset per convention with metadata that records the thresholds, flood-fill seed strategy, and sign convention.

The core numerical functions live in polaris.mesh.spherical.coastline; ComputeCoastlineStep is responsible only for task-level configuration, shared critical-transect loading, and writing outputs.

RemapCoastlineStep (coarser resolutions)

RemapCoastlineStep.run() reads coastline.cfg, then for each convention:

  1. Reads the 0.03125° ocean_mask (linked as fine_coastline_{convention}.nc) and signed_distance.

  2. Block-averages the fine ocean_mask onto the coarser grid (_block_average), yielding an ocean fraction in [0, 1], then thresholds at mask_threshold to produce a binary ocean_mask. No second flood fill is performed; connectivity is inherited from the 0.03125° result.

  3. Bilinearly remaps the absolute value of the fine signed_distance (_bilinear_zoom) and re-signs using the coarser ocean_mask.

  4. Writes the output with provenance attributes that record the source resolution and source step path.

Because all four grids are perfectly nested (each coarser resolution is an exact 2ⁿ multiple of 0.03125°), block averaging is exact conservative remapping with no ESMF or pyremap dependency.

Visualization

VizCoastlineStep reads the coastline files and writes:

  • global and Antarctic binary plots of the final ocean_mask for each convention; and

  • global and Antarctic signed-distance plots for each convention.

It also writes debug_summary.txt, which records convention-specific counts such as ocean and land cells and the min/max signed distance.

VizCoastlineStep is duck-typed on output_filenames and path, so it works with both ComputeCoastlineStep (0.03125°) and RemapCoastlineStep (coarser resolutions) as its coastline_step.

Extension points

The current implementation is intentionally narrow: lat-lon target grids, three coastline conventions, and raster outputs. Common developer changes are:

  • Adding a new target resolution. Add the resolution to LAT_LON_TARGET_GRID_RESOLUTIONS in polaris.mesh.spherical.unified.resolutions. The new resolution must be an exact 2ⁿ multiple of 0.03125° so that RemapCoastlineStep can block-average from the finest grid. Also add the resolution to the e3sm/init/topo/combine tasks if combined topography at that resolution will be needed by other workflows.

  • Adding a new convention. Extend CONVENTIONS and the candidate_masks dictionary in build_coastline_datasets(), then update the visualization step and the associated tests.

  • Extending the output contract. Update _build_single_coastline_dataset() and _coastline_remap_dataset() in parallel so both the prepare and remap paths produce the new variable, then update the plotting code in viz.py and the tests.

Configuration plumbing

The coastline workflow is configured through a single shared coastline.cfg that covers all resolution tiers.

ComputeCoastlineStep consumes [coastline] options:

  • include_critical_transects

  • mask_threshold

  • sea_level_elevation

  • distance_chunk_size

RemapCoastlineStep consumes [coastline] options:

  • mask_threshold — applied to the block-averaged ocean fraction

VizCoastlineStep consumes [viz_coastline] options:

  • antarctic_max_latitude

  • dpi

  • signed_distance_limit

The Coastline tasks page explains how these options affect the user-visible behavior of the workflow.

Example usage

To register the default coastline tasks for the mesh component:

from polaris.tasks.mesh.spherical.unified.coastline import add_coastline_tasks

add_coastline_tasks(component)

To reuse the shared finest-resolution ComputeCoastlineStep inside another workflow that needs the 0.03125° coastline products:

from polaris.tasks.mesh.spherical.unified.coastline import (
    get_unified_mesh_coastline_steps,
)

steps, config = get_unified_mesh_coastline_steps(
    resolution=0.03125,
    cached=True,
    include_viz=False,
)
fine_coastline_step = steps['coastline_final']

To get coastline steps at a coarser resolution:

from polaris.tasks.mesh.spherical.unified.coastline import (
    get_unified_mesh_coastline_steps,
)

steps, config = get_unified_mesh_coastline_steps(
    resolution=0.25,
    cached=True,
    include_viz=False,
)
# steps['coastline_compute'] is the shared ComputeCoastlineStep at 0.03125°
# steps['coastline_final'] is the RemapCoastlineStep at 0.25°
coarse_coastline_step = steps['coastline_final']

get_unified_mesh_coastline_steps returns a 2-tuple (steps, config). The combine step is obtained internally by the factory; callers do not need to provide it. The cached parameter controls whether the returned steps have their cached flag set (default True for use in downstream tasks; False for standalone coastline tasks that run the steps unconditionally).

Test coverage

Unit tests in tests/mesh/spherical/unified/test_coastline.py validate the public coastline dataset contract, convention-specific Antarctic behavior, exclusion of disconnected inland water, and the use of the northernmost latitude row for flood-fill seeding.

Unit tests in tests/mesh/spherical/unified/test_coastline_remap.py validate the remap helpers (_block_average, _bilinear_zoom, _coarsen_coordinate, _compute_scale), the thresholding and sign convention of _coastline_remap_dataset, end-to-end execution of RemapCoastlineStep.run(), and that get_unified_mesh_coastline_steps creates a RemapCoastlineStep when resolution differs from FINEST_RESOLUTION.