Repository navigation
Conversation
…odule + flags YMF_MODEL_FAMILIES_C42 section 6, D1 and D8. A ymf spec states the model, the formulation (a weak_forms entry, named by from_weak_form) and the discretization (spaces, time integration, stabilization, the split into sub-problems, bound symbols, regularization). proteus.Dispatch reads one discretization of a closed spec and returns, per sub-problem in solve order, the mprans module, its Coefficients flags, the physics-module attributes and the numerics-module attributes, each with its source (cell, spec, default, hint). - proteus/DispatchTable.py: data only. Families (by physical_model), roles, and 13 cells: RANS2P conservative and non-conservative (one module, two cells: NONCONSERVATIVE_FORM 0/1), RANS3PF projection + PresInc/Pres/PresInit, VOF, NCLS, RDLS, MCorr, CLSVOF; SW2DCV; GN_SW2DCV. - proteus/Dispatch.py: role from the closed spec's structure (which unknowns a sub-problem's equations are for, what it enforces/introduces), cell by formulation and each stated option; epsFact from regularize widths in element sizes, useVF from lagging the heaviside coefficient, shock capturing from stabilization, maxNonlinearIts from solver, quadrature from the highest space order. An uncovered cell is refused by name with each candidate's mismatch. A proteus: hint is checked: disagreeing with the spec or the cell is refused, a hint on a defaulted flag replaces the default, an unknown hint is refused. - test/dispatch: the C42 dam-break family + case with the two inertia forms as weak forms and three discretizations; ymf's shallow-water fixtures (copied from ymf tests/fixtures/shallow_water at c2e646f). Force-added: .gitignore ignores *.ymf (archives), as for test/poisson_2d/square4x4.ymf. Finding: both in-tree dam breaks solve the NON-conservative inertia form. RANS2P.Coefficients defaults NONCONSERVATIVE_FORM=1.0 and RANS3PF.h hardwires it, so the C42 note's "from_weak_form: conservative_inertia" (marked "to confirm") is wrong for both; (conservative_inertia, P2 projection) is a cell no module covers and is refused. Measured (env proteus-bc-261025, macOS arm64, serial; ymf main c2e646f): test/dispatch 20 passed. Object by object against the decks' built p/n modules (TwoPhaseFlowProblem.initializeAll, SWFlow sw_p/sw_n, nothing solved): spec discretization deck models attributes compared level_set_five damBreakLevelSet.py 5 100 (cell 33, spec 51, default 16, hint 1) level_set_clsvof damBreakLevelSet.py interface=1 2 49 clsvof_projection damBreak.py 5 75 convex_limited dam3Bumps.py (SW2DCV) 1 23 (relaxed, from test) dSWEs_steady_state.py (GN) 1 16 10 of 10 single-value mutations of a dispatch result (a flag, a space, the quadrature order, a step controller, a level model, a lag) fail the comparison. Refusals tested: conservative projection, a P2 RANS2P velocity, SSP_RK3 on VOF, no family, no role, an unknown formulation, RANS3PF without PresInit, an unregularized heaviside, an unread scheme option; hints disagreeing with the spec (useVF, RDLS epsFact), with the cell (NONCONSERVATIVE_FORM), naming another module, or unknown to the cell. The test restores PETSc's options database and the global Context after building each deck (checked: no option leaks). Not here: building pnList from the dispatch and running the solve (C5 step 2, through ymf_run). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…traceback
Before: `pro run` on a spec whose model only a split can solve (the dam break,
the lake at rest) died in adr_problem with a SymbolicError traceback
("DiracDelta(φ) has no value at a point", "a dirichlet condition on the normal
component ... runs in a split discretization's solver"), before blockers()
could say anything. After: split discretizations are caught before the model
is classified as one ADR system; each prints what proteus.Dispatch maps it
onto (or the dispatch's refusal), exit 2, nothing written. --ignore drops the
split ones when others are selected. blockers() uses the same message
(split_reason), so the split check there keeps "split into sub-problems (...)".
pro run test/dispatch/dambreak.ymf -> exit 2:
level_set_five: ... It dispatches to flow RANS2P, vof VOF, ncls NCLS,
rdls RDLS, mcorr MCorr; running a split discretization from the
dispatch is not wired up yet
clsvof_projection: ... clsvof CLSVOF, flow RANS3PF, pressureInc PresInc,
pressure Pres, pressureInit PresInit; ...
pro run test/dispatch/lake_at_rest.ymf -> exit 2: ... swe SW2DCV; ...
test_pro_cli.py, test_adr_problem.py, test_domain_ymf.py, test/dispatch:
213 passed, 1 skipped (was 191 passed, 1 skipped without test/dispatch).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…plication The coverage check failed on this PR for proteus/mprans/NCLS3P.py: floor 76.2%, measured 75.7%. This PR does not touch NCLS3P. 76f3e12 (on main, "One scatterDOFArray, on OneLevelTransport, replacing the 11 copies in mprans") removed 15 covered statements from the module. The same 163 statements are missed before and after, compared line by line between the c47-cython3 run 42031161865 and this PR's run 42109633045. So the percentage falls with the denominator: before 522/685 = 76.2% after 507/670 = 75.67% The floor is set the way ratchet.py writes one: floor(10 * now) / 10 = 75.6. Every branch off current main hits this check. If another PR lowers the same floor, the change is identical and merges cleanly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cekees
added a commit
that referenced
this pull request
Nov 5, 2026
…patch, bitwise the deck
ymf_run used to refuse every split discretization (exit 2). A split discretization the dispatch covers now runs:
proteus.DispatchRun builds it through the deck machinery, not a parallel path. It builds a TwoPhaseFlowProblem from
the dispatch result (models in dispatched order, each with its TwoPhaseFlow Parameters class; coefficient flags and
numerics knobs set before initializeAll) and from ymf's plain data of the split (ymf.symbolic.split.split_problem).
The domain becomes a SpatialTools Tank2D, and each side gets the BC_RANS setter whose signature matches the closed
(expanded) conditions of its region. Initial data come from the model's unknowns; heaviside(φ) under
smoothed_heaviside is evaluated with Proteus's own smoothedHeaviside. rho/nu/g come from the family's ρ, μ, g at
phase indicator 0 and 1, simplified symbolically, so nu_0 is νw itself. After initializeAll, every attribute the
dispatch gives is compared with the built p and n modules (DispatchRun.differences, the comparison the step-1
tests made); a difference is refused before anything solves. The archive records the dispatch and what the
realization took from where; --check reruns and compares bitwise.
Kept: a cell the table does not cover is refused before anything runs (DispatchError, exit 2); so is a family
with no realizer yet (the shallow-water families, next commit).
Oracle: test/dispatch/dambreak_short.ymf (level_set_five, t in (0, 0.03], 3 outputs, h = 0.2576) against
damBreakLevelSet.py -C "final_time=0.03 dt_output=0.01 he=0.08 genMesh=True" (h = 3.22 * 0.08 = 0.2576 exactly).
triangle meshes the same PSLG to 161 nodes and 273 triangles. macOS arm64, env proteus-bc-261025:
run datasets compared bitwise equal max |velocity| at t = 0.03
parun deck vs pro run spec, 1 rank 103 103 0.522
parun deck vs pro run spec, 2 ranks 141 141 (same run, partition pinned:
-mat_partitioning_type current)
pro run --check of its own archive 1 output reproduced, bitwise
negative control: ε = 1.6 h for 1.5 h 103 differ: vof_t0 by 1.7e-2 (39 of 161 nodes),
v_t2 by 2.8e-2
The mesh records (Mesh_Spatial_Domain_*) differ only in the HDF5 file's name; the mesh fingerprint is the same.
Wall time: deck 1.2 s, spec 1.9 s (serial).
Found on the way:
- useSuperlu is a direct solve on any number of ranks (SuperLU serially, SuperLU_DIST through PETSc in
parallel), so linear_solver: superlu maps onto it on 2 ranks. Mapping petsc there gives GMRES+ASM: p differs
from the deck by 3.2e-2.
- phi_init uses hypot. The spec's sqrt(max(..)² + max(..)²) form differs from it by 1 ulp at 2 of the 109 nodes
of the stored mesh. dambreak_short.ymf therefore writes hypot, which needs ymf's notation to have it (cekees/ymf
branch notation-hypot); without it the two run tests skip, saying so. dambreak.ymf keeps the sqrt form, so the
step-1 tests run on ymf main.
- The archive writer rewrites the free-form hint value 1.0e6 as '1000000.0'. Reading the archive back then keys
the output differently, so --check found no record. dambreak.ymf writes 1000000.0; the root cause is ymf's.
Tests: test/dispatch 23 passed (with notation-hypot), 20 passed + 2 skipped (ymf main); with test_pro_cli,
test_adr_problem and test_domain_ymf: 216 passed, 1 skipped (-n 4).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…patch, bitwise dam3Bumps The second family through the deck machinery. proteus.DispatchRun.shallow_water builds an SWFlowProblem from the dispatch and from ymf's split plain data, then loads SWFlow's own sw_p/sw_n through Context's mySWFlowProblem, as parun --SWEs loads them: - the domain is a RectangularDomain's PSLG meshed by triangle at h (SWFlow's unstructured path); - the bed Z and the initial depth are the spec's formulas; - g, n (Manning), θ, α, β become physical_parameters, in copies (SWFlowProblem hands out its module's default dicts, which decks edit in place); - the dispatched flags become swe_parameters, and SSPOrder comes from the dispatched time order; - walls on the whole boundary (the closed expansion of `wall`: q·n = 0, zero tangential flux) become reflectingBCs. Any other boundary is refused until SWFlow's open boundaries are wired up. The built p and n go through the same check as the two-phase models before anything solves. Also refused before anything runs: a split discretization meshed by cells or with levels > 1 (the lake at rest's cells study). The deck machinery meshes by element size. The dispersive family (GN_SW2DCV) still dispatches and is refused: nothing realizes it, and ymf cannot state its auxiliary unknowns' data. Dispatch: `outputs` in the free-form scheme block is the runner's (as on ymf_run's ADR path), not an unread scheme option. Oracle: test/dispatch/dam3bumps.ymf (dam break over three cones, 75 m x 30 m, t in (0, 0.5], 5 outputs, h = 2) against dam3Bumps.py -C "final_time=0.5 dt_output=0.1 structured=False he=2.0". triangle meshes 969 nodes. macOS arm64, env proteus-bc-261025: run datasets compared bitwise equal parun deck vs pro run spec, 1 rank 70 numeric 70 parun deck vs pro run spec, 2 ranks 77 numeric 77 (-mat_partitioning_type current) (for scale: the deck on 1 vs 2 ranks differs by up to 4.3e-6 in the momentum) The bed is written with 47.5 as 95/2. With the decimal, sympy factors it out of the square under the sqrt (3 - 14.25*sqrt((0.0210526*x - 1)**2 + ...)): the same number, other arithmetic. SWFlowProblem's he is not read by SW2DCV: the deck's 0.9375 and the spec's 2.0 give the same bits. This case needs nothing new from ymf, so it runs on CI with ymf main. The dam break needs the notation's hypot, and its two runs skip there, saying so. Tests: test/dispatch 26 passed (ymf notation-hypot); with test_pro_cli, test_adr_problem and test_domain_ymf on ymf main: 216 passed, 4 skipped (-n 4). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…re anything runs
What realize() refuses on the data alone is now checked in split_blockers, with every other blocker, before
anything is solved or written (DispatchRun.precheck). That covers the family, the box, the boundary (each tank
side's region and the BC_RANS setter its closed conditions match, or SWFlow's treatment of the whole boundary)
and the two-phase physical values. Before this, such a refusal surfaced mid-run as a RealizeError traceback,
after earlier outputs of the same run had been solved.
Found with level_set_clsvof (dambreak.ymf, RANS2P + CLSVOF). No sub-problem carries χ, so ymf's split gives the
closed atmosphere no χ inflow. What is left (p = 0, zero velocity flux) matches no setter in the table, so it is
refused:
before: ymf_run ... --discretization level_set_clsvof -> traceback in the solve, exit 1
after: exit 2, nothing written: "level_set_clsvof: split into sub-problems (flow, clsvof). It dispatches to
flow RANS2P, clsvof CLSVOF, and cannot run: region top (side y+): no BC_RANS setter imposes its closed
conditions ..."
The deck (damBreakLevelSet.py interface=1) calls setAtmosphere there. Whether the table should map that
two-condition signature onto setAtmosphere for CLSVOF is a question for the handoff, not decided here.
Tests: test/dispatch 27 passed (ymf notation-hypot), 24 passed + 3 skipped (ymf main), -n 4.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cekees
added a commit
to cekees/ymf
that referenced
this pull request
Nov 6, 2026
…k's phi_init tests/fixtures/two_phase/dambreak.ymf states the case of proteus's test/TwoPhaseFlow/damBreakLevelSet.py. Its initial signed distance is now written with hypot (previous commit), as the deck's phi_init computes it. The sqrt of a sum of squares rounds twice. Measured with proteus cekees/proteus#211 (C5 step 2), macOS arm64, numpy 2. The deck is damBreakLevelSet.py -C "final_time=0.03 dt_output=0.01 he=0.08 genMesh=True"; the spec is the same case run through ymf_run, with 161 nodes: sqrt form hypot form phi0 at the deck's stored mesh (109 nodes) 2 nodes differ, max 4.4e-16 0 differ (1 ulp) phi0 at the run's mesh (161 nodes) 2 nodes differ, max 4.4e-16 0 differ deck vs spec archive at t = 0 4 values differ (phi, phid), 0 differ (103/103 datasets max 4.4e-16 bitwise) deck vs spec archive at t = 0.03 1182 values differ, max 1.5e-12 0 differ (p) So without hypot no run from a spec can reproduce the deck bitwise. test_notation_functions keeps the sqrt form's three-branch check at abs_tol 1e-15, and adds the hypot form's bitwise one. Tests: 795 passed, 11 skipped (tests/, -n 4). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cekees/ymf#12 The two dam-break runs and the in-process ymf_run test skipped when the installed ymf lacked hypot. CI would then have been green without the oracle running. They now run, and with ymf main (c2e646f) they fail: dambreak_short.ymf does not parse there. proteus CI installs ymf from proteustoolkit/ymf@main, so they stay red until cekees/ymf#12 (hypot in the notation) is merged upstream. That is the order: ymf#12 first, then this PR. ymf notation-hypot (6feb177): test/dispatch 27 passed ymf main (c2e646f): 24 passed, 3 failed (the dam-break runs on 1 and 2 ranks, and the ymf_run test) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
C5 steps 1 and 2 (claim A1,
PARALLEL_SESSIONS§10), following YMF_MODEL_FAMILIES_C42 §6 D1 (dispatch) and D8 (hints are checked, and dispatch wins).A ymf spec states the model, the formulation (a
weak_formsentry named byfrom_weak_form), and the discretization: spaces, time integration, stabilization, sub-problems, bound symbols and regularization.proteus.Dispatchreads one discretization of a closed spec. For each sub-problem, in solve order, it returns the mprans module, theCoefficientsflags, and the physics- and numerics-module attributes. Each value records where it came from:cell,spec,defaultorhint. The table,proteus/DispatchTable.py, is data only and can be reviewed on its own.DispatchTable.py(13 cells: RANS2P ×2 forms, RANS3PF + PresInc/Pres/PresInit, VOF, NCLS, RDLS, MCorr, CLSVOF, SW2DCV, GN_SW2DCV),Dispatch.py,test/dispatchlevel_set_five= damBreakLevelSet (5 models, 100 attributes),level_set_clsvof= damBreakLevelSetinterface=1(2, 49),clsvof_projection= damBreak (5, 75), SW2DCV = dam3Bumps (23), GN_SW2DCV = dSWEs_steady_state (16). 10 of 10 single-value mutations are caught.ymf_runrefuses split discretizations beforeadr_problemand prints what each one dispatches to.github/coverage/floors.json: NCLS3P.py 76.2 → 75.6floor(10·now)/10. Every branch off main c09280c hits this check.ymf_runruns a split discretization from its dispatch.proteus/DispatchRun.pybuilds aTwoPhaseFlowProblemfrom the dispatch and from ymf'ssplit_problem: Tank2D +BC_RANSsetters matched on the closed conditions, ICs (Proteus'ssmoothedHeavisidefor heaviside(φ)), and ρ/ν/g from the family's ρ, μ, g. It checks the built p/n against the dispatch before solving; the archive records the dispatch and the realization, and--checkworksdambreak_short.ymf(level_set_five, 3 outputs, h = 0.2576) vsdamBreakLevelSet.py -C "final_time=0.03 dt_output=0.01 he=0.08 genMesh=True": 103/103 datasets bitwise equal on 1 rank, 141/141 on 2 (-mat_partitioning_type current).--checkreproduces bitwise. Negative control ε = 1.6 h: vof_t0 differs by 1.7e-2. Needs ymf'shypot(below)SWFlowProblemwith SWFlow's ownsw_p/sw_nloaded through Context; walls →reflectingBCs. A cells-meshed split discretization is refused up frontdam3bumps.ymf(t ∈ (0, 0.5], 5 outputs, h = 2, 969 nodes) vsdam3Bumps.py -C "final_time=0.5 dt_output=0.1 structured=False he=2.0": 70/70 numeric datasets bitwise equal on 1 rank, 77/77 on 2. For scale, the deck on 1 vs 2 ranks differs by up to 4.3e-6. Runs on ymf mainymf_runrefuses, before anything runs, a split discretization the realizer would refuse on the data alone (DispatchRun.precheck: family, box, boundary setters, two-phase values)level_set_clsvof: before, a traceback mid-solve (exit 1); after, exit 2 with nothing written. The reason: no sub-problem carries χ, so the closed atmosphere has no χ inflow, and noBC_RANSsetter matches{p = 0, zero velocity flux}. 27 passed (hypot) / 24 + 3 skipped (ymf main)test/dispatch: no skip without ymf'shypot; the dam-break oracle needs cekees/ymf#12ymf_runtest)test_ymf_run_says_what_a_split_discretization_dispatches_tois in commit 1's test file and needs commit 2. Since 6f0d07c it describes the run: what the split dispatched to and what the archive records. The refusal has its own tests: an uncovered cell, a cells-meshed split, and a boundary no setter imposes.Needs cekees/ymf#12 merged into proteustoolkit/ymf main first. It adds
hypot(a, b)to ymf's notation.damBreakLevelSet.py'sphi_inituseshypot; the spec's sqrt-of-squares form differs from it by 1 ulp (4.4e-16) at 2 of the 109 stored-mesh nodes, and by t = 0.03 that grows to 1182 values, up to 1.5e-12 in p. Withhypot, 0 values differ. proteus CI installs ymf from proteustoolkit/ymf@main, so until ymf#12 merges upstream the dam-break runs and the in-processymf_runtest cannot pass on CI. They are not skipped: until then they fail on CI (unknown name 'hypot'), which is the intended order. The dam3Bumps runs do not need it.Finding: both in-tree dam breaks solve the non-conservative inertia form.
RANS2P.Coefficientsdefaults toNONCONSERVATIVE_FORM=1.0, and RANS3PF.h hardwires that form. The C42 note'sfrom_weak_form: conservative_inertia("to confirm") is therefore wrong for both. (conservative, P2 projection) is a cell no module covers, and dispatch refuses it by name.How a sub-problem finds its cell: the family comes from
physical_model. The role comes from the closed spec's structure: which unknowns its equations arefor, and what itenforcesorintroduces. The cell is then chosen by formulation and by each option the spec states. Values the dispatcher infers from typed keys:epsFactand the other widths, fromregularizewidths in element sizesuseVF, from lagging χ = heaviside(φ)stabilizationmaxNonlinearIts, fromsolverRefusals tested:
useVF, RDLSepsFact) or with the cell (NONCONSERVATIVE_FORM), name another module, or are unknown to the cellNot in this PR: the CLSVOF and projection discretizations as runs. They dispatch, and the realizer should build them, but no oracle has been run for them yet. Also not here: the dispersive SWE (refused, since nothing realizes it), gauges, open SWE boundaries, 3-D tanks, and stored meshes as a spec domain (C7.1).
Run locally: env proteus-bc-261025, macOS arm64; ymf main c2e646f, and ymf
notation-hypotd51ca2d for the dam-break runs.🤖 Generated with Claude Code