Repository navigation
Increment 26b: exact land-cover class fractions per triangle (--land-cover, --land-cover-year) - #235
Merged
Merged
Conversation
…OADMAP row 35 merged, by the main session Ola, 2026-10-12, asked whether to rule Numedalslagen's features clip (6.0 s of 8.8 s, 68 %, docs/benchmarks/2026-10-11/cleanup-speed/README.md) expected and leave the fix to the cached-extract idea: "Rule it expected at 6 s, cached extract is the fix". The hotspots.toml entry carries the words verbatim, so the quick check stays quiet until the share grows 10 points. Lagan's 43.6 % is within 10 points of its 40.7 % ruling and gets no new entry. ROADMAP row 35: built -> merged (#229); its stale "next the push" phrase replaced by the ruling. Increment 35's section 11 gets the ruling in one sentence after the default-taken line. Checked: tests/python/test_bench_quick.py -k shipped, 2 passed (hotspots.toml loads, every entry has a ruling). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ain session Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…main session Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ings and 36's Status fixed, by the main session Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… to the reviewer's wording, by the main session Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@tester) docs/increments/26-land-cover.md, section 10 "26b", on 26a's merged head 5f28292. Four suites, 92 cases, all red for the right reason; no production code, no throwaway implementation, no mutation round (section 9 names none for 26b). C++ (Catch2), tests/cpp/unit/test_land_cover_overlap.cpp, 17 cases, registered in tests/cpp/CMakeLists.txt with the plain helper (overlap.hpp names no kernel) plus Threads: the hand cases of section 10 (a triangle in one cell; a right triangle with legs 2 on a 2 x 2 grid giving 1, 0.5, 0.5 and the fourth cell absent; vertices on grid corners; an edge on a grid line; a sliver along a row; a nanometre triangle), a cell area per row, vertex order and mirror orientation, two triangles on a shared edge summing per cell, 2000 random triangles summing to the shoelace area, four threads and all cores giving one thread's bits, chunks concatenated equal to one call bit for bit, the closed window [0, cols] x [0, rows] with OutsideWindow past it, zero-area, non-finite and wrong-length refusals. Python, tests/python/: - fraction_fixtures.py: the pins (its docstring) and the oracles, which share nothing with the producer: GEOS's clip of each triangle against each cell box, GEOS's Delaunay of a seeded point set with points snapped to grid corners and lines, pyproj.Geod's cell area per row, pyproj's Transformer from the mesh's CRS; the CLI scene (a UTM 23S DEM over the class raster's class-0 quarter, the class cache with a fetch date). - test_land_cover_overlap.py (36): F2 against GEOS on random triangulations of a 20 x 20 class grid, with unit and with ellipsoidal row areas; class totals against the square's exact cover; per-cell sums on a 15 x 15 grid of unique classes (uint8 holds 255, so not 20 x 20) to 1e-12 of a cell; threads 1, 4 and 0 equal; refusals; row_areas against Geod and the design's 887.5 / 836.0 m2 figures; the ClassFractions table; and the window-corner pin for PixelIsArea and PixelIsPoint (green on 26a's code: read_page puts the node at the cell's centre for both registrations, so decode_class_window's half-cell move is right either way and no refusal is needed; 26a's code review, round 1). - test_io_land_cover_arrays.py (17): the .vtk FieldData arrays land_cover_offsets (unsigned_int), land_cover_classes (unsigned_char), land_cover_fractions (float) read back through vtkread in both encodings, the names reserved, a wrong triangle count refused; the .ply face lists (list uchar uchar, list uchar float) and the property order read back through plyread, refused beside edges. - test_cli_mesh_land_cover_fractions.py (22): --land-cover and --land-cover-year; F1 on the file; land_cover_code the largest class and 0 on every line cell; the fractions against the oracle to 1e-6; class 0 among the classes; the strings (codes, source, credit with the fetch date and URL, licence note, cite) in the file, --stats and --record; the year honoured and 2025 the default; refusals (year out of range, year without the option, a heights source, a year not in the cache naming fetch, a coded features map beside it, no --dem); the control without the option; the .ply lists against the .vtk table; the VTK reader read-back (skipped without vtk, as 16c's). Red check, run in this worktree's own build and venv: - cmake -S . -B build && cmake --build build --target test_land_cover_overlap: "fatal error: 'terrain/land_cover/overlap.hpp' file not found"; the only error in cmake --build build -j 6 -- -k. - ctest --test-dir build -j 6 -E test_land_cover_overlap: 100% of 1014 existing tests passed. - .venv/bin/python -m pytest tests/python/test_land_cover_overlap.py tests/python/test_io_land_cover_arrays.py tests/python/test_cli_mesh_land_cover_fractions.py -o addopts="" --no-cov: 68 red (AttributeError: _core has no class_areas; ImportError: ClassFractions; "No such option: --land-cover"), 6 green (the window-corner pin, the cover oracle's self-check, the three controls without the option), 1 skipped (vtk absent). - .venv/bin/python -m pytest tests/python (with coverage): 7120 passed, 139 skipped, coverage 99%; red: the 68 of these suites and one pre-existing, environment-bound failure also red on the untouched head 5f28292 (test_io_geotiff_parametric.py::test_the_real_austrian_file_reads_as_austria_lambert, `AUSTRIA_FILE is None`: the real file is not on this machine). - ruff check and ruff format --check on the four files: clean. Pinned beyond the design (also in fraction_fixtures.py's docstring): a trailing `threads` parameter on class_areas (1.2's signature has none, yet the result must not depend on the thread count); index space with y the row growing downward and the window closed; the view's geometry RasterGeometry{0, 0, 1, 1, cols, rows} with only rows(), cols() and row() read; either orientation accepted; OutsideWindow and the zero-area refusal as std::invalid_argument, ValueError through the binding; the table as io.models.ClassFractions (the design names the arrays, not a container); land_cover_fractions.row_areas(window); the writers' keywords class_fractions and face_fractions and the .ply property order; the CLI's refusal wording asserted by option name; land_cover_source asserted by the year only (RemoteSource has no display name for "MapBiomas Collection 11"). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Provisional message; amended with the verification record after the full run. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…out, pins added (@tester) Follows @developer's green 5b8bb3e on docs/increments/26-land-cover.md, section 10 "26b". Tests only (tests/); no production file touched. The four cases red because of the tests, fixed: - tests/cpp/unit/test_land_cover_overlap.cpp case 6: the nanometre triangle's expected area was the intended 0.5e-18, but 0.5 + 1e-9 rounds to legs of 1e-9 - 2.8e-17, so its true area is 4.9999997e-19 (relative 5.7e-8 off, past the 1e-9 tolerance). Now compared against the shoelace area of the corners as rounded, at relative 1e-9, plus a floor of 0.4e-18. - tests/python/plyread.py: list properties of varying length (the 26b face lists) are stacked into an object array, one record each; fixed-length lists (vertex_indices) stay 2-D as every older ply test expects. - TestTheYear: tmp_path / "a" is created before the run writes into it. - tests/python/test_layering.py: land_cover_fractions at L3 importing `_core crs io.models io.repository`; cli gains land_cover_fractions; io.ply and io.vtk_legacy gain io.models. Each row checked against importscan on 5b8bb3e before writing. Red-step scaffolding removed (tester.md section 1): the importlib fixtures (`core`, `fractions`, `sources`), the call-time imports of ClassFractions, decode_class_window and read_page, the "HOW THIS FILE GOES RED" paragraphs and the C++ "RED at the commit" note. The `fractions` fixture was also a class-scoped fixture as an instance method, a PytestRemovedIn10Warning. Pins added, with the reasons in the tests and fraction_fixtures' docstring: - land_cover_codes == "<source id> class number; 0 = no data, and every constraint line" and land_cover_source == "<source id>, <year>" (1.6 spells both with a display name RemoteSource does not have; the id is what --land-cover and fetch take). - assign(..., chunk=5) equals the default bit for bit and equals the file's arrays: the stitching of several chunks, each with its own window and row areas, which the CLI scene (far under 2^18 triangles) never runs. The chunk size itself is not pinned. - Refusals the green code has and the red suite did not reach: an unknown --land-cover key (naming the catalogue), no --cache and no RASPUTIN_DATA, a cache root without the source (naming fetch), a mesh past the raster and an object not cached through assign, a row without entries in fractions_of, a 256-class face in write_ply; dominant's tie rule and the empty mesh. Not pinned: a cache without a fetch date credited with today's date (fetch/run.py:169 does the same for NOTICE.txt; raised as a question). Verification, this worktree's build and venv, after `cmake --build build-pyext --target _core`, the copy into the venv and `touch`: - cmake --build build -j 8: exit 0, no warnings; ctest --test-dir build: 100% of 1031 tests passed (1014 before 26b + 17). - pytest tests/python (coverage gate on): 7192 passed, 139 skipped, 1 failed (test_io_geotiff_parametric.py::test_the_real_austrian_file_reads_as_austria_lambert: GeoTiffError "Predictor 3 cannot be decoded as installed; imagecodecs"; io/geotiff.py is unchanged against the base 5f28292), total coverage 98.48%, floor 85. That run preceded the pins added here; the three 26b suites were rerun after them: 84 passed, 1 skipped (vtk absent). - Coverage of the green commit's Python files in the full run: cli.py 97%, io/models.py 99%, io/ply.py 99%, io/repository.py 97%, io/vtk_legacy.py 99%, land_cover_fractions.py 94%, run_record.py 99%; _core.pyi and the C++ are not measured. 26b lines missed in that run: land_cover_fractions 79, 100, 115, 133, 146; cli 1401-1402, 1424-1425; ply 218. After the pins only land_cover_fractions 115 (more than 2^32 - 1 entries: unreachable) and cli 1424-1425 (the except around assign; the mesh past the raster needs a scene the fixtures do not have) remain. - mypy: no issues in 69 files; ruff check and ruff format --check: clean. Case count: 92 at red (17 C++ + 75 Python), 103 now (17 + 86, of which one skips without vtk); all green. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…rded, by the main session Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…e the MapBiomas band), pass 0.77 s per million triangles at 8 threads, quick check meshes unchanged, timings judged back to back under a foreign load (@Perf) Evidence in docs/benchmarks/2026-10-12/26b-fractions/ (README, run_meshes.sh, analyse.py, raw/). AC power throughout; Apple M1 Max; tree 4149b50, Release _core 55bb3993 built into build-bench and installed into the worktree venv. Gate 1, the Velhas piece (ANADEM 30 m UTM grid, outline 11,667.6 km2) at 10 m (649,504 triangles) and 5 m (1,571,955) with --land-cover mapbiomas-c11 --land-cover-year 2025 (the design's default year, Ola's Q1 ruling; the cache fetched 5.1 MB in 10 s): - Class areas: all 19 classes inside the reference band [cells wholly inside, cells wholly inside plus cells the outline crosses] (28.7 km2 of boundary cells), 0 outside, identical for both meshes; the worst difference from the centre count is class 15, +4.49 ha (+0.0011 %). ACCEPTED. - Fractions pass: CLI phase 0.493 s (10 m) and 0.984 s (5 m) on 10 cores; assign at 8 threads 0.500 and 0.999 s, 0.77 and 0.64 s per million triangles (gate 2 s). _core.class_areas alone scales 7.4x from 1 to 8 threads; the pass 2.6x and 2.2x, the rest being serial Python (window reads of nearly the whole raster per chunk in file order, row areas, fractions, dominant class). ACCEPTED. - Per-cell sums on a 1 km square against GEOS and the cell's area: 2.7e-16 worst relative, gate 1e-6. ACCEPTED. - Peak RSS added by the pass: +146 MB at 10 m (225 B per triangle), +42 MB at 5 m (27 B); the design estimated 25 B. Recorded, not a gate. - File arrays equal assign's output bit for bit; mesh geometry equal with and without --land-cover; misplaced share reported as a binning bound only. Gate 2, tools/bench_quick.py against the stored AC baseline 357808b: no MESH CHANGED line in three runs (every mesh SHA-256 equal), but SLOWER on every case (+7 to +33 %), for the untouched base commit 5f28292 as much as for the branch, under a measured foreign load (Microsoft Teams call, load average 7). Back to back, branch/base is within 1 % on six cases and at most 1.11 on quarter (0.41 vs under 0.37 s). No change attributable to 26b; the quick check should be re-run on an idle machine before the merge. HOTSPOT lines are the same set the 2026-10-11 runs printed, Numedalslagen features clip 67 % among them (ruled on another branch); Lagan features clip 43 %. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…sion Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…es applied, by the main session Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…26b built and review-approved, by the main session Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…is master's drift since the baseline, not 26b's, by the main session Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
skavhaug
enabled auto-merge
October 12, 2026 10:36
github-merge-queue
Bot
removed this pull request from the merge queue due to invalid changes in the merge commit
Oct 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Increment 26b, the second PR of
docs/increments/26-land-cover.md(section 14 is the as-built record). 621 net production lines bypython3 tools/count_loc.py 5f28292c HEADagainst the estimate of 420; under 700. The branch also carries the ruling-record commits of #233, merged in to keep the Status line and ROADMAP row consistent.include/terrain/land_cover/overlap.hpp: the exact triangle-against-cell overlap on an index-space raster (strips, full-cell spans, canonical crossings so shared edges give complementary areas, chunks in parallel); the core sees arrays only.bindings/core.cpp,_core.pyi:class_areasand theuint8view.land_cover_fractions.py: index-space corners, row areas, chunks throughclass_areas, theClassFractionstable and dominant class.io/vtk_legacy.py,io/ply.py: the fractions arrays;cli.py:--land-cover,--land-cover-year, the run-record entries and seven refusals.Evidence: red
1820c1d4(92 cases), green5b8bb3e0, test-side fixesf165282b(103 cases green);@perfACCEPTED98eea44f(docs/benchmarks/2026-10-12/26b-fractions/): on the Velhas basin piece all 19 classes inside the raster's own count band, 0.77 s per million triangles at 8 threads, every quick-check mesh unchanged; idle re-run clean (Lagan features read +14 % is master's drift since the baseline, seen on master itself). Code review rounds 1 and 2 recorded, doc fixes only. No mutation round (section 9 names none for 26b).🤖 Generated with Claude Code