Nested hybrid grid: import as a reconstructed LGR hierarchy#14231
Draft
kriben wants to merge 7 commits into
Draft
Nested hybrid grid: import as a reconstructed LGR hierarchy#14231kriben wants to merge 7 commits into
kriben wants to merge 7 commits into
Conversation
912ee2c to
46fc505
Compare
Add support for importing Eclipse "nested hybrid grids" (produced by xtgeo/fmu-tools). Such a grid is a single flat EGRID in which the refined region is appended to the end of the I axis at higher resolution and connected to the coarse grid through NNCs; in IJK space the refined cells are far from their coarse parent, but their COORD/ZCORN place them inside the coarse region. The coarse parent cells are collapsed to zero volume, so the parent of each refined cell is supplied explicitly by a HOSTNUM sidecar. Both sidecars are auto-detected next to the grid file: - <base>_NEST_ID.grdecl : per-cell nesting level, loaded as a discrete category property for coloring/filtering. - <base>_HOSTNUM.grdecl : per refined cell, the 1-based natural index of its parent coarse cell (0 otherwise). RigNestedHybridGridReconstructor rebuilds each refined region as a true RigLocalGrid: it appends contiguous cells/nodes, copies the real refined geometry, links each cell to its parent (subGrid/parentCellIndex), hides the original scattered cells, transfers active-cell result indexing, copies result values onto the LGR cells, and re-points the file NNCs to the LGR cells. The reconstructed LGR is flagged so it is excluded from the on-file grid count, preventing the result reader from reading it as a phantom grid. The refined region then appears as a proper LGR with correct geometry, INDEX_I/J/K, static/dynamic results and computed results (e.g. SOIL). Normal grids (no sidecar present) are unaffected. Key changes: - RigNestedHybridGridReconstructor (new) + RimEclipseResultCase hooks - RigLocalGrid isReconstructedGrid flag; RigMainGrid gridCountOnFile and nestedHybridLgrSourceCells - RigCaseCellResultsData: copy results onto reconstructed-LGR cells - RiaResultNames: NEST_ID name + category-result handling - RigActiveCellInfo::computeDerivedData made idempotent - Unit tests in RigNestedHybridGridReconstructor-Test.cpp
…sidecars
Adapt the nested hybrid grid import to the current generator export format,
which no longer provides HOSTNUM. The refined region is described by sidecars
next to the flat EGRID: <base>_REFINE.grdecl (per-cell nesting level, replaces
NEST_ID) and <base>_OLDIJK.grdecl (OLDI/OLDJ/OLDK = the parent coarse cell IJK,
TMPI/TMPJ/TMPK = the cell's local refined coordinates).
The flat grid is kept as the main grid (result reading is untouched) and one
LGR is appended per refinement level: each level whose cells are a uniform
refinement of the coarse grid (verified via TMP/OLD) becomes a single
CARFIN-style RigLocalGrid over the coarse block, with missing cells left as
inactive holes. Levels that refine another level rather than the coarse grid
(level 4 inside level 3) are reconstructed as true LGR-in-LGR: their cells are
merged into connected regions in the refined-parent coordinate space (so a stack
of refined parent cells becomes a single LGR), one LGR per region, nested under
the level-3 cells it subdivides, with synthesized bounding-box geometry for the
collapsed host cells.
Also derive the parent-child mapping (each refined cell to its coarse parent)
and add a volume-weighted QC aggregate: computeNestedHybridCoarseAggregate
produces a <RESULT>_COARSE result holding, on every cell of a coarse parent, the
volume-weighted average of the source result over its refined cells.
Fix a hard crash when opening a project whose persisted grid set no longer
matches the regenerated LGRs: RimGridCollection::indicesToVisibleGrids now skips
grid indices beyond the current grid count.
Key changes:
- RiaResultNames: add refine() ("REFINE") and treat it as a category result
- RimEclipseResultCase: REFINE + OLDIJK sidecar detection and reconstruction trigger
- RigNestedHybridGridReconstructor: rewritten for multi-level, non-rectangular,
nested reconstruction; new NestedHybridInput API
- RigMainGrid: store the per-cell coarse-parent mapping
- RigCaseCellResultsData: computeNestedHybridCoarseAggregate
- RimGridCollection: guard against stale persisted grid indices
- Unit tests rewritten for the new format and L4 nesting
Replace the fixed two-pass (primary level + one nesting layer) with a single shallow-to-deep pass that supports nested refinement chains of any depth. Every reconstructed cell is indexed by its TMP. Primary levels (direct uniform refinements of the coarse grid) record all of their box cells, including holes, so a deeper level can nest under a cell that was itself further refined and has no geometry of its own. For each level, the cell's immediate parent is resolved as the unique already-built cell one level shallower that shares its TMP; if enough cells resolve, the level is nested (buildLocalGrid placed inside the resolved parent grid, grouped by parent grid and merged into connected regions), otherwise it is treated as a direct coarse refinement. Cells whose parent cannot be resolved unambiguously are deferred (left as flat cells) rather than mis-nested, so reconstruction never corrupts geometry. How deep it reaches depends on the export's TMP encoding; the DROGON test case still reconstructs identically (level 2, level 3, and level 4 merged into 12 nested regions). The OLD-based parent mapping and QC aggregate work at any depth regardless.
Add computeNestedHybridPerLevelAggregate, which produces one result "<RESULT>_COARSE_L<level>" per refinement level: on each level-N cell it stores the volume-weighted average of the source result over the level-N cells of that cell's immediate parent (from the reconstructed LGR hierarchy). All other cells are left undefined so each level's result shows only that level. Each cell's level is taken from the REFINE result (full-length, authoritative) so cells of different refinement levels are never combined; the accumulation is keyed by (level, parent) and falls back to the LGR name only if REFINE is not loaded. On load, these per-level aggregates are computed for PRESSURE and the saturations alongside the existing collapse-to-coarse aggregate. A unit test verifies the L4 averages against hand-computed values and that the result is defined only on the level's own cells.
Reconstructed nested hybrid LGRs are laid out on a regular IJK box, but their
refinement can be non-conforming: two visible cells may be IJK neighbours
without geometrically sharing the face between them. The cell face visibility
filter hid such faces as if they were internal, leaving see-through gaps
("missing cell walls") on levels 2 and 3.
In RigGridCellFaceVisibilityFilter::isFaceVisible, when a shared face would be
hidden and the grid is a reconstructed LGR, draw the face unless the cell's face
corners actually coincide with the neighbour's opposite-face corners (within a
size-relative tolerance). Gated on RigLocalGrid::isReconstructedGrid(), so normal
grids and file-based LGRs are unaffected.
Add the nested hybrid grid test dataset (flat 150x84x96 EGRID plus the REFINE and OLDIJK sidecars and INIT/UNRST results) used by the RigNestedHybridGridReconstructor unit tests.
46fc505 to
f765609
Compare
The flat nested hybrid grid piles the refined and collapsed coarse cells into the same physical space, so a single findIntersectingCells query in a refined region returns tens of thousands of overlapping cells. Running computeCachedData() (the search tree, geometric fault detection and NNC computation) on that flat grid is pathologically slow, and it was done before the LGR reconstruction and then again afterwards. Reconstruct the LGR hierarchy before computeCachedData() when the REFINE + OLDIJK sidecars are present (loading input properties first so they are extended onto the LGR cells), and compute the grid caches once, on the clean reconstructed grid. Normal cases keep the previous order. Also drop the now-redundant computeCachedData call inside reconstructNestedHybridGridIfPresent. Because geometric fault detection now runs with the LGRs present, exclude reconstructed-LGR cells from addUnNamedFaultFaces: their refinement boundaries are not geological faults, and flagging them as such hid those cell faces during rendering (the fault check precedes the face-conformance check in isFaceVisible).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add support for importing Eclipse "nested hybrid grids" (produced by xtgeo/fmu-tools). Such a grid is a single flat EGRID in which the refined region is appended to the end of the I axis at higher resolution and connected to the coarse grid through NNCs; in IJK space the refined cells are far from their coarse parent, but their COORD/ZCORN place them inside the coarse region. The coarse parent cells are collapsed to zero volume, so the parent of each refined cell is supplied explicitly by a HOSTNUM sidecar.
Both sidecars are auto-detected next to the grid file:
RigNestedHybridGridReconstructor rebuilds each refined region as a true RigLocalGrid: it appends contiguous cells/nodes, copies the real refined geometry, links each cell to its parent (subGrid/parentCellIndex), hides the original scattered cells, transfers active-cell result indexing, copies result values onto the LGR cells, and re-points the file NNCs to the LGR cells. The reconstructed LGR is flagged so it is excluded from the on-file grid count, preventing the result reader from reading it as a phantom grid.
The refined region then appears as a proper LGR with correct geometry, INDEX_I/J/K, static/dynamic results and computed results (e.g. SOIL). Normal grids (no sidecar present) are unaffected.
Key changes: