Add a typed FILTER declaration to the ORIONEVENTS 2.0 grammar, e.g.
FILTER POROPERM = "PORO > 0.4 AND PERMX > 100.0". A PERFORATION event
references it with FILTER=POROPERM or supplies an inline quoted
expression. When applied, each used filter is materialized as a
case-level combined data filter (one property filter per term, one-sided
inclusive bounds, AND/OR combine mode) and attached to the perforation.
Unqualified result names are searched in STATIC_NATIVE, DYNAMIC_NATIVE
then GENERATED results; a TYPE. qualifier restricts the search. Missing
results raise before any event is applied. apply_orion_document gains an
optional case= parameter defaulting to the project's first case.
RimWellEventPerf carries a RimCellFilter ptr-field with scriptable
AddFilter/cell_filter methods, and the filter is copied onto the
RimPerforationInterval when the timeline materializes completions.
deleteSummaryCaseCollection() looped over every case in the ensemble, and for each case scanned every summary plot and called updateConnectedEditors() on every multi plot. For an ensemble with many realizations this scanned each plot once per realization, and updated the connected editors once per realization and multi plot. This showed up as a hot spot in the profiler.
Replace deleteCurvesAssosiatedWithCase() with deleteCurvesAssosiatedWithCases(), which takes a set of cases and returns whether anything was deleted. Each plot is now scanned once, and the connected editors of a multi plot are updated only when that multi plot actually lost a curve.
RicCloseSummaryCaseFeature and RicCloseObservedDataFeature are updated to the new signature. RicCloseSummaryCaseFeature also scans each plot once instead of once per case.
The destructor called updateReferringCurveSets(), which runs loadDataAndUpdate() on every referring curve set. At that point the summary cases are already deleted, so reloading the curve data has nothing to read. The reload also syncs UI fields, reloads the curve filters, rebuilds the address list, recomputes statistics over an empty case set and updates three legends, and it calls updateAll() on the parent plot once per curve set instead of once per plot.
Add clearReferringCurveSets(), which deletes the ensemble and statistics curves directly and updates each affected plot once. For an ensemble with many realizations spread over several curve sets in the same plot this removes most of the work done while deleting.
Query the referring objects as RimEnsembleCurveSet instead of walking all referring objects and casting. The previous loop discarded everything that was not a curve set, so the behavior is unchanged.
The lower limit of a logarithmic color range was computed from the value closest to zero, which is not always available. When this value was zero, log10() returned -inf and the lower limit ended up as zero. Use the closest power of ten below the lowest value instead, and use the value closest to zero only when the lowest value is zero or negative. Guard computeTenExponentCeil() and computeTenExponentFloor() against zero, and make sure the range always spans at least one decade.
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.
Use I as the default direction when creating an IJK intersection, and center the fixed index on the I axis.
Allow multiselect of surfaces for a Surface Curve. The field keyword is changed from Surface1 to Surfaces, with a keyword alias so existing project files are read as before. One curve is drawn per selected surface, each with its own label and color.
Use the color defined in the Surfaces collection for Surface Band and Surface Curve. The color is shown as read only, and a Custom Color option allows the user to specify a color. Bands created from an ensemble surface keep the structural uncertainty colors, as the statistics surfaces share the same color.
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().
loadMainCaseAndActiveCellInfo() calls openAndReadActiveCellData() for each
source case in a grid case group. That function returns false before
setReservoirData() when the grid file is missing, and the loop only continues,
so the case stays in the collection with a null eclipseCaseData().
computeUnionOfActiveCells() then iterates every reservoir and calls
eclipseCaseData()->activeCellInfo() on it, which reads m_activeCellInfo off a
null case data and crashes.
Collect the source cases that have case data once, before the cell loops, and
iterate those. This also removes the per-cell case lookup from the innermost
loop.
transferStaticNNCData() takes the connection count from the INIT file using
ecl_nnc_data_get_size(), but iterates the geometry from the grid file using
ecl_nnc_geometry_iget(). The two counts were only compared in an assert, which
is compiled out in release builds, so an INIT file out of sync with the grid
reads past the end of the geometry vector inside resdata.
Compare the counts at run time, log a warning and iterate the smaller of the
two. Both nncConnections and transmissibilityValuesTemp are filled in the same
loop and stay aligned.
addRftCurve() selects the first Eclipse result case in the project without
checking that it has an RFT reader, and then dereferences rftReader(). The
command is enabled by hasRftData(), which returns true if any case has a
reader, so with several Eclipse cases loaded an enabled menu entry can select
a case with no RFT data and crash.
Null check the reader before use, matching the guard already used by
hasRftData() and hasRftDataForWell().
The COMPSEGS rows were emitted in the order the branches are listed in, so they followed the WELSEGS order where the completion branches come before the laterals with a lower branch number.
The rows are now collected while the segments are visited and sorted by branch number before they are added. The sort is stable, so the rows of a branch keep their order along the well path.
Branch numbers are handed out from two counters. The well path laterals are numbered first, so that the main bore and the laterals occupy the lowest branch numbers. The completion branches (valves, fractures and fishbones) are numbered after all laterals, and are still listed immediately after the lateral they are connected to.
The multiple_laterals test project is reduced to a single Eclipse case, and is used by two new unit tests covering the branch numbers and the order the branches are listed in.
RiaCurveMerger::addCurveData and RiaWellLogCurveMerger::addCurveData only
validated that the X and Y vectors have the same size with CAF_ASSERT, which is
compiled out in optimized builds. Mismatching sizes are a legitimate run-time
condition for data read from file, so the check has to hold in release builds as
well.
In RiaCurveMerger the shared-X fast path in computeInterpolatedValues() indexes
the Y vector of every curve using the sample count of the first curve. A curve
with identical X values but fewer Y values therefore read past the end of its
heap buffer inside the OpenMP loop. RimEnsembleStatisticsCase passes time steps
and values straight from the summary reader without reconciling the sizes, and
realizations in an ensemble normally share time steps, so this was reachable for
an ensemble containing an ongoing simulation.
Both mergers now truncate the incoming data to the common sample count instead.
For RiaWellLogCurveMerger this is also an improvement in behaviour, since
lookupYValue() used to discard the whole curve when the sizes differed.
Add unit tests covering a single curve with fewer values than time steps and
curves with shared time steps where one curve has fewer values.
When several perforation intervals overlap the same grid cell, the main bore COMPSEGS table emitted one row per interval. Two perforations placed back to back therefore reported the same IJK twice, while COMPDAT correctly reported a single connection for that cell.
The candidate intersections collected for one cell all describe the same IJK, so they are now merged into a single COMPSEGS row spanning the union of the overlapping measured depth ranges.
Add TestModels/msw-export/project-files/perf_two_back_to_back.rsp covering the case.
Deleting PDM objects on a worker thread is not safe. PdmObjectHandle::prepareForDelete()
mutates state owned by other objects, it nulls the guarded pointers held by other objects
and clears m_pointersReferencingMe, an unsynchronised std::set that every PdmPointer
construction and destruction touches. Destroying an object off the main thread therefore
races with the main thread on the shared object graph. See issue 14491.
Profiling a summary ensemble teardown shows the mechanism does not pay for itself. Releasing
397 Drogon realizations takes 0.24 s sequentially and 0.24 s in parallel, and for a heavy
case the parallel release is slower than the sequential one, because free() is serialised
inside the allocator. The PDM bookkeeping itself is 0.4 to 2.8 percent of the teardown.
Remove the class and deleteChildrenAsync(), and delete synchronously instead. The call sites
that used clearWithoutDelete() and a manual delete loop to work around the race can now call
deleteChildren() directly. Add caf::PdmObjectHandleTools::deleteObjects() for the case where
the objects are no longer owned by a child array field.
The observer disconnection from issue 12262 does not depend on clearWithoutDelete(). ~Signal()
unregisters itself from every observer, so a deleted child detaches itself. That fix addressed
the async race, where ~Signal() mutated the observer list from a worker thread. The unit test
is updated to assert the observed signal count directly instead of relying on a crash.
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.
cvfBase.h includes cvfAssert.h, so these six files were the last indirect route
into the assert header that the previous commit removed from ApplicationLibCode.
Five files dropped the include with no further change. RimSeismicAlphaMapper
declared alphaValue as returning cvf::ubyte, a typedef defined in cvfBase.h
itself, so no smaller VizFwk header provides it. Since cvf::ubyte is
unsigned char, use that directly in the declaration, the definition and the
cast. The type is identical, so callers are unaffected, and the class no longer
depends on VizFwk at all.
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.
cvfAssert.h tests CVF_ENABLE_ASSERTS but did not include cvfConfigCore.h, which
is where that macro gets its default value of 1. A translation unit processing
cvfAssert.h before cvfConfigCore.h evaluated the undefined identifier as 0 and
silently compiled every CVF_ASSERT, CVF_ASSERT_MSG and CVF_FAIL_MSG in that unit
into a no-op, without any warning and without evaluating the expressions.
Because the header uses pragma once, including cvfConfigCore.h later in the same
unit did not recover the macros. Alphabetical include sorting actively produces
the broken order, since cvfAssert.h sorts before cvfBase.h.
Include cvfConfigCore.h before the macro definitions. It only defines macros, has
pragma once and no dependencies, so this is immune to future include reordering.
This turns the asserts back on in the affected translation units, in both debug
and release builds, and immediately exposed one assert that had never compiled:
in RigFemPartResultCalculatorNormalized::calculate, isNormalizableResult was
called unqualified even though it is a static member of
RigFemPartResultsCollection. Qualify it, matching isMatching in the same file.
The first segment of a lateral had its comment cleared when the lateral had a tie-in valve, leaving the rows unlabelled. Write the well path name instead, so the exported segments can be traced back to the lateral they belong to.
The geometry path emitted one WELSEGS row per cell intersection of a fishbones lateral, ignoring the max segment length and the custom segment intervals. The tree path split them like every other completion, in collectCompletionWelsegsSegments.
Split each cell intersection with createSubSegmentMDPairs and chain the resulting rows. The lateral geometry is not part of the well path, so the TVD of a sub-segment cannot be interpolated along the well path. Interpolate linearly between the start and end TVD of the intersection instead, as the tree path did for fishbones. The cell is connected by the first sub-segment only, leaving COMPSEGS unchanged, and the lateral label stays on the first row.
An intersection now covers several segment numbers that share one effective diameter, and must still contribute once to the sum for its cell. FishbonesLateralSegment therefore holds the segment numbers of an intersection rather than a single one, and the intersections are grouped per lateral in FishbonesLateral. This replaces the separate list of first and second segment numbers, since the reduction rule is now expressed on the intersections of a lateral.
Verified with a copy of fishbones.rsp with max segment length enforced at 4 m: the three laterals are split into three or four rows each, depths are evenly interpolated, effective diameters are unchanged at 0.01664 and 0.00960, and COMPSEGS is identical. The sweep against TestModels/msw-export is unchanged, as none of the projects enforce a max segment length.
The summation reproduced the tree implementation, where an ICD sub connected to several cells took part in the sum of each of them, reading areas that earlier cells had already replaced. The result depended on the order the cells were visited in, and an ICD sub could contribute an already combined area to the next cell.
Compute every cell sum from the original areas instead. An ICD sub spans a 0.1 m valve segment and normally connects to a single cell, and when it reaches into more than one it now reports the largest of the sums it takes part in.
Behaviour is unchanged for the common case of one ICD sub per cell, and the sweep against TestModels/msw-export is unaffected. Added tests for the multi-cell case and for independence of the recording order.
The legacy tree path gave every fishbones ICD sub connected to the same grid cell the sum of their areas, so the cell sees the total flow area of the ICDs completing it. That was part of updateDataForMultipleItemsInSameGridCell and disappeared with the rest of the tree code, leaving each ICD sub with its own area.
Record the grid cells each ICD sub connects to while the branches are built, and apply the summation together with the effective diameters. FishbonesDiameterContext now carries both, and is renamed to FishbonesExportContext.
An ICD sub connected to several cells takes part in the sum of each of them and ends up with the value of the last cell in ascending cell order. This is order dependent, and is kept because the tree implementation behaved the same way.
None of the projects in TestModels/msw-export has more than one ICD sub per cell, so the sweep against the stored reference output is unchanged. Added unit tests for applyIcdAreaPerCell and applyEffectiveDiameters instead, since neither function had coverage.
The geometry path exported the raw equivalent diameter for every fishbones lateral segment. The legacy tree path replaced it with an effective diameter, computed in updateDataForMultipleItemsInSameGridCell, which was removed together with the rest of the tree code.
Reinstate both rules. Laterals sharing a grid cell get Deff = sqrt(d1^2 + d2^2 + ..) over the lateral segments in that cell (#7686). The first segment of a lateral shares its cell with the main bore and with the first segment of every other lateral on the same sub, so it inherits the effective diameter of the second segment of the same lateral (#7731). A lateral contained in a single grid cell has no second segment and keeps the combined value, which is where the difference from the tree path was most visible.
Lateral segments are recorded while the branches are built, since the grid cell of a segment is not recoverable afterwards. COMPSEGS deduplication clears the cell intersections of segments in an already connected cell. The context is shared by the main bore and all tie-in laterals, and applied once the branches are assembled.
Verified against the twelve projects in TestModels/msw-export: every well with stored reference output now matches the legacy values, including the fishbones laterals that previously differed.
The fishbones ICD sub segment left RigMswSegment::diameter and roughness unset, and the formatter renders an empty optional as the 1* default marker. The legacy tree path emitted 0.15 and 5.0e-5 for these rows, taken from the RicMswSegment constructor defaults. RigMswSegment has never had such defaults, so the comment claiming the tree behaviour was matched was wrong.
Set both values explicitly, as buildFractureBranches already does. Verified against TestModels/msw-export/project-files/fishbones.rsp: the ICD sub WELSEGS row again exports 0.15000 and 0.0000500, matching the stored legacy reference output.
Four crashes reported from release builds share the same shape: a pointer that
is null during teardown or before a view is fully created is dereferenced
without a check.
RiuViewer::paintOverlayItems() used the owner case of the view and of the
comparison view without checking it, and dereferenced the result of a
dynamic_cast directly. The owner case is null while a case is being closed.
RicIntersectionFeatureImpl::createIntersectionBoxSlize() checked
activeMainOrComparisonGridView() but dereferenced activeGridView(), which is a
different object and can be null or have no viewer.
RimEclipseContourMapView::onCreateDisplayModel() called viewer()->mainCamera()
before the viewer exists.
RimCorrelationPlotCollection::applyFirstEnsembleFieldAddressesToPlot() called
front() on the ensemble parameter vector, which is empty for an ensemble
without realization parameters.
RivSingleCellPartGenerator uses the grid and cell index stored in the 3D
selection item. These are plain indices, and they are not revalidated when
the case data is rebuilt behind a live selection. Both RigMainGrid::gridByIndex()
and RigGridBase::cell() guard only with CVF_ASSERT, so in release builds a stale
index reads out of bounds and the resulting garbage corner indices crash in
RigGridBase::cellCornerVertices().
Validate the grid and cell index before creating the mesh drawable.
* 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.
* #14411 Enforce name uniqueness for surfaces, polygons and folders
Names must be unique among siblings sharing the same parent folder. Items in different folders may keep identical names, and comparison is case sensitive.
Siblings are the objects held by the same caf::PdmChildArrayField. Items and folders live in two distinct child arrays in caf::PdmNestedCollection, so a folder and an item may share a name under the same parent.
The Python API gets an OnNameConflict flag on AddFolder, CreatePolygon, ImportSurface and NewRegularSurface, supporting FAIL (default), AUTO_RENAME and OVERWRITE. NewSurface is left out, as grid case surfaces derive their tree label from the case and K index and carry no name of their own.
The ensemble file set removed the file extension by searching for the last dot in the complete path. When the path pattern was already without extension, the last dot was found in a folder name, truncating the path pattern and causing the search for SMSPEC files to fail.
Add RiaFilePathTools::removeFileExtension based on std::filesystem::path::replace_extension, and use it both in RimEnsembleFileSet and in the grid and summary ensemble import, replacing a duplicated lambda doing the same operation.
The label is moved from the anchor point towards the camera to be drawn in front of other geometry. The offset was derived from the zoom level, and was not related to the distance between the camera and the anchor point. In a 3D view the offset is usually larger than this distance, moving the label behind the camera. Labels outside the view frustum are silently discarded by the text renderer.
Limit the offset to the smaller of half the distance to the anchor point and the distance to the near plane. The limit is derived from the anchor point and not from the near plane, as the label parts are part of the scene and are used to compute the clipping planes.
Reject anchor point candidates behind the camera. Coordinates behind the camera are mirrored into the viewport by the perspective divide in cvf::Camera::project(), and could be selected as the coordinate closest to the label position.
Rim2dIntersectionViewCollection::syncFromExistingIntersections() found the
intersections by walking the PDM child tree of the case. Views located in a
grid ensemble view collection or in the project level view collection are not
children of the case, so no 2D intersection view was created for their
intersections and "Show 2D Intersection View" did nothing.
Collect the intersections from the grid views displaying the case instead.
Display the 2D intersection views as a child of RimReservoirGridEnsemble, next
to the 3D views they are created from, and skip the node on the case to avoid
showing the same object twice in the project tree.
* Add RivSurfaceIntersectionCurveTools for shared surface intersection curve geometry
* Move the surface intersection collection to RimIntersection
* Add surface curtain footprints for the box and i/j/k intersections
* Build surface intersection curves for the box and i/j/k intersections
* Follow the pillar tilt when projecting a surface onto an intersection
* Estimate the surface intersection by continuing the pillar past the curtain
Replace the QString* errorMessage out-parameter with std::expected<RigFormationNames, QString> in RifFormationNamesReader, and propagate the pattern to RimFormationNames::readFormationNamesFile() which now returns std::expected<void, QString>.
Fatal errors (file cannot be opened, FMU line-parse failure) return std::unexpected. Malformed .lyr lines are still skipped so the rest of the file loads, with warnings logged via RiaLogging instead of collected in the out-parameter. RimFormationNamesCollection::readAllFormationNames() now logs errors it previously discarded.
Keywords in invalidPropertyDataKeywords() (e.g. ECHO/NOECHO) are skipped without setting an error message, but readProperties() logged the empty string as an error. Only log when there is an actual message.
Build the reconstructed nested hybrid grid case once in SetUpTestSuite() and share it across all seven tests instead of repeating the expensive setup (open ~1.2M cell EGRID, parse sidecars, reconstruct LGRs, compute cached data) per test. Suite run time drops from ~34s to ~4s.
The aggregate helpers fully rewrite their generated results on every call, so the MEAN and SUM tests do not interfere even though they share result names. Results needed before reconstruction (first static result, REFINE input property) are loaded in the fixture, and the pre-reconstruction active cell count is captured for the growth check.
* #14319 Compute all pending ensemble contour maps in one sweep over realizations
* #14319 Initialize result definition and open primary case before building contour map grid
* Contour Map: Compute histogram from map projection values to show correct sample count in overlay info
* #14319 Add comments describing the realization sweep and grid caching
Document why the realization loop is the outer loop, when a realization case is
closed again after processing, and that the contour map grid doubles as the
"statistics computed" flag in ensureResultsComputed().
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.
RimFracture::startMD() and endMD() dereferenced the fracture template without checking for null. A fracture with no template assigned crashed MSW completion export, which calls startMD() for all completions on a well path.
RimWellRftPlot::dataSource() returned a default constructed variant when no source was selected. The variant then held a null RimSummaryCase pointer, and RicCreateRftPlotsFeature dereferenced it. Add std::monostate as first alternative to represent no data source.
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.
Cloud services are configured from RiaApplication::initialize(), which runs before the subclasses append their logger instances. All messages from the cloud config file search were therefore dropped. Add a virtual initializeLoggers() called before the cloud configuration is read, and move creation of the file logger and the std out logger into the overrides. The message panel logger depends on the main windows, and is still created in RiaGuiApplication::initialize().
Do not write fields with IO disabled to the application store, mirroring the check already present when reading. This stops the cloud service configuration from being persisted into the user preferences file.
Make the Z-scale combo boxes in the toolbar and property editor editable, so any positive scale value can be entered as text. Invalid input is rejected and the previous value is restored.
Add keyboard shortcuts Ctrl+Shift+Up and Ctrl+Shift+Down to step the Z-scale of the active view through the predefined scale values.
A lateral gets its well path geometry from the parent well, and is
visualized even when it has no active well targets. Building the well
target spheres then calls setVectors() with empty arrays, which asserts.