mirror of
https://github.com/OPM/ResInsight.git
synced 2025-01-03 20:57:39 -06:00
4365b0dfb9
* Update opm-common EGRID reader to support LGRs, NNCs, dual porosity, unit system info and time step filters * Rearrange well reading code into separate class * Update resdata library to not require an ecl_grid when reading well information. Only lgr names are needed, allows reused by opm_common reader
348 lines
13 KiB
C++
348 lines
13 KiB
C++
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (C) 2011-2012 Statoil ASA, Ceetron AS
|
|
//
|
|
// 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 "RigSimWellData.h"
|
|
#include "RigWellResultFrame.h"
|
|
#include "RigWellResultPoint.h"
|
|
|
|
#include <map>
|
|
|
|
#include <QDebug>
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RigSimWellData::RigSimWellData()
|
|
: m_isMultiSegmentWell( false )
|
|
{
|
|
m_staticWellCells = std::make_unique<RigWellResultFrame>();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
const RigWellResultFrame* RigSimWellData::wellResultFrame( size_t resultTimeStepIndex ) const
|
|
{
|
|
CVF_ASSERT( resultTimeStepIndex < m_resultTimeStepIndexToWellTimeStepIndex.size() );
|
|
|
|
size_t wellTimeStepIndex = m_resultTimeStepIndexToWellTimeStepIndex[resultTimeStepIndex];
|
|
CVF_ASSERT( wellTimeStepIndex < m_wellCellsTimeSteps.size() );
|
|
|
|
return &( m_wellCellsTimeSteps[wellTimeStepIndex] );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RigSimWellData::computeMappingFromResultTimeIndicesToWellTimeIndices( const std::vector<QDateTime>& simulationTimeSteps )
|
|
{
|
|
m_resultTimeStepIndexToWellTimeStepIndex.clear();
|
|
if ( m_wellCellsTimeSteps.empty() ) return;
|
|
|
|
m_resultTimeStepIndexToWellTimeStepIndex.resize( simulationTimeSteps.size(), cvf::UNDEFINED_SIZE_T );
|
|
|
|
size_t wellTimeStepIndex = 0;
|
|
for ( size_t resultTimeStepIndex = 0; resultTimeStepIndex < simulationTimeSteps.size(); resultTimeStepIndex++ )
|
|
{
|
|
while ( wellTimeStepIndex < m_wellCellsTimeSteps.size() &&
|
|
m_wellCellsTimeSteps[wellTimeStepIndex].timestamp() < simulationTimeSteps[resultTimeStepIndex] )
|
|
{
|
|
wellTimeStepIndex++;
|
|
}
|
|
|
|
if ( ( wellTimeStepIndex < m_wellCellsTimeSteps.size() ) &&
|
|
( m_wellCellsTimeSteps[wellTimeStepIndex].timestamp() == simulationTimeSteps[resultTimeStepIndex] ) )
|
|
{
|
|
m_resultTimeStepIndexToWellTimeStepIndex[resultTimeStepIndex] = wellTimeStepIndex;
|
|
}
|
|
else
|
|
{
|
|
m_resultTimeStepIndexToWellTimeStepIndex[resultTimeStepIndex] = cvf::UNDEFINED_SIZE_T;
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RigSimWellData::hasWellResult( size_t resultTimeStepIndex ) const
|
|
{
|
|
if ( resultTimeStepIndex >= m_resultTimeStepIndexToWellTimeStepIndex.size() )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
size_t wellTimeStepIndex = m_resultTimeStepIndexToWellTimeStepIndex[resultTimeStepIndex];
|
|
|
|
return wellTimeStepIndex != cvf::UNDEFINED_SIZE_T;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RigSimWellData::hasAnyValidCells( size_t resultTimeStepIndex ) const
|
|
{
|
|
if ( resultTimeStepIndex >= m_resultTimeStepIndexToWellTimeStepIndex.size() )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
size_t wellTimeStepIndex = m_resultTimeStepIndexToWellTimeStepIndex[resultTimeStepIndex];
|
|
|
|
if ( wellTimeStepIndex == cvf::UNDEFINED_SIZE_T ) return false;
|
|
|
|
if ( wellResultFrame( resultTimeStepIndex )->wellHead().isCell() ) return true;
|
|
|
|
const std::vector<RigWellResultBranch> resBranches = wellResultFrame( resultTimeStepIndex )->wellResultBranches();
|
|
for ( const auto& branch : resBranches )
|
|
{
|
|
for ( const auto& branchResPoint : branch.branchResultPoints() )
|
|
{
|
|
if ( branchResPoint.isCell() ) return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool operator==( const RigWellResultPoint& p1, const RigWellResultPoint& p2 )
|
|
{
|
|
// TODO : Remove when <=> operator has been added to RigWellResultPoint
|
|
return p1.gridIndex() == p2.gridIndex() && p1.cellIndex() == p2.cellIndex() && p1.branchId() == p2.branchId() &&
|
|
p1.segmentId() == p2.segmentId();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RigSimWellData::computeStaticWellCellPath() const
|
|
{
|
|
if ( m_wellCellsTimeSteps.empty() ) return;
|
|
|
|
// Mapping of Branch ERT ID to ResultPoint list
|
|
std::map<int, std::list<RigWellResultPoint>> staticWellBranches;
|
|
|
|
// Add ResultCell data from the first timestep to the final result.
|
|
for ( const auto& wellResultBranch : m_wellCellsTimeSteps[0].wellResultBranches() )
|
|
{
|
|
const int branchErtId = wellResultBranch.ertBranchId();
|
|
std::list<RigWellResultPoint>& branch = staticWellBranches[branchErtId];
|
|
|
|
for ( const auto& frameCell : wellResultBranch.branchResultPoints() )
|
|
{
|
|
branch.push_back( frameCell );
|
|
}
|
|
}
|
|
|
|
bool doSkipTimeStep = true;
|
|
for ( const auto& wellCellsTimeStep : m_wellCellsTimeSteps )
|
|
{
|
|
if ( doSkipTimeStep ) // Skip first
|
|
{
|
|
doSkipTimeStep = false;
|
|
continue;
|
|
}
|
|
|
|
// Merge well branches separately
|
|
for ( const auto& wellResultBranch : wellCellsTimeStep.wellResultBranches() )
|
|
{
|
|
const int branchId = wellResultBranch.ertBranchId();
|
|
const std::vector<RigWellResultPoint> resBranch = wellResultBranch.branchResultPoints();
|
|
|
|
std::list<RigWellResultPoint>& stBranch = staticWellBranches[branchId];
|
|
std::list<RigWellResultPoint>::iterator sEndIt;
|
|
size_t rStartIdx = -1;
|
|
size_t rEndIdx = -1;
|
|
|
|
// First detect if we have cells on the start of the result frame, that is not in the static frame
|
|
{
|
|
sEndIt = stBranch.begin();
|
|
bool found = false;
|
|
if ( !stBranch.empty() )
|
|
{
|
|
for ( rEndIdx = 0; !found && rEndIdx < resBranch.size(); ++rEndIdx )
|
|
{
|
|
if ( ( *sEndIt ) == ( resBranch[rEndIdx] ) )
|
|
{
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( found )
|
|
{
|
|
if ( rEndIdx > 0 )
|
|
{
|
|
// Found cells in start, merge them in
|
|
for ( size_t cIdx = 0; cIdx < rEndIdx; ++cIdx )
|
|
{
|
|
stBranch.insert( sEndIt, resBranch[cIdx] );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// The result probably starts later in the well
|
|
rEndIdx = 0;
|
|
}
|
|
|
|
rStartIdx = rEndIdx;
|
|
}
|
|
|
|
// Now find all result cells in ranges between pairs in the static path
|
|
// If the result has items that "compete" with those in the static path,
|
|
// those items are inserted after the ones in the static path. This
|
|
// is not necessarily correct. They could be in front, and also merged in
|
|
// strange ways. A geometric test could make this more robust, but we will
|
|
// not solve before we see that it actually ends up as a problem
|
|
|
|
if ( sEndIt != stBranch.end() ) ++sEndIt;
|
|
for ( ; sEndIt != stBranch.end(); ++sEndIt )
|
|
{
|
|
bool found = false;
|
|
for ( rEndIdx += 1; !found && rEndIdx < resBranch.size(); ++rEndIdx )
|
|
{
|
|
if ( ( *sEndIt ) == ( resBranch[rEndIdx] ) )
|
|
{
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( found )
|
|
{
|
|
if ( rEndIdx - rStartIdx > 1 )
|
|
{
|
|
// Found cell range in result that we do not have in the static result, merge them in
|
|
for ( size_t cIdx = rStartIdx + 1; cIdx < rEndIdx; ++cIdx )
|
|
{
|
|
stBranch.insert( sEndIt, resBranch[cIdx] );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// The static path probably has some extra cells
|
|
rEndIdx = rStartIdx;
|
|
}
|
|
|
|
rStartIdx = rEndIdx;
|
|
}
|
|
|
|
// Then add cells from the end of the resultpath not present in the static path
|
|
for ( size_t cIdx = rEndIdx + 1; cIdx < resBranch.size(); ++cIdx )
|
|
{
|
|
stBranch.push_back( resBranch[cIdx] );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Populate the static well info
|
|
|
|
m_staticWellCells->clearWellResultBranches();
|
|
m_staticWellCells->setWellHead( m_wellCellsTimeSteps[0].wellHead() );
|
|
|
|
for ( const auto& [ertBranchId, resultPoints] : staticWellBranches )
|
|
{
|
|
// Copy from first time step
|
|
RigWellResultBranch rigBranch;
|
|
rigBranch.setErtBranchId( ertBranchId );
|
|
|
|
for ( const auto& resultPoint : resultPoints )
|
|
{
|
|
rigBranch.addBranchResultPoint( resultPoint );
|
|
}
|
|
|
|
m_staticWellCells->addWellResultBranch( rigBranch );
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RigSimWellData::setMultiSegmentWell( bool isMultiSegmentWell )
|
|
{
|
|
m_isMultiSegmentWell = isMultiSegmentWell;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RigSimWellData::isMultiSegmentWell() const
|
|
{
|
|
return m_isMultiSegmentWell;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RigSimWellData::setWellName( const QString& wellName )
|
|
{
|
|
m_wellName = wellName;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RiaDefines::WellProductionType RigSimWellData::wellProductionType( size_t resultTimeStepIndex ) const
|
|
{
|
|
if ( hasWellResult( resultTimeStepIndex ) )
|
|
{
|
|
const RigWellResultFrame* wResFrame = wellResultFrame( resultTimeStepIndex );
|
|
return wResFrame->productionType();
|
|
}
|
|
else
|
|
{
|
|
return RiaDefines::WellProductionType::UNDEFINED_PRODUCTION_TYPE;
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
const RigWellResultFrame* RigSimWellData::staticWellResultFrame() const
|
|
{
|
|
// Make sure we have computed the static representation of the well
|
|
if ( m_staticWellCells->wellResultBranches().empty() )
|
|
{
|
|
computeStaticWellCellPath();
|
|
}
|
|
|
|
return m_staticWellCells.get();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RigSimWellData::isOpen( size_t resultTimeStepIndex ) const
|
|
{
|
|
if ( hasWellResult( resultTimeStepIndex ) )
|
|
{
|
|
const RigWellResultFrame* wResFrame = wellResultFrame( resultTimeStepIndex );
|
|
return wResFrame->isOpen();
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|