asp_plot.dem_benchmark#

Benchmark many DEMs against one altimetry reference (issue #169).

The report scores one DEM against ICESat-2 (or LOLA/MOLA). This module scores any number of DEMs – different scene combinations, joint multi-view triangulation vs. pairwise stereo + dem_mosaic, parameter sweeps – against the same fixed altimetry sample, so the numbers are directly comparable:

  • coverage inside a common area of interest (by default the intersection of all DEM footprints, so crop windows that differ per run compare fairly)

  • triangulation error, from the *-IntersectionErr.tif point2dem writes next to each *-DEM.tif (absent for a mosaic)

  • altimetry residuals (altimetry minus DEM: n, median, NMAD, RMSE) before and, optionally, after a pc_align --compute-translation-only per DEM, with the translation that removed

  • optionally, each DEM’s difference against one of the candidates named as the reference (DEM minus reference median / NMAD)

Every DEM is scored with the same recipe the report uses for one DEM: the cached ATL06-SR parquet is replayed (no SlideRule request), water returns are dropped with the ESA WorldCover classes stored in the cache, and dh outliers beyond 3σ are removed per DEM (after a gross-outlier cut at 30 NMAD). pc_align products and translated DEM copies are kept out of the candidates’ folders, under <directory>/dem_benchmark/<label>/, so nothing is written into the stereo runs.

Examples

>>> from asp_plot.dem_benchmark import DEMBenchmark
>>> bench = DEMBenchmark(
...     directory="atlanta_mvs",
...     dems={
...         "MVS 3-scene": "atlanta_mvs/stereo_mvs3/run-DEM.tif",
...         "MVS 5-scene": "atlanta_mvs/stereo_mvs5/run-DEM.tif",
...         "3 pairs + mosaic": "atlanta_mvs/pairwise_mosaic-DEM.tif",
...     },
...     parquet="atlanta_mvs/atl06sr_all.parquet",
... )
>>> stats = bench.run()
>>> bench.summary_plot(save_dir="atlanta_mvs", fig_fn="dem_benchmark.png")

Attributes#

Classes#

DEMBenchmark

Score many DEMs against one altimetry sample.

Functions#

intersection_error_path(dem_fn)

Path of the point2dem --errorimage sibling of <prefix>-DEM.tif, or None.

label_from_dem_path(dem_fn)

Derive a short label for a DEM from its path.

parse_dem_specs(specs)

Turn CLI-style DEM specs into an ordered {label: path} mapping.

Module Contents#

class asp_plot.dem_benchmark.DEMBenchmark(directory, dems, parquet=None, altimetry_csv=None, key='all', reference=None, aoi='intersection', filter_out='water', n_sigma=3, title=None)#

Score many DEMs against one altimetry sample.

Parameters:
  • directory (str) – Working folder. pc_align products, the pc_align CSV and the translated DEM copy for each candidate go under <directory>/dem_benchmark/<label>/.

  • dems (dict or list) – {label: dem_fn} (order preserved), or a list of paths / "label=path" strings (see parse_dem_specs()).

  • parquet (str or dict, optional) – ICESat-2 ATL06-SR parquet cache written by a prior report or Altimetry.request_atl06sr_multi_processing(save_to_parquet=True); either one path (used as processing level key) or a {key: path} mapping. Required for Earth DEMs.

  • altimetry_csv (str, optional) – LOLA/MOLA CSV (see request_planetary_altimetry). Required for Moon/Mars DEMs.

  • key (str, optional) – ATL06-SR processing level to score against, default "all".

  • reference (str, optional) – Label of the candidate the others are differenced against for the vs_ref_* columns. Default None (columns left NaN).

  • aoi (str, tuple or None, optional) – Area for the coverage and triangulation-error statistics: "intersection" (default) uses the common footprint of all DEMs; a (left, bottom, right, top) tuple is taken in the first DEM’s CRS; None uses each DEM’s own extent (not comparable across crops).

  • filter_out (str or None, optional) – ESA WorldCover group dropped before differencing, default "water" (the report’s setting). None keeps every return.

  • n_sigma (float or None, optional) – Per-DEM dh outlier cut, default 3 (the report’s setting).

  • title (str, optional) – Figure title.

Notes

After run(), stats_df holds one row per DEM with the columns in STATS_COLUMNS (residual columns are altimetry minus DEM, in meters); altimetry maps each label to its Altimetry object, for per-DEM figures such as mapview_plot_atl06sr_to_dem() or histogram_by_landcover(); and dh / dh_aligned map each label to the residual series scored (aligned only when pc_align ran for it).

aoi_area_km2()#

Area of the coverage/IE window in km² (None when each DEM uses its own extent).

histogram_plot(aligned='auto', bins=100, xlim=None, sort=True, save_dir=None, fig_fn=None, dpi=None)#

Overlaid residual histograms, one outline per DEM.

Parameters:
  • aligned ({"auto", True, False}, optional) – Plot post-alignment residuals when every DEM has them ("auto", default), always (True, DEMs without them fall back to pre-alignment), or never (False).

  • bins (int, optional) – Histogram bins, default 100.

  • xlim (float, optional) – Half-width of the plotted range in meters; default 3× the largest NMAD among the DEMs. Residuals beyond it are not drawn (the legend counts all of them).

  • sort (bool, optional) – Order the legend best-first as in summary_plot(), default True.

Return type:

matplotlib.figure.Figure

label_directory(label)#

Working folder for one candidate.

run(pc_align=True, minimum_points=500, max_displacement=None)#

Score every DEM and return the stats table.

Parameters:
  • pc_align (bool, optional) – Also run pc_align --compute-translation-only per DEM and re-score against the translated copy. Default True. Existing pc_align outputs under the benchmark folder are reused, so a re-run makes no pc_align call and works offline.

  • minimum_points (int, optional) – Skip pc_align for a DEM with fewer valid dh points, default 500 (the report’s threshold).

  • max_displacement (float, optional) – pc_align --max-displacement in meters. Default None: 20 m on Earth, 500 m on the Moon/Mars, matching Alignment.

Returns:

self.stats_df: one row per DEM, columns STATS_COLUMNS.

Return type:

pandas.DataFrame

save_stats(csv_fn)#

Write stats_df to csv_fn (creating its folder) and return the path.

summary_plot(sort=True, save_dir=None, fig_fn=None, dpi=None)#

One row per DEM, one panel per metric.

Panels: coverage (% valid inside the AOI, area printed), triangulation error (median, NMAD printed; omitted when no DEM has an IntersectionErr raster), and altimetry-minus-DEM median and NMAD – as dumbbells from before (open) to after (filled) pc_align when alignment ran. A translation-only pc_align leaves NMAD essentially unchanged by construction, so that panel’s two markers coincide; the median panel is where the alignment shows. Rows are sorted best-first by post-alignment NMAD (pre-alignment when pc_align did not run) unless sort=False.

Return type:

matplotlib.figure.Figure

altimetry#
altimetry_csv#
property benchmark_directory#

Folder holding the per-label pc_align products and translated DEMs.

body#
dh#
dh_aligned#
directory#
filter_out = 'water'#
key = 'all'#
n_sigma = 3#
parquet#
reference = None#
stats_df = None#
title = None#
asp_plot.dem_benchmark.intersection_error_path(dem_fn)#

Path of the point2dem --errorimage sibling of <prefix>-DEM.tif, or None.

asp_plot.dem_benchmark.label_from_dem_path(dem_fn)#

Derive a short label for a DEM from its path.

Strips the ASP -DEM.tif suffix; when what remains is a generic ASP output prefix (run, out, …) the containing folder is used instead, since that is what distinguishes one run from another.

Examples

>>> label_from_dem_path("atlanta_mvs/stereo_mvs3/run-DEM.tif")
'stereo_mvs3'
>>> label_from_dem_path("atlanta_mvs/pairwise_mosaic-DEM.tif")
'pairwise_mosaic'
asp_plot.dem_benchmark.parse_dem_specs(specs)#

Turn CLI-style DEM specs into an ordered {label: path} mapping.

Each spec is either a path (labelled via label_from_dem_path()) or label=path. Duplicate labels are disambiguated with the containing folder so two run-DEM.tif never collapse into one row.

asp_plot.dem_benchmark.GENERIC_STEMS#
asp_plot.dem_benchmark.MAX_WINDOW_PIXELS = 16000000#
asp_plot.dem_benchmark.STATS_COLUMNS = ['label', 'dem_fn', 'gsd_m', 'valid_pct', 'valid_area_km2', 'ie_median_m', 'ie_nmad_m',...#
asp_plot.dem_benchmark.logger#