Give element blocks one canonical order, and match physics by name - #321
Merged
Conversation
Per-block mesh data lives in `Dict`s keyed by block name, while the block
names themselves live in an ordered `Vector`. `Dict` iteration is hash
order, so `values(mesh.element_conns)` and `mesh.element_block_names` are
two different orderings of the same blocks, and code that indexes blocks
positionally was mixing them:
* `FunctionSpace` took connectivity and element id maps from
`values(...)` but block names and reference elements from
`element_block_names`. On a three block mesh named b1/b2/b3 with 1, 2
and 3 elements, `block_names(fspace)` read ["b1","b2","b3"] while
`num_elements(fspace, b)` read [3, 2, 1] -- block `b`'s name and block
`b`'s elements were different blocks.
* `BCBookKeeping` and `_setup_sideset` numbered blocks with
`enumerate(values(mesh.element_id_maps))` and then used that number to
index `element_block_names`, so a side set resolved to the wrong block
name, and from there to the wrong connectivity and reference element.
* `write_to_file` wrote block names in file order but the blocks
themselves in `Dict` order, pairing each block with another's name.
Introduce `block_names(mesh)` as the single source of truth for what
"block b" means, with `block_conns` / `block_id_maps` returning per-block
data in that same order, and route every positional use through them.
`block_names(fspace)` exposes the same order downstream.
With one order established, `physics` and `properties` can be matched to
blocks by name instead of by position. `Parameters` now permutes a
supplied `NamedTuple` into block order and requires its keys to be exactly
the block names, replacing the `TODO re-arrange physics tuple to match
fspaces` -- previously a `NamedTuple` written in any other order silently
gave each block another block's material, with nothing to flag it. A
single physics/properties object is still shared across all blocks, but is
now keyed by the real block names rather than invented `region_N`
placeholders.
Nothing caught any of this because every multi-block fixture in the suite
has two blocks named block_1/block_2, whose hash order happens to equal
their file order. `test/TestBlockOrdering.jl` adds a three block fixture
where it does not, with blocks of different sizes so a permutation shows
up as a size and not just a name.
Behavior changes for downstream users: `p.physics` / `p.properties` are
keyed by block name rather than `region_N`, and a `NamedTuple` whose keys
are not exactly the block names now raises `BlockMismatchError` instead of
being accepted.
lxmota
force-pushed
the
fix-block-ordering
branch
from
July 25, 2026 09:02
1e45416 to
fd58593
Compare
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #321 +/- ##
==========================================
+ Coverage 68.99% 69.07% +0.07%
==========================================
Files 55 55
Lines 6112 6134 +22
==========================================
+ Hits 4217 4237 +20
- Misses 1895 1897 +2 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
lxmota
added a commit
to Cthonios/Carina.jl
that referenced
this pull request
Jul 26, 2026
FEC now guarantees a single block order (`block_names`), derived from the mesh file rather than from `Dict` iteration, and matches `physics` / `properties` to blocks by name. Carina was deriving its own block order from `keys(mesh.element_conns)`, which is hash order and disagrees with FEC's for three or more blocks. Material assignment itself was already safe, since Carina keys the physics and properties NamedTuples by real block names and FEC now permutes them into block order. What was not safe was the startup ordering check, which compared Carina's Dict-ordered list against the function space's file-ordered one and would have failed a perfectly valid run on any mesh with three or more blocks. Requires FiniteElementContainers with `block_names`; do not merge before Cthonios/FiniteElementContainers.jl#321.
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 bug
Per-block mesh data lives in
Dicts keyed by block name, while the block names themselves live in an orderedVector.Dictiteration is hash order, sovalues(mesh.element_conns)andmesh.element_block_namesare two different orderings of the same blocks — and the code that indexes blocks positionally was mixing them.On a three-block mesh with blocks
b1,b2,b3holding 1, 2 and 3 elements:Block
b's name and blockb's elements were different blocks. Three consequences:FunctionSpacetookelem_connsandelem_id_mapsfromvalues(...)but block names andref_fesfromelement_block_names. With mixed element types across blocks this pairs a block's connectivity with another block's reference element.BCBookKeeping/_setup_sidesetnumbered blocks withenumerate(values(mesh.element_id_maps))and then used that number to indexelement_block_names, so a side set resolved to the wrong block name — and from there the wrong connectivity and reference element for its tractions.write_to_filewrote block names in file order but the blocks themselves inDictorder, pairing each block with another block's name on round-trip.Two blocks is the boundary case where it happens not to bite: every multi-block fixture in the suite is two blocks named
block_1/block_2, for which hash order equals file order. That is why 51k passing tests never saw it.The fix
block_names(mesh)is now the single source of truth for what "blockb" means, withblock_conns(mesh)/block_id_maps(mesh)returning per-block data in that same order. Every positional use is routed through them, andblock_names(fspace)exposes the same order downstream.With one order established,
physicsandpropertiescan be matched to blocks by name rather than by position.Parametersnow permutes a suppliedNamedTupleinto block order and requires its keys to be exactly the block names. This resolves the standing# TODO re-arrange physics tuple to match fspaces when appropriate— previously aNamedTuplewritten in any other order silently gave each block another block's material, and nothing downstream could flag it, since a run with swapped materials converges perfectly well to the wrong answer.Tests
test/TestBlockOrdering.jlbuilds a three-block fixture (viaExodus, at test time — no new binary in the repo) whose hash order and file order differ, with deliberately different element counts per block so a permutation shows up as a size and not just a name. It covers the mesh/function-space invariant, theNamedTuplepermutation, and each rejection case.Verified failing on
mainbefore the fix:Full suite green after: 51824 passed.
Behavior changes for downstream users
p.physics/p.propertiesare keyed by real block names instead ofregion_Nplaceholders. (region_Nappeared nowhere else in this repo and nothing indexed by it, but it was observable.)physics/propertiesNamedTuplewhose keys are not exactly the block names now raisesBlockMismatchErrorinstead of being accepted.Tupleis rejected rather than assumed to be in block order.Version bumped to
0.15.0on that account rather than a patch release.Not addressed
The
p_degree > 1path inFunctionSpacestill builds connectivity fromvalues(create_higher_order_mesh(...)). That path is untested and already broken independently (create_higher_order_meshdestructures aVector{String}as if it were anid => namepair, and keys aDict{Symbol,...}withStrings), so straightening out only its ordering would have implied a fix it does not have.