mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
Rename ApplicationCode to ApplicationLibCode
This commit is contained in:
@@ -0,0 +1,936 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "RigActiveCellInfo.h"
|
||||
#include "RigFlowDiagResults.h"
|
||||
#include "RigMainGrid.h"
|
||||
#include "RigSimWellData.h"
|
||||
#include "RigSimulationWellCoordsAndMD.h"
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
///
|
||||
//==================================================================================================
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
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 );
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
///
|
||||
//==================================================================================================
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
/// The pipeBranchesWellResultPoints are describing the lines between the points, starting with the first line
|
||||
// and is thus expected to be one less than the number of centerline points
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RigAccWellFlowCalculator::RigAccWellFlowCalculator(
|
||||
const std::vector<std::vector<cvf::Vec3d>>& pipeBranchesCLCoords,
|
||||
const std::vector<std::vector<RigWellResultPoint>>& pipeBranchesWellResultPoints,
|
||||
const std::map<QString, const std::vector<double>*>& tracerCellFractionValues,
|
||||
const RigEclCellIndexCalculator& cellIndexCalculator,
|
||||
double smallContribThreshold,
|
||||
bool isProducer )
|
||||
: m_pipeBranchesCLCoords( pipeBranchesCLCoords )
|
||||
, m_pipeBranchesWellResultPoints( pipeBranchesWellResultPoints )
|
||||
, m_tracerCellFractionValues( &tracerCellFractionValues )
|
||||
, m_cellIndexCalculator( cellIndexCalculator )
|
||||
, m_smallContributionsThreshold( smallContribThreshold )
|
||||
, m_isProducer( isProducer )
|
||||
, m_useTotalWellPhaseRateOnly( false )
|
||||
{
|
||||
m_connectionFlowPrBranch.resize( m_pipeBranchesWellResultPoints.size() );
|
||||
m_pseudoLengthFlowPrBranch.resize( m_pipeBranchesWellResultPoints.size() );
|
||||
|
||||
for ( const auto& it : ( *m_tracerCellFractionValues ) )
|
||||
m_tracerNames.push_back( it.first );
|
||||
|
||||
m_tracerNames.push_back( RIG_RESERVOIR_TRACER_NAME );
|
||||
|
||||
initializePipeBranchesMeasuredDepths();
|
||||
calculateAccumulatedFlowPrConnection( 0, 0 );
|
||||
calculateFlowPrPseudoLength( 0, 0.0 );
|
||||
sortTracers();
|
||||
groupSmallContributions();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RigAccWellFlowCalculator::RigAccWellFlowCalculator( const std::vector<std::vector<cvf::Vec3d>>& pipeBranchesCLCoords,
|
||||
const std::vector<std::vector<RigWellResultPoint>>& pipeBranchesWellResultPoints,
|
||||
double smallContribThreshold )
|
||||
: m_pipeBranchesCLCoords( pipeBranchesCLCoords )
|
||||
, m_pipeBranchesWellResultPoints( pipeBranchesWellResultPoints )
|
||||
, m_tracerCellFractionValues( nullptr )
|
||||
, m_cellIndexCalculator( RigEclCellIndexCalculator( nullptr, nullptr ) )
|
||||
, m_smallContributionsThreshold( smallContribThreshold )
|
||||
, m_isProducer( true )
|
||||
, m_useTotalWellPhaseRateOnly( false )
|
||||
{
|
||||
m_connectionFlowPrBranch.resize( m_pipeBranchesWellResultPoints.size() );
|
||||
m_pseudoLengthFlowPrBranch.resize( m_pipeBranchesWellResultPoints.size() );
|
||||
|
||||
if ( !m_useTotalWellPhaseRateOnly )
|
||||
{
|
||||
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
|
||||
{
|
||||
m_tracerNames.push_back( RIG_FLOW_TOTAL_NAME );
|
||||
}
|
||||
|
||||
initializePipeBranchesMeasuredDepths();
|
||||
calculateAccumulatedFlowPrConnection( 0, 0 );
|
||||
calculateFlowPrPseudoLength( 0, 0.0 );
|
||||
|
||||
if ( !m_useTotalWellPhaseRateOnly ) sortTracers();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RigAccWellFlowCalculator::RigAccWellFlowCalculator( const std::vector<cvf::Vec3d>& pipeBranchCLCoords,
|
||||
const std::vector<RigWellResultPoint>& pipeBranchesWellResultPoints,
|
||||
const std::vector<double>& pipeBranchMeasuredDepths,
|
||||
bool totalFlowOnly )
|
||||
: m_tracerCellFractionValues( nullptr )
|
||||
, m_cellIndexCalculator( RigEclCellIndexCalculator( nullptr, nullptr ) )
|
||||
, m_smallContributionsThreshold( 0.0 )
|
||||
, m_isProducer( true )
|
||||
, m_useTotalWellPhaseRateOnly( totalFlowOnly )
|
||||
{
|
||||
m_pipeBranchesCLCoords.push_back( pipeBranchCLCoords );
|
||||
m_pipeBranchesWellResultPoints.push_back( pipeBranchesWellResultPoints );
|
||||
m_pipeBranchesMeasuredDepths.push_back( pipeBranchMeasuredDepths );
|
||||
|
||||
m_connectionFlowPrBranch.resize( m_pipeBranchesWellResultPoints.size() );
|
||||
m_pseudoLengthFlowPrBranch.resize( m_pipeBranchesWellResultPoints.size() );
|
||||
|
||||
if ( !m_useTotalWellPhaseRateOnly )
|
||||
{
|
||||
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
|
||||
{
|
||||
m_tracerNames.push_back( RIG_FLOW_TOTAL_NAME );
|
||||
}
|
||||
|
||||
initializePipeBranchesMeasuredDepths();
|
||||
calculateAccumulatedFlowPrConnection( 0, 0 );
|
||||
calculateFlowPrPseudoLength( 0, 0.0 );
|
||||
|
||||
if ( !m_useTotalWellPhaseRateOnly ) sortTracers();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigAccWellFlowCalculator::initializePipeBranchesMeasuredDepths()
|
||||
{
|
||||
for ( const auto& branchClPoints : m_pipeBranchesCLCoords )
|
||||
{
|
||||
RigSimulationWellCoordsAndMD mdCalculator( branchClPoints );
|
||||
m_pipeBranchesMeasuredDepths.push_back( mdCalculator.measuredDepths() );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const std::vector<double>& RigAccWellFlowCalculator::connectionNumbersFromTop( size_t branchIdx ) const
|
||||
{
|
||||
return m_connectionFlowPrBranch[branchIdx].depthValuesFromTop;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const std::vector<double>& RigAccWellFlowCalculator::pseudoLengthFromTop( size_t branchIdx ) const
|
||||
{
|
||||
return m_pseudoLengthFlowPrBranch[branchIdx].depthValuesFromTop;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const std::vector<double>& RigAccWellFlowCalculator::trueVerticalDepth( size_t branchIdx ) const
|
||||
{
|
||||
return m_pseudoLengthFlowPrBranch[branchIdx].trueVerticalDepth;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<std::pair<QString, double>> RigAccWellFlowCalculator::totalWellFlowPrTracer() const
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<std::pair<QString, double>> RigAccWellFlowCalculator::totalTracerFractions() const
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RigAccWellFlowCalculator::isWellFlowConsistent() const
|
||||
{
|
||||
bool isConsistent = true;
|
||||
for ( const std::vector<RigWellResultPoint>& branch : m_pipeBranchesWellResultPoints )
|
||||
{
|
||||
for ( const RigWellResultPoint& wrp : branch )
|
||||
{
|
||||
isConsistent = isFlowRateConsistent( wrp.flowRate() );
|
||||
|
||||
if ( !isConsistent ) break;
|
||||
}
|
||||
if ( !isConsistent ) break;
|
||||
}
|
||||
return isConsistent;
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
std::vector<double>
|
||||
RigAccWellFlowCalculator::calculateAccumulatedFractions( const std::vector<double>& accumulatedFlowPrTracer ) const
|
||||
{
|
||||
double totalFlow = 0.0;
|
||||
for ( double tracerFlow : accumulatedFlowPrTracer )
|
||||
{
|
||||
totalFlow += tracerFlow;
|
||||
}
|
||||
|
||||
std::vector<double> flowFractionsPrTracer( accumulatedFlowPrTracer.size(), 0.0 );
|
||||
|
||||
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
|
||||
{
|
||||
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::isConnectionFlowConsistent( const RigWellResultPoint& wellCell ) const
|
||||
{
|
||||
if ( !m_tracerCellFractionValues ) return true; // No flow diagnostics.
|
||||
|
||||
return isFlowRateConsistent( wellCell.flowRate() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RigAccWellFlowCalculator::isFlowRateConsistent( double flowRate ) const
|
||||
{
|
||||
if ( !m_tracerCellFractionValues ) return true; // No flow diagnostics.
|
||||
|
||||
return ( flowRate >= 0.0 && m_isProducer ) || ( flowRate <= 0.0 && !m_isProducer );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigAccWellFlowCalculator::calculateAccumulatedFlowPrConnection( size_t branchIdx, size_t startConnectionNumberFromTop )
|
||||
{
|
||||
const std::vector<RigWellResultPoint>& branchCells = m_pipeBranchesWellResultPoints[branchIdx];
|
||||
|
||||
std::vector<size_t> resPointUniqueIndexFromBottom = wrpToUniqueWrpIndexFromBottom( branchCells );
|
||||
|
||||
size_t prevConnIndx = -1;
|
||||
int clSegIdx = static_cast<int>( branchCells.size() ) - 1;
|
||||
|
||||
std::vector<double> accFlowPrTracer( m_tracerNames.size(), 0.0 );
|
||||
|
||||
while ( clSegIdx >= 0 )
|
||||
{
|
||||
// Skip point if referring to the same cell as the previous centerline segment did
|
||||
{
|
||||
if ( resPointUniqueIndexFromBottom[clSegIdx] == prevConnIndx )
|
||||
{
|
||||
--clSegIdx;
|
||||
continue;
|
||||
}
|
||||
|
||||
prevConnIndx = resPointUniqueIndexFromBottom[clSegIdx];
|
||||
}
|
||||
|
||||
// Accumulate the connection-cell's fraction flows
|
||||
|
||||
const RigWellResultPoint& wellCell = branchCells[clSegIdx];
|
||||
|
||||
std::vector<double> flowPrTracer = calculateWellCellFlowPrTracer( wellCell, accFlowPrTracer );
|
||||
|
||||
addDownStreamBranchFlow( &accFlowPrTracer, flowPrTracer );
|
||||
|
||||
if ( !isConnectionFlowConsistent( 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();
|
||||
}
|
||||
|
||||
// Add the total accumulated (fraction) flows from any branches connected to this cell
|
||||
|
||||
size_t connNumFromTop = connectionIndexFromTop( resPointUniqueIndexFromBottom, clSegIdx ) +
|
||||
startConnectionNumberFromTop;
|
||||
|
||||
std::vector<size_t> downStreamBranchIndices = findDownStreamBranchIdxs( branchCells[clSegIdx] );
|
||||
for ( size_t dsBidx : downStreamBranchIndices )
|
||||
{
|
||||
BranchFlow& downStreamBranchFlow = m_connectionFlowPrBranch[dsBidx];
|
||||
if ( dsBidx != branchIdx && downStreamBranchFlow.depthValuesFromTop.size() == 0 ) // Not this branch or
|
||||
// already calculated
|
||||
{
|
||||
calculateAccumulatedFlowPrConnection( dsBidx, connNumFromTop );
|
||||
std::vector<double> accBranchFlowPrTracer = accumulatedDsBranchFlowPrTracer( downStreamBranchFlow );
|
||||
addDownStreamBranchFlow( &accFlowPrTracer, accBranchFlowPrTracer );
|
||||
if ( m_pipeBranchesWellResultPoints[dsBidx].size() <= 3 )
|
||||
{
|
||||
// Short branch. Will not be visible. Show branch flow as addition to this connections direct flow
|
||||
addDownStreamBranchFlow( &flowPrTracer, accBranchFlowPrTracer );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Push back the accumulated result into the storage
|
||||
|
||||
BranchFlow& branchFlow = m_connectionFlowPrBranch[branchIdx];
|
||||
|
||||
storeFlowOnDepth( &branchFlow, connNumFromTop, accFlowPrTracer, flowPrTracer );
|
||||
|
||||
--clSegIdx;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigAccWellFlowCalculator::calculateFlowPrPseudoLength( size_t branchIdx, double startPseudoLengthFromTop )
|
||||
{
|
||||
const std::vector<RigWellResultPoint>& branchCells = m_pipeBranchesWellResultPoints[branchIdx];
|
||||
const std::vector<cvf::Vec3d>& branchClPoints = m_pipeBranchesCLCoords[branchIdx];
|
||||
const std::vector<double>& branchMDs = m_pipeBranchesMeasuredDepths[branchIdx];
|
||||
|
||||
int clSegIdx = static_cast<int>( branchCells.size() ) - 1;
|
||||
|
||||
std::vector<double> accFlowPrTracer( m_tracerNames.size(), 0.0 );
|
||||
|
||||
BranchFlow& branchFlow = m_pseudoLengthFlowPrBranch[branchIdx];
|
||||
|
||||
RigWellResultPoint previousResultPoint;
|
||||
|
||||
while ( clSegIdx >= 0 )
|
||||
{
|
||||
int cellBottomPointIndex = -1;
|
||||
int cellUpperPointIndex = -1;
|
||||
int currentSegmentIndex = -1;
|
||||
|
||||
// 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;
|
||||
}
|
||||
const RigWellResultPoint& wellCell = branchCells[currentSegmentIndex];
|
||||
std::vector<double> flowPrTracerToAccumulate = calculateWellCellFlowPrTracer( wellCell, accFlowPrTracer );
|
||||
|
||||
double pseudoLengthFromTop_lower = branchMDs[cellBottomPointIndex] + startPseudoLengthFromTop;
|
||||
double tvd_lower = -branchClPoints[cellBottomPointIndex][2];
|
||||
|
||||
// Push back the new start-of-cell flow, with the previously accumulated result into the storage
|
||||
|
||||
std::vector<double> flowPrTracer;
|
||||
if ( !isConnectionFlowConsistent( 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;
|
||||
}
|
||||
|
||||
storeFlowOnDepthWTvd( &branchFlow, pseudoLengthFromTop_lower, tvd_lower, accFlowPrTracer, flowPrTracer );
|
||||
|
||||
// Accumulate the connection-cell's fraction flows
|
||||
|
||||
addDownStreamBranchFlow( &accFlowPrTracer, flowPrTracerToAccumulate );
|
||||
|
||||
double pseudoLengthFromTop_upper = branchMDs[cellUpperPointIndex] + startPseudoLengthFromTop;
|
||||
double tvd_upper = -branchClPoints[cellUpperPointIndex][2];
|
||||
|
||||
// Push back the accumulated result into the storage
|
||||
|
||||
storeFlowOnDepthWTvd( &branchFlow, pseudoLengthFromTop_upper, tvd_upper, accFlowPrTracer, flowPrTracer );
|
||||
|
||||
// Add the total accumulated (fraction) flows from any branches connected to this cell
|
||||
|
||||
std::vector<size_t> downStreamBranchIndices = findDownStreamBranchIdxs( branchCells[cellUpperPointIndex] );
|
||||
for ( size_t dsBidx : downStreamBranchIndices )
|
||||
{
|
||||
BranchFlow& downStreamBranchFlow = m_pseudoLengthFlowPrBranch[dsBidx];
|
||||
if ( dsBidx != branchIdx && downStreamBranchFlow.depthValuesFromTop.size() == 0 ) // Not this branch or
|
||||
// already calculated
|
||||
{
|
||||
calculateFlowPrPseudoLength( dsBidx, pseudoLengthFromTop_upper );
|
||||
std::vector<double> accBranchFlowPrTracer = accumulatedDsBranchFlowPrTracer( downStreamBranchFlow );
|
||||
addDownStreamBranchFlow( &accFlowPrTracer, accBranchFlowPrTracer );
|
||||
if ( m_pipeBranchesWellResultPoints[dsBidx].size() <= 3 )
|
||||
{
|
||||
// Short branch. Will not be visible. Show branch flow as addition to this connections direct flow
|
||||
addDownStreamBranchFlow( &flowPrTracer, accBranchFlowPrTracer );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Push back the accumulated result after adding the branch result into the storage
|
||||
|
||||
if ( downStreamBranchIndices.size() )
|
||||
storeFlowOnDepthWTvd( &branchFlow, pseudoLengthFromTop_upper, tvd_upper, accFlowPrTracer, flowPrTracer );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigAccWellFlowCalculator::addDownStreamBranchFlow( std::vector<double>* accFlowPrTracer,
|
||||
const std::vector<double>& accBranchFlowPrTracer ) const
|
||||
{
|
||||
double totalThisBranchFlow = 0.0;
|
||||
for ( double tracerFlow : *accFlowPrTracer )
|
||||
{
|
||||
totalThisBranchFlow += tracerFlow;
|
||||
}
|
||||
|
||||
double totalDsBranchFlow = 0.0;
|
||||
for ( double tracerFlow : accBranchFlowPrTracer )
|
||||
{
|
||||
totalDsBranchFlow += tracerFlow;
|
||||
}
|
||||
|
||||
bool isAccumulationConsistent = isFlowRateConsistent( totalThisBranchFlow ); // If inconsistent, is it always only
|
||||
// the Reservoir tracer that has the
|
||||
// flow ?
|
||||
bool isBranchConsistent = isFlowRateConsistent( totalDsBranchFlow );
|
||||
|
||||
if ( isAccumulationConsistent == isBranchConsistent )
|
||||
{
|
||||
for ( size_t tracerIdx = 0; tracerIdx < ( *accFlowPrTracer ).size(); ++tracerIdx )
|
||||
{
|
||||
( *accFlowPrTracer )[tracerIdx] += accBranchFlowPrTracer[tracerIdx];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
double totalAccFlow = totalThisBranchFlow + totalDsBranchFlow;
|
||||
|
||||
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
|
||||
accFlowPrTracer->back() = totalThisBranchFlow + totalDsBranchFlow;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// 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 );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
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 )
|
||||
{
|
||||
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 );
|
||||
branchFlow->trueVerticalDepth.push_back( trueVerticalDepth );
|
||||
}
|
||||
|
||||
std::vector<double> RigAccWellFlowCalculator::accumulatedDsBranchFlowPrTracer( const BranchFlow& downStreamBranchFlow ) const
|
||||
{
|
||||
std::vector<double> accBranchFlowPrTracer( m_tracerNames.size(), 0.0 );
|
||||
|
||||
size_t tracerIdx = 0;
|
||||
for ( const auto& tracerName : m_tracerNames )
|
||||
{
|
||||
const auto trNameAccFlowsPair = downStreamBranchFlow.accFlowPrTracer.find( tracerName );
|
||||
if ( trNameAccFlowsPair != downStreamBranchFlow.accFlowPrTracer.end() )
|
||||
{
|
||||
accBranchFlowPrTracer[tracerIdx] = trNameAccFlowsPair->second.back();
|
||||
}
|
||||
tracerIdx++;
|
||||
}
|
||||
|
||||
return accBranchFlowPrTracer;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Calculate the flow pr tracer. If inconsistent flow, keep the existing fractions constant
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<double>
|
||||
RigAccWellFlowCalculator::calculateWellCellFlowPrTracer( const RigWellResultPoint& wellCell,
|
||||
const std::vector<double>& currentAccumulatedFlowPrTracer ) const
|
||||
{
|
||||
std::vector<double> flowPrTracer( m_tracerNames.size(), 0.0 );
|
||||
|
||||
if ( !isConnectionFlowConsistent( 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& tracerFractionValsPair : ( *m_tracerCellFractionValues ) )
|
||||
{
|
||||
const std::vector<double>* fractionVals = tracerFractionValsPair.second;
|
||||
if ( fractionVals )
|
||||
{
|
||||
double cellTracerFraction = ( *fractionVals )[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
|
||||
{
|
||||
if ( !m_useTotalWellPhaseRateOnly )
|
||||
{
|
||||
flowPrTracer[0] = wellCell.oilRate();
|
||||
flowPrTracer[1] = wellCell.gasRate();
|
||||
flowPrTracer[2] = wellCell.waterRate();
|
||||
}
|
||||
else
|
||||
{
|
||||
flowPrTracer[0] = wellCell.flowRate();
|
||||
}
|
||||
}
|
||||
|
||||
return flowPrTracer;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<size_t>
|
||||
RigAccWellFlowCalculator::wrpToUniqueWrpIndexFromBottom( const std::vector<RigWellResultPoint>& branchCells ) const
|
||||
{
|
||||
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;
|
||||
|
||||
size_t prevGridIdx = branchCells[clSegIdx].m_gridIndex;
|
||||
size_t prevGridCellIdx = branchCells[clSegIdx].m_gridCellIndex;
|
||||
int prevErtSegId = branchCells[clSegIdx].m_ertSegmentId;
|
||||
int prevErtBranchId = branchCells[clSegIdx].m_ertBranchId;
|
||||
|
||||
while ( clSegIdx >= 0 )
|
||||
{
|
||||
if ( branchCells[clSegIdx].isValid() && ( branchCells[clSegIdx].m_gridIndex != prevGridIdx ||
|
||||
branchCells[clSegIdx].m_gridCellIndex != prevGridCellIdx ||
|
||||
branchCells[clSegIdx].m_ertSegmentId != prevErtSegId ||
|
||||
branchCells[clSegIdx].m_ertBranchId != prevErtBranchId ) )
|
||||
{
|
||||
++connIdxFromBottom;
|
||||
|
||||
prevGridIdx = branchCells[clSegIdx].m_gridIndex;
|
||||
prevGridCellIdx = branchCells[clSegIdx].m_gridCellIndex;
|
||||
prevErtSegId = branchCells[clSegIdx].m_ertSegmentId;
|
||||
prevErtBranchId = branchCells[clSegIdx].m_ertBranchId;
|
||||
}
|
||||
|
||||
resPointToConnectionIndexFromBottom[clSegIdx] = connIdxFromBottom;
|
||||
|
||||
--clSegIdx;
|
||||
}
|
||||
|
||||
return resPointToConnectionIndexFromBottom;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
size_t RigAccWellFlowCalculator::connectionIndexFromTop( const std::vector<size_t>& resPointToConnectionIndexFromBottom,
|
||||
size_t clSegIdx )
|
||||
{
|
||||
return resPointToConnectionIndexFromBottom.front() - resPointToConnectionIndexFromBottom[clSegIdx];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<size_t> RigAccWellFlowCalculator::findDownStreamBranchIdxs( const RigWellResultPoint& connectionPoint ) const
|
||||
{
|
||||
std::vector<size_t> downStreamBranchIdxs;
|
||||
|
||||
for ( size_t bIdx = 0; bIdx < m_pipeBranchesWellResultPoints.size(); ++bIdx )
|
||||
{
|
||||
if ( m_pipeBranchesWellResultPoints[bIdx][0].m_gridIndex == connectionPoint.m_gridIndex &&
|
||||
m_pipeBranchesWellResultPoints[bIdx][0].m_gridCellIndex == connectionPoint.m_gridCellIndex &&
|
||||
m_pipeBranchesWellResultPoints[bIdx][0].m_ertBranchId == connectionPoint.m_ertBranchId &&
|
||||
m_pipeBranchesWellResultPoints[bIdx][0].m_ertSegmentId == connectionPoint.m_ertSegmentId )
|
||||
{
|
||||
downStreamBranchIdxs.push_back( bIdx );
|
||||
}
|
||||
}
|
||||
return downStreamBranchIdxs;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
void RigAccWellFlowCalculator::sortTracers()
|
||||
{
|
||||
std::multimap<double, QString> sortedTracers;
|
||||
for ( const QString& tracerName : m_tracerNames )
|
||||
{
|
||||
const std::vector<double>& mainBranchAccFlow = accumulatedTracerFlowPrConnection( tracerName, 0 );
|
||||
|
||||
double totalFlow = 0.0;
|
||||
|
||||
if ( mainBranchAccFlow.size() )
|
||||
totalFlow = -fabs( mainBranchAccFlow.back() ); // Based on size in reverse order (biggest to least)
|
||||
|
||||
sortedTracers.insert( { totalFlow, tracerName } );
|
||||
}
|
||||
|
||||
m_tracerNames.clear();
|
||||
for ( const auto& tracerPair : sortedTracers )
|
||||
{
|
||||
m_tracerNames.push_back( tracerPair.second );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Concatenate small tracers into an "Other" group
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigAccWellFlowCalculator::groupSmallContributions()
|
||||
{
|
||||
if ( !( m_smallContributionsThreshold > 0.0 ) ) return;
|
||||
|
||||
// Find the tracers we need to group
|
||||
|
||||
std::vector<QString> tracersToGroup;
|
||||
{
|
||||
bool hasConsistentWellFlow = isWellFlowConsistent();
|
||||
|
||||
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 )
|
||||
{
|
||||
if ( fabs( 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( tracersToGroup.size() < 2 ) return; // Must at least group two ...
|
||||
|
||||
// Concatenate the values for each branch, erasing the tracers being grouped, replaced with the concatenated values
|
||||
|
||||
for ( BranchFlow& brRes : m_connectionFlowPrBranch )
|
||||
{
|
||||
groupSmallTracers( &brRes.accFlowPrTracer, tracersToGroup );
|
||||
groupSmallTracers( &brRes.flowPrTracer, tracersToGroup );
|
||||
}
|
||||
|
||||
for ( BranchFlow& brRes : m_pseudoLengthFlowPrBranch )
|
||||
{
|
||||
groupSmallTracers( &brRes.accFlowPrTracer, tracersToGroup );
|
||||
groupSmallTracers( &brRes.flowPrTracer, tracersToGroup );
|
||||
}
|
||||
|
||||
// Remove the grouped tracer names from the tracerName list, and replace with the "Others" name
|
||||
|
||||
std::vector<QString> filteredTracernames;
|
||||
for ( const QString& tracerName : m_tracerNames )
|
||||
{
|
||||
bool isDeleted = false;
|
||||
for ( const QString& deletedTracerName : tracersToGroup )
|
||||
{
|
||||
if ( tracerName == deletedTracerName )
|
||||
{
|
||||
isDeleted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !isDeleted ) filteredTracernames.push_back( tracerName );
|
||||
}
|
||||
|
||||
m_tracerNames.swap( filteredTracernames );
|
||||
m_tracerNames.push_back( RIG_TINY_TRACER_GROUP_NAME );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigAccWellFlowCalculator::groupSmallTracers( std::map<QString, std::vector<double>>* branchFlowSet,
|
||||
const std::vector<QString>& tracersToGroup )
|
||||
{
|
||||
if ( branchFlowSet->empty() ) return;
|
||||
|
||||
size_t depthCount = branchFlowSet->begin()->second.size();
|
||||
std::vector<double> groupedAccFlowValues( depthCount, 0.0 );
|
||||
|
||||
for ( const QString& tracername : tracersToGroup )
|
||||
{
|
||||
auto it = branchFlowSet->find( tracername );
|
||||
|
||||
if ( it != branchFlowSet->end() )
|
||||
{
|
||||
const std::vector<double>& tracerVals = it->second;
|
||||
for ( size_t cIdx = 0; cIdx < groupedAccFlowValues.size(); ++cIdx )
|
||||
{
|
||||
groupedAccFlowValues[cIdx] += tracerVals[cIdx];
|
||||
}
|
||||
}
|
||||
|
||||
branchFlowSet->erase( it );
|
||||
}
|
||||
|
||||
( *branchFlowSet )[RIG_TINY_TRACER_GROUP_NAME] = groupedAccFlowValues;
|
||||
}
|
||||
Reference in New Issue
Block a user