2016-12-14 09:50:30 +01:00
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2016- 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 "RimFlowDiagSolution.h"
2017-01-09 19:04:45 +01:00
2017-02-10 18:53:14 +01:00
#include "RiaApplication.h"
2017-02-10 08:39:25 +01:00
#include "RiaColorTables.h"
2016-12-14 09:50:30 +01:00
2017-01-09 19:14:07 +01:00
#include "RigActiveCellInfo.h"
2016-12-20 11:41:05 +01:00
#include "RigCaseCellResultsData.h"
2017-01-10 09:51:39 +01:00
#include "RigEclipseCaseData.h"
2017-01-09 19:04:45 +01:00
#include "RigFlowDiagResults.h"
#include "RigMainGrid.h"
2017-01-09 19:51:15 +01:00
#include "RigSingleWellResultsData.h"
2017-02-10 08:39:25 +01:00
#include "RimEclipseResultCase.h"
2017-02-24 11:07:15 +01:00
#include "RimEclipseView.h"
2017-02-10 18:53:14 +01:00
#include "RimEclipseWell.h"
2017-02-02 09:56:39 +01:00
#include "RimEclipseWellCollection.h"
2016-12-16 14:17:56 +01:00
2016-12-14 09:50:30 +01:00
CAF_PDM_SOURCE_INIT ( RimFlowDiagSolution , "FlowDiagSolution" );
2017-03-16 17:46:45 +01:00
#define CROSS_FLOW_ENDING "-XF"
2017-03-06 16:33:29 +01:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-03-17 18:11:06 +01:00
bool RimFlowDiagSolution :: hasCrossFlowEnding ( const QString & tracerName )
2017-03-06 16:33:29 +01:00
{
2017-03-16 17:46:45 +01:00
return tracerName . endsWith ( CROSS_FLOW_ENDING );
2017-03-06 16:33:29 +01:00
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-03-17 18:11:06 +01:00
QString RimFlowDiagSolution :: removeCrossFlowEnding ( const QString & tracerName )
2017-03-06 16:33:29 +01:00
{
2017-03-16 17:46:45 +01:00
if ( tracerName . endsWith ( CROSS_FLOW_ENDING ))
2017-03-06 16:33:29 +01:00
{
return tracerName . left ( tracerName . size () - 3 );
}
else
{
return tracerName ;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-03-17 18:11:06 +01:00
QString RimFlowDiagSolution :: addCrossFlowEnding ( const QString & wellName )
2017-03-06 16:33:29 +01:00
{
2017-03-16 17:46:45 +01:00
return wellName + CROSS_FLOW_ENDING ;
2017-03-06 16:33:29 +01:00
}
2016-12-14 09:50:30 +01:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimFlowDiagSolution :: RimFlowDiagSolution ( void )
{
CAF_PDM_InitObject ( "Flow Diagnostics Solution" , "" , "" , "" );
CAF_PDM_InitField ( & m_userDescription , "UserDescription" , QString ( "All Wells" ) , "Description" , "" , "" , "" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimFlowDiagSolution ::~ RimFlowDiagSolution ( void )
{
}
2017-03-09 10:03:52 +01:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimFlowDiagSolution :: userDescription () const
{
return m_userDescription ();
}
2016-12-16 14:17:56 +01:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RigFlowDiagResults * RimFlowDiagSolution :: flowDiagResults ()
{
2016-12-17 10:46:57 +01:00
if ( m_flowDiagResults . isNull () )
{
size_t timeStepCount ;
{
RimEclipseResultCase * eclCase ;
this -> firstAncestorOrThisOfType ( eclCase );
2017-03-15 09:10:16 +01:00
CVF_ASSERT ( eclCase && eclCase -> eclipseCaseData () );
2016-12-17 10:46:57 +01:00
2017-03-15 09:10:16 +01:00
timeStepCount = eclCase -> eclipseCaseData () -> results ( RifReaderInterface :: MATRIX_RESULTS ) -> maxTimeStepCount ();
2016-12-17 10:46:57 +01:00
}
m_flowDiagResults = new RigFlowDiagResults ( this , timeStepCount );
}
2016-12-16 14:17:56 +01:00
return m_flowDiagResults . p ();
}
2016-12-14 09:50:30 +01:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-03-09 10:03:52 +01:00
std :: vector < QString > RimFlowDiagSolution :: tracerNames () const
2016-12-14 09:50:30 +01:00
{
RimEclipseResultCase * eclCase ;
this -> firstAncestorOrThisOfType ( eclCase );
2017-01-03 09:27:25 +01:00
std :: vector < QString > tracerNameSet ;
2016-12-14 09:50:30 +01:00
if ( eclCase )
{
2017-03-15 09:10:16 +01:00
const cvf :: Collection < RigSingleWellResultsData >& wellResults = eclCase -> eclipseCaseData () -> wellResults ();
2016-12-14 09:50:30 +01:00
for ( size_t wIdx = 0 ; wIdx < wellResults . size (); ++ wIdx )
{
2017-01-03 09:27:25 +01:00
tracerNameSet . push_back ( wellResults [ wIdx ] -> m_wellName );
2017-03-06 16:33:29 +01:00
tracerNameSet . push_back ( addCrossFlowEnding ( wellResults [ wIdx ] -> m_wellName ));
2016-12-14 09:50:30 +01:00
}
}
return tracerNameSet ;
}
2016-12-20 11:41:05 +01:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-03-09 10:03:52 +01:00
std :: map < std :: string , std :: vector < int > > RimFlowDiagSolution :: allInjectorTracerActiveCellIndices ( size_t timeStepIndex ) const
2016-12-20 11:41:05 +01:00
{
return allTracerActiveCellIndices ( timeStepIndex , true );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-03-09 10:03:52 +01:00
std :: map < std :: string , std :: vector < int > > RimFlowDiagSolution :: allProducerTracerActiveCellIndices ( size_t timeStepIndex ) const
2016-12-20 11:41:05 +01:00
{
return allTracerActiveCellIndices ( timeStepIndex , false );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-03-09 10:03:52 +01:00
std :: map < std :: string , std :: vector < int > > RimFlowDiagSolution :: allTracerActiveCellIndices ( size_t timeStepIndex , bool useInjectors ) const
2016-12-20 11:41:05 +01:00
{
RimEclipseResultCase * eclCase ;
this -> firstAncestorOrThisOfType ( eclCase );
std :: map < std :: string , std :: vector < int > > tracersWithCells ;
if ( eclCase )
{
2017-03-15 09:10:16 +01:00
const cvf :: Collection < RigSingleWellResultsData >& wellResults = eclCase -> eclipseCaseData () -> wellResults ();
RigMainGrid * mainGrid = eclCase -> eclipseCaseData () -> mainGrid ();
RigActiveCellInfo * activeCellInfo = eclCase -> eclipseCaseData () -> activeCellInfo ( RifReaderInterface :: MATRIX_RESULTS ); //Todo: Must come from the results definition
2016-12-20 11:41:05 +01:00
for ( size_t wIdx = 0 ; wIdx < wellResults . size (); ++ wIdx )
{
if ( ! wellResults [ wIdx ] -> hasWellResult ( timeStepIndex ) ) continue ;
2017-03-07 12:19:19 +01:00
const RigWellResultFrame & wellResFrame = wellResults [ wIdx ] -> wellResultFrame ( timeStepIndex );
bool isInjectorWell = ( wellResFrame . m_productionType != RigWellResultFrame :: PRODUCER
&& wellResFrame . m_productionType != RigWellResultFrame :: UNDEFINED_PRODUCTION_TYPE );
2016-12-20 11:41:05 +01:00
2017-03-22 14:04:13 +01:00
std :: string wellName = wellResults [ wIdx ] -> m_wellName . toStdString ();
2017-03-06 16:33:29 +01:00
std :: string wellNameXf = addCrossFlowEnding ( wellResults [ wIdx ] -> m_wellName ). toStdString ();
2016-12-20 11:41:05 +01:00
2017-03-22 14:04:13 +01:00
std :: vector < int >& tracerCells = tracersWithCells [ wellName ];
2017-03-06 16:33:29 +01:00
std :: vector < int >& tracerCellsCrossFlow = tracersWithCells [ wellNameXf ];
2016-12-20 11:41:05 +01:00
2017-03-06 16:33:29 +01:00
for ( const RigWellResultBranch & wBr : wellResFrame . m_wellResultBranches )
{
for ( const RigWellResultPoint & wrp : wBr . m_branchResultPoints )
2016-12-20 11:41:05 +01:00
{
2017-03-06 16:33:29 +01:00
if ( wrp . isValid () && wrp . m_isOpen
&& ( ( useInjectors && wrp . flowRate () < 0.0 ) || ( ! useInjectors && wrp . flowRate () > 0.0 ) ) )
2016-12-20 11:41:05 +01:00
{
2017-03-06 16:33:29 +01:00
RigGridBase * grid = mainGrid -> gridByIndex ( wrp . m_gridIndex );
size_t reservoirCellIndex = grid -> reservoirCellIndex ( wrp . m_gridCellIndex );
int cellActiveIndex = static_cast < int > ( activeCellInfo -> cellResultIndex ( reservoirCellIndex ));
2016-12-20 11:41:05 +01:00
2017-03-06 16:33:29 +01:00
if ( useInjectors == isInjectorWell )
{
2016-12-20 11:41:05 +01:00
tracerCells . push_back ( cellActiveIndex );
}
2017-03-06 16:33:29 +01:00
else
{
tracerCellsCrossFlow . push_back ( cellActiveIndex );
}
2016-12-20 11:41:05 +01:00
}
}
}
2017-03-22 14:04:13 +01:00
if ( tracerCells . empty ()) tracersWithCells . erase ( wellName );
if ( tracerCellsCrossFlow . empty ()) tracersWithCells . erase ( wellNameXf );
2016-12-20 11:41:05 +01:00
}
}
return tracersWithCells ;
}
2016-12-14 09:50:30 +01:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-03-09 10:03:52 +01:00
RimFlowDiagSolution :: TracerStatusType RimFlowDiagSolution :: tracerStatusOverall ( const QString & tracerName ) const
2016-12-14 09:50:30 +01:00
{
RimEclipseResultCase * eclCase ;
2017-03-06 16:33:29 +01:00
this -> firstAncestorOrThisOfTypeAsserted ( eclCase );
2016-12-14 09:50:30 +01:00
TracerStatusType tracerStatus = UNDEFINED ;
2017-03-06 16:33:29 +01:00
2017-03-15 09:10:16 +01:00
const cvf :: Collection < RigSingleWellResultsData >& wellResults = eclCase -> eclipseCaseData () -> wellResults ();
2017-03-06 16:33:29 +01:00
for ( size_t wIdx = 0 ; wIdx < wellResults . size (); ++ wIdx )
2016-12-14 09:50:30 +01:00
{
2017-03-06 16:33:29 +01:00
QString wellName = removeCrossFlowEnding ( tracerName );
2016-12-14 09:50:30 +01:00
2017-03-06 16:33:29 +01:00
if ( wellResults [ wIdx ] -> m_wellName != wellName ) continue ;
tracerStatus = CLOSED ;
for ( const RigWellResultFrame & wellResFrame : wellResults [ wIdx ] -> m_wellCellsTimeSteps )
2016-12-14 09:50:30 +01:00
{
2017-03-07 12:19:19 +01:00
if ( wellResFrame . m_productionType == RigWellResultFrame :: GAS_INJECTOR
|| wellResFrame . m_productionType == RigWellResultFrame :: OIL_INJECTOR
|| wellResFrame . m_productionType == RigWellResultFrame :: WATER_INJECTOR )
2016-12-14 09:50:30 +01:00
{
2017-03-07 12:19:19 +01:00
if ( tracerStatus == PRODUCER ) tracerStatus = VARYING ;
else tracerStatus = INJECTOR ;
}
else if ( wellResFrame . m_productionType == RigWellResultFrame :: PRODUCER )
{
if ( tracerStatus == INJECTOR ) tracerStatus = VARYING ;
else tracerStatus = PRODUCER ;
2016-12-14 09:50:30 +01:00
}
2017-03-06 16:33:29 +01:00
if ( tracerStatus == VARYING ) break ;
2016-12-14 09:50:30 +01:00
}
2017-03-06 16:33:29 +01:00
break ;
}
if ( hasCrossFlowEnding ( tracerName ))
{
if ( tracerStatus == PRODUCER ) tracerStatus = INJECTOR ;
else if ( tracerStatus == INJECTOR ) tracerStatus = PRODUCER ;
2016-12-14 09:50:30 +01:00
}
return tracerStatus ;
}
2016-12-21 17:14:13 +01:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-03-09 10:03:52 +01:00
RimFlowDiagSolution :: TracerStatusType RimFlowDiagSolution :: tracerStatusInTimeStep ( const QString & tracerName , size_t timeStepIndex ) const
2016-12-21 17:14:13 +01:00
{
RimEclipseResultCase * eclCase ;
2017-03-06 16:33:29 +01:00
this -> firstAncestorOrThisOfTypeAsserted ( eclCase );
2016-12-21 17:14:13 +01:00
2017-03-15 09:10:16 +01:00
const cvf :: Collection < RigSingleWellResultsData >& wellResults = eclCase -> eclipseCaseData () -> wellResults ();
2017-03-06 16:33:29 +01:00
for ( size_t wIdx = 0 ; wIdx < wellResults . size (); ++ wIdx )
2016-12-21 17:14:13 +01:00
{
2017-03-06 16:33:29 +01:00
QString wellName = removeCrossFlowEnding ( tracerName );
2016-12-21 17:14:13 +01:00
2017-03-06 16:33:29 +01:00
if ( wellResults [ wIdx ] -> m_wellName != wellName ) continue ;
2017-03-07 12:19:19 +01:00
if ( ! wellResults [ wIdx ] -> hasWellResult ( timeStepIndex )) return CLOSED ;
2017-03-06 16:33:29 +01:00
2017-03-07 12:19:19 +01:00
const RigWellResultFrame & wellResFrame = wellResults [ wIdx ] -> wellResultFrame ( timeStepIndex );
2017-03-06 16:33:29 +01:00
2017-03-07 12:19:19 +01:00
if ( wellResFrame . m_productionType == RigWellResultFrame :: GAS_INJECTOR
|| wellResFrame . m_productionType == RigWellResultFrame :: OIL_INJECTOR
|| wellResFrame . m_productionType == RigWellResultFrame :: WATER_INJECTOR )
2016-12-21 17:14:13 +01:00
{
2017-03-07 12:19:19 +01:00
if ( hasCrossFlowEnding ( tracerName ) ) return PRODUCER ;
2017-03-06 16:33:29 +01:00
2017-03-07 12:19:19 +01:00
return INJECTOR ;
}
else if ( wellResFrame . m_productionType == RigWellResultFrame :: PRODUCER
|| wellResFrame . m_productionType == RigWellResultFrame :: UNDEFINED_PRODUCTION_TYPE )
{
if ( hasCrossFlowEnding ( tracerName ) ) return INJECTOR ;
2017-01-11 12:34:48 +01:00
2017-03-07 12:19:19 +01:00
return PRODUCER ;
}
else
{
CVF_ASSERT ( false );
2016-12-21 17:14:13 +01:00
}
}
CVF_ASSERT ( false );
return UNDEFINED ;
}
2017-02-02 09:56:39 +01:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-03-09 10:03:52 +01:00
cvf :: Color3f RimFlowDiagSolution :: tracerColor ( const QString & tracerName ) const
2017-02-02 09:56:39 +01:00
{
2017-04-06 14:12:24 +02:00
QString wellName = removeCrossFlowEnding ( tracerName );
if ( wellName == RIG_FLOW_TOTAL_NAME ) return cvf :: Color3f :: LIGHT_GRAY ;
if ( wellName == RIG_RESERVOIR_TRACER_NAME ) return cvf :: Color3f :: LIGHT_GRAY ;
if ( wellName == RIG_TINY_TRACER_GROUP_NAME ) return cvf :: Color3f :: DARK_GRAY ;
2017-02-02 09:56:39 +01:00
RimEclipseResultCase * eclCase ;
this -> firstAncestorOrThisOfType ( eclCase );
if ( eclCase )
{
2017-04-06 14:12:24 +02:00
return eclCase -> defaultWellColor ( wellName );
2017-02-02 09:56:39 +01:00
}
2017-02-17 11:18:58 +01:00
return cvf :: Color3f :: LIGHT_GRAY ;
2017-02-02 09:56:39 +01:00
}
2016-12-14 09:50:30 +01:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
caf :: PdmFieldHandle * RimFlowDiagSolution :: userDescriptionField ()
{
return & m_userDescription ;
}