Move the coastline signed distance into Rust - #11
Open
lispandfound wants to merge 1 commit into
Open
lispandfound wants to merge 1 commit into
lispandfound wants to merge 1 commit into
Conversation
lispandfound
added this pull request to stack #9
September 11, 2026 11:42
Benchmark for a2ace4cClick to view benchmark
|
lispandfound
force-pushed
the
coastline-rust
branch
from
September 11, 2026 12:07
a6d3917 to
81ddd08
Compare
Benchmark for 0af3828Click to view benchmark
|
lispandfound
force-pushed
the
coastline-rust
branch
from
September 11, 2026 19:58
81ddd08 to
ea845a5
Compare
Benchmark for 11a4434Click to view benchmark
|
lispandfound
force-pushed
the
coastline-rust
branch
from
September 20, 2026 21:32
ea845a5 to
315fa84
Compare
Benchmark for ff97bf8Click to view benchmark
|
Benchmark for ff97bf8Click to view benchmark
|
lispandfound
force-pushed
the
coastline-rust
branch
from
September 20, 2026 21:36
315fa84 to
01ed71f
Compare
Benchmark for 49ef9a3Click to view benchmark
|
Benchmark for 49ef9a3Click to view benchmark
|
lispandfound
removed this pull request from stack #9
September 20, 2026 21:55
lispandfound
added this pull request to stack #15
September 20, 2026 21:56
lispandfound
force-pushed
the
coastline-rust
branch
from
September 20, 2026 22:19
01ed71f to
2be8cd9
Compare
Benchmark for 6d3873cClick to view benchmark
|
Benchmark for 6d3873cClick to view benchmark
|
The coastline layer computed its signed distance in three steps: shapely's
STRtree for the unsigned distance, a second STRtree query to collect the
segments a horizontal ray might cross, and a numba kernel to count the
crossings. Per chunk that allocated one shapely Point and one LineString for
every grid column, which is what the layer's own TODO complained about.
`src/coastline.rs` does the whole thing over one 2-D BVH: `nearest_to` for
the magnitude, and an AABB traversal along the ray for the sign. The Python
layer drops from 178 lines to 82 and stops building geometry objects
per chunk.
Measured against the implementation it replaces, over the synthetic
coastline:
n= 1000 old 7.1 ms new 0.2 ms 34x
n= 20000 old 145.8 ms new 2.0 ms 72x
n= 200000 old 1451.4 ms new 15.5 ms 94x
Two differences worth naming, both from `Real` being float32 where shapely
worked in float64.
The magnitude moves by a few float32 steps. Over 40,000 points against
shapely the median error is 0.48 steps and the largest 3.5, where one step is
0.125 m at NZTM magnitudes. A coastline distance feeds a taper that runs over
kilometres, so this does not reach the output; `--features high_precision`
removes it for anyone who disagrees.
The sign can differ for a point closer to the coast than float32 can
represent. One point in 200,000 flipped, and it sat 0.012 m from the
coastline, an order of magnitude inside the 0.125 m resolution at that
easting. There is no fact of the matter about which side it falls on.
`tests/test_coastline.py` checks both halves against shapely as an
independent oracle, with the tolerance derived from that resolution and a
median assertion that a wrong nearest segment would fail. The Rust tests use
the unit square, whose signed distance is known in closed form, and cover the
tie-break where a ray passes exactly through a shared vertex.
The terminal layer the tests need moves to `tests/conftest.py`, since
`test_layer_coordinates.py` had already grown its own copy.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
lispandfound
force-pushed
the
coastline-rust
branch
from
September 20, 2026 22:28
2be8cd9 to
aa4d5f3
Compare
Benchmark for c41290fClick to view benchmark
|
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.
The coastline layer computed its signed distance in three steps: shapely's
STRtreefor the unsigned distance, a secondSTRtreequery to collect thesegments a horizontal ray might cross, and a numba kernel to count the
crossings. Per chunk that allocated one shapely
Pointand oneLineStringfor every grid column, which is what the layer's own TODO complained about.
src/coastline.rsdoes the whole thing over one 2-D BVH:nearest_tofor themagnitude, and an AABB traversal along the ray for the sign. The Python layer
drops from 178 lines to 82 and stops building geometry objects per chunk.
Measured against what it replaces
Over the synthetic coastline, comparing directly against the old
implementation checked out of git:
Two differences worth naming
Both come from
Realbeing float32 where shapely worked in float64.The magnitude moves by a few float32 steps. Over 40,000 points against
shapely the median error is 0.48 steps and the largest 3.5, where one step is
0.125 m at NZTM eastings. A coastline distance feeds a taper running over
kilometres, so it does not reach the output.
--features high_precisionremoves it for anyone who disagrees.
The sign can differ within the resolution of the coordinate. One point in
200,000 flipped. It sat 0.012 m from the coastline, an order of magnitude
inside the 0.125 m float32 resolution at that easting, so there is no fact of
the matter about which side it falls on. Shapely agreed with the old answer;
at that distance both are guesses.
Testing
tests/test_coastline.pychecks both halves against shapely as an independentoracle, with the tolerance derived from that float32 resolution rather than
guessed, and a median assertion that a wrong nearest segment would fail. The
Rust tests use the unit square, whose signed distance is known in closed form,
and cover the tie-break where a ray passes exactly through a shared vertex
(which naive parity counting gets wrong, reporting an interior point as
exterior).
--distributedstill worksThe Rust index has no Python representation, and
--distributedpickles thelayer chain even with thread workers, so the first version of this broke that
path with
cannot pickle 'nzcvm.PyCoastline'.CoastlineLayernow handsdask a registry key through the same
__getstate__/__setstate__patternSurfaceandModelTreeuse. Verified: the distributed run onexamples/synthetic.tomlmatches the pre-#11 distributed output element forelement. Replacing the registry itself is a separate, larger piece of work.
The terminal layer these tests need moved to
tests/conftest.py, sincetest_layer_coordinates.pyhad already grown its own copy.Co-Authored-By: Claude Opus 5 noreply@anthropic.com
Stack created with GitHub Stacks CLI • Give Feedback 💬