Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
372bb99
red: increment 15b (the domain in its own CRS)
skavhaug Sep 27, 2026
0011741
green: increment 15b (the domain in its own CRS)
skavhaug Sep 27, 2026
4387fb6
15b docs: re-point the check_crs citation to d34d79d; crs.py in the l…
skavhaug Sep 27, 2026
0dd586a
15b docs: re-wrap the R9 paragraph the citation re-point lengthened
skavhaug Sep 27, 2026
8dc7298
15b docs: finish the R9 re-wrap
skavhaug Sep 27, 2026
bb0886c
15b: increment 16's U1 superseded; ROADMAP: inputs in their own CRS s…
skavhaug Sep 27, 2026
16bd418
15b review fixes: prose (project_structure, 15's plan-equals note, 16…
skavhaug Sep 27, 2026
6143d87
15b tests: needed region grown by the plan's spacing, the snap band p…
skavhaug Sep 27, 2026
914dfc8
15b: the needed region is grown by the chosen plan's spacing
skavhaug Sep 27, 2026
68c1f34
15b docs: the red-suite pins name the chosen plan's cell, the snap ba…
skavhaug Sep 27, 2026
f115846
15b review fixes: the CI comment names what the codecs step runs; the…
skavhaug Sep 27, 2026
c813dde
15b tests: the re-plan loop grows again when the lattice changes
skavhaug Sep 27, 2026
55c5d9d
15b review fixes: the re-plan test's docstring, the codecs-step comme…
skavhaug Sep 27, 2026
80fda64
Merge 15a (#105 tip) into 15b
skavhaug Sep 28, 2026
b4c1e4f
15b: the status line says 15b is implemented; LOC against 15a's tip
skavhaug Sep 28, 2026
6519a26
15b tests: the seam report on the domain path
skavhaug Sep 28, 2026
be8c8d3
ROADMAP: DOM10 for shading and canopy height, for later (Ola)
skavhaug Sep 28, 2026
d52f6c5
ROADMAP: the DOM10 note's provenance no stronger than known; 15a merg…
skavhaug Sep 28, 2026
5d12ad0
15b: Ola's ruling: with --domain, seams are counted inside the needed…
skavhaug Sep 28, 2026
248bc50
15: the fresh DTM10 download measured: still per-tile exports, overla…
skavhaug Sep 28, 2026
320ea75
15b tests: with a domain, seams inside the needed region only (Ola)
skavhaug Sep 28, 2026
e6b69de
15b: with a domain, seams are counted inside the needed region only (…
skavhaug Sep 28, 2026
8f46f13
15b: LOC at the tip (162 added, 2 over the worst case, why); the prob…
skavhaug Sep 28, 2026
24d178c
15b tests: the same-CRS guarantee without machine-recorded digests
skavhaug Sep 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -185,15 +185,20 @@ jobs:
- name: Tests
run: pytest

# The GeoTIFF suites branch on the `codecs` extra: some tests need
# imagecodecs (LZW, the real Kartverket DEM), others test its absence.
# No single environment runs both halves, so the step above covers the
# absent half and this one installs the extra and re-runs both files.
# Suites that branch on the `codecs` extra: some tests need imagecodecs
# (LZW, the real Kartverket DEM and DTM10 extracts), others test its
# absence. No single environment runs both halves, so the step above
# covers the absent half and this one installs the extra and re-runs the
# codecs-gated suites: the GeoTIFF ones, and the CLI and golden suites that
# mesh the real tile (test_cli_mesh_dem.py runs in the viewer step below).
- name: Tests with the codecs extra
run: |
python -m pip install -e ".[dev,codecs]"
pytest --no-cov tests/python/test_io_geotiff.py tests/python/test_geotiff_fixtures.py \
tests/python/test_io_read_meta.py tests/python/test_cli_mesh_mosaic.py
tests/python/test_io_read_meta.py tests/python/test_cli_mesh_mosaic.py \
tests/python/test_cli_mesh_domain_crs.py tests/python/test_cli_mesh_domain.py \
tests/python/test_refine_golden.py tests/python/test_cli_constraint_feet.py \
tests/python/test_cli_mesh_refine.py tests/python/test_cli_start_quality.py

# Increment 13, ruling 10: read the .vtk output back with the readers
# ParaView uses. The suite skips when vtk is absent, so it is run only
Expand Down
19 changes: 15 additions & 4 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ increment that most needs a picture to check against
| — | `tools/bench.py`: the 1 m benchmark and the thread-scaling sweep from one checked-in command, with power state, quality and commit recorded per run; the one-off scripts in `docs/benchmarks/2026-09-26/` are its specification. Rule 2's acceptance run needs it | shipped with branch `tools-bench`'s PR | `docs/benchmarks/bench-py.md` |
| — | The serial phase: profile refine's serial insert-and-flip phase, then parallelise what the profile blames. Scaling tops out at about 2.0-2.2×. Profiled 2026-09-27: serial part about a third of 1-thread refine, mostly Lawson legalisation; the scan stops near 5× from load imbalance | profiled; designed as increment 21 (Ola's rulings 2026-09-27: L1 determinism, one path, at most 2 % more triangles). **21a shipped with branch `increment21a-quick-wins`'s PR**: dynamic scan blocks, active merge, reused flip stack; mesh bit-identical; on AC refine -10 to -15 % at 8 threads, ceiling 2.1x -> 2.3x (`docs/benchmarks/2026-09-27/21a-acceptance.md`). **21b shipped with branch `increment21b-lattice-incircle`'s PR**: an int64 lattice incircle answers 99.97-100 % of refine's incircle tests; mesh bit-identical; on battery refine -15 % at 8 threads, ceiling 2.3x -> 2.5x (`docs/benchmarks/2026-09-27/21b-acceptance.md`). **21c measured** (`docs/benchmarks/2026-09-27/21c/README.md`): option C costs 6.5-10 % more triangles; A1 about 1 %; A0 is bit-identical (on these two inputs, not proven), and with evaluate-once is modelled at only 7-11 % faster refine at 8 threads and slower at 4. **21d is deferred** (Ola, 2026-09-27: "Review and push 21c, then basin-work"), behind the work in "Order of work" below; domain decomposition parallelises scan and split together | `docs/increments/21-parallel-refine.md`, `docs/benchmarks/2026-09-27/serial-profile/README.md` |
| — | Release hardening: measure libc++'s `_LIBCPP_HARDENING_MODE_FAST` (and libstdc++'s assertions on the GCC leg), which bounds-check `std::vector`, `span` and the like in Release, on the 1 m benchmark; switch it on if the cost is small. Today an out-of-range index in shipped code the tests miss is undefined behaviour and crashes Python (Ola, 2026-09-27: "I'm surprised we don't have proper memory control"; CI's ASan/UBSan/TSan cover what the tests reach) | to measure (Ola, 2026-09-27); 21d, which it was placed after, is deferred behind the basin work | none yet |
| 15 | A DEM in several tiles, and the domain in its own CRS: 15a Norway, many tiles in one projected CRS (Ola's 254 DTM10 UTM33 tiles; only the selected tiles must share a lattice, since 8 of them sit half a cell off); 15b the domain polygon reprojected into the DEM's CRS; 15c and 15d the São Francisco basin (geographic DEMs meshed in the DEM's own lattice frame, not resampled; window decoding and memory) | **15a shipped with branch `increment15-dem-mosaic`'s PR**: `--dem DIR` or several files, `--bbox`, tiles selected and stitched on one lattice, Q2-Q5 refusals; overlaps that disagree (real DTM10 tiles exported on different dates, up to 52 m) are split down the middle and reported per seam (Ola's Q1 revised, 2026-09-28). The design's acceptance box, 9 tiles and 10,051² nodes, meshes: 11.05 M triangles in 31 s on battery. 15b next (Ola, 2026-09-27: Norway first) | `docs/increments/15-dem-mosaic.md` |
| 15 | A DEM in several tiles, and the domain in its own CRS: 15a Norway, many tiles in one projected CRS (Ola's 254 DTM10 UTM33 tiles; only the selected tiles must share a lattice, since 8 of them sit half a cell off); 15b the domain polygon reprojected into the DEM's CRS; 15c and 15d the São Francisco basin (geographic DEMs meshed in the DEM's own lattice frame, not resampled; window decoding and memory) | **15a shipped with branch `increment15-dem-mosaic`'s PR**: `--dem DIR` or several files, `--bbox`, tiles selected and stitched on one lattice, Q2-Q5 refusals; overlaps that disagree (real DTM10 tiles exported on different dates, up to 52 m) are split down the middle and reported per seam (Ola's Q1 revised, 2026-09-28). The design's acceptance box, 9 tiles and 10,051² nodes, meshes: 11.05 M triangles in 31 s on battery. **15b built with branch `increment15b-domain-crs`'s PR**: `--domain` in its own CRS (e.g. EPSG:4326) over a UTM33 mosaic, reprojected vertex by vertex. Then 16b (Ola, 2026-09-27: Norway first) | `docs/increments/15-dem-mosaic.md` |
| 16b | Interior polygons and polylines as constraints ("terrain polygons": lakes, land cover, roads, rivers): `--features PATH`, a GeoJSON `FeatureCollection`, each feature naming a vocabulary property; closed or open `Breakline`s, crossings noded, off-node vertices with bilinear z. **Its working example is real data** (Ola, 2026-09-27): CORINE Land Cover 2018 over the benchmark tile `7908_3_10m_z33.tif`. The source is Ola's local copy, `rasputin_data/corine_sql/.../U2018_CLC2018_V2020_20u1.gpkg` (8.2 GB, EPSG:3035, a sibling of this repository, which also holds the 254-tile DTM10 archive for gap 6). It reads without GDAL: sqlite3 over its R-tree, the GeoPackage blob header stripped, `shapely.wkb`, then `pyproj` to 25833, so CRS stops in Python as before. Probed 2026-09-27 in 0.2 s: 60 polygons in 8 classes (heath, bare rock, sparse vegetation, bogs, intertidal flats, water, sea, urban), 11 068 vertices clipped to the tile, median segment 54 m against 10 m cells. The EEA's public ArcGIS service (`image.discomap.eea.europa.eu`, `Corine/CLC2018_WM`) returns the same 11 068 clipped vertices and is the route for anyone without the file. What it forces on 16b's design: neighbouring polygons share their boundaries, so each shared edge arrives twice; the polygons run past the domain and must be clipped; the extract is committed as a fixture with the Copernicus attribution. Placed before 20c because 20c may split constraint segments and should be designed and measured on inputs that have interior ones | designed in 16's R6, no increment file yet; after the serial phase, before 20c | `docs/increments/16-domain-polygon.md` (R6) |
| 20c | Soft quality criterion: a penalty that each Steiner node or constraint split must pay for in angle gained, instead of 20's hard 25°; applied at the start and during DEM refinement; may split constraint segments when that improves the mesh. Ola's rulings on 20's C1-C3 | to design after 16b (`@architect` measures cost against 20 first) | `docs/increments/20-start-quality.md` (Ola's rulings) |
| — | Auto-catchment: the watershed upstream of a coordinate, computed from the DEM and handed to `--domain`, so a catchment no longer has to be supplied as a file (Ola, 2026-09-27: "not far into the future"). The textbook route is depression handling (Priority-Flood, Barnes, Lehman and Mulla 2014), D8 flow directions (O'Callaghan and Mark 1984) and accumulation, the pour point snapped to the strongest flow nearby, the upstream cells traced and their outline turned into a polygon; the literature check is `@architect`'s. Open for its design: whether it runs in the C++ core (a 10 m tile is 25 M cells); how a stair-stepped cell outline becomes a domain polygon, which meets input coarsening; and that a real catchment crosses tile edges, so it needs gap 6 (a DEM in several tiles) first. Legacy has nothing on it (`grep -rliE "watershed|flow.?acc|flow.?dir|pour.?point|catchment" legacy` returns no files) | to design; after gap 6, which it needs; placed after 20c, can move ahead of it on Ola's word | none yet |
Expand Down Expand Up @@ -100,9 +100,10 @@ Norwegian cases sorted first"): 15a and 15b (Norwegian multi-tile DEM), then
Open and not MVP-blocking: **inputs in their own CRS**. The user (2026-09-26):
"I don't think the domain CRS should have to match the DEM CRS in the future.
This must be written down. The questions will be in which coordinate system we
shall do the math." Increment 16 requires a match for now; a later increment
chooses the computation CRS and reprojects inputs into it (see
`docs/increments/16-domain-polygon.md`, "Ruled by the user"). Also **a general point insertion policy**, which the user
shall do the math." **Settled for the domain and a projected DEM by increment
15b**: the domain comes in its own CRS and is reprojected into the DEM's, which
is the computation CRS. Feature geometry (16b) follows the same path; a
geographic DEM's computation frame is 15c (`docs/increments/15-dem-mosaic.md`). Also **a general point insertion policy**, which the user
wants to discuss (2026-09-26): which points refinement inserts, beyond
increment 14b's worst DEM node, and how that meets the sizing field, coastline
constraints and points that are not DEM nodes. The user's direction for it
Expand All @@ -115,6 +116,16 @@ coarsening input geometry (`parallel_refinement.md` step 2), 5d above, and
land-cover partitioning, whose foundation is increment 7's property sets and
whose consumer does not exist.

Open, for later (Ola, 2026-09-28): **the surface model, DOM10, alongside the
terrain model.** Kartverket's DOM10 is the top surface (tree crowns, roofs,
bridges) where DTM10 is the bare ground; both are published on hoydedata.no
and, where laser coverage exists, derive from the same NDH laser data (DTM10
falls back to the 2013 contour model elsewhere). Two uses Ola wants to keep open: **shading** (terrain and surface
shadowing, e.g. for solar radiation), which needs the surface, not the ground;
and **canopy and building height, DOM10 minus DTM10**, for vegetation-related
work and land-cover classification. Hydrology keeps meshing the DTM: a DOM
mesh would dam rivers at bridges. Not designed; no increment yet.

Known defect: increment 14's NoData carving from a NoData corner appears to
advance one node per round. Meshing the real tile from its outline alone took
5 054 rounds and 109 s against 0.35 s from the stride grid
Expand Down
Loading
Loading