Selecting a contour map projection in the tree could crash when the
associated legend config was null. RimContourMapProjection::defineUiOrdering
called legendConfig()->uiOrdering() unguarded. Because PdmUiObjectHandle::uiOrdering
is non-virtual, the call entered with a null this and then crashed on the
virtual defineUiOrdering dispatch.
Guard the legendConfig() dereference, matching the existing null checks
elsewhere in the file. Apply the same guard to RimEclipseCellColors::defineUiOrdering.
The case-level Data Filters node (RimDataFilterCollection) was always shown under
RimEclipseCase, cluttering the tree when empty. Gate it in
RimEclipseCase::defineUiTreeOrdering on a new shouldBeVisibleInTree() check, and
refresh the owner case from onItemsChanged/onChildDeleted so the node appears and
disappears as the collection crosses the empty boundary.
Because a hidden node cannot be right-clicked to create the first filter, add a
RimEclipseCase::appendMenuItems override that exposes the filter-creation
commands as a Filters submenu on the case node. A shared
RicCellFilterFeatureTools::selectedDataFilterCollection() resolves a selected
RimEclipseCase to its data filter collection, so the cell, property and combined
filter create features target the case-level collection.
The view filter nodes were unified under a read-only RimFilterInViewCollection
facade, and the source collections are now tree-hidden. As a result, the
existing collection->updateConnectedEditors() calls no longer refresh the tree:
the filters are shown under the facade, which only refreshes when a source emits
filtersChanged/wrappersChanged.
Several property-filter mutations changed the child array without emitting that
signal (insertAt/push_back/erase do not auto-fire onChildAdded/onChildDeleted),
so newly created or removed filters did not appear under the Filters node:
property filter insert, new combined filter, add linked filter, undo of a
property-filter creation, and Show Contributing Wells.
Emit the change signal from these paths (via the existing onChildAdded hook, or
filtersChanged on removal) so the single facade handler refreshes the tree. The
cell-filter, paste, property-add and data-filter paths already emit the signal
and are unchanged.
Gate the OSDU well log import menu item and the command undo/redo history view
behind the discoverable experimental features registry instead of
RiaApplication::enableDevelopmentFeatures(), so they can be toggled from
Preferences -> System without setting the RESINSIGHT_DEVEL environment variable.
Register the 'osdu-well-logs' and 'undo-redo-view' features in
RiaExperimentalFeatures and gate the code paths via
RiaPreferencesSystem::isFeatureEnabled().
Add an align_columns option to schedule generation. When enabled, each
keyword is serialized with a '--'-prefixed column-header comment and data
rows right-aligned into fixed-width columns, instead of the compact default
form. The default output is unchanged.
A new RimKeywordFactory::deckKeywordToAlignedString introspects the OPM deck
model and renders each item in its own column (consecutive defaults are not
collapsed into 'N*'). The flag is threaded through RicScheduleDataGenerator
and exposed on the GenerateSchedule scriptable method as align_columns in the
Python generate_schedule_text wrapper.
Reparent RimFaultDistanceResultCollection so it is owned directly by
RimEclipseView instead of RimFaultInViewCollection, and show it as a
top-level node next to the Faults node in the project tree.
RimFaultDistanceResult::calculateValueOptions now reaches the fault list
through the view (the fault collection is a sibling rather than an
ancestor after the move). RicNewFaultDistanceResultFeature resolves the
view from the selection and takes both the distance collection and the
all-faults fallback from it.
The scriptable API moves with the collection: add_fault_distance_result
is now exposed on RimEclipseView (view.add_fault_distance_result(...))
via the new RimcEclipseView, replacing RimcFaultInViewCollection.
Expose the new RimFaultDistanceResult facility to Python by marking the
relevant PDM classes and fields scriptable. RimEclipseView's
m_faultCollection, RimFaultInViewCollection, RimFaultInView,
RimFaultDistanceResult, and RimFaultDistanceResultCollection are now
scriptable, so faults can be enumerated from Python via
view.fault_collection().faults().
A new Rimc method add_fault_distance_result on RimFaultInViewCollection
takes a name and a list of fault objects, creates the result
(auto-numbered FAULTDIST<n> when the name is empty), and returns the
new RimFaultDistanceResult. An empty fault list falls back to every
fault in the view, matching the static-native FAULTDIST behaviour.
Add a Python test exercising both a subset call and a parity check
that asserts the all-faults result matches the existing static-native
FAULTDIST cell-for-cell.
The existing FAULTDIST result always considered every fault in the main
grid. Users with many faults need to compute distance fields against a
named subset, so this adds a Fault Distance Results collection under
each view's Faults node. Each entry holds a multiselect of faults and a
name (FAULTDIST1, FAULTDIST2, ...) and publishes the result into the
Generated cell-result category.
The per-cell BVH-based distance loop was extracted from
RigFaultDistanceResultCalculator into a reusable utility that accepts
the subset of faults to include; the original all-faults entry point
delegates to the same utility and keeps the static-native FAULTDIST
behavior unchanged.
On project reload the simulation well disks were not drawn until the user
toggled the Simulation Wells visibility. Two load-ordering issues caused this:
scaleWellDisks() ran before synchronizeWellsWithResults() had populated the
wells list, so it iterated an empty collection. It also bailed out early on the
transient m_showWellDisks aggregate (disableIO), which is only synced from the
restored per-well states when the property panel is built.
Move scaleWellDisks() after synchronizeWellsWithResults(), and sync the
visibility checkbox state at the start of scaleWellDisks() so the disks are
scaled and marked valid before the first display-model build.
Normalize disk radius over all wells instead of only the currently
visible ones. Computing the min/max range over visible wells only made
one well's disk radius depend on whether unrelated wells were filtered
out, so toggling a range filter on one well changed another well's disk.
Fixes#14083.
Add a completion_number parameter to the add_perf_event Python API
(AddPerfEvent scriptable method) and a matching field on
RimWellEventPerf. When a timeline perforation event is materialised into
a RimPerforationInterval, a non-zero completion number is copied across,
so it flows through the existing completion-data path onto
RigCompletionData.
The schedule generator now emits COMPLUMP alongside COMPDAT: COMPDAT
generation is folded into generateCompletionsForWell, which computes the
completion data once and builds both keywords from it via the existing
RimKeywordFactory::complumpKeyword (added in #13273). COMPLUMP only
produces records for perforations that have a completion number and is
merged across wells like COMPDAT.
* Agent docs: Recommend cmake --build over ninja when sharing build/ with Visual Studio
* Disable Create Well Target Mapping for grid ensembles with individual grids
* Move RimSummaryCaseMainCollection context menu items into appendMenuItems override
* Reorganize import menus: split per-window, group submenus, rename actions, add Import/Export icons
* Show icons on "New Statistics Case" and "New Grid Case Group" menu actions
* Rename grid/summary import submenus to "More" and use the import icon
The schedule generator previously concatenated full keyword blocks
(`KEYWORD ... /\n/\n`) — one per well — producing verbose output where
each WELSPECS / COMPDAT / WCONHIST / WELSEGS / COMPSEGS / etc. block
appeared once per contributing well. Eclipse keywords are designed to
hold multiple records under a single header; the per-well repetition is
syntactically valid but bloats the file and obscures intent.
Switch `RicScheduleDataGenerator` to accumulate
`std::map<QString, Opm::DeckKeyword>` instead of raw concatenated text.
Each per-well helper now returns an `Opm::DeckKeyword`, and a new
`mergeKeyword` primitive appends its records into the accumulator entry,
creating the entry from the helper's keyword on first encounter. At
emission time each accumulated keyword is serialised once.
To support this, `RifEventKeywordFormatter` is split: each `format*`
QString function now wraps a corresponding `build*` function that
returns `std::optional<Opm::DeckKeyword>`. `RimWellEventKeyword` and
`RimKeywordEvent` expose a parallel `generateDeckKeyword` accessor.
The text-scraping `extractKeywordName` helper becomes dead code and is
removed.
Schedule-level keywords whose OPM ParserRecord is a single ALL-sized item
(RPTRST, RPTSCHED, ...) are not positional — they take a free-form list
of mnemonic tokens like `BASIC=2 DEN ROCKC NORST=1`. Previously each
`keyword_data` entry became its own DeckItem, and OPM emitted them
either as truncated positional values or as a quoted, space-collapsed
single string.
Detect that schema shape in `RifEventKeywordFormatter::formatKeyword`
and pack the user's entries into one RawString DeckItem of mnemonic
tokens: `KEY` for FLAG items, `KEY=VALUE` otherwise.
To distinguish flag mnemonics (`DEN`) from `KEY=1`-style entries, add a
new `FLAG` value to `RimWellEventKeywordItem::ItemType` plumbed end to
end (Python -> GRPC -> Rimc -> storage -> formatter). The Python API
now maps `bool True` to FLAG and silently drops `bool False`.
For positional keywords (WCONHIST etc.) FLAG items have no value to
emit and are rendered as default markers ("1*").
A `rawStringItem` helper is added to `RifOpmDeckTools` so the
mnemonic-list path can produce DeckItems whose OPM output is not
quoted.
Adds a collection-level checkbox in the simulation well "Visibility"
group that hides wells which are not open at the current time step.
Mirrors the existing "Wells Through Visible Cells Only" sibling toggle
in placement, default (off), and contour-map gating.
The frame-aware predicates isWellPipeVisible, isWellSpheresVisible,
isWellValvesVisible and isWellDiskVisible now short-circuit to false
when the toggle is on and RigSimWellData::isOpen(frameIndex) is false,
placed before the active-intersection bypass so the user's filter is
not overridden.
Fixes#13913
Production disks were drawn for wells that the visible-cells filter
hides, because RimSimWellInView::isWellDiskVisible() never consulted
the showWellsIntersectingVisibleCells toggle.
Add a frameIndex parameter and the same active-intersection / visible-
cells filter logic that isWellPipeVisible already uses, and update the
two call sites to pass the current frame.
* CMake: Remove dead CODE_HEADER_FILES variable
* CMake: Remove dead COMMAND_CODE_HEADER_FILES and COMMAND_MOC_SOURCE_FILES
* CMake: Remove dead MOC_SOURCE_FILES and FORM_FILES_CPP references
* CMake: Remove dead HEADER_FILES reference
* CMake: Delete unused CustomPCH.cmake superseded by target_precompile_headers
Changing the time step filter combo box crashed when the plot had no
available time steps: filteredTimeStepIndices returned an empty vector
and .back() invoked undefined behaviour. Skip the m_timeStep assignment
when either allDateTimes or filteredTimeStepIndices is empty.
Fixes#14006.
The case-level RimDataFilterCollection lacked an equivalent of
RimEclipsePropertyFilterCollection::loadAndInitializePropertyFilters, so a
saved FORMATION_NAMES selection had its value preserved on reload but no
category options list to render against. The selection only appeared after
the user toggled the filter, which routes through fieldChangedByUi and
rebuilds the category cache. Add loadAndInitializeFilters and invoke it
from RimEclipseView::onLoadDataAndUpdate, once openReservoirCase has loaded
the grid and active formation names.
* Completions: Apply perforation cell filter to COMPDAT and MSW export
* PerforationInterval: Limit Cell Filter dropdown to case-level filters
* PerforationInterval: Prefix Cell Filter entries with case name when multiple cases
* Completions: Use std::format for cell filter suppression log messages
Adds a new HUD label in the upper-left of the 3D view that reads
"Filter : <name(s)>" whenever a cell, property, or per-view data
filter is active. The label is hidden when nothing is enabled.
Names are joined per the source collection's AND/OR combine mode, and
contributions from different collections are concatenated with ", ".
On Eclipse views the unified RimFilterInViewCollection is used as the
single anchor; GeoMech views aggregate cell and GeoMech property
filters directly.
When the user toggles "Show Curve" off, updateCurvePresentation runs
updateCurveVisibility, which detaches and deletes m_plotCurve, before
calling updateCurveAppearance. The override in RimWellFlowRateCurve
dereferenced m_plotCurve unconditionally and crashed. Match the null
guard already present in RimPlotCurve::updateCurveAppearance.
Fixes#14011.
Three fixes from PR review on the data-filters refactor.
RimDataFilterInViewCollection::syncWithSource: avoid double-free on
project load when m_sourceCollection has not yet resolved. The first
pass deletes orphan wrappers but leaves them in the local snapshot;
the null-source branch then deleted them again. Replace the second
deletion with deleteChildren() on the wrapper field.
RimDataFilterInViewCollection::setSourceCollection: disconnect from
the previous source's filtersChanged signal before reassigning, so
edits to a previously-bound case no longer trigger spurious geometry
regen on this view.
RimEclipsePropertyFilter::fieldChangedByUi: always emit
triggerFilterChanged() after updating bounds and related fields.
Otherwise, when the property filter lives inside a combined filter
under a per-view RimEclipsePropertyFilterCollection, the combined
parent's auto-derived display name was never recomputed.
Lets a script attach a cell filter to a RimPerforationInterval as a
typed reference so subsequent work can gate completion-export
connections by the filter's cell mask. Pure metadata in this commit:
no consumer of RimPerforationInterval is modified, the field exists
purely as an API surface.
Add a non-scriptable caf::PdmPtrField<RimCellFilter*> m_cellFilter to
RimPerforationInterval with public cellFilter()/setCellFilter()
accessors and a "Cell Filter" group in the property panel between the
existing geometry/flow group and the Date Settings group. The field is
deliberately non-scriptable: a scriptable PdmPtrField round-trips in
Python as an opaque "ClassName:0xADDR" string rather than a resolved
object, defeating the point. Two CAF object methods on
RimcPerforationInterval expose the relationship:
- AddFilter (perf.add_filter(filter)) sets the pointer; replaces any
existing filter (single filter per perforation).
- cell_filter (perf.cell_filter()) resolves to the referenced
RimCellFilter object on read, mirroring the valve.template() pattern.
Composition stays in RimCombinedFilter: a script that wants AND/OR
across multiple filters attaches a combined filter as the single
filter on the perforation.
The Python example in PythonExamples builds a case-level AND combined
filter (PERMX 100..20000 AND K=5..10), creates a modeled well path
with two perforation intervals, and shares the same filter between
them. test_perforation_filter.py covers single-set, replace-on-second-
add, and shared-pointer round-trips.
Combined filters used to always show whatever literal string the user
passed in (or the default "Combined Filter"). For programmatic creation
without a name, that string never reflected the children, leaving the
case-level "Data Filters" tree row stale when child bounds changed.
Add an m_autoDeriveName flag (default true) to RimCombinedFilter. When
on, the display name is recomputed on every relevant change — addFilter,
removeFilter, onChildAdded, onChildFilterChanged, and combineMode
toggle — by joining children's name() with " AND " / " OR ". The flag
flips to false the first time the user renames the filter via the UI
property panel or via Python (combined.user_description = "..."),
preserving any explicitly typed name verbatim from then on.
Two child-creation paths needed an extra triggerFilterChanged() so the
combined parent recomputes after the child's final name is set:
addPropertyFilterToCombinedFilter (setDefaults updates name without a
signal) and RimcCombinedFilter_addRangeFilter (Rimc applies user
params after addNewFilter).
The Rimc factory passes setAutoDeriveName(false) only when a name is
supplied. The Python example demonstrates both modes side by side, and
test_combined_filter.py adds three cases: named filter preserves its
name, auto-derived filter tracks bound mutations, and Python rename
locks the auto-derived filter.
RimDataFilterInView previously copied the source filter's name once, in
setSourceFilter() and initAfterRead() via syncNameFromSource(). That
left the wrapper showing the default "Combined Filter" when the source
was renamed after the wrapper was created — typical for the Python
add_combined_filter(name=...) flow, where the wrapper is constructed
during addFilter() before the user-supplied name reaches the source.
Replace the wrapper's reliance on its inherited m_name field for
display with a caf::PdmProxyValueField<QString> that delegates the
read to m_sourceFilter()->name() and the write to setName(). Override
userDescriptionField() so the PDM tree label and property panel route
through the proxy — both directions of rename now propagate.
Matches the m_nameProxy pattern already established in RimCellFilter.
The inherited m_name is no longer the display source of truth but is
left in place so RimNamedObject's serialization stays unchanged.
Expose the case-level RimDataFilterCollection (introduced for
case-shared cell filters) to Python so scripts can build combined
filters with property-filter and IJK-range children without going
through a view.
Scriptable surface:
- RimEclipseCase.m_dataFilterCollection -> case.data_filter_collection()
- RimDataFilterCollection (object + Filters child array) -> filters()
- RimEclipsePropertyFilter (object + m_lowerBound + m_upperBound) ->
pf.lower_bound, pf.upper_bound
- RimCellRangeFilter (object + start_index_{i,j,k}, cell_count_{i,j,k})
New CAF object methods under ProjectDataModelCommands/:
- RimcDataFilterCollection: add_combined_filter(name, combine_mode)
- RimcCombinedFilter: add_property_filter(result_variable, result_type)
and add_range_filter(name, start_{i,j,k}, cell_count_{i,j,k}).
Bounds are not part of add_property_filter because the Python class
generator emits a bare nan literal as the default for double fields
initialised to quiet_NaN, which fails to import. Bounds are set via
the now-scriptable lower_bound/upper_bound fields after creation,
matching the update() pattern used elsewhere in the API.
RicEclipsePropertyFilterFeatureImpl::addPropertyFilterToCombinedFilter
now returns the new RimEclipsePropertyFilter* so the CAF method can
hand it back to Python. setDefaults is relaxed to be view-tolerant:
case-level filters have no Rim3dView ancestor and the eclipse case is
already wired by RimEclipsePropertyFilter::setCase via the owning
collection's onItemsChanged hook.
End-to-end coverage in tests/test_combined_filter.py: round-trip
create, mode toggle, property-filter add/mutate, range-filter
add/mutate. Example script in PythonExamples builds an AND combined
filter that gates PERMX between 100 and 20000 against a K=5..10
slice.
Introduce RimDataFilterCollection on RimEclipseCase to hold filter
configuration that is shared across all views of the case. Each
RimEclipseView gets a RimDataFilterInViewCollection of
RimDataFilterInView wrappers that auto-sync with the case-level list
and expose an independent on/off toggle per view. The wrapper's
applyToCellVisibility delegates to the wrapped RimCellFilter via the
existing unified virtual, so property, range, and combined filters all
work uniformly.
RimDataFilterCollection is built on caf::PdmObjectCollection<RimCellFilter>
and emits a filtersChanged signal on add/remove/reorder/child changes.
The wrapper collection mirrors RimSurfaceInViewCollection's sync pattern:
new wrappers default to checked, removed sources drop their wrappers,
and the wrapper list follows the case order. Per-view wrappers feed into
RivReservoirViewPartMgr::computePropertyVisibility after the existing
view-level property-filter loop.
The RicNew*Feature commands now route into a selected RimDataFilterCollection,
and the existing combined-filter path is generalized to allow combined
filters living under either a per-view RimEclipsePropertyFilterCollection
or the new case-level collection. Several Asserted ancestor lookups in
RimEclipsePropertyFilter, RimCellFilter and RimEclipseResultDefinition
that assumed a Rim3dView ancestor were relaxed to the non-asserting
variant with graceful fallbacks, so case-level filters can be created
and edited without a host view.
Backwards compatible: empty Data Filter collection is a no-op,
existing per-view RimEclipsePropertyFilterCollection and
RimCellFilterCollection paths are unchanged. GeoMech parity deferred.
Replace the dynamic_cast dispatch in RimPolygonCollection::loadData() with a
virtual loadData() on RimPolygonContainer. The base recurses through
subCollections; RimPolygonFile overrides to load file data. The folder
RimPolygonCollection no longer needs its own loadData().
Move RimPolygonFile::canAddSubCollection() and RimPolygonInView::sourceItem()
implementations from headers to .cpp.
Simplify std::unexpected calls in RimcNestedCollectionBase by removing
redundant explicit QString construction.
Port RimSurfaceCollection, RimPolygonCollection and the polygon-in-view
side onto the new caf::PdmNestedCollection framework, replacing the
per-class folder plumbing (m_subCollections field, topmost-folder flag,
add/remove/find sub-collection, factory, "new folder" command) with the
shared base.
- RimSurfaceCollection and RimPolygonCollection now derive from
caf::PdmNestedCollection. Each constructor uses the generic folder
icon and exposes a static createTopmost() that marks the top instance
and applies the branded domain icon; RimOilField calls the factory.
- RimPolygonInViewCollection uses the new RimNestedMirrorCollectionInView
helper, and a new RimPolygonContainer carries the source-side polygon
link.
- RicNewSurfaceCollectionFeature is removed; the generic
RicNewNestedCollectionFeature drives the "Add Folder" action against
both collections.
- Update callers (RimAnnotationCollection, RimEnsembleSurface, polygon
command features) and the scripting wrapper (RimcSurfaceCollection),
plus the Python add-folder binding and polygon test.
Introduce a shared base for tree-shaped folder containers that hold a
list of leaf items together with a list of subcontainers of the same
kind. Replaces the per-class plumbing (subcollections field, top-folder
flag, add/remove/find sub-collection, factory) that is duplicated across
RimSurfaceCollection, RimPolygonCollection and similar candidates.
- caf::PdmNestedCollectionBase: non-templated PdmObject base exposing
collection-name, add-new-subcollection, leaf-check and topmost-folder
marking for generic command features and script methods.
- caf::PdmNestedCollection<SelfT, ItemT>: CRTP template that owns the
typed m_subCollections field and inherits the m_items array from
PdmObjectCollection<ItemT>. Provides allItems(), find-sub-collection,
and a typed factory hook.
- RimNestedMirrorCollectionInView: view-side analogue for in-view
collections that mirror a nested source collection, with orphan-sweep
+ find-or-create + reorder sync.
Design rationale (templated vs non-templated, break-even on derived
class count) lives in docs/pdm-nested-collection-design.md.
No callers migrated in this commit.
Move the element-type include from each migrated collection header into
its .cpp, leaving only a forward declaration in the header. Follows the
pattern from 9e4d79159 for RimJobCollection, made possible by the
constructor-time PdmObject base check.
Migrated to the templated base, preserving each collection's existing XML
field keyword for project-file backward compatibility:
- RimEnsembleFractureStatisticsCollection
- RimEclipseInputPropertyCollection
- RimPlotDataFilterCollection
- RimGeoMechContourMapViewCollection
- RimIntersectionResultsDefinitionCollection
- RimCustomObjectiveFunctionCollection
- RimStimPlanModelTemplateCollection
- RimEnsembleWellLogsCollection
- RimEclipseContourMapViewCollection
- RimSeismicViewCollection
- RimGridInfoCollection
- RimEclipseStatisticsCaseCollection
- RimWellIASettingsCollection
- RimVfpDataCollection
External callers that accessed the old public/named array fields directly
(RimEclipseInputPropertyCollection::inputProperties,
RimEclipseStatisticsCaseCollection::cases) now use addItem/items() from
the base. RimCustomObjectiveFunction.h replaced its include of the
collection header with a forward declaration to break the new include
cycle introduced by the migration.
RimEnsembleFileSetCollection, RimJobCollection, RimQuickAccessCollection,
RimRefinementRegionCollection and RimFractureTemplateCollection now inherit
from the templated caf::PdmObjectCollection<T> base, reusing the shared
add/insert/delete/items plumbing introduced for RimValveTemplateCollection.
XML field keywords are preserved on every collection so existing project
files continue to load.
Bind a PdmProxyValueField that inverts the Z sign to the Points group in
RimPolygon's property panel, mirroring the pattern already used by
RimExtrudedCurveIntersection. The raw m_pointsInDomainCoords field keeps
its XYZ semantics, scriptable keyword, and serialization unchanged.
Fixes#12106.
Replace inline bar-to-Pascal magic constants with RiaEclipseUnitTools::barToPascal
for initial stress and pore pressure parameters passed to the Well Impact Analysis
exporter. Behavior is unchanged; both sites previously multiplied by 100000.0.
Fixes#5840.
When a project file persisted FlipXAxis or FlipYAxis as true, the flag was
restored to the PdmField but never propagated to the grid nodes during
RimEclipseResultCase::importGridAndResultMetaData. Only the UI change handler
applied the flip, so on reload the grid stayed un-flipped while the checkbox
appeared active.
Mirror the call already present in RimEclipseInputCase and RimRoffCase by
invoking setFlipAxis before computeCachedData.
Expose XYZ extent and XY UTM offset as user-editable fields in the
Customize Mock Model dialog instead of hard-coding them in
RimEclipseResultCase. Defaults match the previous hard-coded values
(6000/12000/500 extent, 400000/6000000 offset).
Switch the message parameter from const QString& to std::string_view so
callers with std::string in hand no longer need a QString::fromStdString
wrapper. The internal duration formatting still uses QString::arg, fed
from a single QString::fromUtf8 conversion.
Callers passing QString locals are updated with .toStdString() at the
call site.