Skip to content

Add BakedSatfuncTables: exact baked-table saturation-function evaluation - #5284

Draft
hnil wants to merge 1 commit into
OPM:masterfrom
hnil:pr-baked-satfunc-tables
Draft

Add BakedSatfuncTables: exact baked-table saturation-function evaluation#5284
hnil wants to merge 1 commit into
OPM:masterfrom
hnil:pr-baked-satfunc-tables

Conversation

@hnil

@hnil hnil commented Aug 10, 2026

Copy link
Copy Markdown
Member

Bakes each cell's scaled material law (endpoint scaling included, ECL-default three-phase) into minimal exact piecewise-linear tables on three saturation axes, deduplicated across cells. Vertical endpoint scales (maxKr*, maxPc*, e.g. from SWATINIT) are linear in the ordinate and factored into per-cell multipliers instead of keying tables. Node placement is found by midpoint refinement with kink snapping against the installed law, so no endpoint-scaling semantics are reimplemented and the build validates itself (max rel err ~1e-10).

Norne, 44 927 cells, eval3, identical states and checksums:

relperm + pc ns/cell
generic law stack 89.9
baked 20.6

7 unique tables, 33.7 KB pool for the whole field; 60 B per cell; bake < 0.01 s. Wired into flow it cut Props/update 10.9 → 8.5 s (−23 %) with unchanged iteration counts. Consumer-side hook: OPM/opm-simulators#7304.

Scope of this branch: ECL-default approach, no hysteresis, no directional relperm. A prototype adding Carlson KR hysteresis (second pool for the two hysteretic columns, four scalars per cell, one compare and one add) measures 201.6 → 24.6 ns/cell on Norne with EHYSTR active; it is not in this PR yet. Stone 1/2 should be cheaper still — both put the oil constituents on the sw and sg axes — but is not implemented.

Draft: feedback welcome on where this belongs and how the fallback should be gated.

🤖 Generated with Claude Code

For the ECL-default three-phase law, bake each cell's scaled material law
(EPS included) into minimal exact piecewise-linear tables on three axes
(Sw, Sg, S=Sw+Sg), deduplicated across cells by the shape of the scaled
endpoints. Vertical endpoint scales (maxKr*, maxPc*, e.g. from SWATINIT)
are linear in the ordinate and factored into per-cell multipliers instead
of keying tables; with 3pt vertical scaling active the residual/max ratio
keys the shape. Node placement is discovered by midpoint refinement with
kink snapping and collinear pruning, so the representation is exact
without reimplementing any EPS semantics; build-time validation compares
against the installed law.

Evaluation is one hint-grid-accelerated segment lookup per axis with the
node values interleaved per cache line and derivatives constructed
analytically. On Norne (44k cells, SWATINIT) this yields 7 unique tables
in 31 KB and evaluates ~2-4x faster than the generic law stack.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@hnil
hnil force-pushed the pr-baked-satfunc-tables branch from 7baa38c to b1f53dc Compare August 10, 2026 11:53
@hnil hnil added the manual:new-feature This is a new feature and should be described in the manual label Aug 11, 2026
@hnil

hnil commented Aug 11, 2026

Copy link
Copy Markdown
Member Author

Two follow-up results that bear on how this should be judged.

Hysteresis is where the table representation gains most, not where it struggles. Norne runs EHYSTR ... KR (Carlson). With that active the generic path costs 201.6 ns/cell versus 110.8 without — a 2x overhead that returns identical values at drainage state, because the per-cell parameter object doubles (drainage + imbibition) rather than because any extra mathematics is done. Carlson reduces to imbibition_curve(arg + delta) guarded by one comparison, and only two of the six curves are hysteretic, so a prototype adds a second pool for those two columns plus four scalars per cell:

Norne, eval3, EHYSTR active ns/cell
generic + hysteresis law 201.6
baked + Carlson, cells at drainage 24.6 (checksum identical)
baked + Carlson, all cells forced reversed 27.7

Pool 33.7 → 49.3 KB, per-cell 60 → 92 B. Not in this branch yet; the imbibition branch still needs end-to-end validation against a reversed state.

A cheaper, independent step exists. Deriving the two-phase arguments once, with no representation change at all, gives 89.9 → 59.8 ns/cell — about a third of the win for none of the machinery here. That is now #5287, and it is worth landing on its own merits regardless of what happens to this PR.

For calibration, the ladder on Norne (eval3, identical checksums): generic 89.9, fused arguments 59.8, baked 20.6; with hysteresis 201.6 → 24.6.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

manual:new-feature This is a new feature and should be described in the manual

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant