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"
2017-10-13 06:44:53 -05:00
# include "RigSimWellData.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 ) ;
}
//==================================================================================================
///
///
//==================================================================================================
2017-05-08 09:02:42 -05:00
# define USE_WELL_PHASE_RATES
2017-04-18 09:47:37 -05:00
2017-02-17 04:13:27 -06:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
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-04-18 09:47:37 -05:00
# ifdef USE_WELL_PHASE_RATES
m_tracerNames . push_back ( RIG_FLOW_OIL_NAME ) ;
m_tracerNames . push_back ( RIG_FLOW_GAS_NAME ) ;
m_tracerNames . push_back ( RIG_FLOW_WATER_NAME ) ;
# else
2017-02-03 08:51:42 -06:00
m_tracerNames . push_back ( RIG_FLOW_TOTAL_NAME ) ;
2017-04-18 09:47:37 -05:00
# endif
2017-01-31 08:28:15 -06:00
calculateAccumulatedFlowPrConnection ( 0 , 1 ) ;
2017-02-18 17:48:07 -06:00
calculateFlowPrPseudoLength ( 0 , 0.0 ) ;
2017-05-08 09:02:42 -05:00
# ifdef USE_WELL_PHASE_RATES
sortTracers ( ) ;
# endif
2017-02-18 17:48:07 -06:00
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
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 : : 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 : : 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 : : 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 : : 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-04-18 09:47:37 -05:00
bool RigAccWellFlowCalculator : : isWellFlowConsistent ( ) 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 )
{
2017-03-15 10:33:42 -05:00
isConsistent = isFlowRateConsistent ( wrp . flowRate ( ) ) ;
2017-02-15 05:29:36 -06:00
if ( ! isConsistent ) break ;
}
if ( ! isConsistent ) break ;
}
return isConsistent ;
}
2017-03-10 04:50:17 -06:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-03-15 10:33:42 -05:00
std : : vector < double > RigAccWellFlowCalculator : : calculateAccumulatedFractions ( const std : : vector < double > & accumulatedFlowPrTracer ) const
2017-03-10 04:50:17 -06:00
{
double totalFlow = 0.0 ;
for ( double tracerFlow : accumulatedFlowPrTracer )
{
totalFlow + = tracerFlow ;
}
std : : vector < double > flowFractionsPrTracer ( accumulatedFlowPrTracer . size ( ) , 0.0 ) ;
2017-03-15 10:33:42 -05:00
if ( totalFlow = = 0.0 | | ! isFlowRateConsistent ( totalFlow ) ) // If we have no accumulated flow, we set all the flow associated to the last tracer, which is the reservoir
2017-03-10 04:50:17 -06:00
{
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 ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-03-15 10:33:42 -05:00
bool RigAccWellFlowCalculator : : isConnectionFlowConsistent ( const RigWellResultPoint & wellCell ) const
2017-03-10 04:50:17 -06:00
{
if ( ! m_tracerCellFractionValues ) return true ; // No flow diagnostics.
2017-03-15 10:33:42 -05:00
return isFlowRateConsistent ( wellCell . flowRate ( ) ) ;
2017-03-10 04:50:17 -06:00
}
2017-03-15 10:33:42 -05:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RigAccWellFlowCalculator : : isFlowRateConsistent ( double flowRate ) const
{
2017-04-18 09:47:37 -05:00
if ( ! m_tracerCellFractionValues ) return true ; // No flow diagnostics.
2017-03-15 10:33:42 -05:00
return ( flowRate > = 0.0 & & m_isProducer ) | | ( 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 ] ;
2017-03-10 07:50:27 -06:00
std : : vector < size_t > resPointUniqueIndexFromBottom = wrpToUniqueWrpIndexFromBottom ( branchCells ) ;
2017-01-31 08:28:15 -06:00
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
{
2017-03-10 07:50:27 -06:00
if ( resPointUniqueIndexFromBottom [ clSegIdx ] = = prevConnIndx )
2017-01-31 08:28:15 -06:00
{
- - clSegIdx ;
continue ;
}
2017-03-10 07:50:27 -06:00
prevConnIndx = resPointUniqueIndexFromBottom [ clSegIdx ] ;
2017-01-31 08:28:15 -06:00
}
// Accumulate the connection-cell's fraction flows
2017-03-09 10:04:43 -06:00
const RigWellResultPoint & wellCell = branchCells [ clSegIdx ] ;
2017-03-16 04:37:12 -05:00
std : : vector < double > flowPrTracer = calculateWellCellFlowPrTracer ( wellCell , accFlowPrTracer ) ;
2017-02-03 08:51:42 -06:00
2017-03-16 04:37:12 -05:00
addDownStreamBranchFlow ( & accFlowPrTracer , flowPrTracer ) ;
2017-01-31 08:28:15 -06:00
2017-03-15 10:33:42 -05:00
if ( ! isConnectionFlowConsistent ( wellCell ) )
2017-03-10 04:50:17 -06:00
{
// 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
2017-03-10 07:50:27 -06:00
size_t connNumFromTop = connectionIndexFromTop ( resPointUniqueIndexFromBottom , clSegIdx ) + startConnectionNumberFromTop ;
2017-01-31 08:28:15 -06:00
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-16 04:37:12 -05:00
std : : vector < double > accBranchFlowPrTracer = accumulatedDsBranchFlowPrTracer ( downStreamBranchFlow ) ;
addDownStreamBranchFlow ( & accFlowPrTracer , accBranchFlowPrTracer ) ;
2017-03-10 07:50:27 -06:00
if ( m_pipeBranchesCellIds [ dsBidx ] . size ( ) < = 3 )
{
// Short branch. Will not be visible. Show branch flow as addition to this connections direct flow
2017-03-16 04:37:12 -05:00
addDownStreamBranchFlow ( & flowPrTracer , accBranchFlowPrTracer ) ;
2017-03-10 07:50:27 -06:00
}
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 ] ;
2017-03-16 04:37:12 -05:00
std : : vector < double > flowPrTracerToAccumulate = calculateWellCellFlowPrTracer ( 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 ;
2017-03-15 10:33:42 -05:00
if ( ! isConnectionFlowConsistent ( wellCell ) )
2017-03-10 04:50:17 -06:00
{
// 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-16 04:37:12 -05:00
addDownStreamBranchFlow ( & accFlowPrTracer , flowPrTracerToAccumulate ) ;
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-16 04:37:12 -05:00
std : : vector < double > accBranchFlowPrTracer = accumulatedDsBranchFlowPrTracer ( downStreamBranchFlow ) ;
addDownStreamBranchFlow ( & accFlowPrTracer , accBranchFlowPrTracer ) ;
2017-03-10 07:50:27 -06:00
if ( m_pipeBranchesCellIds [ dsBidx ] . size ( ) < = 3 )
{
// Short branch. Will not be visible. Show branch flow as addition to this connections direct flow
2017-03-16 04:37:12 -05:00
addDownStreamBranchFlow ( & flowPrTracer , accBranchFlowPrTracer ) ;
2017-03-10 07:50:27 -06:00
}
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-16 04:37:12 -05:00
void RigAccWellFlowCalculator : : addDownStreamBranchFlow ( std : : vector < double > * accFlowPrTracer ,
const std : : vector < double > & accBranchFlowPrTracer ) const
2017-02-18 17:48:07 -06:00
{
2017-03-15 10:33:42 -05:00
2017-03-16 04:37:12 -05:00
double totalThisBranchFlow = 0.0 ;
2017-03-15 10:33:42 -05:00
for ( double tracerFlow : * accFlowPrTracer )
{
2017-03-16 04:37:12 -05:00
totalThisBranchFlow + = tracerFlow ;
2017-03-15 10:33:42 -05:00
}
double totalDsBranchFlow = 0.0 ;
2017-03-16 04:37:12 -05:00
for ( double tracerFlow : accBranchFlowPrTracer )
2017-02-18 17:48:07 -06:00
{
2017-03-16 04:37:12 -05:00
totalDsBranchFlow + = tracerFlow ;
2017-03-15 10:33:42 -05:00
}
2017-03-16 04:37:12 -05:00
bool isAccumulationConsistent = isFlowRateConsistent ( totalThisBranchFlow ) ; // If inconsistent, is it always only the Reservoir tracer that has the flow ?
2017-03-15 10:33:42 -05:00
bool isBranchConsistent = isFlowRateConsistent ( totalDsBranchFlow ) ;
if ( isAccumulationConsistent = = isBranchConsistent )
{
for ( size_t tracerIdx = 0 ; tracerIdx < ( * accFlowPrTracer ) . size ( ) ; + + tracerIdx )
2017-02-18 17:48:07 -06:00
{
2017-03-15 10:33:42 -05:00
( * accFlowPrTracer ) [ tracerIdx ] + = accBranchFlowPrTracer [ tracerIdx ] ;
2017-02-18 17:48:07 -06:00
}
2017-03-15 10:33:42 -05:00
return ;
}
2017-03-16 04:37:12 -05:00
double totalAccFlow = totalThisBranchFlow + totalDsBranchFlow ;
2017-03-15 10:33:42 -05:00
if ( ! isFlowRateConsistent ( totalAccFlow ) )
{
// Reset the accumulated values, as everything must be moved to the "Reservoir" tracer.
for ( double & val : ( * accFlowPrTracer ) ) val = 0.0 ;
// Put all flow into the Reservoir tracer
2017-03-16 04:37:12 -05:00
accFlowPrTracer - > back ( ) = totalThisBranchFlow + totalDsBranchFlow ;
2017-03-15 10:33:42 -05:00
return ;
2017-02-18 17:48:07 -06:00
}
2017-03-15 10:33:42 -05:00
// We will end up with a consistent accumulated flow, and need to keep the accumulated distribution in this branch
// or to use the ds branch distribution
std : : vector < double > accFractionsPrTracer ;
if ( ! isAccumulationConsistent & & isBranchConsistent )
{
accFractionsPrTracer = calculateAccumulatedFractions ( accBranchFlowPrTracer ) ;
}
else if ( isAccumulationConsistent & & ! isBranchConsistent )
{
accFractionsPrTracer = calculateAccumulatedFractions ( * accFlowPrTracer ) ;
}
// Set the accumulated values to the totalFlow times the tracer fraction selected.
for ( size_t tIdx = 0 ; tIdx < accFlowPrTracer - > size ( ) ; + + tIdx )
{
( * accFlowPrTracer ) [ tIdx ] = accFractionsPrTracer [ tIdx ] * ( totalAccFlow ) ;
}
2017-02-18 17:48:07 -06:00
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-10-25 09:03:48 -05:00
void RigAccWellFlowCalculator : : storeFlowOnDepth ( BranchFlow * branchFlow ,
double depthValue ,
const std : : vector < double > & accFlowPrTracer ,
const std : : vector < double > & flowPrTracer )
2017-03-01 09:00:32 -06:00
{
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 ) ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-10-25 09:03:48 -05:00
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-15 10:33:42 -05:00
std : : vector < double > RigAccWellFlowCalculator : : accumulatedDsBranchFlowPrTracer ( const BranchFlow & downStreamBranchFlow ) const
{
2017-03-16 04:37:12 -05:00
std : : vector < double > accBranchFlowPrTracer ( m_tracerNames . size ( ) , 0.0 ) ;
2017-03-15 10:33:42 -05:00
size_t tracerIdx = 0 ;
for ( const auto & tracerName : m_tracerNames )
{
const auto trNameAccFlowsPair = downStreamBranchFlow . accFlowPrTracer . find ( tracerName ) ;
2017-03-16 04:37:12 -05:00
if ( trNameAccFlowsPair ! = downStreamBranchFlow . accFlowPrTracer . end ( ) )
{
accBranchFlowPrTracer [ tracerIdx ] = trNameAccFlowsPair - > second . back ( ) ;
}
2017-03-15 10:33:42 -05:00
tracerIdx + + ;
}
return accBranchFlowPrTracer ;
}
2017-03-10 04:50:17 -06:00
//--------------------------------------------------------------------------------------------------
/// Calculate the flow pr tracer. If inconsistent flow, keep the existing fractions constant
//--------------------------------------------------------------------------------------------------
2017-03-16 04:37:12 -05:00
std : : vector < double > RigAccWellFlowCalculator : : calculateWellCellFlowPrTracer ( const RigWellResultPoint & wellCell ,
const std : : vector < double > & currentAccumulatedFlowPrTracer ) const
2017-03-10 04:50:17 -06:00
{
std : : vector < double > flowPrTracer ( m_tracerNames . size ( ) , 0.0 ) ;
2017-03-15 10:33:42 -05:00
if ( ! isConnectionFlowConsistent ( wellCell ) )
2017-03-10 04:50:17 -06:00
{
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 ;
2017-03-23 06:32:02 -05:00
for ( const auto & tracerFractionValsPair : ( * m_tracerCellFractionValues ) )
2017-03-10 04:50:17 -06:00
{
2017-03-23 06:32:02 -05:00
const std : : vector < double > * fractionVals = tracerFractionValsPair . second ;
if ( fractionVals )
2017-03-10 04:50:17 -06:00
{
2017-03-23 06:32:02 -05:00
double cellTracerFraction = ( * fractionVals ) [ resCellIndex ] ;
if ( cellTracerFraction ! = HUGE_VAL & & cellTracerFraction = = cellTracerFraction )
{
double tracerFlow = cellTracerFraction * wellCell . flowRate ( ) ;
flowPrTracer [ tracerIdx ] = tracerFlow ;
totalTracerFractionInCell + = cellTracerFraction ;
}
2017-03-10 04:50:17 -06:00
}
tracerIdx + + ;
}
double reservoirFraction = 1.0 - totalTracerFractionInCell ;
double reservoirTracerFlow = reservoirFraction * wellCell . flowRate ( ) ;
flowPrTracer [ tracerIdx ] = reservoirTracerFlow ;
}
}
else
{
2017-04-18 09:47:37 -05:00
# ifdef USE_WELL_PHASE_RATES
flowPrTracer [ 0 ] = wellCell . oilRate ( ) ;
flowPrTracer [ 1 ] = wellCell . gasRate ( ) ;
flowPrTracer [ 2 ] = wellCell . waterRate ( ) ;
# else
2017-03-10 04:50:17 -06:00
flowPrTracer [ 0 ] = wellCell . flowRate ( ) ;
2017-04-18 09:47:37 -05:00
# endif
2017-03-10 04:50:17 -06:00
}
return flowPrTracer ;
}
2017-02-17 10:15:48 -06:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-03-10 07:50:27 -06:00
std : : vector < size_t > RigAccWellFlowCalculator : : wrpToUniqueWrpIndexFromBottom ( 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-03-14 13:11:45 -05:00
if ( mainBranchAccFlow . size ( ) ) totalFlow = - fabs ( 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-04-18 09:47:37 -05:00
bool hasConsistentWellFlow = isWellFlowConsistent ( ) ;
2017-03-10 04:50:17 -06:00
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-14 13:11:45 -05:00
if ( fabs ( tracerPair . second ) < = m_smallContributionsThreshold
2017-03-10 04:50:17 -06:00
& & ( 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
}