Meshes/Domains: range-check vertex indices, promote stretching and sphere-radius parameters - #2613
Open
imreddyTeja wants to merge 3 commits into
Open
Meshes/Domains: range-check vertex indices, promote stretching and sphere-radius parameters#2613imreddyTeja wants to merge 3 commits into
imreddyTeja wants to merge 3 commits into
Conversation
This was referenced Aug 31, 2026
`Meshes.coordinates(mesh, elem, vert)` selects a vertex with a chain of `vert == ...` comparisons, so an out-of-range `vert` fell through to the last branch and returned another vertex's coordinates instead of erroring: `coordinates(mesh, CartesianIndex(1,1,1), 5)` returned vertex 3. Add a shared `check_vertex_index` and call it from the `AbstractMesh2D`, `AbstractCubedSphere` and `RectilinearMesh` methods (`vert` in `1:4`). `IntervalMesh` has the same bug in 1D — `coordinates(mesh, 1, 3)` indexes past the element's two faces into the next element's, so on a 2-element mesh it returned element 2's upper face — so check it there too (`1:2`). That turned up four call sites in the interval tests that were passing a *face* index as `vert` (`coordinates(mesh, 1, nelems)`, and `vert = 28` in "Truncated IntervalMesh"). They only worked because the index was unchecked; rewrite them as the equivalent in-range `(elem, vert)` pair. The values asserted are unchanged. Note this changes the error type for an out-of-range 1D `vert` from `BoundsError` to `ArgumentError`, which two existing tests asserted on. Closes #1026 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HJ8VbwbMadrhvCtBV3jkjc
`GeneralizedExponentialStretching(30, 5000.0)` raised a `MethodError`, and
so did `IntervalMesh(domain, ExponentialStretching(7500))` on a `Float64`
domain: the two-parameter rule had no promoting constructor, and the
`IntervalMesh` methods pinned the rule's float type to the domain's with a
shared `FT` typevar.
- `GeneralizedExponentialStretching` now promotes mixed parameters. Note it
has to call the parametric constructor rather than recursing: a `(::Real,
::Real)` method is *more* specific than the generated diagonal `(::FT,
::FT) where {FT}` (whose typevar is implicitly bounded by `Any`), so every
`Real` pair dispatches to it and `promote` alone would not terminate.
- `IntervalMesh` now accepts a stretching rule of any float type and
converts it to the domain's via the new `Meshes.convert_stretch`. This
also covers a `Float64` rule on a `Float32` domain, not just integers.
The mesh stores the converted rule, so `mesh.stretch` always matches the
domain's float type.
Closes #1434
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HJ8VbwbMadrhvCtBV3jkjc
`SphereDomain(1000)` built a `SphereDomain{Int}`. The declared constraint
was written `struct SphereDomain{FT} <: AbstractDomain where {FT <:
AbstractFloat}`, where the `where` clause attaches to the (unparameterized)
supertype and is silently discarded, so it never applied.
The radius is what fixes the float type of everything built on the domain,
so this surfaced far away as `no method matching legendre(::Type{Int64},
::Int64, ::GaussQuadrature.EndPt)` when the space's quadrature rule was
built. Move the bound onto the type parameter where it binds, and promote a
non-float `Real` radius instead of rejecting it.
Closes #1468
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HJ8VbwbMadrhvCtBV3jkjc
imreddyTeja
force-pushed
the
tr/meshes-fixes
branch
from
August 31, 2026 21:45
171ac6b to
3347180
Compare
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.
Stack 2/4 — base
tr/geometry-coordinates(#2612). Next:tr/space-ndims.Review only the last three commits; the first four belong to #2612.
1.
Meshes.coordinatesdoes not range-check the vertex index (#1026)coordinates(mesh, elem, vert)picks a vertex with a chain ofvert == ...comparisons, so an out-of-range
vertfell through to the last branch andreturned another vertex's coordinates instead of erroring:
Added a shared
check_vertex_index, called from theAbstractMesh2D,AbstractCubedSphereandRectilinearMeshmethods (vert ∈ 1:4).IntervalMeshhas the same bug in 1D —coordinates(mesh, 1, 3)indexes pastthe element's two faces into the next element's, so on a 2-element mesh it
returned element 2's upper face — so it is checked there too (
vert ∈ 1:2).Two things worth a reviewer's attention:
vertfromBoundsErrortoArgumentError, which two existing tests asserted on.ArgumentErrormatcheshow
unit_interval.jlalready reports other invalid parameters (nelems).index as
vert—coordinates(mesh, 1, nelems),coordinates(mesh, 1, nelems + 1), andvert = 28in "Truncated IntervalMesh". They only workedbecause the index was unchecked. They are rewritten as the equivalent in-range
(elem, vert)pair; every asserted value is unchanged.2. No
Int→Floatpromotion for stretching rules (#1434)GeneralizedExponentialStretching(30, 5000.0)raised aMethodError, and sodid
IntervalMesh(domain, ExponentialStretching(7500))on aFloat64domain —the rule had no promoting constructor, and the
IntervalMeshmethods pinned therule's float type to the domain's with a shared
FTtypevar.GeneralizedExponentialStretchingnow promotes mixed parameters. It has tocall the parametric constructor rather than recursing: a
(::Real, ::Real)method is more specific than the generated diagonal
(::FT, ::FT) where {FT}(whose typevar is implicitly bounded byAny), so everyRealpairdispatches to it and a plain
promote(...)forward stack-overflows. I hitthis; the reasoning is in a source comment.
IntervalMeshnow accepts a rule of any float type and converts it to thedomain's via the new
Meshes.convert_stretch. This also covers aFloat64rule on a
Float32domain, not just integers. The mesh stores the convertedrule, so
mesh.stretchalways matches the domain.3.
SphereDomaindoes not supportInts (#1468)SphereDomain(1000)built aSphereDomain{Int}. The intended constraint waswritten
where the
whereclause attaches to the (unparameterized) supertype and issilently discarded — so it never applied. The radius fixes the float type of
everything built on the domain, so this surfaced far away as
no method matching legendre(::Type{Int64}, ...)when the space's quadrature rule was built. Thebound is moved onto the type parameter, and a non-float
Realradius ispromoted rather than rejected.
Testing
The reproducers from #1434 and #1468 both run; the #1468 sphere space integrates
to 4πR².
Domains,Meshes,Geometry,Spaces,Fields,InputOutput(including
unit_hybrid2dbox_stretched) andRemappingunit tests pass.Closes #1026, closes #1434, closes #1468
🤖 Generated with Claude Code
https://claude.ai/code/session_01HJ8VbwbMadrhvCtBV3jkjc