RigCombMultResultAccessor::cellFaceScalar called oppositeFace() with the
face passed from the picked selection. A plain cell pick leaves the face
as NO_FACE, which has no opposite and tripped CVF_ASSERT(false) in
oppositeFace, crashing the application.
Guard against a non-directional face and return 1.0, consistent with the
no-change-in-MULT-factor convention already used in nativeMultScalar.
A file-based well path whose source file is missing has a null wellPathGeometry(). Add null checks at the remaining call sites that dereferenced it without one, so operations on such a well path no longer crash:
- RimWellPathGroup: skip geometry merging for a child with no geometry (grouping runs on import and project load).
- RimWellPathFracture::computeFractureDirectionNormal: return undefined when geometry is missing.
- RivWellPathPartMgr: extend the existing well path null checks to also require geometry in the attribute, well measurement, and valve append paths.
- RimCompletionCellIntersectionCalc, RicExportLgrFeature, RicCreateMultipleWellPathLaterals, RigLasFileExporter, RiuWellPathComponentPlotItem: guard the geometry before use.
Sites that were already guarded or only reachable through guarded paths were left unchanged.
When a project references an RMS well path file that no longer exists, the well path geometry is null. The MSW completion export validated the eclipse case, well path, and MSW parameters but not the geometry, so generateCellSegments asserted and crashed when triggering Export Completion Data for Visible Well Paths.
Guard the single MSW export dispatcher extractSingleWellMswData with a well path geometry null check that returns an error, protecting all export callers. Harden generateCellSegments to return empty instead of asserting on null geometry.
Also log a warning on the interactive well path import path when a file cannot be read, matching the existing project-load behavior.
Fixes#14121.
Install a Qt message handler at startup that filters out the cosmetic Qt6
warning "QColorSpace attempted constructed from invalid primaries" seen on
some Linux platforms (e.g. RHEL8). The warning originates in Qt6 when it
validates an empty, all-zero QColorSpacePrimaries and has no functional
impact. All other messages are forwarded to the previous handler unchanged.
The tree selection editor can grow to a large height, which is useful when it is the last field editor in the property dialog. When other field editors are located below, the heightHint is now used as the maximum height instead. The form layout tracks whether an editor occupies the bottom-most row of the form and passes this to the editor. In the Analysis Plot, the time step selection is constrained to its height hint because other input fields are located below it.
The Event Timeline stores event timestamps with full time-of-day precision, but the exported SCHEDULE deck only emitted DAY/MONTH/YEAR in the DATES keyword, dropping any sub-day precision the user had set.
Emit the optional TIME field (HH:MM:SS[.SSS]) in datesKeyword() whenever the timestamp is non-midnight, formatting with millisecond precision when present. Date-only events keep their previous DAY/MONTH/YEAR-only output. The first-date comment in the schedule generator mirrors the same time so it stays consistent with the keyword.
A grid created via the create_corner_point_grid API populated the internal
active cell info but never created an ACTNUM result property, so the grid did
not expose ACTNUM the way a grid loaded from an Eclipse file does. Since the
corner point case has no reader interface, the data cannot be loaded lazily and
is now materialized as a STATIC_NATIVE result sized per active cell, mirroring
native Eclipse ACTNUM.
Select the summary plot as the current item before any menu commands are
created, so every command in the context menu operates on that plot. This is
the root fix for plot-level commands (New Analysis Plot, correlation plots,
etc.) that derive their enablement from the selected plot: previously the
selection could be left on an ensemble realization's summary case, disabling
them.
Because the plot is now selected, the Show Plot Data / Edit Plot / Split / Delete
commands resolve the plot from the selection, so passing it as user data is no
longer needed. The RicShowPlotDataCtxFeature and RicEditSummaryPlotCtxFeature
subclasses existed only to force isCommandEnabled to true for the context menu;
they are now obsolete and removed, and the menu uses the base RicShowPlotData
and RicEditSummaryPlot features directly.
Also highlight the curve under the cursor before showing the menu, giving the
same visual feedback as a left-click. Separate highlighting from selection:
extract the visual-only part of selectClosestPlotItem into
applyHighlightForClosestItem, shared by selectClosestPlotItem (left-click:
highlight + select) and the new highlightClosestPlotItem (highlight only). The
context menu uses the highlight-only path, so it does not change the selection.
Add highlightClosestPlotItemAtPosition that takes widget coordinates and
converts them to canvas coordinates internally, so the caller does not depend
on qwt headers.
Persist the geometry of PdmUiPropertyViewDialog and RiuPropertyViewTabWidget to the application settings on close and restore it on the next show. Restoring is done in showEvent rather than the constructor so it is applied reliably for a modal dialog. The settings key includes the bound object class keyword so distinct dialogs that share a window title do not collide.
This behaviour is gated behind a new "Remember Dialog Size" experimental feature, disabled by default. PdmUiPropertyViewDialog cannot access RiaPreferencesSystem, so the application pushes the current setting via the static enableGeometryPersistence(), following the existing pattern used for class-name display. RiuPropertyViewTabWidget queries the feature directly.
Override sizeHint() and minimumSizeHint() in PdmUiPropertyViewDialog so the dialog cannot open collapsed. The inner scroll area reports an artificially small minimum size hint that some window managers honor literally, shrinking the dialog to an unusable size (issue #14104). The floor is capped by the content's preferred size so intentionally small dialogs are not enlarged.
ecl_grid_alloc can return null for a corrupt or truncated grid file.
When a valid INIT file was present, loadAllGrids dereferenced the null
grid pointer via ecl_grid_dual_grid/ecl_grid_get_global_size before
returning, causing a segfault.
Guard the init-file active cell logic on a non-null grid so the function
returns null cleanly, letting the existing null check in open() report
the error gracefully.
stepListIndexToTimeStepAndDataFrameIndex only guarded against negative indices, relying on a CVF_ASSERT for the upper bound. That assert is compiled out in release builds, so when a GeoMech case has no steps loaded (empty m_stepList) the clamped current time step of 0 caused an out-of-bounds read of m_stepList[0]. Extend the early-return guard to also cover indices past the end, returning the existing (stepIndex, -1) sentinel.
The add() overloads aborted via CAF_ASSERT when passed a null field or
object, forcing every call site that adds an optional child to pre-guard.
Adding an optional node is inherently an "add it if it exists" operation,
so make both overloads a no-op on null instead: the field overload returns,
and the object overload returns nullptr. This removes a class of latent
release crashes and the need for repetitive null checks at call sites.
Also remove a redundant dynamic_cast (and its "// What ???" comment) in
containsField, since child() already returns PdmUiTreeOrdering*.
Guard the remaining unguarded legendConfig() uses so a null legend config
cannot crash: both updateLegend() implementations (eclipse and statistics
projections) now capture the pointer and return early when null, and the
statistics view tree ordering skips a null legend config.
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.
Use a numeric-aware QCollator in RiuGroupedBarChartBuilder::BarEntry::operator< so that tick and legend texts containing numbers (e.g. realization-2 vs realization-10) sort in natural numerical order instead of lexicographically.
Fixes#14105
Revert 380b471. The 'Export Layout to Clipboard' window menu action is a developer-only utility, not an experimental feature. Gate it behind RiaApplication::enableDevelopmentFeatures() again and drop the 'export-dock-layout' experimental feature registration.
Plain pip has no time-based cutoff, so route the workflow's package
installs through uv and set UV_EXCLUDE_NEWER to refuse releases
published within the last week as supply-chain hardening. Mirror the
policy in the rips pyproject for local uv installs.
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.
Promote the experimental feature checkboxes out of the development-only System tab into a dedicated, always-visible Experimental tab so end users can opt into experimental features without enabling development features.
The m_enabledFeatures field stays owned by RiaPreferencesSystem, so its keyword, value options and legacy-keyword migration are unchanged.
Gate the derived oil volume cell result behind the new 'oil-volume-result'
experimental feature instead of RiaApplication::enableDevelopmentFeatures().
In the ROFF file reader, drop the enableDevelopmentFeatures() gates around the
grid dimension, timing and array diagnostics and log them at debug level instead,
so the output is available without RESINSIGHT_DEVEL but stays quiet in normal
runs.
Gate the 'Export Layout to Clipboard' window menu action behind the experimental
features registry instead of RiaApplication::enableDevelopmentFeatures(). Register
the 'export-dock-layout' feature and drop the now-unused RiaApplication include.
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().
Replace the free-text experimental-feature keyword box with a discoverable
registry and a checkbox list in Preferences -> System.
Add RiaExperimentalFeatures as a single, discoverable list of available
experimental features (keyword, display name, description). RiaPreferencesSystem
now stores the enabled features in a tree-selection (checkbox) field populated
from this registry, and isFeatureEnabled() checks that selection. The legacy
semicolon-separated keyword string is migrated in initAfterRead(), preserving
existing preference files and the 'enable-all' keyword.
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.
* Refactor: add MACOSX_BUNDLE option to qt_add_executable in multiple CMakeLists.txt files
* #14045 macOS: Guard std::stacktrace usage and skip ucontext on Apple platforms
* #14045 macOS: Guard std::ispanstream with std::istringstream fallback
* #14045 macOS: Add vcpkg overlay triplets for osx and exclude grpc on osx
* #14045 macOS: CMake macOS build support and openzgy OpenMP-disable patch
* #14045 CI: Add macOS build workflow
* #14045 macOS: Use feature-test macros to detect <stacktrace> and <spanstream>
* #14045 macOS: Make MAX_STIMPLAN_LAYERS constexpr to fix arm64 link error
* #14045 CI: Ship README-macOS.txt with artifact to document Gatekeeper workaround
* #14045 CI: Pin macOS runner to macos-14 and set deployment target to 14.0
* #14045 CI: Move macOS runner to macos-15 and fix README step on configure failure
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.
Some commercial simulators reject a DATES keyword whose value equals the
simulation start date. The earliest event date is, by construction, that start
date, so generate_schedule_text now emits it as a comment line (e.g.
"-- Date: 1 JAN 2024") instead of a DATES keyword by default.
The new first_date_as_comment parameter (default True) threads from the Python
wrapper through the GenerateSchedule scriptable method into
RicScheduleDataGenerator. Only the first/earliest date is affected; later dates
are always emitted as DATES keywords. Pass first_date_as_comment=False to
restore the previous behavior.
Well disks are flat, zero-thickness discs drawn at a fixed elevation above each
well head. When the disks of different wells overlap horizontally they end up
coplanar at the same depth and z-fight.
Offset each disk along Z by a small per-well amount derived from the stable
resultWellIndex(), scaled by arrowLength so the spacing tracks the disk scale and
view zoom. Coincident disks fan out into a readable vertical stack instead of
fighting.
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.
The well list driving schedule generation originates from a
std::set<RimWellPath*>, so it was ordered by pointer address and the
per-well keyword records (WELSPECS, COMPDAT, COMPLUMP, MSW keywords, well
control) came out in a non-deterministic order that only looked sorted by
coincidence.
Sort the well list once by the deck export name in generateSchedule, so
every per-well keyword is emitted in a stable, well-name-sorted order,
matching the convention already used by the file-based completion export.
Schedule-level keywords (GRUPTREE, RPTRST, TUNING) are left untouched.
buildKeyword placed every user-supplied item into a single DeckRecord,
so multi-record keywords such as TUNING (3 records, each terminated by
its own '/') were emitted with only one record/slash and rejected by the
simulator.
Distribute items across the keyword's records using the OPM ParserKeyword
schema: each item is matched to the record that defines it. Every record
is emitted (empty records are written as a bare '/') so the schema's
record structure is preserved, and items unknown to the schema are now
reported via a warning. Single-record keywords keep their previous
behaviour, including appending non-schema items after the canonical
block.
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.
WELSEGS and COMPSEGS carry a per-well header record followed by that
well's segment records, so segments from different wells cannot share a
single header. Commit 6ef024c merged records of the same keyword across
wells, which is invalid for these two keywords.
Accumulate WELSEGS and COMPSEGS as separate per-well blocks in a
dedicated container and serialise each block individually, while the
remaining keywords (WELSPECS, COMPDAT, WSEGVALV, WSEGAICD, well-control
and schedule keywords) continue to merge. Emission preserves the
existing priority ordering.
Replace the include_welsegs / include_compsegs boolean flags on the
schedule-generation API with a list of wells (export_msw_for_wells) that
gates the multi-segment-well keywords. WSEGVALV and WSEGAICD are now gated
the same way as WELSEGS and COMPSEGS: all four are emitted only for wells
present in the list. An empty list (the default) suppresses MSW export for
all wells, while COMPDAT and well-control keywords are unaffected.
C++: RicScheduleDataGenerator takes a std::set<const RimWellPath*> mswWells
and generateMswForWell early-returns for wells not in the set.
RimcWellEventTimeline_generateSchedule replaces the two bool fields with a
scriptable PdmPtrArrayField<RimWellPath*>, resolved via
ptrReferencedObjectsByType().
Python: generate_schedule_text / generate_schedule expose
export_msw_for_wells (List[WellPath]) instead of the boolean flags. Updates
the well_event_schedule example and adds regression tests covering the
empty-list default, per-well selection, and WSEGVALV/WSEGAICD gating.