2017-01-31 15:28:15 +01: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 11:13:27 +01:00
#include "RigMainGrid.h"
#include "RigActiveCellInfo.h"
#include "RigFlowDiagResults.h"
2017-02-19 00:48:07 +01:00
#include "RigSimulationWellCoordsAndMD.h"
2017-01-31 15:28:15 +01:00
2017-02-17 11:13:27 +01:00
//==================================================================================================
///
///
//==================================================================================================
2017-01-31 15:28:15 +01:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-02-17 11:13:27 +01: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 16:02:42 +02:00
#define USE_WELL_PHASE_RATES
2017-04-18 16:47:37 +02:00
2017-02-17 11:13:27 +01: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 16:23:20 +01:00
const RigEclCellIndexCalculator & cellIndexCalculator ,
2017-02-15 12:29:36 +01:00
double smallContribThreshold ,
2017-02-17 11:13:27 +01:00
bool isProducer )
: m_pipeBranchesCLCoords ( pipeBranchesCLCoords ),
m_pipeBranchesCellIds ( pipeBranchesCellIds ),
m_tracerCellFractionValues ( & tracerCellFractionValues ),
m_cellIndexCalculator ( cellIndexCalculator ),
2017-03-09 17:04:43 +01:00
m_smallContributionsThreshold ( smallContribThreshold ),
m_isProducer ( isProducer )
2017-01-31 15:28:15 +01:00
{
2017-02-17 15:48:42 +01:00
m_connectionFlowPrBranch . resize ( m_pipeBranchesCellIds . size ());
2017-02-19 00:48:07 +01:00
m_pseudoLengthFlowPrBranch . resize ( m_pipeBranchesCellIds . size ());
2017-02-03 15:51:42 +01:00
2017-02-15 12:29:36 +01:00
2017-03-10 11:50:17 +01:00
for ( const auto & it : ( * m_tracerCellFractionValues ) ) m_tracerNames . push_back ( it . first );
2017-02-15 12:29:36 +01:00
2017-03-10 11:50:17 +01:00
m_tracerNames . push_back ( RIG_RESERVOIR_TRACER_NAME );
2017-02-15 12:29:36 +01:00
2017-03-10 11:50:17 +01:00
calculateAccumulatedFlowPrConnection ( 0 , 1 );
calculateFlowPrPseudoLength ( 0 , 0.0 );
sortTracers ();
groupSmallContributions ();
2017-02-19 00:48:07 +01:00
2017-01-31 15:28:15 +01:00
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-02-15 08:46:23 +01:00
RigAccWellFlowCalculator :: RigAccWellFlowCalculator ( const std :: vector < std :: vector < cvf :: Vec3d > >& pipeBranchesCLCoords ,
2017-02-17 11:13:27 +01: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 17:04:43 +01:00
m_smallContributionsThreshold ( smallContribThreshold ),
m_isProducer ( true )
2017-01-31 15:28:15 +01:00
{
2017-02-17 15:48:42 +01:00
m_connectionFlowPrBranch . resize ( m_pipeBranchesCellIds . size ());
2017-02-19 00:48:07 +01:00
m_pseudoLengthFlowPrBranch . resize ( m_pipeBranchesCellIds . size ());
2017-02-15 12:29:36 +01:00
2017-04-18 16:47:37 +02: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 15:51:42 +01:00
m_tracerNames . push_back ( RIG_FLOW_TOTAL_NAME );
2017-04-18 16:47:37 +02:00
#endif
2017-01-31 15:28:15 +01:00
calculateAccumulatedFlowPrConnection ( 0 , 1 );
2017-02-19 00:48:07 +01:00
calculateFlowPrPseudoLength ( 0 , 0.0 );
2017-05-08 16:02:42 +02:00
#ifdef USE_WELL_PHASE_RATES
sortTracers ();
#endif
2017-02-19 00:48:07 +01:00
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std :: vector < double >& RigAccWellFlowCalculator :: connectionNumbersFromTop ( size_t branchIdx ) const
{
return m_connectionFlowPrBranch [ branchIdx ]. depthValuesFromTop ;
2017-01-31 15:28:15 +01:00
}
2017-02-17 15:48:42 +01: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 15:28:15 +01:00
}
2017-02-17 15:48:42 +01: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 15:28:15 +01:00
}
2017-02-19 00:48:07 +01:00
2017-01-31 15:28:15 +01:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-02-19 00:48:07 +01:00
const std :: vector < double >& RigAccWellFlowCalculator :: pseudoLengthFromTop ( size_t branchIdx ) const
2017-01-31 15:28:15 +01:00
{
2017-02-19 00:48:07 +01:00
return m_pseudoLengthFlowPrBranch [ branchIdx ]. depthValuesFromTop ;
2017-01-31 15:28:15 +01:00
}
2017-03-01 16:00:32 +01:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std :: vector < double >& RigAccWellFlowCalculator :: trueVerticalDepth ( size_t branchIdx ) const
{
return m_pseudoLengthFlowPrBranch [ branchIdx ]. trueVerticalDepth ;
}
2017-02-19 00:48:07 +01: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 08:46:23 +01:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-02-17 15:48:42 +01:00
std :: vector < std :: pair < QString , double > > RigAccWellFlowCalculator :: totalWellFlowPrTracer () const
2017-02-15 08:46:23 +01: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 15:48:42 +01:00
std :: vector < std :: pair < QString , double > > RigAccWellFlowCalculator :: totalTracerFractions () const
2017-02-15 08:46:23 +01: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 11:13:27 +01:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-04-18 16:47:37 +02:00
bool RigAccWellFlowCalculator :: isWellFlowConsistent () const
2017-02-15 12:29:36 +01:00
{
bool isConsistent = true ;
for ( const std :: vector < RigWellResultPoint > & branch : m_pipeBranchesCellIds )
{
for ( const RigWellResultPoint & wrp : branch )
{
2017-03-15 16:33:42 +01:00
isConsistent = isFlowRateConsistent ( wrp . flowRate ());
2017-02-15 12:29:36 +01:00
if ( ! isConsistent ) break ;
}
if ( ! isConsistent ) break ;
}
return isConsistent ;
}
2017-03-10 11:50:17 +01:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-03-15 16:33:42 +01:00
std :: vector < double > RigAccWellFlowCalculator :: calculateAccumulatedFractions ( const std :: vector < double >& accumulatedFlowPrTracer ) const
2017-03-10 11:50:17 +01:00
{
double totalFlow = 0.0 ;
for ( double tracerFlow : accumulatedFlowPrTracer )
{
totalFlow += tracerFlow ;
}
std :: vector < double > flowFractionsPrTracer ( accumulatedFlowPrTracer . size (), 0.0 );
2017-03-15 16:33:42 +01: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 11:50:17 +01: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 16:33:42 +01:00
bool RigAccWellFlowCalculator :: isConnectionFlowConsistent ( const RigWellResultPoint & wellCell ) const
2017-03-10 11:50:17 +01:00
{
if ( ! m_tracerCellFractionValues ) return true ; // No flow diagnostics.
2017-03-15 16:33:42 +01:00
return isFlowRateConsistent ( wellCell . flowRate ());
2017-03-10 11:50:17 +01:00
}
2017-03-15 16:33:42 +01:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RigAccWellFlowCalculator :: isFlowRateConsistent ( double flowRate ) const
{
2017-04-18 16:47:37 +02:00
if ( ! m_tracerCellFractionValues ) return true ; // No flow diagnostics.
2017-03-15 16:33:42 +01:00
return ( flowRate >= 0.0 && m_isProducer ) || ( flowRate <= 0.0 && ! m_isProducer );
}
2017-02-15 08:46:23 +01:00
2017-01-31 15:28:15 +01:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigAccWellFlowCalculator :: calculateAccumulatedFlowPrConnection ( size_t branchIdx , size_t startConnectionNumberFromTop )
{
const std :: vector < RigWellResultPoint >& branchCells = m_pipeBranchesCellIds [ branchIdx ];
2017-03-10 14:50:27 +01:00
std :: vector < size_t > resPointUniqueIndexFromBottom = wrpToUniqueWrpIndexFromBottom ( branchCells );
2017-01-31 15:28:15 +01:00
size_t prevConnIndx = - 1 ;
int clSegIdx = static_cast < int > ( branchCells . size ()) - 1 ;
2017-02-17 15:48:42 +01:00
std :: vector < double > accFlowPrTracer ( m_tracerNames . size (), 0.0 );
2017-01-31 15:28:15 +01:00
while ( clSegIdx >= 0 )
{
// Skip point if referring to the same cell as the previous centerline segment did
{
2017-03-10 14:50:27 +01:00
if ( resPointUniqueIndexFromBottom [ clSegIdx ] == prevConnIndx )
2017-01-31 15:28:15 +01:00
{
-- clSegIdx ;
continue ;
}
2017-03-10 14:50:27 +01:00
prevConnIndx = resPointUniqueIndexFromBottom [ clSegIdx ];
2017-01-31 15:28:15 +01:00
}
// Accumulate the connection-cell's fraction flows
2017-03-09 17:04:43 +01:00
const RigWellResultPoint & wellCell = branchCells [ clSegIdx ];
2017-03-16 10:37:12 +01:00
std :: vector < double > flowPrTracer = calculateWellCellFlowPrTracer ( wellCell , accFlowPrTracer );
2017-02-03 15:51:42 +01:00
2017-03-16 10:37:12 +01:00
addDownStreamBranchFlow ( & accFlowPrTracer , flowPrTracer );
2017-01-31 15:28:15 +01:00
2017-03-15 16:33:42 +01:00
if ( ! isConnectionFlowConsistent ( wellCell ))
2017-03-10 11:50:17 +01: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 15:28:15 +01:00
// Add the total accumulated (fraction) flows from any branches connected to this cell
2017-03-10 14:50:27 +01:00
size_t connNumFromTop = connectionIndexFromTop ( resPointUniqueIndexFromBottom , clSegIdx ) + startConnectionNumberFromTop ;
2017-01-31 15:28:15 +01:00
2017-02-19 00:48:07 +01:00
std :: vector < size_t > downStreamBranchIndices = findDownStreamBranchIdxs ( branchCells [ clSegIdx ]);
for ( size_t dsBidx : downStreamBranchIndices )
2017-01-31 15:28:15 +01:00
{
2017-02-19 00:48:07 +01:00
BranchFlow & downStreamBranchFlow = m_connectionFlowPrBranch [ dsBidx ];
if ( dsBidx != branchIdx && downStreamBranchFlow . depthValuesFromTop . size () == 0 ) // Not this branch or already calculated
2017-01-31 15:28:15 +01:00
{
calculateAccumulatedFlowPrConnection ( dsBidx , connNumFromTop );
2017-03-16 10:37:12 +01:00
std :: vector < double > accBranchFlowPrTracer = accumulatedDsBranchFlowPrTracer ( downStreamBranchFlow );
addDownStreamBranchFlow ( & accFlowPrTracer , accBranchFlowPrTracer );
2017-03-10 14:50:27 +01: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 10:37:12 +01:00
addDownStreamBranchFlow ( & flowPrTracer , accBranchFlowPrTracer );
2017-03-10 14:50:27 +01:00
}
2017-01-31 15:28:15 +01:00
}
}
// Push back the accumulated result into the storage
2017-02-19 00:48:07 +01:00
BranchFlow & branchFlow = m_connectionFlowPrBranch [ branchIdx ];
2017-03-01 16:00:32 +01:00
storeFlowOnDepth ( & branchFlow , connNumFromTop , accFlowPrTracer , flowPrTracer );
2017-02-19 00:48:07 +01: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 20:57:40 +01:00
RigWellResultPoint previousResultPoint ;
2017-02-19 00:48:07 +01:00
while ( clSegIdx >= 0 )
{
2017-02-27 16:46:34 +01:00
int cellBottomPointIndex = - 1 ;
int cellUpperPointIndex = - 1 ;
int currentSegmentIndex = - 1 ;
2017-02-19 00:48:07 +01:00
2017-02-27 16:46:34 +01: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 11:50:17 +01:00
const RigWellResultPoint & wellCell = branchCells [ currentSegmentIndex ];
2017-03-16 10:37:12 +01:00
std :: vector < double > flowPrTracerToAccumulate = calculateWellCellFlowPrTracer ( wellCell , accFlowPrTracer );
2017-02-19 00:48:07 +01:00
2017-02-27 16:46:34 +01:00
double pseudoLengthFromTop_lower = mdCalculator . measuredDepths ()[ cellBottomPointIndex ] + startPseudoLengthFromTop ;
2017-03-01 16:00:32 +01:00
double tvd_lower = - mdCalculator . wellPathPoints ()[ cellBottomPointIndex ][ 2 ];
2017-02-19 00:48:07 +01:00
// Push back the new start-of-cell flow, with the previously accumulated result into the storage
2017-03-10 11:50:17 +01:00
std :: vector < double > flowPrTracer ;
2017-03-15 16:33:42 +01:00
if ( ! isConnectionFlowConsistent ( wellCell ))
2017-03-10 11:50:17 +01: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 16:00:32 +01:00
storeFlowOnDepthWTvd ( & branchFlow , pseudoLengthFromTop_lower , tvd_lower , accFlowPrTracer , flowPrTracer );
2017-02-19 00:48:07 +01:00
// Accumulate the connection-cell's fraction flows
2017-02-27 16:46:34 +01:00
2017-03-16 10:37:12 +01:00
addDownStreamBranchFlow ( & accFlowPrTracer , flowPrTracerToAccumulate );
2017-02-17 15:48:42 +01:00
2017-02-27 16:46:34 +01:00
double pseudoLengthFromTop_upper = mdCalculator . measuredDepths ()[ cellUpperPointIndex ] + startPseudoLengthFromTop ;
2017-03-01 16:00:32 +01:00
double tvd_upper = - mdCalculator . wellPathPoints ()[ cellUpperPointIndex ][ 2 ];
2017-02-19 00:48:07 +01:00
2017-02-28 11:46:45 +01:00
// Push back the accumulated result into the storage
2017-03-01 16:00:32 +01:00
storeFlowOnDepthWTvd ( & branchFlow , pseudoLengthFromTop_upper , tvd_upper , accFlowPrTracer , flowPrTracer );
2017-02-28 11:46:45 +01:00
// Add the total accumulated (fraction) flows from any branches connected to this cell
2017-02-27 16:46:34 +01:00
std :: vector < size_t > downStreamBranchIndices = findDownStreamBranchIdxs ( branchCells [ cellUpperPointIndex ]);
2017-02-19 00:48:07 +01: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 15:48:42 +01:00
{
2017-02-19 00:48:07 +01:00
calculateFlowPrPseudoLength ( dsBidx , pseudoLengthFromTop_upper );
2017-03-16 10:37:12 +01:00
std :: vector < double > accBranchFlowPrTracer = accumulatedDsBranchFlowPrTracer ( downStreamBranchFlow );
addDownStreamBranchFlow ( & accFlowPrTracer , accBranchFlowPrTracer );
2017-03-10 14:50:27 +01: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 10:37:12 +01:00
addDownStreamBranchFlow ( & flowPrTracer , accBranchFlowPrTracer );
2017-03-10 14:50:27 +01:00
}
2017-02-17 15:48:42 +01:00
}
}
2017-01-31 15:28:15 +01:00
2017-02-28 11:46:45 +01:00
// Push back the accumulated result after adding the branch result into the storage
2017-02-19 00:48:07 +01:00
2017-03-01 16:00:32 +01:00
if ( downStreamBranchIndices . size ()) storeFlowOnDepthWTvd ( & branchFlow , pseudoLengthFromTop_upper , tvd_upper , accFlowPrTracer , flowPrTracer );
2017-02-19 00:48:07 +01:00
2017-01-31 15:28:15 +01:00
}
}
2017-02-19 00:48:07 +01:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-03-16 10:37:12 +01:00
void RigAccWellFlowCalculator :: addDownStreamBranchFlow ( std :: vector < double > * accFlowPrTracer ,
const std :: vector < double >& accBranchFlowPrTracer ) const
2017-02-19 00:48:07 +01:00
{
2017-03-15 16:33:42 +01:00
2017-03-16 10:37:12 +01:00
double totalThisBranchFlow = 0.0 ;
2017-03-15 16:33:42 +01:00
for ( double tracerFlow : * accFlowPrTracer )
{
2017-03-16 10:37:12 +01:00
totalThisBranchFlow += tracerFlow ;
2017-03-15 16:33:42 +01:00
}
double totalDsBranchFlow = 0.0 ;
2017-03-16 10:37:12 +01:00
for ( double tracerFlow : accBranchFlowPrTracer )
2017-02-19 00:48:07 +01:00
{
2017-03-16 10:37:12 +01:00
totalDsBranchFlow += tracerFlow ;
2017-03-15 16:33:42 +01:00
}
2017-03-16 10:37:12 +01:00
bool isAccumulationConsistent = isFlowRateConsistent ( totalThisBranchFlow ); // If inconsistent, is it always only the Reservoir tracer that has the flow ?
2017-03-15 16:33:42 +01:00
bool isBranchConsistent = isFlowRateConsistent ( totalDsBranchFlow );
if ( isAccumulationConsistent == isBranchConsistent )
{
for ( size_t tracerIdx = 0 ; tracerIdx < ( * accFlowPrTracer ). size () ; ++ tracerIdx )
2017-02-19 00:48:07 +01:00
{
2017-03-15 16:33:42 +01:00
( * accFlowPrTracer )[ tracerIdx ] += accBranchFlowPrTracer [ tracerIdx ];
2017-02-19 00:48:07 +01:00
}
2017-03-15 16:33:42 +01:00
return ;
}
2017-03-16 10:37:12 +01:00
double totalAccFlow = totalThisBranchFlow + totalDsBranchFlow ;
2017-03-15 16:33:42 +01: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 10:37:12 +01:00
accFlowPrTracer -> back () = totalThisBranchFlow + totalDsBranchFlow ;
2017-03-15 16:33:42 +01:00
return ;
2017-02-19 00:48:07 +01:00
}
2017-03-15 16:33:42 +01: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-19 00:48:07 +01:00
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-03-01 16:00:32 +01: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-19 00:48:07 +01:00
{
size_t tracerIdx = 0 ;
for ( const auto & tracerName : m_tracerNames )
{
2017-03-01 16:00:32 +01:00
branchFlow -> accFlowPrTracer [ tracerName ]. push_back ( accFlowPrTracer [ tracerIdx ]);
branchFlow -> flowPrTracer [ tracerName ]. push_back ( flowPrTracer [ tracerIdx ]);
2017-02-19 00:48:07 +01:00
tracerIdx ++ ;
}
2017-03-01 16:00:32 +01:00
branchFlow -> depthValuesFromTop . push_back ( depthValue );
branchFlow -> trueVerticalDepth . push_back ( trueVerticalDepth );
2017-02-19 00:48:07 +01:00
}
2017-03-15 16:33:42 +01:00
std :: vector < double > RigAccWellFlowCalculator :: accumulatedDsBranchFlowPrTracer ( const BranchFlow & downStreamBranchFlow ) const
{
2017-03-16 10:37:12 +01:00
std :: vector < double > accBranchFlowPrTracer ( m_tracerNames . size (), 0.0 );
2017-03-15 16:33:42 +01:00
size_t tracerIdx = 0 ;
for ( const auto & tracerName : m_tracerNames )
{
const auto trNameAccFlowsPair = downStreamBranchFlow . accFlowPrTracer . find ( tracerName );
2017-03-16 10:37:12 +01:00
if ( trNameAccFlowsPair != downStreamBranchFlow . accFlowPrTracer . end ())
{
accBranchFlowPrTracer [ tracerIdx ] = trNameAccFlowsPair -> second . back ();
}
2017-03-15 16:33:42 +01:00
tracerIdx ++ ;
}
return accBranchFlowPrTracer ;
}
2017-03-10 11:50:17 +01:00
//--------------------------------------------------------------------------------------------------
/// Calculate the flow pr tracer. If inconsistent flow, keep the existing fractions constant
//--------------------------------------------------------------------------------------------------
2017-03-16 10:37:12 +01:00
std :: vector < double > RigAccWellFlowCalculator :: calculateWellCellFlowPrTracer ( const RigWellResultPoint & wellCell ,
const std :: vector < double >& currentAccumulatedFlowPrTracer ) const
2017-03-10 11:50:17 +01:00
{
std :: vector < double > flowPrTracer ( m_tracerNames . size (), 0.0 );
2017-03-15 16:33:42 +01:00
if ( ! isConnectionFlowConsistent ( wellCell ) )
2017-03-10 11:50:17 +01: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 12:32:02 +01:00
for ( const auto & tracerFractionValsPair : ( * m_tracerCellFractionValues ) )
2017-03-10 11:50:17 +01:00
{
2017-03-23 12:32:02 +01:00
const std :: vector < double >* fractionVals = tracerFractionValsPair . second ;
if ( fractionVals )
2017-03-10 11:50:17 +01:00
{
2017-03-23 12:32:02 +01:00
double cellTracerFraction = ( * fractionVals )[ resCellIndex ];
if ( cellTracerFraction != HUGE_VAL && cellTracerFraction == cellTracerFraction )
{
double tracerFlow = cellTracerFraction * wellCell . flowRate ();
flowPrTracer [ tracerIdx ] = tracerFlow ;
totalTracerFractionInCell += cellTracerFraction ;
}
2017-03-10 11:50:17 +01:00
}
tracerIdx ++ ;
}
double reservoirFraction = 1.0 - totalTracerFractionInCell ;
double reservoirTracerFlow = reservoirFraction * wellCell . flowRate ();
flowPrTracer [ tracerIdx ] = reservoirTracerFlow ;
}
}
else
{
2017-04-18 16:47:37 +02:00
#ifdef USE_WELL_PHASE_RATES
flowPrTracer [ 0 ] = wellCell . oilRate ();
flowPrTracer [ 1 ] = wellCell . gasRate ();
flowPrTracer [ 2 ] = wellCell . waterRate ();
#else
2017-03-10 11:50:17 +01:00
flowPrTracer [ 0 ] = wellCell . flowRate ();
2017-04-18 16:47:37 +02:00
#endif
2017-03-10 11:50:17 +01:00
}
return flowPrTracer ;
}
2017-02-17 17:15:48 +01:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-03-10 14:50:27 +01:00
std :: vector < size_t > RigAccWellFlowCalculator :: wrpToUniqueWrpIndexFromBottom ( const std :: vector < RigWellResultPoint > & branchCells ) const
2017-01-31 15:28:15 +01: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 10:50:25 +01:00
size_t prevGridIdx = branchCells [ clSegIdx ]. m_gridIndex ;
2017-01-31 15:28:15 +01:00
size_t prevGridCellIdx = branchCells [ clSegIdx ]. m_gridCellIndex ;
2017-02-07 10:50:25 +01:00
int prevErtSegId = branchCells [ clSegIdx ]. m_ertSegmentId ;
2017-01-31 15:28:15 +01:00
int prevErtBranchId = branchCells [ clSegIdx ]. m_ertBranchId ;
while ( clSegIdx >= 0 )
{
2017-02-07 10:50:25 +01: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 15:28:15 +01:00
{
++ connIdxFromBottom ;
prevGridIdx = branchCells [ clSegIdx ]. m_gridIndex ;
prevGridCellIdx = branchCells [ clSegIdx ]. m_gridCellIndex ;
2017-02-07 10:50:25 +01:00
prevErtSegId = branchCells [ clSegIdx ]. m_ertSegmentId ;
prevErtBranchId = branchCells [ clSegIdx ]. m_ertBranchId ;
2017-01-31 15:28:15 +01:00
}
resPointToConnectionIndexFromBottom [ clSegIdx ] = connIdxFromBottom ;
-- clSegIdx ;
}
return resPointToConnectionIndexFromBottom ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-02-17 15:48:42 +01:00
size_t RigAccWellFlowCalculator :: connectionIndexFromTop ( const std :: vector < size_t >& resPointToConnectionIndexFromBottom , size_t clSegIdx )
2017-01-31 15:28:15 +01:00
{
return resPointToConnectionIndexFromBottom . front () - resPointToConnectionIndexFromBottom [ clSegIdx ];
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-02-19 00:48:07 +01:00
std :: vector < size_t > RigAccWellFlowCalculator :: findDownStreamBranchIdxs ( const RigWellResultPoint & connectionPoint ) const
2017-01-31 15:28:15 +01: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 10:50:25 +01:00
2017-02-15 08:46:23 +01:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-02-13 13:34:08 +01: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 11:13:27 +01:00
2017-02-13 13:34:08 +01:00
double totalFlow = 0.0 ;
2017-02-17 11:13:27 +01:00
2017-03-14 19:11:45 +01:00
if ( mainBranchAccFlow . size ()) totalFlow = - fabs ( mainBranchAccFlow . back () ); // Based on size in reverse order (biggest to least)
2017-02-17 11:13:27 +01:00
2017-02-13 13:34:08 +01:00
sortedTracers . insert ({ totalFlow , tracerName });
}
m_tracerNames . clear ();
for ( const auto & tracerPair : sortedTracers )
{
m_tracerNames . push_back ( tracerPair . second );
}
2017-02-15 08:46:23 +01:00
}
//--------------------------------------------------------------------------------------------------
2017-02-17 11:13:27 +01:00
/// Concatenate small tracers into an "Other" group
2017-02-15 08:46:23 +01:00
//--------------------------------------------------------------------------------------------------
void RigAccWellFlowCalculator :: groupSmallContributions ()
{
2017-02-17 11:13:27 +01:00
if ( ! ( m_smallContributionsThreshold > 0.0 ) ) return ;
// Find the tracers we need to group
std :: vector < QString > tracersToGroup ;
2017-02-15 08:46:23 +01:00
{
2017-04-18 16:47:37 +02:00
bool hasConsistentWellFlow = isWellFlowConsistent ();
2017-03-10 11:50:17 +01:00
2017-02-15 08:46:23 +01: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 19:11:45 +01:00
if ( fabs ( tracerPair . second ) <= m_smallContributionsThreshold
2017-03-10 11:50:17 +01: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 08:46:23 +01:00
}
2017-02-17 11:13:27 +01:00
}
2017-02-15 08:46:23 +01:00
2017-02-17 11:13:27 +01:00
if ( tracersToGroup . size () < 2 ) return ; // Must at least group two ...
2017-02-15 08:46:23 +01:00
2017-02-17 11:13:27 +01:00
// Concatenate the values for each branch, erasing the tracers being grouped, replaced with the concatenated values
2017-02-17 15:48:42 +01:00
for ( BranchFlow & brRes : m_connectionFlowPrBranch )
2017-02-17 11:13:27 +01:00
{
2017-03-01 15:54:46 +01: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 11:13:27 +01:00
}
// Remove the grouped tracer names from the tracerName list, and replace with the "Others" name
2017-02-15 08:46:23 +01:00
2017-02-17 11:13:27 +01: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 08:46:23 +01:00
}
2017-02-17 11:13:27 +01:00
if ( ! isDeleted ) filteredTracernames . push_back ( tracerName );
2017-02-15 08:46:23 +01:00
}
2017-02-17 11:13:27 +01:00
m_tracerNames . swap ( filteredTracernames );
m_tracerNames . push_back ( RIG_TINY_TRACER_GROUP_NAME );
2017-02-15 08:46:23 +01:00
}
2017-02-17 15:48:42 +01:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-03-01 15:54:46 +01:00
void RigAccWellFlowCalculator :: groupSmallTracers ( std :: map < QString , std :: vector < double > >* branchFlowSet , const std :: vector < QString >& tracersToGroup )
2017-02-17 15:48:42 +01:00
{
2017-03-01 15:54:46 +01:00
if ( branchFlowSet -> empty () ) return ;
2017-02-17 15:48:42 +01:00
2017-03-01 15:54:46 +01:00
size_t depthCount = branchFlowSet -> begin () -> second . size ();
2017-02-17 15:48:42 +01:00
std :: vector < double > groupedAccFlowValues ( depthCount , 0.0 );
for ( const QString & tracername : tracersToGroup )
{
2017-03-01 15:54:46 +01:00
auto it = branchFlowSet -> find ( tracername );
2017-02-17 15:48:42 +01:00
2017-03-01 15:54:46 +01:00
if ( it != branchFlowSet -> end () )
2017-02-17 15:48:42 +01:00
{
const std :: vector < double >& tracerVals = it -> second ;
for ( size_t cIdx = 0 ; cIdx < groupedAccFlowValues . size (); ++ cIdx )
{
groupedAccFlowValues [ cIdx ] += tracerVals [ cIdx ];
}
}
2017-03-01 15:54:46 +01:00
branchFlowSet -> erase ( it );
2017-02-17 15:48:42 +01:00
}
2017-03-01 15:54:46 +01:00
( * branchFlowSet )[ RIG_TINY_TRACER_GROUP_NAME ] = groupedAccFlowValues ;
2017-02-17 15:48:42 +01:00
}