RigStatisticsCalculator::mobileVolumeWeightedMean() accumulated into a sum
from an out-parameter that callees were not required to write. Every
implementation of the per time step overload has early-return paths that
leave the value untouched, as does RigWeightedMeanCalc::weightedMeanOverCells,
so indeterminate stack memory could be summed and presented in the UI.
Return std::optional<double> from the computation layer instead of using an
out-parameter, making "value not available" explicit and impossible to ignore:
- RigWeightedMeanCalc::weightedMeanOverCells
- RigStatisticsCalculator::mobileVolumeWeightedMean and all overrides
Time steps without a computable mean no longer contribute to the accumulated
sum, and are excluded from the divisor. Previously they would either add
garbage or, with a naive zero initialisation, bias the average towards zero.
RigStatisticsDataCache keeps the existing HUGE_VAL marker on its public API
via value_or(), so behaviour seen by RigHistogramData and the overlay info
is unchanged apart from the fix.
Also:
- Set m_isVolumeWeightedMeanCalculated in the per time step cache, which was
never assigned, so the cached value was recomputed on every call.
- Remove a duplicated ensureKnownResultLoaded() call in
RigEclipseNativeVisibleCellsStatCalc.
Fixes#14766
Log at debug level, for each case and time step, how many input values
contribute to a grid calculation aggregation and how many were replaced
with the default value (non-visible cells and undefined values). Also
log the sum and number of values used when computing visible cells
statistics, to allow comparison with the histogram sum in the 3d view.
* #14654 Fix Linux Release build defining NO_DEBUG instead of NDEBUG
CMAKE_CXX_FLAGS_RELEASE was overwritten with -DNO_DEBUG on Linux in
both CMakeLists.txt and Fwk/CMakeLists.txt. NO_DEBUG is not a standard
macro, so NDEBUG was never defined in Linux Release builds.
As a result, cafAssert.h fell back to CAF_ENABLE_ASSERTS 1, keeping
CAF_ASSERT (and standard assert()) active in Release and aborting the
app, even though RESINSIGHT_ENABLE_ASSERTS_IN_RELEASE defaults to OFF.
Windows and macOS Release builds were unaffected.
Drop the override entirely so CMake supplies its default Release
flags (-O3 -DNDEBUG) on Linux, matching Windows and macOS.
Also simplify CEE_USE_QT5/CEE_USE_QT6 handling: set them directly
instead of via option() with malformed NOT DEFINED(...) guards.
Fixed missing initialization in VfpValueSelection and WellPathCellIntersectionInfo
Realizations whose calculated summary vector value is NaN or Inf at
the selected timestep are now excluded from the Pearson correlation
computation instead of propagating NaN through the whole result,
which corrupted the correlation tornado plot. Also guard the final
correlation value against NaN, since the previous check only compared
against +Infinity.
RigEnsembleParameter::stdDeviation() sums squared parameter values,
which can overflow to +Inf for extreme (but finite) magnitudes,
turning normalizedStdDeviation() into NaN. Since NaN compares false
against the variation epsilon, such parameters were silently treated
as having no variation and dropped from parameterCorrelations(),
producing an empty tornado plot for that parameter and calculated
vector combination. Fall back to a range-based variation estimate
when the standard deviation calculation overflows, so the parameter
is retained and the Pearson correlation guard above can take over
instead.
The bounds check on timeStepIndex was only applied when timeStepCount
was greater than zero. When a DYNAMIC_NATIVE result has zero known
time steps for a case, the check was skipped entirely and the
function still returned scalarResultIndex as valid, even though
m_cellScalarResults for it was never resized. Callers such as
RigSoilResultCalculator::calculate then indexed it out of bounds via
a CAF_ASSERT-only check (a no-op in Release builds), causing a
segfault.
* Fail gracefully when exportSnapshots command has no main window
* Guard against unopened plot panels in selection change handler
* Guard ecl_rsthead_alloc against missing INTEHEAD_KW
* Guard against detached flow diag solution in solverInterface
* Never rewrite all crash-triage reports when updating registry
The grid calculator releases result data per time step to reduce memory
usage when calculating for many cases. If only some time steps are
released, findOrLoadKnownScalarResult() returned early because data was
present for other time steps, leaving the released time steps empty.
Results computed by ResInsight, like riOILVOLUME, then appeared as
undefined in the 3d view after running a calculation for a selected
time step.
Recompute results computed by ResInsight when data is missing for any
time step. Skip the delegation from the single time step variant when
the requested time step already has data, to avoid repeated
recomputation while the calculator releases other time steps.
findOrLoadKnownScalarResultForTimeStep() tried to read ResInsight-
calculated results like riOILVOLUME from the restart file. For lazily
loaded grid case group members these results are never computed, so
every cell ended up undefined and the grid calculator produced zero
sums for all additional cases.
Delegate to findOrLoadKnownScalarResult(), which dispatches to the
result calculators, for results flagged as must-be-calculated and for
the ri* volume results. Already computed data is not computed again.
Sector model export removed all ACTNUM and FAULTS keywords from the deck
and re-inserted the sector-specific replacements at the end of the GRID
section, which always lands in the main DATA file. Decks that keep these
keywords in separate include files lost their file organization, leaving
the original include files empty while the data was written inline.
Collapse duplicates to a single occurrence instead of removing all
occurrences, so the subsequent in-place replacement keeps the keyword in
its original file when the deck is saved with OutputMode::COPY. ACTNUM
keeps the last occurrence since a later ACTNUM overrides an earlier one;
FAULTS keeps the first so fault definitions do not move past keywords
referencing them.
RigWellTargetMappingTools accessed cellScalarResults() and result vectors without verifying the requested time step or index was within bounds, and without checking for null case data pointers. Add the missing guards.
A grid cell has a single COMPDAT connection and must be connected to exactly one segment, but the geometry-based export emitted one COMPSEGS row per branch intersecting the cell. Restore the well-global bookkeeping the removed tree path had: tag each branch with its origin and let the branch carrying most flow claim a shared cell, perforations before fishbones before fractures.
A case in an ensemble can have fewer time steps than the case defining the time step axis of a statistics case. The time step index was used to index m_cellScalarResults directly, reading past the end of the vector in Release where CAF_ASSERT is a no-op.
The map size of the sample grid was recomputed from the expanded bounding box and the sample spacing stored in the project file. The expanded bounding box is an exact multiple of the sample spacing, but after the limited precision of the project file the division can land just above a whole number of cells, and the map size gets one extra cell. The cache files were then rejected, and the ensemble statistics recomputed.
Store the map size in the project file, and use it directly when the sample grid is restored from the cache.
Identify the input grids of the cache validity key by file path, size and modification time, so that the cache is also invalidated when a grid file is modified in place. Label and count the primary case and the ensemble cases, so that a primary case can not be mistaken for the first ensemble case.
A refinement level with a single reconstructed LGR keeps the bare level name (LGR_NHG_L2). A level with several LGRs now numbers all of them with 1-based suffixes (LGR_NHG_L4_1 .. LGR_NHG_L4_N) instead of leaving the first one without a suffix.
All unnamed critical regions map to the same implicit name, so a single process wide lock was shared by summary import, geometry generation, grid bounding box computation and NNC merging. Unrelated parallel loops therefore serialized against each other.
Give each region a critical_section_ name describing what it protects. The two regions guarding RifOpmCommonEclipseSummary::sm_createdEsmryFileCount deliberately share one name, as they protect the same counter.
totalNumberOfConnections was declared, listed in the reduction clause and used to size otherConnections, but it was never incremented. The counting was lost when the loop body was moved into extractConnectionsForFace, so the call has always been reserve( size() + 0 ), which RigConnectionContainer::reserve turns into a no-op.
The reserve was also called by every thread on the shared container without synchronization. Removing it eliminates that data race. The explicit barrier is redundant as well, since the omp for construct has no nowait clause and therefore already synchronizes before the merge.
Simulators for two-phase gas/water models may report only SWAT. In this case no SGAS result entry was created, so SGAS was missing from the result list and TERNARY fell back to computing SOIL = 1 - SWAT, presenting the gas saturation as oil saturation.
Add RigSgasResultCalculator that creates a placeholder SGAS entry when the model has gas and water but no oil phase, SWAT is present and SGAS is missing. SGAS is then computed as SGAS = 1 - SWAT. The computation is dispatched from findOrLoadKnownScalarResult() and findOrLoadKnownScalarResultForTimeStep() the same way as SOIL.
The equivalent logic in RigCaseCellResultsData::testAndComputeSgasForTimeStep() was only reachable from RigSoilResultCalculator, which never runs for models without an oil phase. This function is replaced by computeSgasForTimeStep() delegating to the new calculator, and the unreachable call in RigSoilResultCalculator is removed.
findOrLoadKnownScalarResultForTimeStep asserted when the reader failed to
load a result. A result listed in the meta data that cannot be read from
file is a run-time condition, not a programming error, and aborted the
application in builds with asserts enabled.
Report the failing result name and time step through RiaLogging instead.
Add BinningMode (Linear/Logarithmic) and OutOfRangeHandling (Exclude/Include in
Boundary Bins) to RigHistogramCalculator, with defaulted constructor arguments so
existing callers are unaffected. All four histogram plot data sources get shared
options for binning mode and an optional user-defined bin range through new PDM
fields on RimHistogramDataSource.
The grid statistics data source computes non-default histograms through a new
non-caching RigStatisticsDataCache::computeHistogram() pass-through, leaving the
cached statistics used by the 3D overlay and the P10/P90/mean annotation lines
untouched.
Selecting logarithmic binning enables logarithmic scale on the plot X axis once,
via a new signal handled by RimHistogramCurve.
Also fix the bin index computation to use uniform bins of width range/nBins,
consistent with calculatePercentil() and the bin edges drawn by the plots. The
previous divisor (nBins - 1) shifted counts by up to one bin width relative to
the drawn bars and slightly biased histogram-based percentile estimates.
A new contour map created from the right-click menu on a case used a hardcoded SOIL result, resulting in an empty view when SOIL was not present in the case. Use the cell result of an existing view for the same case if one is available, and otherwise fall back to RigCaseCellResultsData::defaultResult(), which verifies that the result exists before selecting it. Completion Type is a category result and is now excluded as a default result for both 3d views and contour maps.
RigAllGridCellsResultAccessor bounds checked the cell index with an assert that is compiled out in release builds, and then called std::vector::at(), which throws. RimGridCalculation::getActiveCellValues() calls the accessor from an OpenMP loop, using active cell indices from the destination case to read results from the source case, so an index beyond the source result vector threw an exception that could not escape the parallel region and called std::terminate. Return undefined for an out of range index instead, and guard against a null result accessor.
computeRiTransComponent() checks the transmissibility index and the neighbor
cell permeability index for cvf::UNDEFINED_SIZE_T, but not the permeability
index of the cell itself. The transmissibility and permeability results are
indexed independently, so a defined transmissibility index does not imply a
defined permeability index. For a case where transmissibility is stored per
cell and permeability per active cell, an inactive cell passes the
transmissibility check and then indexes the permeability vector with
UNDEFINED_SIZE_T.
Check the permeability index of the cell before use, matching the guard in
computeNncCombRiTrans().
Remove 95 cvf include lines that the including file does not use. Found by
extracting the symbols declared by every VizFwk header, including symbols they
re-export, and flagging includes where none of those symbols appear anywhere in
the file. Each removal is verified by a full build.
Most of them are cvfVector3.h and cvfObject.h, left behind as the files they
were once needed by changed.
pch.h is left untouched. It includes cvfObject.h and cvfVector3.h on purpose, so
that the files using the precompiled header do not have to.
Note that a clean build after removing an include does not prove the include was
unnecessary, only that the declarations still arrive some other way. That path
can differ between platforms and with RESINSIGHT_ENABLE_UNITY_BUILD, so this
needs a CI round on Linux as well.
Migrate all assert macros in ApplicationLibCode to CAF_ASSERT and remove every
use of cvfAssert.h.
CVF_ASSERT is replaced one to one. CVF_TIGHT_ASSERT is also replaced by
CAF_ASSERT, which is semantically exact: CVF_ENABLE_TIGHT_ASSERTS is 1 only
under _DEBUG, and that is what CAF_ASSERT now does. The two CVF_FAIL_MSG sites
become CAF_ASSERT( false && "message" ), preserving the message with the idiom
already used elsewhere in the code base.
Counts before and after: CVF_ASSERT 1044 to 0, CVF_TIGHT_ASSERT 66 to 0,
CVF_FAIL_MSG 2 to 0, cvfAssert.h references 154 to 0.
Include handling: files that included cvfAssert.h directly now include
cafAssert.h instead, includes left dead by the migration are removed, and files
that were relying on cvfAssert.h transitively get an explicit cafAssert.h. Files
that reach cafAssert.h through another caf header are left unchanged; a missing
include here is a compile error, not a silently disabled assert.
ResultStatisticsCache links only LibCore and therefore had no path to
cafAssert.h. Add the cafPdmCore directory as a private include path rather than
linking the library, since cafAssert.h is header only.
Note that this stops these asserts from firing in Release and RelWithDebInfo,
where CVF_ASSERT was previously active.
* Use guarded pointer for delayed plot updates
The cached result definition can be deleted before the delayed update is
executed, causing a crash in the PVT and relative permeability plot panels.
* Guard against fracture definition without conductivity result
The list of conductivity result names is empty for some fracture
definitions, causing an out of range access when computing statistics.
* Guard against missing data source in custom VFP plot
The data source of a VFP table can be null, and the VFP tables are not
available until the data has been imported.
* Recompute well cell arrays when the grids change
computeWellCellsPrGrid() returned early whenever the arrays had been computed once, so the
size check below it was unreachable and a stale array was kept when the grids changed. The
too-short array triggered an assert in RivReservoirViewPartMgr::computeNativeVisibility.
Return early only when the cached arrays still match the current set of grids.
* Guard against missing GUI application when applying style sheet
RiaGuiApplication::instance() does a dynamic_cast and returns null outside a GUI context. The
assert guarding this is compiled out in release, so the null pointer was dereferenced.
* Guard against missing case in flow characteristics plot field change
The case field can be set to nothing from the UI. RimEclipseResultCase::defaultFlowDiagSolution()
and reservoirViews() were then called on a null pointer.
* Guard against missing case and out of range time steps when updating flow characteristics plot
onLoadDataAndUpdate() dereferenced the case without checking, although the same function handles
a missing case further down. The time step indices come from the flow diagnostics solution, and
were used to index arrays sized by the number of case time steps without a range check.
The gap intersection inserted when the well path leaves the grid was pushed to
the result vector before the cell it follows, leaving the intersections
unsorted. This produced a non-increasing Length column in the exported WELSEGS
table.
RigWellPath::interpolatedVectorValuesAlongWellPath indexed vectorValuesAlongWellPath.at( vxIdx - 1 ) when no measured depths were present, causing an out of range exception and terminate. Return cvf::Vec3d::UNDEFINED for empty geometry, matching tangentAlongWellPath. RimWellPathFracture keeps the zero anchor position when the point is undefined.
RigCaseCellResultsData and RigFemPartResultsCollection held a raw pointer to RigFormationNames owned by a unique_ptr in RimFormationNames. Reloading or deleting the formation names left the case data with a dangling pointer. Store a copy instead, as RigFormationNames is a small value type with no identity.
The sign of the projected formation direction vector flips with the fracture
direction normal, which follows the well drilling direction, while the fracture
azimuth defining the dip rotation in RimFracture::transformMatrix() is only
defined mod 180 degrees. Canonicalize the formation direction against the
fracture azimuth direction before computing the dip, so a positive dip means
the formation descends toward the azimuth direction.
Restore std::abs() in calculateFormationDipFromHorizontal() so the StimPlan
model formation dip (BedDipDeg in the Asymmetric FRK export) keeps the
non-negative convention from #8877.
The depth-related geometry results (DEPTH/DX/DY/DZ/TOPS/BOTTOM) are derived
purely from the shared grid geometry and were computed independently for the
matrix and fracture porosity models. For dual-porosity cases this recomputed the
identical per-cell geometry twice.
Replace the per-model computeDepthRelatedResults() with a single static routine
that traverses the shared main grid once, computing each cell's geometry a single
time and writing it to every porosity model in which the cell is active. The
per-property already-computed guards and the temporary-grid recompute path are
preserved, so the stored values are unchanged. All six matrix+fracture call sites
now go through a thin RigEclipseCaseData::computeDepthRelatedResults() wrapper.
Reloading a grid file frees and recreates RigEclipseCaseData. The contour map projection caches raw pointers into the case data and previously only refreshed them when reset explicitly via RimReloadCaseTools::updateAll3dViews(). Callers of RimEclipseCase::reloadEclipseGridFile() that bypass updateAll3dViews(), such as RimOpmFlowJob::onCompleted(), left the projection holding dangling pointers that crashed in generateResults/hasResultEntry on the next redraw. The projection now detects that its cached RigEclipseCaseData no longer matches the current case and rebuilds itself before the stale pointers are dereferenced.