This commit introduces consistency checks for the scaled displacing
saturation in the three point horizontal scaling method
(SCALECRS=YES). These plug into the framework introduced in commit
c3939c544 (PR #5438). We implement the following two checks
- SGCR < 1-SOGCR-SWL < SGU
- SWCR < 1-SOWCR-SGL < SWU
which collectively guarantee a mobile displacing oil saturation in
the two phase gas/oil and oil/water systems.
If the user chooses a specific number of NLDD domains, there is no
need to compute the default number of domains based on a specific
target number of cells per domain. Defer the, potentially costly,
calculation to when we know we need it.
While here, also split/rejoin a couple of long lines.
This commit introduces a set of consistency checks for the water
phase saturation functions. These plug into the framework
introduced in commit c3939c544 (PR #5438). We implement the
following three checks
- 0 <= SWL < 1
- 0 < SWU <= 1
- SWL <= SWCR < SWU
which collectively enable a non-negative oil saturation in the two
phase oil/water system.
This commit introduces a set of consistency checks for the gas phase
saturation functions. These plug into the framework introduced in
commit c3939c544 (PR #5438). We implement the following three checks
- 0 <= SGL < 1
- 0 <= SGU < 1
- SGL <= SGCR < SGU
which collectively enable a non-negative oil saturation in the two
phase gas/oil system.
This commit introduces a set of consistency checks for the oil phase
saturation functions. These plug into the framework introduced in
commit c3939c544 (PR #5438). We implement the following four checks
for the gas/oil two-phase system
- 0 <= SOGCR < 1
- SWL + SGU <= 1
- SOGCR < 1 - SWL - SGL
- SOGCR < 1 - SWL - SGCR
which all guarantee a non-negative (mobile) oil saturation in the
gas/oil system. Similarly, we implement the following four checks
for the oil/water two-phase system
- 0 <= SOWCR < 1
- SGL + SWU <= 1
- SOWCR < 1 - SWL - SGL
- SOWCR < 1 - SWCR - SGL
which provide the same guarantees as outlined above, but for the
oil/water system.
We add a base class, PhaseCheckBase<Scalar>, which provides a common
representation of the violated/critical predicates and implement the
specific checks as derived types of this base class.
This commit broadens the scope of commit 2ad332e0b (PR #922) to
apply to all compilers/libraries, not just Clang/libc++, which do
not have support for floating-point types in std::from_chars().
While hopefully a transient situation, this enables building the
parameter system with GCC versions prior to GCC 11. We expect to
require version 11 in the not too distant future, though. At that
point we should revert this commit.
We use a configure-time feature test of the compiler (CMake command
'try_compile') to detect whether or not the compiler supports
floating-point overloads of std::from_chars() and emit the result to
config.h as the new preprocessor symbol
HAVE_FLOATING_POINT_FROM_CHARS
We use std::strtod() as the fall-back alternative for floating point
conversion if this symbol is defined to false (zero).
This commit introduces helper functions for each individual part of
a convergence report record in the INFOITER file. In particular, we
create helpers for
- Time related columns (report step, time step, time &c)
- CNV pore-volume histogram columns
- Reservoir convergence metrics (CNV and MB values per phase)
- Well convergence metrics
This makes the body of the main loop in writeConvergenceRequest()
slightly easier to read and means that we can apply some additional
logic to the CNV pore-volume histograms if the number of values does
not match the expected 3 per type. In that case we output sentinel
values (e.g., NaN and -1) to signify that the corresponding pieces
of information are unavailable.
This commit switches the parallel implemenation of function
Opm::gatherConvergenceReport() into using the general serialisation
framework (classes Opm::Serializer<> and Opm::Mpi::Packer). In
particular, we add serializeOp() functions to each of the types
- ConvergenceReport
- ConvergenceReport::ReservoirFailure
- ConvergenceReport::ReservoirConvergenceMetric
- ConvergenceReport::WellFailure
and defer the job of converting the objects between in-memory and
byte stream representations to Opm::Serializer<>. The new special
purpose class CollectConvReports inherits from the latter and uses
its pack() and unpack() member functions, along with its internal
m_buffer data member, to distribute each rank's convergence report
object to all ranks. We add this feature here, in a very narrowly
scoped use case, to enable testing and experimentation before we
consider adding this distribution mechanism as a general feature in
Opm::MpiSerializer.
This commit tracks the number of cells and their associate fraction
of the model's "eligible" pore volume (total pore volume in
numerical aquifers subtracted from the model's total pore volume) in
three distinct categories as a function of the non-linear iteration
number:
- 0: MAX_p { CNV_p } <= strict CNV tolerance
- 1: MAX_p { CNV_p } \in (strict, relaxed]
- 2: MAX_p { CNV_p } > relaxed CNV tolerance
We then output these cell counts and pore volume fractions as new
items in the INFOITER file to enable more targeted analysis of the
non-linear convergence behaviour.
To this end, introduce a type alias CnvPvSplit in the
ConvergenceReport and aggregate these across the MPI ranks before we
collect them in the ConvergenceReport objects.
While here, also reduce the amount of repeated logic in
gatherConvergenceReport.cpp through a few local lambdas.
This commit switches the approach introduced in commit eeb1b7e36 (PR
#3169) to using a mobility weighted average of cell level densities
for the connection level mixture densities in no-flow producing
wells. We also use the recent stoppedOrZeroRateTarget() predicate
to identify those no-flow producing wells instead of inspecting the
connection flow rates.
The mobility weighted average gives a more monotone pressure buildup
for the stopped wells and this is usually what the engineer wants.
This revised approach furthermore needs fewer cell-level dynamic
properties so simplify the computeProperties() signature by
introducing a structure for the property callback functions and
update the callers accordingly.
This commit switches computePropertiesForPressures() to return a
Properties object directly instead of populating an object
constructed in the caller. There is just a single call site for
this function so there's no benefit to using an out parameter here.
While here, also collect the property callbacks into a structure to
simplify the function signature. This also enables not filling in
the solvent properties unless solvent is active in the run. Update
caller accordingly.
In particular, split the sections of the main loop out to helper
functions
- calculatePerforationOutflow() uses the global container factory
to compute the outflow from each connection
- initialiseConnectionMixture() computes the 'mix' array depending
on the local flowing conditions of the connection. We have
renamed 'x' and 'mix' arrays to 'currentMixture' and
'previousMixture' respectively to give more descriptive names in
the process.
We've also split out the redistribution of the individual phases to
the new private helper functions reapportionGasOilMixture() and
reapportionGasWaterMixture() in order to reduce the cognitive load
of the main loop in computePropertiesForPressures(). While here,
employ pointer arithmetic to expose the underlying structure of the
assignment expressions.
In particular
* Split some long lines
* Reverse conditions to reduce nesting
* Mark potentially unused arguments as [[maybe_unused]]
* Try to remove redundant calculations
* Mark some objets 'const' where possible
This commit broadens the scope of commit c1e2a3a9b (PR #922) to
apply to all compilers/libraries, not just Clang/libc++, which do
not have support for floating-point types in std::from_chars().
While hopefully a transient situation, this enables building the
parameter system with GCC versions prior to GCC 11. We expect to
require version 11 in the not too distant future, though. At that
point we should revert this commit.
We use a configure-time feature test of the compiler (CMake command
'try_compile') to detect whether or not the compiler supports
floating-point overloads of std::from_chars() and emit the result to
config.h as the new preprocessor symbol
HAVE_FLOATING_POINT_FROM_CHARS
We use std::strtod() as the fall-back alternative for floating point
conversion if this symbol is defined to false (zero).
This commit adds a new public member function
SatfuncConsistencyChecks<>::collectFailures(root, comm)
which aggregates consistency check violations from all ranks in the
MPI communication object 'comm' onto rank 'root' of 'comm'. This
amounts to summing the total number of violations from all ranks and
potentially resampling the failure points for reporting purposes.
To this end, extract the body of function processViolation() into a
general helper which performs reservoir sampling and records point
IDs and which uses a call-back function to populate the check values
associated to a single failed check. Re-implement the original
function in terms of this helper by wrapping exportCheckValues() in
a lambda function. Extract similar helpers for numPoints() and
anyFailedChecks(), and add a new helper function
SatfuncConsistencyChecks<>::incorporateRankViolations()
which brings sampled points from an MPI rank into the 'root's
internal data structures.
One caveat applies here. Our current approach to collecting check
failures implies that calling member function reportFailures() is
safe only on the 'root' process in a parallel run. On the other
hand functions anyFailedChecks() and anyFailedCriticalChecks() are
safe, and guaranteed to return the same answer, on all MPI ranks.
On a final note, the internal helper functions are at present mostly
implemented in terms of non-owning pointers. I intend to switch to
using 'std::span<>' once we enable C++20 mode.
The intention is that this will ultimately replace the existing
RelpermDiagnostics component which does not really work in parallel
and which does not report enough context to help diagnose underlying
issues. For now, though, we just add the shell of a new set of
checks and hook that up to the build.
Class SatfuncConsistencyChecks<Scalar> manages a configurable set of
consistency checks, the implementations of which must publicly
derive from SatfuncConsistencyChecks<Scalar>::Check. Client code
will configure a set of checks by first calling
SatfuncConsistencyChecks<Scalar>::resetCheckSet()
then register individual checks by calling
SatfuncConsistencyChecks<Scalar>::addCheck()
and finally build requisite internal structures by calling
SatfuncConsistencyChecks<Scalar>::finaliseCheckSet()
Client code will then run the checks by calling
SatfuncConsistencyChecks<Scalar>::checkEndpoints()
typically in a loop. Class SatfuncConsistencyChecks<Scalar> will
count consistency check failures and attribute these to each
individual check as needed. We also maintain separate counts for
"Standard" and "Critical" failures. The former will typically
generate warnings while the latter will typically cause the
simulation run to stop. Individual checks get to decide which check
is "Critical", and client code gets to decide how to respond to
"Critical" failures.
Member function SatfuncConsistencyChecks<Scalar>::reportFailures()
will generate a textual report of the known set of consistency check
failures at a give severity level.
As an internal implementation detail, SatfuncConsistencyChecks uses
"reservoir sampling"
(https://en.wikipedia.org/wiki/Reservoir_sampling) to track details
about individual failed checks. We maintain at most a fixed number
of individual points (constructor argument).