Use the ensemble data filter collection as the source for views owned by a reservoir grid ensemble. Apply the source for newly inserted views, case changes, and project-load initialization while preserving case-level sources for ordinary case views.
Add a regression test verifying that an ensemble view switches from its case collection to the ensemble collection.
Rebind the ensemble data filter collection after file-set cases are recreated. This ensures the collection uses the new main case and clears its source when no replacement cases are found.
The data filter collection node is hidden in the project tree while the
collection is empty, and the owner must be refreshed to re-run its tree
ordering when the first filter appears. The refresh targeted the source
case, which for a grid ensemble collection is the main case of the
ensemble, not the ensemble owning the tree node. Newly created ensemble
data filters were therefore not visible in the tree.
Refresh the PDM parent object instead, which is the case or the grid
ensemble. Also refresh from the programmatic removeFilter path.
Add a data filter collection to RimReservoirGridEnsemble, so filters can be defined once for the ensemble. The filters are bound to the main case of the ensemble for configuration.
Expose filter creation commands from a Data Filters submenu on the ensemble node, and hide the collection node while empty, matching the case-level behavior. Grid calculation integration is intentionally left for the dependent calculation-filtering change.
RicNewPolygonFilterFeature already supports adding polygon filters to
the case-level data filter collection, but the collection menu did not
offer it. Add the polygon filter entries to the menu, matching the cell
filter collection menu in a view. The polygon filter computes its cells
lazily from the collection's source case, so no view is required.
Guard against calling points.back() on an empty vector when all well
path points are filtered out (e.g. due to the zmin check), which
previously caused undefined behavior/crash.
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
Constructing an Opm::Parser populates the complete keyword database (2774
keywords, measured at 2.4 ms per construction) and this was done once per
keyword event in RifEventKeywordFormatter::buildKeyword, and twice more per
keyword in the column-aligned serialisation in RimKeywordFactory. Schedule
generation was therefore completely dominated by parser construction and grew
directly with the number of events on the timeline. Use a single shared parser
instance instead, since the parser is stateless once constructed.
Also compute the events for a date once in generateDateSection and pass them to
the per-well helpers, instead of calling RimWellEventTimeline::getEventsAtDate
four times per well and date, which scaled as dates x wells x events.
Generating a schedule for a production data set with 1737 events over 490 dates
goes from 4.2 s to 0.1 s, and 21000 events over 14 wells now complete in 0.5 s.
RimMultiPlot::recreatePlotWidgets() dereferenced the viewer unconditionally. The viewer does not exist in console mode, so deleting a summary plot from Python through the generic PdmObject delete() crashed ResInsight in onChildDeleted(). Return early when there is no viewer, matching the other viewer accesses in RimMultiPlot.
Add Python regression tests for deleting a single summary plot inside a multi plot and for deleting a whole multi plot, and an example showing how project tree objects are removed with delete().
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.
Three related fixes found while reviewing the feature:
- Clicking the contour map surface inside a regular 3d view selected the internal RimContourMapProjection in the project tree instead of the RimContourMapInView object. Resolve the actual view from the pick event rather than climbing the projection's own ancestor chain, which pointed to a hidden internal contour map view, and select the owning RimContourMapInView when found.
- RimContourMapInView::name() returned only the raw custom name of the underlying contour map view. RimStatisticsContourMapView leaves its custom name empty and builds the displayed name entirely from generated tags, so the name shown for a statistics contour map in a 3d view was empty. Use the view's auto-generated name instead.
- RimContourMapInView is a presentation wrapper around a hidden RimEclipseContourMapView (or RimStatisticsContourMapView) that owns the actual contour map data. Add a Go to Contour Map button, following the existing pattern used by RimPolygonInView and RimDataFilterInView, so the underlying source object can be quickly selected in the project tree.
Give RimGridView a RimContourMapInViewCollection and let RimEclipseView and RimGeoMechView build their 3d model from it. A dedicated contour map view (RimEclipseContourMapView/RimStatisticsContourMapView) shows its own contour map and returns no collection of its own, so it is unaffected. Adjust RimSurfaceInViewCollection so surfaces and contour maps coexist in the same 3d view without z-fighting.
Add the data model for showing contour maps inside a regular 3d view. RimContourMapInView is a presentation wrapper that decides where a contour map is placed vertically in the 3d scene and what parts of it are drawn; the contour map itself, including the result, the aggregation and the computed geometry, remains owned by the contour map view it points at. RimContourMapInViewCollection owns the set of contour maps available in a 3d view. Add a CONTOUR_MAP entry to RiaDefines::ItemIn3dView so the project tree can be refreshed for just the contour map items.
Add RivContourMapElevationProvider and extend RivContourMapProjectionPartMgr so the contour map surface and contour lines can be projected onto the terrain/grid geometry of the 3d view instead of only being drawn as a flat map.
RicNewSummaryEnsembleCurveSetFeature::createPlotForCurveSetsAndUpdate() always
called RiaGuiApplication::instance(), which is null when running as a console
application. Calling new_summary_plot() with an ensemble and no address string
from Python did therefore terminate ResInsight. Only access the plot main
window when the GUI is running.
new_summary_plot() with an ensemble and an address string created an empty
plot. The address filters were applied to an empty list of summary cases, and
no curve sets were created. Use the summary cases of the ensemble, and make
sure the summary addresses are created before the address filters are applied.
Add example script showing how to create summary plots for an ensemble.
* Add performance unit test for RimEnsembleCurveFilter::applyFilter
* Fix O(N^2) scaling in RimEnsembleCurveFilter::applyFilter
RimEnsembleCurveSet::objectiveFunctionTimeConfig() was called once per
summary case inside the applyFilter() loop, for both the OBJECTIVE_FUNCTION
and SUMMARY_VALUE filter modes. Internally it calls allAvailableTimeSteps(),
which scans the full time series of every case in the ensemble, so
recomputing it per case turned applyFilter() into an O(caseCount^2) operation.
* Avoid redundant allAvailableTimeSteps() calls in fullTimeStepRange()
fullTimeStepRange() called allAvailableTimeSteps() three times (once for the
empty check, once for min, once for max), each re-scanning the full time
series of every case in the ensemble. Compute it once and reuse the result.
Also simplify allAvailableTimeSteps() to insert time steps directly into the
result set instead of collecting them into an intermediate vector first.
COMMENT is accepted on all keywords and is stored on the event instead of
being passed as keyword data, so it is not part of the item names reported
by opm-common. The validation error listed only the opm-common items, giving
no hint that COMMENT is allowed when a user mistyped it as COMMENTS.
Append COMMENT to the list of valid item names in the error message. Only the
diagnostic is affected, COMMENT is still handled as event metadata.
Include files containing only INCLUDE statements, such as a wrapper
collecting many lift curve (.ecl/.vfp) files, were dropped during
sector model export, and the includes for all leaf files were written
directly into the exported .DATA file.
Update the custom-opm-common submodule so FileDeck recreates
include-only files in the output directory and preserves the include
hierarchy at any nesting depth. Add a regression test exporting a deck
with a nested include-only wrapper and reloading the result.
Table keywords such as PVTO and SGOF were rewritten by opm-common as one
unbounded line when saving the deck, exceeding the 132 character line
limit of Eclipse 100 and making exported sector models unusable there.
Update the custom-opm-common submodule so DeckOutput tracks the current
line width and wraps records at item boundaries before a line exceeds
132 characters. Quoted values are never split. Add a regression test
that round-trips a deck with a long rel. perm. table and a record of
quoted mnemonics.
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.
std::clamp() invokes undefined behavior when the low bound is greater
than the high bound. In resetMinimumCellValuesToDefault(), the
minimum/maximum bounds for saturation, pressure, permeability and
transmissibility are derived from case data and can end up inverted
when no data is available, which crashed or produced garbage values.
The branch number of a fracture followed the order the fractures were created, so appending a second set of fractures to a well put them after the existing ones regardless of where along the well they sit. Sort by the fracture start MD instead. The order also decides which fracture connects a grid cell shared by two of them.
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.
Selecting a curve or a plot inside a RimHistogramMultiPlot in the project
tree now scrolls the multi plot view to make the containing histogram plot
visible, mirroring the existing behavior for RimSummaryMultiPlot.
When creating a histogram from grid cell results (e.g. PERMX) via
"Create Grid Statistics Plot", zoom the histogram plot to fit the data
right after the curve is populated, instead of leaving it at default axis
ranges.
Reverts the unconditional change from commit 74ffc822f2 and replaces it with
a safer fix: only skip re-initializing the well path name from the source
file on reload when a name has already been set. Older projects that never
serialized the well path Name field (e.g. TestCase_RFT_PLT/RegressionTest.rsp)
still get their name populated from the file on load, while renamed well
paths in newer projects keep their custom name across reloads.
Restores the RMS well round-trip test that verifies a renamed well path
name persists after save/reopen.
Add RicImportOrionEventsFeature to File -> Import -> Well Data and the well
path collection context menu. The feature opens a file dialog and launches
the Python interpreter asynchronously with the new --apply mode of the
rips.orion_events CLI, which connects back to the running instance through
RESINSIGHT_GRPC_PORT and applies the events to the well event timeline.
Output is shown in the Process Monitor panel.
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.
Summary cases are created and given a case id before they are added to the
project. The id search only sees cases already in the project, so every case
in a batch import was given the same id.
The Data Sources tree stores the owning case id in each summary address, and
all lookups resolve to the first case with that id. Selecting the same vector
from several cases therefore produced a single curve, and dropping a vector
from one of the other cases hit the duplicate check and did nothing.
The single-pass sum-of-squares formula subtracts two large and nearly equal numbers. Where a result such as PORO is identical or near-identical across the realizations, the true variance is below the rounding noise floor, the radicand turns negative and sqrt() returns NaN.
Compute the deviation in two passes instead, centering on the exact mean. This also removes the loss of significance the old formula had for values with a large common offset.
Min, max, range, mean and deviation all report HUGE_VAL when the input holds no valid values, but the sum reported the zero it was accumulated from. A caller testing the result with isValidNumber would accept that zero as real data.