Default IMBNUM to SATNUM when not in deck#5110
Conversation
|
Thanks for the PR. Defaulting IMBNUM to SATNUM seems logical. I will ask @bska to review the code since I am not 100% sure if amending the props as you suggest has unintended consequences for restart and output. |
|
Thank you for your work. I appreciate the sentiment, but I don't think this is the right solution. If a model wants hysteresis, then it's (supposed to be) a modelling error if Then you'd get a runtime diagnostic saying that COPY
SATNUM IMBNUM /
/or defining |
7cfac54 to
9b1dff7
Compare
|
Reworked as suggested — force-pushed to the same branch:
One follow-up thought on documentation: in a CO2 storage workflow you often move between hysteresis patterns over a field's lifecycle —early on, using just endpoints (ISGCR etc.) to estimate residual trapping for uncertainty quantification; later, once the field is better characterized, switching to a fully specified IMBNUM with full I-tables is customary. Working out how the mechanics worked was not obvious to me. Would it be useful to document the common hysteresis patterns in the manual? |
bska
left a comment
There was a problem hiding this comment.
Thanks a lot for the updates. This is starting to look good to me now, save for one minor detail in the new unit test.
| BOOST_REQUIRE_EQUAL(imbnum.size(), expected.size()); | ||
| for (std::size_t i = 0; i < expected.size(); ++i) { | ||
| BOOST_CHECK_EQUAL(imbnum[i], expected[i]); | ||
| } |
There was a problem hiding this comment.
Just for your information, the Boost.Test library has a helper macro, BOOST_CHECK_EQUAL_COLLECTIONS, that runs this loop for you and also checks that the collections have the same size. Using that macro you could write
BOOST_CHECK_EQUAL_COLLECTIONS(imbnum.begin(), imbnum.end(), expected.begin(), expected.end());Another benefit of using that macro is that it will also report the corresponding index if one or more elements differ between the two collections.
Previously IMBNUM defaulted to 1 for every cell via .init(1). In multi-SATNUM hysteresis decks where the deck omits IMBNUM, this silently produced wrong imbibition table assignments and a systematic mass-balance drift.
9b1dff7 to
1e06821
Compare
|
jenkins build this please |
|
Thanks for the tip...been learning a lot. :) |
Happy to help! That said, I now see that OPM Flow user manual documents the default value of I personally would prefer to not have a default value for |
|
Just to add practical context: for CO2 storage workflows using analytical hysteresis via EHYSTR + ENDSCALE with per-region endpoints (no full imbibition tables), the current IMBNUM=1 default assigns the wrong imbibition region to every cell where SATNUM != 1. On my test case this produced a silent mass-balance drift where trapped-gas mass more than doubled. Making IMBNUM required would mean every multi-SATNUM deck using analytical hysteresis needs COPY SATNUM IMBNUM / just to get correct behavior — This invalids the purpose of having analytical models. I understand that changing documented behavior needs broader discussion, but I'd argue the current default is actively harmful for multi-region hysteresis decks: it's a silent physics-level error rather than a deliberate design choice. Defaulting IMBNUM to SATNUM when the keyword is omitted fixes the drift, keeps analytical hysteresis usable out of the box, and still allows explicit IMBNUM for users who need different imbibition regions. |
Summary
When a deck activates relperm hysteresis (
SATOPTS HYSTER+EHYSTR) but omits theIMBNUMkeyword, OPM initialises every cell's imbibition region to 1. In decks with multipleSATNUMregions this silently selects the wrong imbibition tables for every cell whose SATNUM is not 1, producing a non-zerodeltaSwImbKrn_in the hysteresis scanning curve and a systematic mass-balance drift.The sign and magnitude of the drift depend on how much of the grid has
SATNUM != 1, how much of that volume is swept by gas, the drainage/imbibition endpoint spread, and the simulation horizon. Single-SATNUM decks are unaffected. Multi-SATNUM decks fail silently: no warning, no error, just a running mismatch inFGMIPvsWGMITthat grows over time.Fix: default
IMBNUM = SATNUMwhen the deck never mentions IMBNUM — the Eclipse-documented idiom for "switch hysteresis off in specific blocks", applied globally. A single 15-line change inFieldProps::FieldProps(...)fixes every downstream consumer (init_satfunc,EclEpsGridProperties,EclMaterialLawInitParams, ...) without touching any of them.How to use hysteresis after this fix
Three patterns are all valid.
IMBNUMcan now be omitted in every case.1. Full I-prefixed saturation tables. Classic setup: one SGFN/SWFN per SATNUM region plus matching ISGFN/ISWFN. Unchanged by this PR.
2.
ENDSCALE+ scaled imbibition endpoints (no I-tables). One drainage set per region, with the imbibition curve built analytically from the per-cell residual endpoint. Recommended when only the residual-Sg endpoint is known — typical of CO2-storage studies.3. No imbibition data at all.
IMBNUM = SATNUMcollapses the scanning curve onto the drainage curve — the simulator behaves as ifSATOPTS HYSTERwere absent. Mass is conserved.For Pattern 2, additional scaled endpoints (
ISGU,ISWCR,ISWU,ISWL) may be supplied per region via the sameEQUALSmechanism if finer control is needed, butISGCRalone is sufficient for residual gas trapping.Worked example (not a universal symptom)
Reproducer: 80x80x14 CO2STORE deck with two SATNUM regions (shale seal over sand reservoir, ~72% of cells in region 2), CO2 injection into region 2 for 30 years, then 370 years of post-injection.
Other deck geometries and injection schedules will land at different magnitudes; the pre-fix blowup on this deck is illustrative, not a universal figure.
Known remaining drift (out of scope for this PR)
A residual sub-percent drift remains on the reproducer deck when hysteresis is active alongside DISGASW + DRSDTCON. Between end-of-injection (y=30) and end-of-simulation (y=399), with WGMIT flat in that window:
e.g. Carlson + ISGCR=0.25: Delta(FGMGP) = -2.50e+10, Delta(FGMDS) = +2.65e+10, net +1.46e+09 lb of gas mass appears in a closed system. Magnitude on this deck: +0.4% (per-region ISGCR) to +2.2% (uniform ISGCR) over 369 years.
Bisection controls on the same reproducer deck:
The drift is therefore localised to the hysteresis-dissolution coupling, not to the scanning-curve math (hysteresis on its own is mass-conservative to within numerical noise). Suspected culprit: dissolution of trapped (residual) gas into the water phase adds dissolved mass without a matching debit on the gas-phase side of the accounting. Flagged here for follow-up; not addressed by this PR.
Tests
Two new cases in
tests/parser/FieldPropsTests.cpp:IMBNUM_DEFAULTS_TO_SATNUM— multi-SATNUM deck without IMBNUM must produceIMBNUM == SATNUMcell-by-cell.IMBNUM_EXPLICIT_PRESERVED— deck-supplied IMBNUM must not be overwritten, even when SATNUM differs.All 62
FieldPropsTests+ 32test_hysteresiscases pass.Test plan
ctest -R FieldPropsTestsctest -R test_hysteresis