2017-01-31 08:28:15 -06:00
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017 Statoil 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 "RigAccWellFlowCalculator.h"
# include "RigSingleWellResultsData.h"
2017-02-17 04:13:27 -06:00
# include "RigMainGrid.h"
# include "RigActiveCellInfo.h"
# include "RigFlowDiagResults.h"
2017-02-18 17:48:07 -06:00
# include "RigSimulationWellCoordsAndMD.h"
2017-01-31 08:28:15 -06:00
2017-02-17 04:13:27 -06:00
//==================================================================================================
///
///
//==================================================================================================
2017-01-31 08:28:15 -06:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-02-17 04:13:27 -06:00
size_t RigEclCellIndexCalculator : : resultCellIndex ( size_t gridIndex , size_t gridCellIndex ) const
{
const RigGridBase * grid = m_mainGrid - > gridByIndex ( gridIndex ) ;
size_t reservoirCellIndex = grid - > reservoirCellIndex ( gridCellIndex ) ;
return m_activeCellInfo - > cellResultIndex ( reservoirCellIndex ) ;
}
//==================================================================================================
///
///
//==================================================================================================
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RigAccWellFlowCalculator : : RigAccWellFlowCalculator ( const std : : vector < std : : vector < cvf : : Vec3d > > & pipeBranchesCLCoords ,
const std : : vector < std : : vector < RigWellResultPoint > > & pipeBranchesCellIds ,
const std : : map < QString , const std : : vector < double > * > & tracerCellFractionValues ,
2017-03-03 09:23:20 -06:00
const RigEclCellIndexCalculator & cellIndexCalculator ,
2017-02-15 05:29:36 -06:00
double smallContribThreshold ,
2017-02-17 04:13:27 -06:00
bool isProducer )
: m_pipeBranchesCLCoords ( pipeBranchesCLCoords ) ,
m_pipeBranchesCellIds ( pipeBranchesCellIds ) ,
m_tracerCellFractionValues ( & tracerCellFractionValues ) ,
m_cellIndexCalculator ( cellIndexCalculator ) ,
2017-03-09 10:04:43 -06:00
m_smallContributionsThreshold ( smallContribThreshold ) ,
m_isProducer ( isProducer )
2017-01-31 08:28:15 -06:00
{
2017-02-17 08:48:42 -06:00
m_connectionFlowPrBranch . resize ( m_pipeBranchesCellIds . size ( ) ) ;
2017-02-18 17:48:07 -06:00
m_pseudoLengthFlowPrBranch . resize ( m_pipeBranchesCellIds . size ( ) ) ;
2017-02-03 08:51:42 -06:00
2017-02-15 05:29:36 -06:00
2017-03-10 04:50:17 -06:00
for ( const auto & it : ( * m_tracerCellFractionValues ) ) m_tracerNames . push_back ( it . first ) ;
2017-02-15 05:29:36 -06:00
2017-03-10 04:50:17 -06:00
m_tracerNames . push_back ( RIG_RESERVOIR_TRACER_NAME ) ;
2017-02-15 05:29:36 -06:00
2017-03-10 04:50:17 -06:00
calculateAccumulatedFlowPrConnection ( 0 , 1 ) ;
calculateFlowPrPseudoLength ( 0 , 0.0 ) ;
sortTracers ( ) ;
groupSmallContributions ( ) ;
2017-02-18 17:48:07 -06:00
2017-01-31 08:28:15 -06:00
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-02-15 01:46:23 -06:00
RigAccWellFlowCalculator : : RigAccWellFlowCalculator ( const std : : vector < std : : vector < cvf : : Vec3d > > & pipeBranchesCLCoords ,
2017-02-17 04:13:27 -06:00
const std : : vector < std : : vector < RigWellResultPoint > > & pipeBranchesCellIds ,
double smallContribThreshold )
: m_pipeBranchesCLCoords ( pipeBranchesCLCoords ) ,
m_pipeBranchesCellIds ( pipeBranchesCellIds ) ,
m_tracerCellFractionValues ( nullptr ) ,
m_cellIndexCalculator ( RigEclCellIndexCalculator ( nullptr , nullptr ) ) ,
2017-03-09 10:04:43 -06:00
m_smallContributionsThreshold ( smallContribThreshold ) ,
m_isProducer ( true )
2017-01-31 08:28:15 -06:00
{
2017-02-17 08:48:42 -06:00
m_connectionFlowPrBranch . resize ( m_pipeBranchesCellIds . size ( ) ) ;
2017-02-18 17:48:07 -06:00
m_pseudoLengthFlowPrBranch . resize ( m_pipeBranchesCellIds . size ( ) ) ;
2017-02-15 05:29:36 -06:00
2017-02-03 08:51:42 -06:00
m_tracerNames . push_back ( RIG_FLOW_TOTAL_NAME ) ;
2017-02-15 05:29:36 -06:00
2017-01-31 08:28:15 -06:00
calculateAccumulatedFlowPrConnection ( 0 , 1 ) ;
2017-02-18 17:48:07 -06:00
calculateFlowPrPseudoLength ( 0 , 0.0 ) ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std : : vector < double > & RigAccWellFlowCalculator : : connectionNumbersFromTop ( size_t branchIdx ) const
{
return m_connectionFlowPrBranch [ branchIdx ] . depthValuesFromTop ;
2017-01-31 08:28:15 -06:00
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-02-17 08:48:42 -06:00
const std : : vector < double > & RigAccWellFlowCalculator : : accumulatedFlowPrConnection ( size_t branchIdx ) const
2017-01-31 08:28:15 -06:00
{
2017-02-17 08:48:42 -06:00
return accumulatedTracerFlowPrConnection ( RIG_FLOW_TOTAL_NAME , branchIdx ) ;
}
2017-01-31 08:28:15 -06:00
2017-02-17 08:48:42 -06:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std : : vector < double > & RigAccWellFlowCalculator : : accumulatedTracerFlowPrConnection ( const QString & tracerName , size_t branchIdx ) const
{
auto flowPrTracerIt = m_connectionFlowPrBranch [ branchIdx ] . accFlowPrTracer . find ( tracerName ) ;
if ( flowPrTracerIt ! = m_connectionFlowPrBranch [ branchIdx ] . accFlowPrTracer . end ( ) )
{
return flowPrTracerIt - > second ;
}
else
{
CVF_ASSERT ( false ) ;
static std : : vector < double > dummy ;
return dummy ;
}
2017-01-31 08:28:15 -06:00
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-02-17 08:48:42 -06:00
const std : : vector < double > & RigAccWellFlowCalculator : : flowPrConnection ( size_t branchIdx ) const
2017-01-31 08:28:15 -06:00
{
2017-02-17 08:48:42 -06:00
return tracerFlowPrConnection ( RIG_FLOW_TOTAL_NAME , branchIdx ) ;
}
2017-01-31 08:28:15 -06:00
2017-02-17 08:48:42 -06:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std : : vector < double > & RigAccWellFlowCalculator : : tracerFlowPrConnection ( const QString & tracerName , size_t branchIdx ) const
{
auto flowPrTracerIt = m_connectionFlowPrBranch [ branchIdx ] . flowPrTracer . find ( tracerName ) ;
if ( flowPrTracerIt ! = m_connectionFlowPrBranch [ branchIdx ] . flowPrTracer . end ( ) )
{
return flowPrTracerIt - > second ;
}
else
{
CVF_ASSERT ( false ) ;
static std : : vector < double > dummy ;
return dummy ;
}
2017-01-31 08:28:15 -06:00
}
2017-02-18 17:48:07 -06:00
2017-01-31 08:28:15 -06:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-02-18 17:48:07 -06:00
const std : : vector < double > & RigAccWellFlowCalculator : : pseudoLengthFromTop ( size_t branchIdx ) const
2017-01-31 08:28:15 -06:00
{
2017-02-18 17:48:07 -06:00
return m_pseudoLengthFlowPrBranch [ branchIdx ] . depthValuesFromTop ;
2017-01-31 08:28:15 -06:00
}
2017-03-01 09:00:32 -06:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std : : vector < double > & RigAccWellFlowCalculator : : trueVerticalDepth ( size_t branchIdx ) const
{
return m_pseudoLengthFlowPrBranch [ branchIdx ] . trueVerticalDepth ;
}
2017-02-18 17:48:07 -06:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std : : vector < double > & RigAccWellFlowCalculator : : accumulatedFlowPrPseudoLength ( size_t branchIdx ) const
{
2017-02-27 07:00:41 -06:00
return accumulatedTracerFlowPrPseudoLength ( RIG_FLOW_TOTAL_NAME , branchIdx ) ;
2017-02-18 17:48:07 -06:00
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std : : vector < double > & RigAccWellFlowCalculator : : accumulatedTracerFlowPrPseudoLength ( const QString & tracerName , size_t branchIdx ) const
{
auto flowPrTracerIt = m_pseudoLengthFlowPrBranch [ branchIdx ] . accFlowPrTracer . find ( tracerName ) ;
if ( flowPrTracerIt ! = m_pseudoLengthFlowPrBranch [ branchIdx ] . accFlowPrTracer . end ( ) )
{
return flowPrTracerIt - > second ;
}
else
{
CVF_ASSERT ( false ) ;
static std : : vector < double > dummy ;
return dummy ;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std : : vector < double > & RigAccWellFlowCalculator : : flowPrPseudoLength ( size_t branchIdx ) const
{
2017-02-27 07:00:41 -06:00
return tracerFlowPrPseudoLength ( RIG_FLOW_TOTAL_NAME , branchIdx ) ;
2017-02-18 17:48:07 -06:00
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std : : vector < double > & RigAccWellFlowCalculator : : tracerFlowPrPseudoLength ( const QString & tracerName , size_t branchIdx ) const
{
auto flowPrTracerIt = m_pseudoLengthFlowPrBranch [ branchIdx ] . flowPrTracer . find ( tracerName ) ;
if ( flowPrTracerIt ! = m_pseudoLengthFlowPrBranch [ branchIdx ] . flowPrTracer . end ( ) )
{
return flowPrTracerIt - > second ;
}
else
{
CVF_ASSERT ( false ) ;
static std : : vector < double > dummy ;
return dummy ;
}
}
2017-02-15 01:46:23 -06:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-02-17 08:48:42 -06:00
std : : vector < std : : pair < QString , double > > RigAccWellFlowCalculator : : totalWellFlowPrTracer ( ) const
2017-02-15 01:46:23 -06:00
{
std : : vector < QString > tracerNames = this - > tracerNames ( ) ;
std : : vector < std : : pair < QString , double > > tracerWithValues ;
for ( const QString & tracerName : tracerNames )
{
const std : : vector < double > & accFlow = this - > accumulatedTracerFlowPrConnection ( tracerName , 0 ) ;
tracerWithValues . push_back ( std : : make_pair ( tracerName , accFlow . back ( ) ) ) ;
}
return tracerWithValues ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-02-17 08:48:42 -06:00
std : : vector < std : : pair < QString , double > > RigAccWellFlowCalculator : : totalTracerFractions ( ) const
2017-02-15 01:46:23 -06:00
{
std : : vector < std : : pair < QString , double > > totalFlows = totalWellFlowPrTracer ( ) ;
float sumTracerFlows = 0.0f ;
for ( const auto & tracerVal : totalFlows )
{
sumTracerFlows + = tracerVal . second ;
}
if ( sumTracerFlows = = 0.0 ) totalFlows . clear ( ) ;
for ( auto & tracerPair : totalFlows )
{
tracerPair . second = tracerPair . second / sumTracerFlows ;
}
return totalFlows ;
}
2017-02-17 04:13:27 -06:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-02-17 08:48:42 -06:00
bool RigAccWellFlowCalculator : : isWellFlowConsistent ( bool isProducer ) const
2017-02-15 05:29:36 -06:00
{
bool isConsistent = true ;
for ( const std : : vector < RigWellResultPoint > & branch : m_pipeBranchesCellIds )
{
for ( const RigWellResultPoint & wrp : branch )
{
if ( isProducer )
isConsistent = ( wrp . flowRate ( ) > = 0.0 ) ;
else
isConsistent = ( wrp . flowRate ( ) < = 0.0 ) ;
if ( ! isConsistent ) break ;
}
if ( ! isConsistent ) break ;
}
return isConsistent ;
}
2017-03-10 04:50:17 -06:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std : : vector < double > calculateAccumulatedFractions ( const std : : vector < double > & accumulatedFlowPrTracer )
{
double totalFlow = 0.0 ;
for ( double tracerFlow : accumulatedFlowPrTracer )
{
totalFlow + = tracerFlow ;
}
std : : vector < double > flowFractionsPrTracer ( accumulatedFlowPrTracer . size ( ) , 0.0 ) ;
if ( totalFlow = = 0.0 ) // If we have no accumulated flow, we set all the flow assosciated to the last tracer, which is the reservoir
{
flowFractionsPrTracer . back ( ) = 1.0 ;
return flowFractionsPrTracer ;
}
for ( size_t tIdx = 0 ; tIdx < accumulatedFlowPrTracer . size ( ) ; + + tIdx )
{
double tracerFlow = accumulatedFlowPrTracer [ tIdx ] ;
flowFractionsPrTracer [ tIdx ] = tracerFlow / totalFlow ;
}
return flowFractionsPrTracer ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RigAccWellFlowCalculator : : hasConsistentFlow ( const RigWellResultPoint & wellCell ) const
{
if ( ! m_tracerCellFractionValues ) return true ; // No flow diagnostics.
return ( wellCell . flowRate ( ) > 0.0 & & m_isProducer ) | | ( wellCell . flowRate ( ) < 0.0 & & ! m_isProducer ) ;
}
2017-02-15 01:46:23 -06:00
2017-01-31 08:28:15 -06:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigAccWellFlowCalculator : : calculateAccumulatedFlowPrConnection ( size_t branchIdx , size_t startConnectionNumberFromTop )
{
const std : : vector < RigWellResultPoint > & branchCells = m_pipeBranchesCellIds [ branchIdx ] ;
std : : vector < size_t > resPointToConnectionIndexFromBottom = wrpToConnectionIndexFromBottom ( branchCells ) ;
size_t prevConnIndx = - 1 ;
int clSegIdx = static_cast < int > ( branchCells . size ( ) ) - 1 ;
2017-02-17 08:48:42 -06:00
std : : vector < double > accFlowPrTracer ( m_tracerNames . size ( ) , 0.0 ) ;
2017-01-31 08:28:15 -06:00
while ( clSegIdx > = 0 )
{
// Skip point if referring to the same cell as the previous centerline segment did
{
if ( resPointToConnectionIndexFromBottom [ clSegIdx ] = = prevConnIndx )
{
- - clSegIdx ;
continue ;
}
prevConnIndx = resPointToConnectionIndexFromBottom [ clSegIdx ] ;
}
// Accumulate the connection-cell's fraction flows
2017-03-09 10:04:43 -06:00
const RigWellResultPoint & wellCell = branchCells [ clSegIdx ] ;
2017-03-10 04:50:17 -06:00
std : : vector < double > flowPrTracer = calculateFlowPrTracer ( wellCell , accFlowPrTracer ) ;
2017-02-03 08:51:42 -06:00
2017-03-10 04:50:17 -06:00
for ( size_t tIdx = 0 ; tIdx < flowPrTracer . size ( ) ; + + tIdx )
2017-01-31 08:28:15 -06:00
{
2017-02-17 10:15:48 -06:00
accFlowPrTracer [ tIdx ] + = flowPrTracer [ tIdx ] ;
2017-01-31 08:28:15 -06:00
}
2017-03-10 04:50:17 -06:00
if ( ! hasConsistentFlow ( wellCell ) )
{
// Associate all the flow with the reservoir tracer for inconsistent flow direction
flowPrTracer = std : : vector < double > ( flowPrTracer . size ( ) , 0.0 ) ;
flowPrTracer . back ( ) = wellCell . flowRate ( ) ;
}
2017-01-31 08:28:15 -06:00
// Add the total accumulated (fraction) flows from any branches connected to this cell
size_t connNumFromTop = connectionIndexFromTop ( resPointToConnectionIndexFromBottom , clSegIdx ) + startConnectionNumberFromTop ;
2017-02-18 17:48:07 -06:00
std : : vector < size_t > downStreamBranchIndices = findDownStreamBranchIdxs ( branchCells [ clSegIdx ] ) ;
for ( size_t dsBidx : downStreamBranchIndices )
2017-01-31 08:28:15 -06:00
{
2017-02-18 17:48:07 -06:00
BranchFlow & downStreamBranchFlow = m_connectionFlowPrBranch [ dsBidx ] ;
if ( dsBidx ! = branchIdx & & downStreamBranchFlow . depthValuesFromTop . size ( ) = = 0 ) // Not this branch or already calculated
2017-01-31 08:28:15 -06:00
{
calculateAccumulatedFlowPrConnection ( dsBidx , connNumFromTop ) ;
2017-03-01 09:00:32 -06:00
addDownStreamBranchFlow ( & accFlowPrTracer , downStreamBranchFlow ) ;
2017-01-31 08:28:15 -06:00
}
}
// Push back the accumulated result into the storage
2017-02-18 17:48:07 -06:00
BranchFlow & branchFlow = m_connectionFlowPrBranch [ branchIdx ] ;
2017-03-01 09:00:32 -06:00
storeFlowOnDepth ( & branchFlow , connNumFromTop , accFlowPrTracer , flowPrTracer ) ;
2017-02-18 17:48:07 -06:00
- - clSegIdx ;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigAccWellFlowCalculator : : calculateFlowPrPseudoLength ( size_t branchIdx , double startPseudoLengthFromTop )
{
const std : : vector < RigWellResultPoint > & branchCells = m_pipeBranchesCellIds [ branchIdx ] ;
const std : : vector < cvf : : Vec3d > & branchClPoints = m_pipeBranchesCLCoords [ branchIdx ] ;
RigSimulationWellCoordsAndMD mdCalculator ( branchClPoints ) ;
int clSegIdx = static_cast < int > ( branchCells . size ( ) ) - 1 ;
std : : vector < double > accFlowPrTracer ( m_tracerNames . size ( ) , 0.0 ) ;
BranchFlow & branchFlow = m_pseudoLengthFlowPrBranch [ branchIdx ] ;
2017-02-19 13:57:40 -06:00
RigWellResultPoint previousResultPoint ;
2017-02-18 17:48:07 -06:00
while ( clSegIdx > = 0 )
{
2017-02-27 09:46:34 -06:00
int cellBottomPointIndex = - 1 ;
int cellUpperPointIndex = - 1 ;
int currentSegmentIndex = - 1 ;
2017-02-18 17:48:07 -06:00
2017-02-27 09:46:34 -06:00
// Find the complete cell span
{
cellBottomPointIndex = clSegIdx + 1 ;
previousResultPoint = branchCells [ clSegIdx ] ;
- - clSegIdx ;
while ( clSegIdx > = 0 & & previousResultPoint . isEqual ( branchCells [ clSegIdx ] ) ) { - - clSegIdx ; }
cellUpperPointIndex = clSegIdx + 1 ;
currentSegmentIndex = cellUpperPointIndex ;
}
2017-03-10 04:50:17 -06:00
const RigWellResultPoint & wellCell = branchCells [ currentSegmentIndex ] ;
std : : vector < double > flowPrTracerToAccumulate = calculateFlowPrTracer ( wellCell , accFlowPrTracer ) ;
2017-02-18 17:48:07 -06:00
2017-02-27 09:46:34 -06:00
double pseudoLengthFromTop_lower = mdCalculator . measuredDepths ( ) [ cellBottomPointIndex ] + startPseudoLengthFromTop ;
2017-03-01 09:00:32 -06:00
double tvd_lower = - mdCalculator . wellPathPoints ( ) [ cellBottomPointIndex ] [ 2 ] ;
2017-02-18 17:48:07 -06:00
// Push back the new start-of-cell flow, with the previously accumulated result into the storage
2017-03-10 04:50:17 -06:00
std : : vector < double > flowPrTracer ;
if ( ! hasConsistentFlow ( wellCell ) )
{
// Associate all the flow with the reservoir tracer for inconsistent flow direction
flowPrTracer = std : : vector < double > ( flowPrTracerToAccumulate . size ( ) , 0.0 ) ;
flowPrTracer . back ( ) = wellCell . flowRate ( ) ;
}
else
{
flowPrTracer = flowPrTracerToAccumulate ;
}
2017-03-01 09:00:32 -06:00
storeFlowOnDepthWTvd ( & branchFlow , pseudoLengthFromTop_lower , tvd_lower , accFlowPrTracer , flowPrTracer ) ;
2017-02-18 17:48:07 -06:00
// Accumulate the connection-cell's fraction flows
2017-02-27 09:46:34 -06:00
2017-03-10 04:50:17 -06:00
for ( size_t tIdx = 0 ; tIdx < flowPrTracerToAccumulate . size ( ) ; + + tIdx )
2017-01-31 08:28:15 -06:00
{
2017-03-10 04:50:17 -06:00
accFlowPrTracer [ tIdx ] + = flowPrTracerToAccumulate [ tIdx ] ;
2017-02-18 17:48:07 -06:00
}
2017-02-17 08:48:42 -06:00
2017-02-27 09:46:34 -06:00
double pseudoLengthFromTop_upper = mdCalculator . measuredDepths ( ) [ cellUpperPointIndex ] + startPseudoLengthFromTop ;
2017-03-01 09:00:32 -06:00
double tvd_upper = - mdCalculator . wellPathPoints ( ) [ cellUpperPointIndex ] [ 2 ] ;
2017-02-18 17:48:07 -06:00
2017-02-28 04:46:45 -06:00
// Push back the accumulated result into the storage
2017-03-01 09:00:32 -06:00
storeFlowOnDepthWTvd ( & branchFlow , pseudoLengthFromTop_upper , tvd_upper , accFlowPrTracer , flowPrTracer ) ;
2017-02-28 04:46:45 -06:00
// Add the total accumulated (fraction) flows from any branches connected to this cell
2017-02-27 09:46:34 -06:00
std : : vector < size_t > downStreamBranchIndices = findDownStreamBranchIdxs ( branchCells [ cellUpperPointIndex ] ) ;
2017-02-18 17:48:07 -06:00
for ( size_t dsBidx : downStreamBranchIndices )
{
BranchFlow & downStreamBranchFlow = m_pseudoLengthFlowPrBranch [ dsBidx ] ;
if ( dsBidx ! = branchIdx & & downStreamBranchFlow . depthValuesFromTop . size ( ) = = 0 ) // Not this branch or already calculated
2017-02-17 08:48:42 -06:00
{
2017-02-18 17:48:07 -06:00
calculateFlowPrPseudoLength ( dsBidx , pseudoLengthFromTop_upper ) ;
2017-03-01 09:00:32 -06:00
addDownStreamBranchFlow ( & accFlowPrTracer , downStreamBranchFlow ) ;
2017-02-17 08:48:42 -06:00
}
}
2017-01-31 08:28:15 -06:00
2017-02-28 04:46:45 -06:00
// Push back the accumulated result after adding the branch result into the storage
2017-02-18 17:48:07 -06:00
2017-03-01 09:00:32 -06:00
if ( downStreamBranchIndices . size ( ) ) storeFlowOnDepthWTvd ( & branchFlow , pseudoLengthFromTop_upper , tvd_upper , accFlowPrTracer , flowPrTracer ) ;
2017-02-18 17:48:07 -06:00
2017-01-31 08:28:15 -06:00
}
}
2017-02-18 17:48:07 -06:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-03-01 09:00:32 -06:00
void RigAccWellFlowCalculator : : addDownStreamBranchFlow ( std : : vector < double > * accFlowPrTracer , const BranchFlow & downStreamBranchFlow ) const
2017-02-18 17:48:07 -06:00
{
size_t tracerIdx = 0 ;
for ( const auto & tracerName : m_tracerNames )
{
auto tracerFlowPair = downStreamBranchFlow . accFlowPrTracer . find ( tracerName ) ;
if ( tracerFlowPair ! = downStreamBranchFlow . accFlowPrTracer . end ( ) )
{
2017-03-01 09:00:32 -06:00
( * accFlowPrTracer ) [ tracerIdx ] + = tracerFlowPair - > second . back ( ) ; // The topmost accumulated value in the branch
2017-02-18 17:48:07 -06:00
}
tracerIdx + + ;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-03-01 09:00:32 -06:00
void RigAccWellFlowCalculator : : storeFlowOnDepth ( BranchFlow * branchFlow , double depthValue , const std : : vector < double > & accFlowPrTracer , const std : : vector < double > & flowPrTracer )
{
size_t tracerIdx = 0 ;
for ( const auto & tracerName : m_tracerNames )
{
branchFlow - > accFlowPrTracer [ tracerName ] . push_back ( accFlowPrTracer [ tracerIdx ] ) ;
branchFlow - > flowPrTracer [ tracerName ] . push_back ( flowPrTracer [ tracerIdx ] ) ;
tracerIdx + + ;
}
branchFlow - > depthValuesFromTop . push_back ( depthValue ) ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigAccWellFlowCalculator : : storeFlowOnDepthWTvd ( BranchFlow * branchFlow , double depthValue , double trueVerticalDepth , const std : : vector < double > & accFlowPrTracer , const std : : vector < double > & flowPrTracer )
2017-02-18 17:48:07 -06:00
{
size_t tracerIdx = 0 ;
for ( const auto & tracerName : m_tracerNames )
{
2017-03-01 09:00:32 -06:00
branchFlow - > accFlowPrTracer [ tracerName ] . push_back ( accFlowPrTracer [ tracerIdx ] ) ;
branchFlow - > flowPrTracer [ tracerName ] . push_back ( flowPrTracer [ tracerIdx ] ) ;
2017-02-18 17:48:07 -06:00
tracerIdx + + ;
}
2017-03-01 09:00:32 -06:00
branchFlow - > depthValuesFromTop . push_back ( depthValue ) ;
branchFlow - > trueVerticalDepth . push_back ( trueVerticalDepth ) ;
2017-02-18 17:48:07 -06:00
}
2017-03-10 04:50:17 -06:00
//--------------------------------------------------------------------------------------------------
/// Calculate the flow pr tracer. If inconsistent flow, keep the existing fractions constant
//--------------------------------------------------------------------------------------------------
std : : vector < double > RigAccWellFlowCalculator : : calculateFlowPrTracer ( const RigWellResultPoint & wellCell , const std : : vector < double > & currentAccumulatedFlowPrTracer ) const
{
std : : vector < double > flowPrTracer ( m_tracerNames . size ( ) , 0.0 ) ;
if ( ! hasConsistentFlow ( wellCell ) )
{
double flowRate = wellCell . flowRate ( ) ;
flowPrTracer = calculateAccumulatedFractions ( currentAccumulatedFlowPrTracer ) ;
for ( double & accFraction : flowPrTracer )
{
accFraction * = flowRate ;
}
return flowPrTracer ;
}
if ( m_tracerCellFractionValues )
{
if ( wellCell . isCell ( ) & & wellCell . m_isOpen )
{
size_t resCellIndex = m_cellIndexCalculator . resultCellIndex ( wellCell . m_gridIndex ,
wellCell . m_gridCellIndex ) ;
size_t tracerIdx = 0 ;
double totalTracerFractionInCell = 0.0 ;
for ( const auto & tracerFractionIt : ( * m_tracerCellFractionValues ) )
{
double cellTracerFraction = ( * tracerFractionIt . second ) [ resCellIndex ] ;
if ( cellTracerFraction ! = HUGE_VAL & & cellTracerFraction = = cellTracerFraction )
{
double tracerFlow = cellTracerFraction * wellCell . flowRate ( ) ;
flowPrTracer [ tracerIdx ] = tracerFlow ;
totalTracerFractionInCell + = cellTracerFraction ;
}
tracerIdx + + ;
}
double reservoirFraction = 1.0 - totalTracerFractionInCell ;
double reservoirTracerFlow = reservoirFraction * wellCell . flowRate ( ) ;
flowPrTracer [ tracerIdx ] = reservoirTracerFlow ;
}
}
else
{
flowPrTracer [ 0 ] = wellCell . flowRate ( ) ;
}
return flowPrTracer ;
}
2017-02-17 10:15:48 -06:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-03-09 10:04:43 -06:00
std : : vector < double > RigAccWellFlowCalculator : : calculateFlowPrTracer ( const RigWellResultPoint & wellCell ) const
2017-02-17 10:15:48 -06:00
{
std : : vector < double > flowPrTracer ( m_tracerNames . size ( ) , 0.0 ) ;
2017-03-09 10:04:43 -06:00
2017-02-17 10:15:48 -06:00
if ( m_tracerCellFractionValues )
{
2017-03-09 10:04:43 -06:00
if ( wellCell . isCell ( ) & & wellCell . m_isOpen )
2017-02-17 10:15:48 -06:00
{
2017-03-09 10:04:43 -06:00
size_t resCellIndex = m_cellIndexCalculator . resultCellIndex ( wellCell . m_gridIndex ,
wellCell . m_gridCellIndex ) ;
2017-02-17 10:15:48 -06:00
size_t tracerIdx = 0 ;
double totalTracerFractionInCell = 0.0 ;
for ( const auto & tracerFractionIt : ( * m_tracerCellFractionValues ) )
{
double cellTracerFraction = ( * tracerFractionIt . second ) [ resCellIndex ] ;
if ( cellTracerFraction ! = HUGE_VAL & & cellTracerFraction = = cellTracerFraction )
{
2017-03-09 10:04:43 -06:00
double tracerFlow = cellTracerFraction * wellCell . flowRate ( ) ;
2017-02-17 10:15:48 -06:00
flowPrTracer [ tracerIdx ] = tracerFlow ;
totalTracerFractionInCell + = cellTracerFraction ;
}
tracerIdx + + ;
}
double reservoirFraction = 1.0 - totalTracerFractionInCell ;
2017-03-09 10:04:43 -06:00
double reservoirTracerFlow = reservoirFraction * wellCell . flowRate ( ) ;
2017-02-17 10:15:48 -06:00
flowPrTracer [ tracerIdx ] = reservoirTracerFlow ;
}
}
else
{
2017-03-09 10:04:43 -06:00
flowPrTracer [ 0 ] = wellCell . flowRate ( ) ;
2017-02-17 10:15:48 -06:00
}
return flowPrTracer ;
}
2017-01-31 08:28:15 -06:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-02-17 08:48:42 -06:00
std : : vector < size_t > RigAccWellFlowCalculator : : wrpToConnectionIndexFromBottom ( const std : : vector < RigWellResultPoint > & branchCells ) const
2017-01-31 08:28:15 -06:00
{
std : : vector < size_t > resPointToConnectionIndexFromBottom ;
resPointToConnectionIndexFromBottom . resize ( branchCells . size ( ) , - 1 ) ;
size_t connIdxFromBottom = 0 ;
int clSegIdx = static_cast < int > ( branchCells . size ( ) ) - 1 ;
if ( clSegIdx < 0 ) return resPointToConnectionIndexFromBottom ;
2017-02-07 03:50:25 -06:00
size_t prevGridIdx = branchCells [ clSegIdx ] . m_gridIndex ;
2017-01-31 08:28:15 -06:00
size_t prevGridCellIdx = branchCells [ clSegIdx ] . m_gridCellIndex ;
2017-02-07 03:50:25 -06:00
int prevErtSegId = branchCells [ clSegIdx ] . m_ertSegmentId ;
2017-01-31 08:28:15 -06:00
int prevErtBranchId = branchCells [ clSegIdx ] . m_ertBranchId ;
while ( clSegIdx > = 0 )
{
2017-02-07 03:50:25 -06:00
if ( branchCells [ clSegIdx ] . isValid ( )
& & ( branchCells [ clSegIdx ] . m_gridIndex ! = prevGridIdx
| | branchCells [ clSegIdx ] . m_gridCellIndex ! = prevGridCellIdx
| | branchCells [ clSegIdx ] . m_ertSegmentId ! = prevErtSegId
| | branchCells [ clSegIdx ] . m_ertBranchId ! = prevErtBranchId ) )
2017-01-31 08:28:15 -06:00
{
+ + connIdxFromBottom ;
prevGridIdx = branchCells [ clSegIdx ] . m_gridIndex ;
prevGridCellIdx = branchCells [ clSegIdx ] . m_gridCellIndex ;
2017-02-07 03:50:25 -06:00
prevErtSegId = branchCells [ clSegIdx ] . m_ertSegmentId ;
prevErtBranchId = branchCells [ clSegIdx ] . m_ertBranchId ;
2017-01-31 08:28:15 -06:00
}
resPointToConnectionIndexFromBottom [ clSegIdx ] = connIdxFromBottom ;
- - clSegIdx ;
}
return resPointToConnectionIndexFromBottom ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-02-17 08:48:42 -06:00
size_t RigAccWellFlowCalculator : : connectionIndexFromTop ( const std : : vector < size_t > & resPointToConnectionIndexFromBottom , size_t clSegIdx )
2017-01-31 08:28:15 -06:00
{
return resPointToConnectionIndexFromBottom . front ( ) - resPointToConnectionIndexFromBottom [ clSegIdx ] ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-02-18 17:48:07 -06:00
std : : vector < size_t > RigAccWellFlowCalculator : : findDownStreamBranchIdxs ( const RigWellResultPoint & connectionPoint ) const
2017-01-31 08:28:15 -06:00
{
std : : vector < size_t > downStreamBranchIdxs ;
for ( size_t bIdx = 0 ; bIdx < m_pipeBranchesCellIds . size ( ) ; + + bIdx )
{
if ( m_pipeBranchesCellIds [ bIdx ] [ 0 ] . m_gridIndex = = connectionPoint . m_gridIndex
& & m_pipeBranchesCellIds [ bIdx ] [ 0 ] . m_gridCellIndex = = connectionPoint . m_gridCellIndex
& & m_pipeBranchesCellIds [ bIdx ] [ 0 ] . m_ertBranchId = = connectionPoint . m_ertBranchId
& & m_pipeBranchesCellIds [ bIdx ] [ 0 ] . m_ertSegmentId = = connectionPoint . m_ertSegmentId )
{
downStreamBranchIdxs . push_back ( bIdx ) ;
}
}
return downStreamBranchIdxs ;
}
2017-02-07 03:50:25 -06:00
2017-02-15 01:46:23 -06:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-02-13 06:34:08 -06:00
void RigAccWellFlowCalculator : : sortTracers ( )
{
std : : multimap < double , QString > sortedTracers ;
for ( const QString & tracerName : m_tracerNames )
{
const std : : vector < double > & mainBranchAccFlow = accumulatedTracerFlowPrConnection ( tracerName , 0 ) ;
2017-02-17 04:13:27 -06:00
2017-02-13 06:34:08 -06:00
double totalFlow = 0.0 ;
2017-02-17 04:13:27 -06:00
2017-02-13 06:34:08 -06:00
if ( mainBranchAccFlow . size ( ) ) totalFlow = - abs ( mainBranchAccFlow . back ( ) ) ; // Based on size in reverse order (biggest to least)
2017-02-17 04:13:27 -06:00
2017-02-13 06:34:08 -06:00
sortedTracers . insert ( { totalFlow , tracerName } ) ;
}
m_tracerNames . clear ( ) ;
for ( const auto & tracerPair : sortedTracers )
{
m_tracerNames . push_back ( tracerPair . second ) ;
}
2017-02-15 01:46:23 -06:00
}
//--------------------------------------------------------------------------------------------------
2017-02-17 04:13:27 -06:00
/// Concatenate small tracers into an "Other" group
2017-02-15 01:46:23 -06:00
//--------------------------------------------------------------------------------------------------
void RigAccWellFlowCalculator : : groupSmallContributions ( )
{
2017-02-17 04:13:27 -06:00
if ( ! ( m_smallContributionsThreshold > 0.0 ) ) return ;
// Find the tracers we need to group
std : : vector < QString > tracersToGroup ;
2017-02-15 01:46:23 -06:00
{
2017-03-10 04:50:17 -06:00
bool hasConsistentWellFlow = isWellFlowConsistent ( m_isProducer ) ;
2017-02-15 01:46:23 -06:00
std : : vector < std : : pair < QString , double > > totalTracerFractions = this - > totalTracerFractions ( ) ;
if ( totalTracerFractions . size ( ) < 5 ) return ; // No grouping for few legend items
for ( const auto & tracerPair : totalTracerFractions )
{
2017-03-10 04:50:17 -06:00
if ( abs ( tracerPair . second ) < = m_smallContributionsThreshold
& & ( hasConsistentWellFlow | | tracerPair . first ! = RIG_RESERVOIR_TRACER_NAME ) ) // Do not group the Reservoir tracer if the well flow is inconsistent, because cross flow is shown as the reservoir fraction
{
tracersToGroup . push_back ( tracerPair . first ) ;
}
2017-02-15 01:46:23 -06:00
}
2017-02-17 04:13:27 -06:00
}
2017-02-15 01:46:23 -06:00
2017-02-17 04:13:27 -06:00
if ( tracersToGroup . size ( ) < 2 ) return ; // Must at least group two ...
2017-02-15 01:46:23 -06:00
2017-02-17 04:13:27 -06:00
// Concatenate the values for each branch, erasing the tracers being grouped, replaced with the concatenated values
2017-02-17 08:48:42 -06:00
for ( BranchFlow & brRes : m_connectionFlowPrBranch )
2017-02-17 04:13:27 -06:00
{
2017-03-01 08:54:46 -06:00
groupSmallTracers ( & brRes . accFlowPrTracer , tracersToGroup ) ;
groupSmallTracers ( & brRes . flowPrTracer , tracersToGroup ) ;
}
for ( BranchFlow & brRes : m_pseudoLengthFlowPrBranch )
{
groupSmallTracers ( & brRes . accFlowPrTracer , tracersToGroup ) ;
groupSmallTracers ( & brRes . flowPrTracer , tracersToGroup ) ;
2017-02-17 04:13:27 -06:00
}
// Remove the grouped tracer names from the tracerName list, and replace with the "Others" name
2017-02-15 01:46:23 -06:00
2017-02-17 04:13:27 -06:00
std : : vector < QString > filteredTracernames ;
for ( const QString & tracerName : m_tracerNames )
{
bool isDeleted = false ;
for ( const QString & deletedTracerName : tracersToGroup )
{
if ( tracerName = = deletedTracerName ) { isDeleted = true ; break ; }
2017-02-15 01:46:23 -06:00
}
2017-02-17 04:13:27 -06:00
if ( ! isDeleted ) filteredTracernames . push_back ( tracerName ) ;
2017-02-15 01:46:23 -06:00
}
2017-02-17 04:13:27 -06:00
m_tracerNames . swap ( filteredTracernames ) ;
m_tracerNames . push_back ( RIG_TINY_TRACER_GROUP_NAME ) ;
2017-02-15 01:46:23 -06:00
}
2017-02-17 08:48:42 -06:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-03-01 08:54:46 -06:00
void RigAccWellFlowCalculator : : groupSmallTracers ( std : : map < QString , std : : vector < double > > * branchFlowSet , const std : : vector < QString > & tracersToGroup )
2017-02-17 08:48:42 -06:00
{
2017-03-01 08:54:46 -06:00
if ( branchFlowSet - > empty ( ) ) return ;
2017-02-17 08:48:42 -06:00
2017-03-01 08:54:46 -06:00
size_t depthCount = branchFlowSet - > begin ( ) - > second . size ( ) ;
2017-02-17 08:48:42 -06:00
std : : vector < double > groupedAccFlowValues ( depthCount , 0.0 ) ;
for ( const QString & tracername : tracersToGroup )
{
2017-03-01 08:54:46 -06:00
auto it = branchFlowSet - > find ( tracername ) ;
2017-02-17 08:48:42 -06:00
2017-03-01 08:54:46 -06:00
if ( it ! = branchFlowSet - > end ( ) )
2017-02-17 08:48:42 -06:00
{
const std : : vector < double > & tracerVals = it - > second ;
for ( size_t cIdx = 0 ; cIdx < groupedAccFlowValues . size ( ) ; + + cIdx )
{
groupedAccFlowValues [ cIdx ] + = tracerVals [ cIdx ] ;
}
}
2017-03-01 08:54:46 -06:00
branchFlowSet - > erase ( it ) ;
2017-02-17 08:48:42 -06:00
}
2017-03-01 08:54:46 -06:00
( * branchFlowSet ) [ RIG_TINY_TRACER_GROUP_NAME ] = groupedAccFlowValues ;
2017-02-17 08:48:42 -06:00
}