Support for loading only active cell geometry (#11624)

* Only load active cells for main grid, skip LGRs for now
* Handle wells with inactive cells
* Validate mapaxes transform before using it.
* Add log message
* Additional guarding when trying to find the geometrical location of a simulation cell
* Add extra safeguarding for init/restart file access in opm common. Only support unified restart files.
This commit is contained in:
jonjenssen
2024-08-28 18:22:57 +02:00
committed by GitHub
parent 27c46a65fd
commit 0572069511
24 changed files with 670 additions and 78 deletions

View File

@@ -22,6 +22,7 @@ set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RigEclipseWellLogExtractor.h
${CMAKE_CURRENT_LIST_DIR}/RigLocalGrid.h
${CMAKE_CURRENT_LIST_DIR}/RigMainGrid.h
${CMAKE_CURRENT_LIST_DIR}/RigActiveCellGrid.h
${CMAKE_CURRENT_LIST_DIR}/RigReservoirBuilderMock.h
${CMAKE_CURRENT_LIST_DIR}/RigCaseCellResultsData.h
${CMAKE_CURRENT_LIST_DIR}/RigSimWellData.h
@@ -124,6 +125,7 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RigEclipseWellLogExtractor.cpp
${CMAKE_CURRENT_LIST_DIR}/RigLocalGrid.cpp
${CMAKE_CURRENT_LIST_DIR}/RigMainGrid.cpp
${CMAKE_CURRENT_LIST_DIR}/RigActiveCellGrid.cpp
${CMAKE_CURRENT_LIST_DIR}/RigReservoirBuilderMock.cpp
${CMAKE_CURRENT_LIST_DIR}/RigCaseCellResultsData.cpp
${CMAKE_CURRENT_LIST_DIR}/RigSimWellData.cpp

View File

@@ -0,0 +1,164 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2024- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RigActiveCellGrid.h"
#include "RigActiveCellInfo.h"
#include "RigEclipseCaseData.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RigActiveCellGrid::RigActiveCellGrid()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RigActiveCellGrid::~RigActiveCellGrid()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigActiveCellGrid::transferActiveInformation( RigEclipseCaseData* eclipseCaseData,
size_t totalActiveCells,
size_t matrixActiveCells,
size_t fractureActiveCells,
const std::vector<int>& activeMatrixIndexes,
const std::vector<int>& activeFracIndexes )
{
const auto totalCells = activeMatrixIndexes.size();
m_globalToActiveMap.resize( totalCells );
size_t activeCells = 0;
size_t anInactiveCellIdx = 0;
for ( size_t i = 0; i < totalCells; i++ )
{
if ( ( activeMatrixIndexes[i] < 0 ) && ( activeFracIndexes[i] < 0 ) )
{
m_globalToActiveMap[i] = totalActiveCells;
anInactiveCellIdx = i;
continue;
}
m_activeToGlobalMap.push_back( i );
m_globalToActiveMap[i] = activeCells++;
}
m_activeToGlobalMap.push_back( anInactiveCellIdx );
RigActiveCellInfo* activeCellInfo = eclipseCaseData->activeCellInfo( RiaDefines::PorosityModelType::MATRIX_MODEL );
RigActiveCellInfo* fractureActiveCellInfo = eclipseCaseData->activeCellInfo( RiaDefines::PorosityModelType::FRACTURE_MODEL );
activeCellInfo->setReservoirCellCount( totalActiveCells + 1 );
fractureActiveCellInfo->setReservoirCellCount( totalActiveCells + 1 );
activeCellInfo->setGridCount( 1 );
fractureActiveCellInfo->setGridCount( 1 );
activeCellInfo->setGridActiveCellCounts( 0, matrixActiveCells );
fractureActiveCellInfo->setGridActiveCellCounts( 0, fractureActiveCells );
#pragma omp parallel for
for ( int opmCellIndex = 0; opmCellIndex < (int)totalCells; opmCellIndex++ )
{
auto activeCellIndex = m_globalToActiveMap[opmCellIndex];
// active cell index
int matrixActiveIndex = activeMatrixIndexes[opmCellIndex];
if ( matrixActiveIndex != -1 )
{
activeCellInfo->setCellResultIndex( activeCellIndex, matrixActiveIndex );
}
int fractureActiveIndex = activeFracIndexes[opmCellIndex];
if ( fractureActiveIndex != -1 )
{
fractureActiveCellInfo->setCellResultIndex( activeCellIndex, fractureActiveIndex );
}
}
activeCellInfo->computeDerivedData();
fractureActiveCellInfo->computeDerivedData();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t RigActiveCellGrid::cellIndexFromIJK( size_t i, size_t j, size_t k ) const
{
auto index = RigGridBase::cellIndexFromIJK( i, j, k );
return m_globalToActiveMap[index];
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t RigActiveCellGrid::cellIndexFromIJKUnguarded( size_t i, size_t j, size_t k ) const
{
auto index = RigGridBase::cellIndexFromIJKUnguarded( i, j, k );
return m_globalToActiveMap[index];
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RigActiveCellGrid::ijkFromCellIndex( size_t cellIndex, size_t* i, size_t* j, size_t* k ) const
{
if ( cellIndex >= m_activeToGlobalMap.size() )
{
return false;
}
auto index = m_activeToGlobalMap[cellIndex];
return RigGridBase::ijkFromCellIndex( index, i, j, k );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigActiveCellGrid::ijkFromCellIndexUnguarded( size_t cellIndex, size_t* i, size_t* j, size_t* k ) const
{
auto index = m_activeToGlobalMap[cellIndex];
RigGridBase::ijkFromCellIndexUnguarded( index, i, j, k );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RigCell& RigActiveCellGrid::cell( size_t gridLocalCellIndex )
{
return m_cells[gridLocalCellIndex];
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const RigCell& RigActiveCellGrid::cell( size_t gridLocalCellIndex ) const
{
return m_cells[gridLocalCellIndex];
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t RigActiveCellGrid::cellCount() const
{
return m_cells.size();
}

View File

@@ -0,0 +1,51 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2024- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RigMainGrid.h"
#include <vector>
class RigActiveCellGrid : public RigMainGrid
{
public:
RigActiveCellGrid();
~RigActiveCellGrid() override;
void transferActiveInformation( RigEclipseCaseData* eclipseCaseData,
size_t totalActiveCells,
size_t matrixActiveCells,
size_t fractureActiveCells,
const std::vector<int>& activeMatrixIndexes,
const std::vector<int>& activeFracIndexes );
size_t cellIndexFromIJK( size_t i, size_t j, size_t k ) const override;
size_t cellIndexFromIJKUnguarded( size_t i, size_t j, size_t k ) const override;
bool ijkFromCellIndex( size_t cellIndex, size_t* i, size_t* j, size_t* k ) const override;
void ijkFromCellIndexUnguarded( size_t cellIndex, size_t* i, size_t* j, size_t* k ) const override;
RigCell& cell( size_t gridLocalCellIndex ) override;
const RigCell& cell( size_t gridLocalCellIndex ) const override;
size_t cellCount() const override;
private:
std::vector<size_t> m_globalToActiveMap;
std::vector<size_t> m_activeToGlobalMap;
RigCell m_invalidCell;
};

View File

@@ -333,12 +333,12 @@ const cvf::UIntArray* RigEclipseCaseData::gridCellToResultWellIndex( size_t grid
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const RigCell& RigEclipseCaseData::cellFromWellResultCell( const RigWellResultPoint& wellResultCell ) const
const RigCell& RigEclipseCaseData::cellFromWellResultCell( const RigWellResultPoint& wellResultPoint ) const
{
CVF_ASSERT( wellResultCell.isCell() );
CVF_ASSERT( wellResultPoint.isCell() );
size_t gridIndex = wellResultCell.gridIndex();
size_t gridCellIndex = wellResultCell.cellIndex();
size_t gridIndex = wellResultPoint.gridIndex();
size_t gridCellIndex = wellResultPoint.cellIndex();
std::vector<const RigGridBase*> grids;
allGrids( &grids );
@@ -429,12 +429,13 @@ void RigEclipseCaseData::computeActiveCellIJKBBox()
CellRangeBB matrixModelActiveBB;
CellRangeBB fractureModelActiveBB;
size_t idx;
for ( idx = 0; idx < m_mainGrid->cellCount(); idx++ )
for ( size_t idx = 0; idx < m_mainGrid->cellCount(); idx++ )
{
size_t i, j, k;
m_mainGrid->ijkFromCellIndex( idx, &i, &j, &k );
if ( !m_mainGrid->isCellValid( i, j, k ) ) continue;
if ( m_activeCellInfo->isActive( idx ) )
{
matrixModelActiveBB.add( i, j, k );
@@ -724,13 +725,16 @@ void RigEclipseCaseData::computeActiveCellsGeometryBoundingBoxOptimized()
{
for ( size_t j = minBB.y(); j <= maxBB.y(); j++ )
{
size_t cellIndex = m_mainGrid->cellIndexFromIJK( i, j, k );
std::array<cvf::Vec3d, 8> hexCorners;
m_mainGrid->cellCornerVertices( cellIndex, hexCorners.data() );
for ( const auto& corner : hexCorners )
if ( m_mainGrid->isCellValid( i, j, k ) )
{
bb.add( corner );
size_t cellIndex = m_mainGrid->cellIndexFromIJK( i, j, k );
std::array<cvf::Vec3d, 8> hexCorners;
m_mainGrid->cellCornerVertices( cellIndex, hexCorners.data() );
for ( const auto& corner : hexCorners )
{
bb.add( corner );
}
}
}
}

View File

@@ -98,7 +98,7 @@ public:
const cvf::UByteArray* wellCellsInGrid( size_t gridIndex );
const cvf::UIntArray* gridCellToResultWellIndex( size_t gridIndex );
const RigCell& cellFromWellResultCell( const RigWellResultPoint& wellResultCell ) const;
const RigCell& cellFromWellResultCell( const RigWellResultPoint& wellResultPoint ) const;
bool findSharedSourceFace( cvf::StructGridInterface::FaceType& sharedSourceFace,
const RigWellResultPoint& sourceWellCellResult,
const RigWellResultPoint& otherWellCellResult ) const;

View File

@@ -208,7 +208,7 @@ void RigGridBase::cellMinMaxCordinates( size_t cellIndex, cvf::Vec3d* minCoordin
//--------------------------------------------------------------------------------------------------
bool RigGridBase::ijkFromCellIndex( size_t cellIndex, size_t* i, size_t* j, size_t* k ) const
{
CVF_TIGHT_ASSERT( cellIndex < cellCount() );
CVF_TIGHT_ASSERT( cellIndex < RigGridBase::cellCount() );
size_t index = cellIndex;
@@ -413,6 +413,27 @@ double RigGridBase::characteristicIJCellSize() const
return characteristicCellSize;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigGridBase::characteristicCellSizes( double* iSize, double* jSize, double* kSize ) const
{
CVF_ASSERT( iSize && jSize && kSize );
if ( !hasValidCharacteristicCellSizes() )
{
std::vector<size_t> reservoirCellIndices;
reservoirCellIndices.resize( cellCount() );
std::iota( reservoirCellIndices.begin(), reservoirCellIndices.end(), 0 );
computeCharacteristicCellSize( reservoirCellIndices );
}
*iSize = m_characteristicCellSizeI;
*jSize = m_characteristicCellSizeJ;
*kSize = m_characteristicCellSizeK;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@@ -49,9 +49,11 @@ public:
size_t cellCountJ() const override;
size_t cellCountK() const override;
size_t cellCount() const;
RigCell& cell( size_t gridLocalCellIndex );
const RigCell& cell( size_t gridLocalCellIndex ) const;
virtual size_t cellCount() const;
virtual RigCell& cell( size_t gridLocalCellIndex );
virtual const RigCell& cell( size_t gridLocalCellIndex ) const;
void characteristicCellSizes( double* iSize, double* jSize, double* kSize ) const override;
size_t reservoirCellIndex( size_t gridLocalCellIndex ) const;
void setIndexToStartOfCells( size_t indexToStartOfCells ) { m_indexToStartOfCells = indexToStartOfCells; }
@@ -91,20 +93,20 @@ public:
cvf::Vec3d maxCoordinate() const override;
cvf::Vec3d displayModelOffset() const override;
size_t cellIndexFromIJK( size_t i, size_t j, size_t k ) const override;
size_t cellIndexFromIJKUnguarded( size_t i, size_t j, size_t k ) const;
bool ijkFromCellIndex( size_t cellIndex, size_t* i, size_t* j, size_t* k ) const override;
void ijkFromCellIndexUnguarded( size_t cellIndex, size_t* i, size_t* j, size_t* k ) const;
size_t cellIndexFromIJK( size_t i, size_t j, size_t k ) const override;
virtual size_t cellIndexFromIJKUnguarded( size_t i, size_t j, size_t k ) const;
bool ijkFromCellIndex( size_t cellIndex, size_t* i, size_t* j, size_t* k ) const override;
virtual void ijkFromCellIndexUnguarded( size_t cellIndex, size_t* i, size_t* j, size_t* k ) const;
std::optional<caf::VecIjk> ijkFromCellIndex( size_t cellIndex ) const;
std::optional<caf::VecIjk> ijkFromCellIndexOneBased( size_t cellIndex ) const;
bool cellIJKFromCoordinate( const cvf::Vec3d& coord, size_t* i, size_t* j, size_t* k ) const override;
bool cellIJKFromCoordinate( const cvf::Vec3d& coord, size_t* i, size_t* j, size_t* k ) const override; // unused
void cellMinMaxCordinates( size_t cellIndex, cvf::Vec3d* minCoordinate, cvf::Vec3d* maxCoordinate ) const override; // unused
void cellCornerVertices( size_t cellIndex, cvf::Vec3d vertices[8] ) const override;
cvf::Vec3d cellCentroid( size_t cellIndex ) const override;
void cellMinMaxCordinates( size_t cellIndex, cvf::Vec3d* minCoordinate, cvf::Vec3d* maxCoordinate ) const override;
size_t gridPointIndexFromIJK( size_t i, size_t j, size_t k ) const override;
cvf::Vec3d gridPointCoordinate( size_t i, size_t j, size_t k ) const override;

View File

@@ -43,20 +43,20 @@ public:
RigMainGrid();
~RigMainGrid() override;
public:
std::vector<cvf::Vec3d>& nodes();
const std::vector<cvf::Vec3d>& nodes() const;
std::vector<RigCell>& globalCellArray();
const std::vector<RigCell>& globalCellArray() const;
RigGridBase* gridAndGridLocalIdxFromGlobalCellIdx( size_t globalCellIdx, size_t* gridLocalCellIdx );
const RigGridBase* gridAndGridLocalIdxFromGlobalCellIdx( size_t globalCellIdx, size_t* gridLocalCellIdx ) const;
virtual RigGridBase* gridAndGridLocalIdxFromGlobalCellIdx( size_t globalCellIdx, size_t* gridLocalCellIdx );
virtual const RigGridBase* gridAndGridLocalIdxFromGlobalCellIdx( size_t globalCellIdx, size_t* gridLocalCellIdx ) const;
const RigCell& cellByGridAndGridLocalCellIdx( size_t gridIdx, size_t gridLocalCellIdx ) const;
size_t reservoirCellIndexByGridAndGridLocalCellIndex( size_t gridIdx, size_t gridLocalCellIdx ) const;
size_t findReservoirCellIndexFromPoint( const cvf::Vec3d& point ) const;
void addLocalGrid( RigLocalGrid* localGrid );
virtual const RigCell& cellByGridAndGridLocalCellIdx( size_t gridIdx, size_t gridLocalCellIdx ) const;
virtual size_t reservoirCellIndexByGridAndGridLocalCellIndex( size_t gridIdx, size_t gridLocalCellIdx ) const;
virtual size_t findReservoirCellIndexFromPoint( const cvf::Vec3d& point ) const;
void addLocalGrid( RigLocalGrid* localGrid );
size_t gridCountOnFile() const;
size_t gridCount() const;
@@ -114,7 +114,7 @@ public:
bool isDualPorosity() const;
void setDualPorosity( bool enable );
private:
protected:
void initAllSubCellsMainGridCellIndex();
void buildCellSearchTree();
void buildCellSearchTreeOptimized( size_t cellsPerBoundingBox );
@@ -123,7 +123,7 @@ private:
static std::array<double, 6> defaultMapAxes();
private:
protected:
std::vector<cvf::Vec3d> m_nodes; ///< Global vertex table
std::vector<RigCell> m_cells; ///< Global array of all cells in the reservoir (including the ones in LGR's)
cvf::Collection<RigLocalGrid> m_localGrids; ///< List of all the LGR's in this reservoir

View File

@@ -243,7 +243,10 @@ void RigSimulationWellCenterLineCalculator::calculateWellPipeCenterlineForTimeSt
// Well head
// Match this position with well head position in RivWellHeadPartMgr::buildWellHeadParts()
const RigCell& whCell = eclipseCaseData->cellFromWellResultCell( wellFrame.wellHeadOrStartCell() );
auto wellPoint = wellFrame.wellHeadOrStartCell();
if ( !wellPoint.isCell() ) return;
const RigCell& whCell = eclipseCaseData->cellFromWellResultCell( wellPoint );
cvf::Vec3d whStartPos = whCell.faceCenter( cvf::StructGridInterface::NEG_K );
RigWellResultPoint wellHead = wellFrame.wellHeadOrStartCell();

View File

@@ -101,7 +101,7 @@ RigWellResultPoint RigWellResultFrame::wellHeadOrStartCell() const
}
}
return m_wellHead; // Nothing else to do
return RigWellResultPoint(); // Nothing else matters
}
//--------------------------------------------------------------------------------------------------