2012-05-18 09:45:23 +02:00
/////////////////////////////////////////////////////////////////////////////////
//
2014-09-23 15:04:57 +02:00
// Copyright (C) 2011- Statoil ASA
// Copyright (C) 2013- Ceetron Solutions AS
// Copyright (C) 2011-2012 Ceetron AS
2012-05-18 09:45:23 +02:00
//
// 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.
//
/////////////////////////////////////////////////////////////////////////////////
2014-08-27 14:05:29 +02:00
#include "RifReaderEclipseOutput.h"
2012-05-18 09:45:23 +02:00
2017-01-17 15:11:02 +01:00
#include "RifEclipseInputFileTools.h"
2012-06-26 16:10:41 +02:00
#include "RifEclipseOutputFileTools.h"
#include "RifEclipseRestartFilesetAccess.h"
2014-08-27 14:05:29 +02:00
#include "RifEclipseUnifiedRestartFileAccess.h"
2012-05-18 09:45:23 +02:00
2017-01-17 15:11:02 +01:00
#include "RigActiveCellInfo.h"
#include "RigCaseCellResultsData.h"
#include "RigEclipseCaseData.h"
#include "RigMainGrid.h"
#include "RigSingleWellResultsData.h"
2014-08-27 14:05:29 +02:00
#include "cafProgressInfo.h"
2012-05-18 09:45:23 +02:00
2017-01-17 15:11:02 +01:00
#include "cvfTrace.h"
2016-05-26 14:49:13 +02:00
#include "ert/ecl/ecl_kw_magic.h"
2017-01-17 15:11:02 +01:00
#include "ert/ecl/ecl_nnc_export.h"
2013-02-27 11:27:02 +01:00
2017-01-17 15:11:02 +01:00
#include <cmath> // Needed for HUGE_VAL on Linux
2014-08-27 14:05:29 +02:00
#include <iostream>
2013-08-26 14:56:34 +02:00
#include <map>
2014-08-27 14:05:29 +02:00
2012-05-18 09:45:23 +02:00
//--------------------------------------------------------------------------------------------------
/// ECLIPSE cell numbering layout:
/// Lower layer: Upper layer
2013-12-18 15:36:28 +01:00
/// Low Depth High Depth
/// Low K High K
/// Shallow Deep
2012-05-18 09:45:23 +02:00
/// 2---3 6---7
/// | | | |
/// 0---1 4---5
///
///
///
//--------------------------------------------------------------------------------------------------
// The indexing conventions for vertices in ECLIPSE
//
2013-12-18 15:36:28 +01:00
// 2-------------3
// /| /|
// / | / | /j
// / | / | /
// 0-------------1 | *---i
// | | | | |
// | 6---------|---7 |
// | / | / |k
2012-05-18 09:45:23 +02:00
// | / | /
// |/ |/
2013-12-18 15:36:28 +01:00
// 4-------------5
2012-05-18 09:45:23 +02:00
// vertex indices
//
// The indexing conventions for vertices in ResInsight
//
2013-01-30 15:02:28 +01:00
// 7-------------6 |k
// /| /| | /j
// / | / | |/
// / | / | *---i
2012-05-18 09:45:23 +02:00
// 4-------------5 |
// | | | |
// | 3---------|---2
// | / | /
// | / | /
// |/ |/
// 0-------------1
// vertex indices
//
static const size_t cellMappingECLRi [ 8 ] = { 0 , 1 , 3 , 2 , 4 , 5 , 7 , 6 };
//**************************************************************************************************
// Static functions
//**************************************************************************************************
2013-03-13 11:50:31 +01:00
bool transferGridCellData ( RigMainGrid * mainGrid , RigActiveCellInfo * activeCellInfo , RigActiveCellInfo * fractureActiveCellInfo , RigGridBase * localGrid , const ecl_grid_type * localEclGrid , size_t matrixActiveStartIndex , size_t fractureActiveStartIndex )
2012-05-18 09:45:23 +02:00
{
2013-03-13 11:50:31 +01:00
CVF_ASSERT ( activeCellInfo && fractureActiveCellInfo );
2013-02-12 11:15:36 +01:00
2012-05-18 09:45:23 +02:00
int cellCount = ecl_grid_get_global_size ( localEclGrid );
2015-11-24 14:21:02 +01:00
size_t cellStartIndex = mainGrid -> globalCellArray (). size ();
2012-05-18 09:45:23 +02:00
size_t nodeStartIndex = mainGrid -> nodes (). size ();
RigCell defaultCell ;
defaultCell . setHostGrid ( localGrid );
2015-11-24 14:21:02 +01:00
mainGrid -> globalCellArray (). resize ( cellStartIndex + cellCount , defaultCell );
2012-05-18 09:45:23 +02:00
mainGrid -> nodes (). resize ( nodeStartIndex + cellCount * 8 , cvf :: Vec3d ( 0 , 0 , 0 ));
2012-09-11 09:22:36 +02:00
int progTicks = 100 ;
double cellsPrProgressTick = cellCount / ( float ) progTicks ;
caf :: ProgressInfo progInfo ( progTicks , "" );
2012-06-26 16:10:41 +02:00
size_t computedCellCount = 0 ;
2012-05-18 09:45:23 +02:00
// Loop over cells and fill them with data
2012-09-11 09:22:36 +02:00
#pragma omp parallel for
2014-08-08 09:50:57 +02:00
for ( int gridLocalCellIndex = 0 ; gridLocalCellIndex < cellCount ; ++ gridLocalCellIndex )
2012-05-18 09:45:23 +02:00
{
2015-11-24 14:21:02 +01:00
RigCell & cell = mainGrid -> globalCellArray ()[ cellStartIndex + gridLocalCellIndex ];
2012-05-18 09:45:23 +02:00
2014-08-22 08:01:31 +02:00
cell . setGridLocalCellIndex ( gridLocalCellIndex );
2013-01-30 15:02:28 +01:00
2013-02-01 15:33:21 +01:00
// Active cell index
2014-08-08 09:50:57 +02:00
int matrixActiveIndex = ecl_grid_get_active_index1 ( localEclGrid , gridLocalCellIndex );
2013-01-30 15:02:28 +01:00
if ( matrixActiveIndex != - 1 )
{
2014-08-08 09:50:57 +02:00
activeCellInfo -> setCellResultIndex ( cellStartIndex + gridLocalCellIndex , matrixActiveStartIndex + matrixActiveIndex );
2013-01-30 15:02:28 +01:00
}
2013-01-30 09:30:48 +01:00
2014-08-08 09:50:57 +02:00
int fractureActiveIndex = ecl_grid_get_active_fracture_index1 ( localEclGrid , gridLocalCellIndex );
2013-01-30 15:02:28 +01:00
if ( fractureActiveIndex != - 1 )
2013-01-30 09:30:48 +01:00
{
2014-08-08 09:50:57 +02:00
fractureActiveCellInfo -> setCellResultIndex ( cellStartIndex + gridLocalCellIndex , fractureActiveStartIndex + fractureActiveIndex );
2013-01-30 15:02:28 +01:00
}
2012-05-18 09:45:23 +02:00
2013-02-01 15:33:21 +01:00
// Parent cell index
2014-08-08 09:50:57 +02:00
int parentCellIndex = ecl_grid_get_parent_cell1 ( localEclGrid , gridLocalCellIndex );
2012-05-18 09:45:23 +02:00
if ( parentCellIndex == - 1 )
{
cell . setParentCellIndex ( cvf :: UNDEFINED_SIZE_T );
}
else
{
cell . setParentCellIndex ( parentCellIndex );
}
// Corner coordinates
int cIdx ;
for ( cIdx = 0 ; cIdx < 8 ; ++ cIdx )
{
2014-08-08 09:50:57 +02:00
double * point = mainGrid -> nodes ()[ nodeStartIndex + gridLocalCellIndex * 8 + cellMappingECLRi [ cIdx ]]. ptr ();
2014-10-09 20:13:04 +02:00
ecl_grid_get_cell_corner_xyz1 ( localEclGrid , gridLocalCellIndex , cIdx , & ( point [ 0 ]), & ( point [ 1 ]), & ( point [ 2 ]));
2013-12-19 08:48:36 +01:00
point [ 2 ] = - point [ 2 ]; // Flipping Z making depth become negative z values
2014-08-08 09:50:57 +02:00
cell . cornerIndices ()[ cIdx ] = nodeStartIndex + gridLocalCellIndex * 8 + cIdx ;
2012-05-18 09:45:23 +02:00
}
// Sub grid in cell
2014-08-08 09:50:57 +02:00
const ecl_grid_type * subGrid = ecl_grid_get_cell_lgr1 ( localEclGrid , gridLocalCellIndex );
2012-05-18 09:45:23 +02:00
if ( subGrid != NULL )
{
2013-09-05 13:03:53 +02:00
int subGridId = ecl_grid_get_lgr_nr ( subGrid );
CVF_ASSERT ( subGridId > 0 );
cell . setSubGrid ( static_cast < RigLocalGrid *> ( mainGrid -> gridById ( subGridId )));
2012-05-18 09:45:23 +02:00
}
2012-06-26 16:10:41 +02:00
2013-02-01 15:33:21 +01:00
// Mark inactive long pyramid looking cells as invalid
2013-02-11 15:12:53 +01:00
// Forslag
//if (!invalid && (cell.isInCoarseCell() || (!cell.isActiveInMatrixModel() && !cell.isActiveInFractureModel()) ) )
2013-08-26 21:56:40 +02:00
cell . setInvalid ( cell . isLongPyramidCell ());
2013-01-30 15:02:28 +01:00
2012-06-26 16:10:41 +02:00
#pragma omp atomic
computedCellCount ++ ;
2012-09-11 09:22:36 +02:00
progInfo . setProgress (( int )( computedCellCount / cellsPrProgressTick ));
2012-05-18 09:45:23 +02:00
}
2012-06-26 16:10:41 +02:00
return true ;
2012-05-18 09:45:23 +02:00
}
//==================================================================================================
//
// Class RigReaderInterfaceECL
//
//==================================================================================================
//--------------------------------------------------------------------------------------------------
/// Constructor
//--------------------------------------------------------------------------------------------------
2012-06-26 16:10:41 +02:00
RifReaderEclipseOutput :: RifReaderEclipseOutput ()
2012-05-18 09:45:23 +02:00
{
2013-02-27 14:30:32 +01:00
m_fileName . clear ();
2013-04-10 11:02:10 +02:00
m_filesWithSameBaseName . clear ();
2013-02-27 14:30:32 +01:00
m_timeSteps . clear ();
m_eclipseCase = NULL ;
2013-02-27 14:13:37 +01:00
m_ecl_init_file = NULL ;
m_dynamicResultsAccess = NULL ;
2012-05-18 09:45:23 +02:00
}
//--------------------------------------------------------------------------------------------------
/// Destructor
//--------------------------------------------------------------------------------------------------
2012-06-26 16:10:41 +02:00
RifReaderEclipseOutput ::~ RifReaderEclipseOutput ()
2012-05-18 09:45:23 +02:00
{
2013-03-08 08:24:40 +01:00
close ();
2012-05-18 09:45:23 +02:00
2013-02-27 14:13:37 +01:00
if ( m_ecl_init_file )
2013-02-27 11:27:02 +01:00
{
2013-02-27 14:13:37 +01:00
ecl_file_close ( m_ecl_init_file );
2013-02-27 11:27:02 +01:00
}
2013-02-27 14:13:37 +01:00
m_ecl_init_file = NULL ;
2013-02-27 11:27:02 +01:00
2013-02-27 14:13:37 +01:00
if ( m_dynamicResultsAccess . notNull ())
{
m_dynamicResultsAccess -> close ();
}
2013-04-29 13:13:42 +02:00
}
//--------------------------------------------------------------------------------------------------
/// Close interface (for now, no files are kept open after calling methods, so just clear members)
//--------------------------------------------------------------------------------------------------
void RifReaderEclipseOutput :: close ()
{
2012-05-18 09:45:23 +02:00
}
//--------------------------------------------------------------------------------------------------
/// Read geometry from file given by name into given reservoir object
//--------------------------------------------------------------------------------------------------
2017-01-10 09:51:39 +01:00
bool RifReaderEclipseOutput :: transferGeometry ( const ecl_grid_type * mainEclGrid , RigEclipseCaseData * eclipseCase )
2012-05-18 09:45:23 +02:00
{
2013-02-13 13:24:39 +01:00
CVF_ASSERT ( eclipseCase );
2012-05-18 09:45:23 +02:00
if ( ! mainEclGrid )
{
// Some error
return false ;
}
2013-03-13 11:50:31 +01:00
RigActiveCellInfo * activeCellInfo = eclipseCase -> activeCellInfo ( RifReaderInterface :: MATRIX_RESULTS );
RigActiveCellInfo * fractureActiveCellInfo = eclipseCase -> activeCellInfo ( RifReaderInterface :: FRACTURE_RESULTS );
CVF_ASSERT ( activeCellInfo && fractureActiveCellInfo );
2013-02-12 11:15:36 +01:00
2013-02-13 13:24:39 +01:00
RigMainGrid * mainGrid = eclipseCase -> mainGrid ();
2013-12-20 14:29:08 +01:00
CVF_ASSERT ( mainGrid );
2012-05-18 09:45:23 +02:00
{
cvf :: Vec3st gridPointDim ( 0 , 0 , 0 );
gridPointDim . x () = ecl_grid_get_nx ( mainEclGrid ) + 1 ;
gridPointDim . y () = ecl_grid_get_ny ( mainEclGrid ) + 1 ;
gridPointDim . z () = ecl_grid_get_nz ( mainEclGrid ) + 1 ;
mainGrid -> setGridPointDimensions ( gridPointDim );
}
2013-12-20 14:29:08 +01:00
// std::string mainGridName = ecl_grid_get_name(mainEclGrid);
// ERT returns file path to grid file as name for main grid
mainGrid -> setGridName ( "Main grid" );
2012-05-18 09:45:23 +02:00
// Get and set grid and lgr metadata
size_t totalCellCount = static_cast < size_t > ( ecl_grid_get_global_size ( mainEclGrid ));
int numLGRs = ecl_grid_get_num_lgr ( mainEclGrid );
int lgrIdx ;
for ( lgrIdx = 0 ; lgrIdx < numLGRs ; ++ lgrIdx )
{
ecl_grid_type * localEclGrid = ecl_grid_iget_lgr ( mainEclGrid , lgrIdx );
std :: string lgrName = ecl_grid_get_name ( localEclGrid );
2013-09-05 13:03:53 +02:00
int lgrId = ecl_grid_get_lgr_nr ( localEclGrid );
2012-05-18 09:45:23 +02:00
cvf :: Vec3st gridPointDim ( 0 , 0 , 0 );
gridPointDim . x () = ecl_grid_get_nx ( localEclGrid ) + 1 ;
gridPointDim . y () = ecl_grid_get_ny ( localEclGrid ) + 1 ;
gridPointDim . z () = ecl_grid_get_nz ( localEclGrid ) + 1 ;
RigLocalGrid * localGrid = new RigLocalGrid ( mainGrid );
2013-09-05 13:03:53 +02:00
localGrid -> setGridId ( lgrId );
2012-05-18 09:45:23 +02:00
mainGrid -> addLocalGrid ( localGrid );
localGrid -> setIndexToStartOfCells ( totalCellCount );
localGrid -> setGridName ( lgrName );
localGrid -> setGridPointDimensions ( gridPointDim );
totalCellCount += ecl_grid_get_global_size ( localEclGrid );
}
2013-02-12 11:15:36 +01:00
2014-08-08 10:27:29 +02:00
activeCellInfo -> setReservoirCellCount ( totalCellCount );
fractureActiveCellInfo -> setReservoirCellCount ( totalCellCount );
2012-05-18 09:45:23 +02:00
// Reserve room for the cells and nodes and fill them with data
2015-11-24 14:21:02 +01:00
mainGrid -> globalCellArray (). reserve ( totalCellCount );
2012-05-18 09:45:23 +02:00
mainGrid -> nodes (). reserve ( 8 * totalCellCount );
2012-09-11 09:22:36 +02:00
caf :: ProgressInfo progInfo ( 3 + numLGRs , "" );
2012-06-26 16:10:41 +02:00
progInfo . setProgressDescription ( "Main Grid" );
2012-09-11 09:22:36 +02:00
progInfo . setNextProgressIncrement ( 3 );
2012-06-26 16:10:41 +02:00
2013-03-13 11:50:31 +01:00
transferGridCellData ( mainGrid , activeCellInfo , fractureActiveCellInfo , mainGrid , mainEclGrid , 0 , 0 );
2012-05-18 09:45:23 +02:00
2012-09-11 09:22:36 +02:00
progInfo . setProgress ( 3 );
2012-06-26 16:10:41 +02:00
2013-01-30 09:30:48 +01:00
size_t globalMatrixActiveSize = ecl_grid_get_nactive ( mainEclGrid );
size_t globalFractureActiveSize = ecl_grid_get_nactive_fracture ( mainEclGrid );
2012-05-18 09:45:23 +02:00
2013-02-12 11:15:36 +01:00
activeCellInfo -> setGridCount ( 1 + numLGRs );
2013-03-13 11:50:31 +01:00
fractureActiveCellInfo -> setGridCount ( 1 + numLGRs );
2013-02-12 11:15:36 +01:00
2013-03-13 11:50:31 +01:00
activeCellInfo -> setGridActiveCellCounts ( 0 , globalMatrixActiveSize );
fractureActiveCellInfo -> setGridActiveCellCounts ( 0 , globalFractureActiveSize );
2013-05-21 11:10:59 +02:00
transferCoarseningInfo ( mainEclGrid , mainGrid );
2013-02-01 15:33:21 +01:00
2012-05-18 09:45:23 +02:00
for ( lgrIdx = 0 ; lgrIdx < numLGRs ; ++ lgrIdx )
{
2012-06-26 16:10:41 +02:00
progInfo . setProgressDescription ( "LGR number " + QString :: number ( lgrIdx + 1 ));
2012-05-18 09:45:23 +02:00
ecl_grid_type * localEclGrid = ecl_grid_iget_lgr ( mainEclGrid , lgrIdx );
2013-02-01 15:33:21 +01:00
RigLocalGrid * localGrid = static_cast < RigLocalGrid *> ( mainGrid -> gridByIndex ( lgrIdx + 1 ));
2013-03-13 11:50:31 +01:00
transferGridCellData ( mainGrid , activeCellInfo , fractureActiveCellInfo , localGrid , localEclGrid , globalMatrixActiveSize , globalFractureActiveSize );
2013-02-12 11:15:36 +01:00
int matrixActiveCellCount = ecl_grid_get_nactive ( localEclGrid );
globalMatrixActiveSize += matrixActiveCellCount ;
2013-02-01 15:33:21 +01:00
2013-02-12 11:15:36 +01:00
int fractureActiveCellCount = ecl_grid_get_nactive_fracture ( localEclGrid );
globalFractureActiveSize += fractureActiveCellCount ;
2013-02-01 15:33:21 +01:00
2013-03-13 11:50:31 +01:00
activeCellInfo -> setGridActiveCellCounts ( lgrIdx + 1 , matrixActiveCellCount );
fractureActiveCellInfo -> setGridActiveCellCounts ( lgrIdx + 1 , fractureActiveCellCount );
2013-05-21 11:10:59 +02:00
transferCoarseningInfo ( localEclGrid , localGrid );
2012-09-11 09:22:36 +02:00
progInfo . setProgress ( 3 + lgrIdx );
2012-05-18 09:45:23 +02:00
}
2013-02-12 11:15:36 +01:00
activeCellInfo -> computeDerivedData ();
2013-03-13 11:50:31 +01:00
fractureActiveCellInfo -> computeDerivedData ();
2013-02-12 11:15:36 +01:00
2012-05-18 09:45:23 +02:00
return true ;
}
//--------------------------------------------------------------------------------------------------
/// Open file and read geometry into given reservoir object
//--------------------------------------------------------------------------------------------------
2017-01-10 09:51:39 +01:00
bool RifReaderEclipseOutput :: open ( const QString & fileName , RigEclipseCaseData * eclipseCase )
2012-05-18 09:45:23 +02:00
{
2013-02-13 13:24:39 +01:00
CVF_ASSERT ( eclipseCase );
2013-02-06 13:44:27 +01:00
caf :: ProgressInfo progInfo ( 100 , "" );
2012-06-26 16:10:41 +02:00
progInfo . setProgressDescription ( "Reading Grid" );
2012-05-18 09:45:23 +02:00
// Make sure everything's closed
close ();
// Get set of files
QStringList fileSet ;
2013-04-10 11:02:10 +02:00
if ( ! RifEclipseOutputFileTools :: findSiblingFilesWithSameBaseName ( fileName , & fileSet )) return false ;
2013-02-06 13:44:27 +01:00
progInfo . incrementProgress ();
2012-06-26 16:10:41 +02:00
2013-02-06 13:44:27 +01:00
progInfo . setNextProgressIncrement ( 20 );
2012-05-18 09:45:23 +02:00
// Keep the set of files of interest
2013-04-10 11:02:10 +02:00
m_filesWithSameBaseName = fileSet ;
2012-05-18 09:45:23 +02:00
// Read geometry
2013-08-26 21:56:40 +02:00
// Todo: Needs to check existence of file before calling ert, else it will abort
2012-06-26 16:10:41 +02:00
ecl_grid_type * mainEclGrid = ecl_grid_alloc ( fileName . toAscii (). data () );
2013-02-06 13:44:27 +01:00
progInfo . incrementProgress ();
progInfo . setNextProgressIncrement ( 10 );
2012-06-26 16:10:41 +02:00
progInfo . setProgressDescription ( "Transferring grid geometry" );
2013-02-13 13:24:39 +01:00
if ( ! transferGeometry ( mainEclGrid , eclipseCase )) return false ;
2013-12-03 20:30:32 +01:00
progInfo . incrementProgress ();
progInfo . setProgressDescription ( "Reading faults" );
progInfo . setNextProgressIncrement ( 10 );
2013-12-20 09:18:52 +01:00
if ( isFaultImportEnabled ())
2013-12-03 20:30:32 +01:00
{
2016-10-21 08:48:33 +02:00
cvf :: Collection < RigFault > faults ;
2013-12-17 11:37:58 +01:00
2016-10-21 09:33:03 +02:00
importFaults ( fileSet , & faults );
2014-01-08 10:07:42 +01:00
2016-10-21 08:48:33 +02:00
RigMainGrid * mainGrid = eclipseCase -> mainGrid ();
mainGrid -> setFaults ( faults );
2013-12-17 11:37:58 +01:00
}
2013-12-03 20:30:32 +01:00
2013-02-06 13:44:27 +01:00
progInfo . incrementProgress ();
2013-08-26 13:56:42 +02:00
m_eclipseCase = eclipseCase ;
2012-06-26 16:10:41 +02:00
2012-05-18 09:45:23 +02:00
// Build results meta data
2013-12-11 14:55:14 +01:00
progInfo . setProgressDescription ( "Reading Result index" );
progInfo . setNextProgressIncrement ( 25 );
2013-04-22 13:24:49 +02:00
buildMetaData ();
2013-12-11 14:55:14 +01:00
progInfo . incrementProgress ();
2012-05-18 09:45:23 +02:00
2014-07-30 09:13:47 +02:00
if ( isNNCsEnabled ())
{
2014-11-06 09:35:39 +01:00
progInfo . setProgressDescription ( "Reading NNC data" );
progInfo . setNextProgressIncrement ( 5 );
2014-07-30 09:13:47 +02:00
transferNNCData ( mainEclGrid , m_ecl_init_file , eclipseCase -> mainGrid ());
2014-11-06 09:35:39 +01:00
progInfo . incrementProgress ();
2013-12-03 20:30:32 +01:00
2014-11-06 09:35:39 +01:00
progInfo . setProgressDescription ( "Processing NNC data" );
progInfo . setNextProgressIncrement ( 20 );
2014-07-30 09:13:47 +02:00
eclipseCase -> mainGrid () -> nncData () -> processConnections ( * ( eclipseCase -> mainGrid ()));
2014-11-06 09:35:39 +01:00
progInfo . incrementProgress ();
}
else
{
progInfo . setNextProgressIncrement ( 25 );
progInfo . incrementProgress ();
2014-07-30 09:13:47 +02:00
}
2013-12-11 14:55:14 +01:00
2013-02-06 13:44:27 +01:00
progInfo . setNextProgressIncrement ( 8 );
2012-06-26 16:10:41 +02:00
progInfo . setProgressDescription ( "Reading Well information" );
2014-10-24 11:38:47 +02:00
readWellCells ( mainEclGrid , isImportOfCompleteMswDataEnabled ());
2014-11-06 09:35:39 +01:00
progInfo . incrementProgress ();
2013-02-05 10:51:32 +01:00
2013-08-26 13:56:42 +02:00
progInfo . setProgressDescription ( "Releasing reader memory" );
ecl_grid_free ( mainEclGrid );
progInfo . incrementProgress ();
2013-02-05 10:51:32 +01:00
2012-05-18 09:45:23 +02:00
return true ;
}
2016-10-21 08:48:33 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifReaderEclipseOutput :: importFaults ( const QStringList & fileSet , cvf :: Collection < RigFault >* faults )
{
if ( this -> filenamesWithFaults (). size () > 0 )
{
for ( size_t i = 0 ; i < this -> filenamesWithFaults (). size (); i ++ )
{
QString faultFilename = this -> filenamesWithFaults ()[ i ];
2016-10-21 09:33:03 +02:00
RifEclipseInputFileTools :: parseAndReadFaults ( faultFilename , faults );
2016-10-21 08:48:33 +02:00
}
}
else
{
foreach ( QString fname , fileSet )
{
if ( fname . endsWith ( ".DATA" ))
{
std :: vector < QString > filenamesWithFaults ;
2017-04-18 11:32:04 +02:00
RifEclipseInputFileTools :: readFaultsInGridSection ( fname , faults , & filenamesWithFaults , faultIncludeFileAbsolutePathPrefix ());
2016-10-21 08:48:33 +02:00
std :: sort ( filenamesWithFaults . begin (), filenamesWithFaults . end ());
std :: vector < QString >:: iterator last = std :: unique ( filenamesWithFaults . begin (), filenamesWithFaults . end ());
filenamesWithFaults . erase ( last , filenamesWithFaults . end ());
this -> setFilenamesWithFaults ( filenamesWithFaults );
}
}
}
}
2016-10-21 09:33:03 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2013-12-10 22:44:40 +01:00
void RifReaderEclipseOutput :: transferNNCData ( const ecl_grid_type * mainEclGrid , const ecl_file_type * init_file , RigMainGrid * mainGrid )
{
if ( ! m_ecl_init_file ) return ;
CVF_ASSERT ( mainEclGrid && mainGrid );
// Get the data from ERT
int numNNC = ecl_nnc_export_get_size ( mainEclGrid );
2015-02-24 14:57:23 +01:00
if ( numNNC > 0 )
{
ecl_nnc_type * eclNNCData = new ecl_nnc_type [ numNNC ];
2013-12-10 22:44:40 +01:00
2015-02-24 14:57:23 +01:00
ecl_nnc_export ( mainEclGrid , init_file , eclNNCData );
2013-12-10 22:44:40 +01:00
2015-02-24 14:57:23 +01:00
// Transform to our own datastructures
//cvf::Trace::show("Reading NNC. Count: " + cvf::String(numNNC));
2013-12-10 22:44:40 +01:00
2015-02-24 14:57:23 +01:00
mainGrid -> nncData () -> connections (). resize ( numNNC );
std :: vector < double >& transmissibilityValues = mainGrid -> nncData () -> makeConnectionScalarResult ( cvf :: UNDEFINED_SIZE_T );
for ( int nIdx = 0 ; nIdx < numNNC ; ++ nIdx )
{
RigGridBase * grid1 = mainGrid -> gridByIndex ( eclNNCData [ nIdx ]. grid_nr1 );
mainGrid -> nncData () -> connections ()[ nIdx ]. m_c1GlobIdx = grid1 -> reservoirCellIndex ( eclNNCData [ nIdx ]. global_index1 );
RigGridBase * grid2 = mainGrid -> gridByIndex ( eclNNCData [ nIdx ]. grid_nr2 );
mainGrid -> nncData () -> connections ()[ nIdx ]. m_c2GlobIdx = grid2 -> reservoirCellIndex ( eclNNCData [ nIdx ]. global_index2 );
transmissibilityValues [ nIdx ] = eclNNCData [ nIdx ]. trans ;
}
2013-12-10 22:44:40 +01:00
2015-02-24 14:57:23 +01:00
delete [] eclNNCData ;
}
2013-12-10 22:44:40 +01:00
}
2013-02-27 11:27:02 +01:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-01-10 09:51:39 +01:00
bool RifReaderEclipseOutput :: openAndReadActiveCellData ( const QString & fileName , const std :: vector < QDateTime >& mainCaseTimeSteps , RigEclipseCaseData * eclipseCase )
2013-02-27 11:27:02 +01:00
{
CVF_ASSERT ( eclipseCase );
2013-02-27 11:54:32 +01:00
// It is required to have a main grid before reading active cell data
if ( ! eclipseCase -> mainGrid ())
{
return false ;
}
2013-02-27 11:27:02 +01:00
close ();
// Get set of files
QStringList fileSet ;
2013-04-10 11:02:10 +02:00
if ( ! RifEclipseOutputFileTools :: findSiblingFilesWithSameBaseName ( fileName , & fileSet )) return false ;
2013-02-27 11:27:02 +01:00
// Keep the set of files of interest
2013-04-10 11:02:10 +02:00
m_filesWithSameBaseName = fileSet ;
2013-02-27 14:13:37 +01:00
m_eclipseCase = eclipseCase ;
2013-02-27 11:27:02 +01:00
2013-02-27 14:13:37 +01:00
if ( ! readActiveCellInfo ())
2013-02-27 11:54:32 +01:00
{
return false ;
}
2013-02-27 11:27:02 +01:00
2013-04-10 11:02:10 +02:00
m_dynamicResultsAccess = createDynamicResultsAccess ();
2013-04-22 13:24:49 +02:00
if ( m_dynamicResultsAccess . notNull ())
{
m_dynamicResultsAccess -> setTimeSteps ( mainCaseTimeSteps );
}
2013-03-05 13:10:26 +01:00
2013-02-27 11:27:02 +01:00
return true ;
}
//--------------------------------------------------------------------------------------------------
///
2013-03-07 13:13:34 +01:00
/// See also RigStatistics::computeActiveCellUnion()
2013-02-27 11:27:02 +01:00
//--------------------------------------------------------------------------------------------------
2013-02-27 14:13:37 +01:00
bool RifReaderEclipseOutput :: readActiveCellInfo ()
2013-02-27 11:27:02 +01:00
{
2013-03-08 08:24:40 +01:00
CVF_ASSERT ( m_eclipseCase );
2013-02-27 14:13:37 +01:00
CVF_ASSERT ( m_eclipseCase -> mainGrid ());
2013-02-27 11:27:02 +01:00
2013-04-10 11:02:10 +02:00
QString egridFileName = RifEclipseOutputFileTools :: firstFileNameOfType ( m_filesWithSameBaseName , ECL_EGRID_FILE );
2013-02-27 11:27:02 +01:00
if ( egridFileName . size () > 0 )
{
2013-04-29 13:13:42 +02:00
ecl_file_type * ecl_file = ecl_file_open ( egridFileName . toAscii (). data (), ECL_FILE_CLOSE_STREAM );
2013-02-27 11:27:02 +01:00
if ( ! ecl_file ) return false ;
int actnumKeywordCount = ecl_file_get_num_named_kw ( ecl_file , ACTNUM_KW );
if ( actnumKeywordCount > 0 )
{
std :: vector < std :: vector < int > > actnumValuesPerGrid ;
actnumValuesPerGrid . resize ( actnumKeywordCount );
2014-08-08 10:45:52 +02:00
size_t reservoirCellCount = 0 ;
2013-03-02 10:18:27 +01:00
for ( size_t gridIdx = 0 ; gridIdx < static_cast < size_t > ( actnumKeywordCount ); gridIdx ++ )
2013-02-27 11:27:02 +01:00
{
RifEclipseOutputFileTools :: keywordData ( ecl_file , ACTNUM_KW , gridIdx , & actnumValuesPerGrid [ gridIdx ]);
2014-08-08 10:45:52 +02:00
reservoirCellCount += actnumValuesPerGrid [ gridIdx ]. size ();
2013-02-27 11:27:02 +01:00
}
2013-02-27 11:54:32 +01:00
// Check if number of cells is matching
2015-11-24 14:21:02 +01:00
if ( m_eclipseCase -> mainGrid () -> globalCellArray (). size () != reservoirCellCount )
2013-02-27 11:54:32 +01:00
{
return false ;
}
2013-03-13 11:50:31 +01:00
RigActiveCellInfo * activeCellInfo = m_eclipseCase -> activeCellInfo ( RifReaderInterface :: MATRIX_RESULTS );
RigActiveCellInfo * fractureActiveCellInfo = m_eclipseCase -> activeCellInfo ( RifReaderInterface :: FRACTURE_RESULTS );
2013-02-27 11:27:02 +01:00
2014-08-08 10:45:52 +02:00
activeCellInfo -> setReservoirCellCount ( reservoirCellCount );
fractureActiveCellInfo -> setReservoirCellCount ( reservoirCellCount );
2013-02-27 11:27:02 +01:00
activeCellInfo -> setGridCount ( actnumKeywordCount );
2013-03-13 11:50:31 +01:00
fractureActiveCellInfo -> setGridCount ( actnumKeywordCount );
2013-02-27 11:27:02 +01:00
size_t cellIdx = 0 ;
2013-03-07 13:13:34 +01:00
size_t globalActiveMatrixIndex = 0 ;
size_t globalActiveFractureIndex = 0 ;
2013-03-02 10:18:27 +01:00
for ( size_t gridIdx = 0 ; gridIdx < static_cast < size_t > ( actnumKeywordCount ); gridIdx ++ )
2013-02-27 11:27:02 +01:00
{
size_t activeMatrixIndex = 0 ;
size_t activeFractureIndex = 0 ;
std :: vector < int >& actnumValues = actnumValuesPerGrid [ gridIdx ];
for ( size_t i = 0 ; i < actnumValues . size (); i ++ )
{
if ( actnumValues [ i ] == 1 || actnumValues [ i ] == 3 )
{
2013-03-22 09:32:42 +01:00
activeCellInfo -> setCellResultIndex ( cellIdx , globalActiveMatrixIndex ++ );
2013-03-07 13:13:34 +01:00
activeMatrixIndex ++ ;
2013-02-27 11:27:02 +01:00
}
if ( actnumValues [ i ] == 2 || actnumValues [ i ] == 3 )
{
2013-03-22 09:32:42 +01:00
fractureActiveCellInfo -> setCellResultIndex ( cellIdx , globalActiveFractureIndex ++ );
2013-03-07 13:13:34 +01:00
activeFractureIndex ++ ;
2013-02-27 11:27:02 +01:00
}
cellIdx ++ ;
}
2013-03-13 11:50:31 +01:00
activeCellInfo -> setGridActiveCellCounts ( gridIdx , activeMatrixIndex );
fractureActiveCellInfo -> setGridActiveCellCounts ( gridIdx , activeFractureIndex );
2013-02-27 11:27:02 +01:00
}
activeCellInfo -> computeDerivedData ();
2013-03-13 11:50:31 +01:00
fractureActiveCellInfo -> computeDerivedData ();
2013-02-27 11:27:02 +01:00
}
ecl_file_close ( ecl_file );
return true ;
}
return false ;
}
2012-05-18 09:45:23 +02:00
//--------------------------------------------------------------------------------------------------
/// Build meta data - get states and results info
//--------------------------------------------------------------------------------------------------
2013-04-22 13:24:49 +02:00
void RifReaderEclipseOutput :: buildMetaData ()
2012-05-18 09:45:23 +02:00
{
2013-03-08 08:24:40 +01:00
CVF_ASSERT ( m_eclipseCase );
2013-04-10 11:02:10 +02:00
CVF_ASSERT ( m_filesWithSameBaseName . size () > 0 );
2012-05-18 09:45:23 +02:00
2013-04-10 11:02:10 +02:00
caf :: ProgressInfo progInfo ( m_filesWithSameBaseName . size () + 3 , "" );
2013-02-06 13:44:27 +01:00
2013-04-10 11:02:10 +02:00
progInfo . setNextProgressIncrement ( m_filesWithSameBaseName . size ());
2012-06-26 16:10:41 +02:00
2013-04-22 14:51:47 +02:00
RigCaseCellResultsData * matrixModelResults = m_eclipseCase -> results ( RifReaderInterface :: MATRIX_RESULTS );
RigCaseCellResultsData * fractureModelResults = m_eclipseCase -> results ( RifReaderInterface :: FRACTURE_RESULTS );
2012-05-18 09:45:23 +02:00
// Create access object for dynamic results
2013-04-10 11:02:10 +02:00
m_dynamicResultsAccess = createDynamicResultsAccess ();
2013-04-22 14:51:47 +02:00
if ( m_dynamicResultsAccess . notNull ())
2013-01-30 14:13:50 +01:00
{
2013-04-22 14:51:47 +02:00
m_dynamicResultsAccess -> open ();
2013-03-05 13:10:26 +01:00
2013-04-22 14:51:47 +02:00
progInfo . incrementProgress ();
2013-02-06 13:44:27 +01:00
2012-06-26 16:10:41 +02:00
// Get time steps
2017-04-26 09:39:17 +02:00
m_dynamicResultsAccess -> timeSteps ( & m_timeSteps , & m_daysSinceSimulationStart );
2017-01-12 12:04:54 +01:00
std :: vector < int > reportNumbers = m_dynamicResultsAccess -> reportNumbers ();
2012-05-18 09:45:23 +02:00
2013-02-05 10:51:32 +01:00
QStringList resultNames ;
std :: vector < size_t > resultNamesDataItemCounts ;
m_dynamicResultsAccess -> resultNames ( & resultNames , & resultNamesDataItemCounts );
2013-02-01 14:39:32 +01:00
{
2013-03-13 11:50:31 +01:00
QStringList matrixResultNames = validKeywordsForPorosityModel ( resultNames , resultNamesDataItemCounts ,
m_eclipseCase -> activeCellInfo ( RifReaderInterface :: MATRIX_RESULTS ),
m_eclipseCase -> activeCellInfo ( RifReaderInterface :: FRACTURE_RESULTS ),
RifReaderInterface :: MATRIX_RESULTS , m_dynamicResultsAccess -> timeStepCount ());
2013-02-01 14:39:32 +01:00
2013-02-05 10:51:32 +01:00
for ( int i = 0 ; i < matrixResultNames . size (); ++ i )
2013-02-01 14:39:32 +01:00
{
2017-06-13 15:41:52 +02:00
size_t resIndex = matrixModelResults -> addEmptyScalarResult ( RiaDefines :: DYNAMIC_NATIVE , matrixResultNames [ i ], false );
2017-04-26 09:39:17 +02:00
matrixModelResults -> setTimeStepDates ( resIndex , m_timeSteps , m_daysSinceSimulationStart , reportNumbers );
2013-02-01 14:39:32 +01:00
}
}
2012-06-26 16:10:41 +02:00
{
2013-03-13 11:50:31 +01:00
QStringList fractureResultNames = validKeywordsForPorosityModel ( resultNames , resultNamesDataItemCounts ,
m_eclipseCase -> activeCellInfo ( RifReaderInterface :: MATRIX_RESULTS ),
m_eclipseCase -> activeCellInfo ( RifReaderInterface :: FRACTURE_RESULTS ),
RifReaderInterface :: FRACTURE_RESULTS , m_dynamicResultsAccess -> timeStepCount ());
2013-02-01 14:39:32 +01:00
2013-02-05 10:51:32 +01:00
for ( int i = 0 ; i < fractureResultNames . size (); ++ i )
2013-02-01 14:39:32 +01:00
{
2017-06-13 15:41:52 +02:00
size_t resIndex = fractureModelResults -> addEmptyScalarResult ( RiaDefines :: DYNAMIC_NATIVE , fractureResultNames [ i ], false );
2017-04-26 09:39:17 +02:00
fractureModelResults -> setTimeStepDates ( resIndex , m_timeSteps , m_daysSinceSimulationStart , reportNumbers );
2013-02-01 14:39:32 +01:00
}
2012-06-26 16:10:41 +02:00
}
2014-08-27 14:05:29 +02:00
// Default units type is METRIC
2017-06-20 10:40:39 +02:00
RiaEclipseUnitTools :: UnitSystem unitsType = RiaEclipseUnitTools :: UNITS_METRIC ;
2014-08-27 14:05:29 +02:00
{
int unitsTypeValue = m_dynamicResultsAccess -> readUnitsType ();
if ( unitsTypeValue == 2 )
{
2017-06-20 10:40:39 +02:00
unitsType = RiaEclipseUnitTools :: UNITS_FIELD ;
2014-08-27 14:05:29 +02:00
}
else if ( unitsTypeValue == 3 )
{
2017-06-20 10:40:39 +02:00
unitsType = RiaEclipseUnitTools :: UNITS_LAB ;
2014-08-27 14:05:29 +02:00
}
}
m_eclipseCase -> setUnitsType ( unitsType );
2012-05-18 09:45:23 +02:00
}
2013-02-06 13:44:27 +01:00
progInfo . incrementProgress ();
2012-06-26 16:10:41 +02:00
2013-03-05 13:10:26 +01:00
openInitFile ();
2013-02-27 14:13:37 +01:00
progInfo . incrementProgress ();
2013-02-05 10:51:32 +01:00
2013-03-05 13:10:26 +01:00
if ( m_ecl_init_file )
2013-02-27 14:13:37 +01:00
{
2013-03-05 13:10:26 +01:00
QStringList resultNames ;
std :: vector < size_t > resultNamesDataItemCounts ;
2016-07-14 13:35:32 +02:00
std :: vector < ecl_file_type * > filesUsedToFindAvailableKeywords ;
filesUsedToFindAvailableKeywords . push_back ( m_ecl_init_file );
RifEclipseOutputFileTools :: findKeywordsAndItemCount ( filesUsedToFindAvailableKeywords , & resultNames , & resultNamesDataItemCounts );
2012-08-31 19:12:47 +02:00
2017-01-12 12:04:54 +01:00
std :: vector < QDateTime > staticDate ;
2017-04-26 09:39:17 +02:00
std :: vector < double > staticDay ;
2017-01-12 12:04:54 +01:00
std :: vector < int > staticReportNumber ;
2012-06-26 16:10:41 +02:00
{
2017-01-12 12:04:54 +01:00
if ( m_timeSteps . size () > 0 )
2013-03-05 13:10:26 +01:00
{
staticDate . push_back ( m_timeSteps . front ());
}
2017-04-26 09:39:17 +02:00
if ( m_daysSinceSimulationStart . size () > 0 )
{
staticDay . push_back ( m_daysSinceSimulationStart . front ());
}
2013-02-01 14:39:32 +01:00
2017-04-05 11:48:48 +02:00
std :: vector < int > reportNumbers ;
if ( m_dynamicResultsAccess . notNull ())
{
reportNumbers = m_dynamicResultsAccess -> reportNumbers ();
}
2017-01-12 12:04:54 +01:00
if ( reportNumbers . size () > 0 )
{
staticReportNumber . push_back ( reportNumbers . front ());
}
}
{
QStringList matrixResultNames = validKeywordsForPorosityModel ( resultNames , resultNamesDataItemCounts ,
m_eclipseCase -> activeCellInfo ( RifReaderInterface :: MATRIX_RESULTS ),
m_eclipseCase -> activeCellInfo ( RifReaderInterface :: FRACTURE_RESULTS ),
RifReaderInterface :: MATRIX_RESULTS , 1 );
2013-08-26 21:56:40 +02:00
// Add ACTNUM
matrixResultNames += "ACTNUM" ;
2013-03-05 13:10:26 +01:00
for ( int i = 0 ; i < matrixResultNames . size (); ++ i )
{
2017-06-13 15:41:52 +02:00
size_t resIndex = matrixModelResults -> addEmptyScalarResult ( RiaDefines :: STATIC_NATIVE , matrixResultNames [ i ], false );
2017-04-26 09:39:17 +02:00
matrixModelResults -> setTimeStepDates ( resIndex , staticDate , staticDay , staticReportNumber );
2013-03-05 13:10:26 +01:00
}
2012-06-26 16:10:41 +02:00
}
2012-05-18 09:45:23 +02:00
2013-02-27 14:13:37 +01:00
{
2013-03-13 11:50:31 +01:00
QStringList fractureResultNames = validKeywordsForPorosityModel ( resultNames , resultNamesDataItemCounts ,
m_eclipseCase -> activeCellInfo ( RifReaderInterface :: MATRIX_RESULTS ),
m_eclipseCase -> activeCellInfo ( RifReaderInterface :: FRACTURE_RESULTS ),
RifReaderInterface :: FRACTURE_RESULTS , 1 );
2013-08-26 21:56:40 +02:00
// Add ACTNUM
fractureResultNames += "ACTNUM" ;
2013-03-05 13:10:26 +01:00
for ( int i = 0 ; i < fractureResultNames . size (); ++ i )
{
2017-06-13 15:41:52 +02:00
size_t resIndex = fractureModelResults -> addEmptyScalarResult ( RiaDefines :: STATIC_NATIVE , fractureResultNames [ i ], false );
2017-04-26 09:39:17 +02:00
fractureModelResults -> setTimeStepDates ( resIndex , staticDate , staticDay , staticReportNumber );
2013-03-05 13:10:26 +01:00
}
2013-02-27 14:13:37 +01:00
}
2012-05-18 09:45:23 +02:00
}
}
//--------------------------------------------------------------------------------------------------
/// Create results access object (.UNRST or .X0001 ... .XNNNN)
//--------------------------------------------------------------------------------------------------
2013-04-10 11:02:10 +02:00
RifEclipseRestartDataAccess * RifReaderEclipseOutput :: createDynamicResultsAccess ()
2012-05-18 09:45:23 +02:00
{
2012-06-26 16:10:41 +02:00
RifEclipseRestartDataAccess * resultsAccess = NULL ;
2012-05-18 09:45:23 +02:00
// Look for unified restart file
2013-04-10 11:02:10 +02:00
QString unrstFileName = RifEclipseOutputFileTools :: firstFileNameOfType ( m_filesWithSameBaseName , ECL_UNIFIED_RESTART_FILE );
2012-05-18 09:45:23 +02:00
if ( unrstFileName . size () > 0 )
{
2013-01-30 14:13:50 +01:00
resultsAccess = new RifEclipseUnifiedRestartFileAccess ();
2013-04-10 11:02:10 +02:00
resultsAccess -> setRestartFiles ( QStringList ( unrstFileName ));
2012-05-18 09:45:23 +02:00
}
else
{
// Look for set of restart files (one file per time step)
2013-04-10 11:02:10 +02:00
QStringList restartFiles = RifEclipseOutputFileTools :: filterFileNamesOfType ( m_filesWithSameBaseName , ECL_RESTART_FILE );
2012-05-18 09:45:23 +02:00
if ( restartFiles . size () > 0 )
{
2013-01-30 14:13:50 +01:00
resultsAccess = new RifEclipseRestartFilesetAccess ();
2013-04-10 11:02:10 +02:00
resultsAccess -> setRestartFiles ( restartFiles );
2012-05-18 09:45:23 +02:00
}
}
return resultsAccess ;
}
//--------------------------------------------------------------------------------------------------
/// Get all values of a given static result as doubles
//--------------------------------------------------------------------------------------------------
2013-01-30 14:13:50 +01:00
bool RifReaderEclipseOutput :: staticResult ( const QString & result , PorosityModelResultType matrixOrFracture , std :: vector < double >* values )
2012-05-18 09:45:23 +02:00
{
CVF_ASSERT ( values );
2013-02-27 14:13:37 +01:00
2013-08-26 21:56:40 +02:00
if ( result . compare ( "ACTNUM" , Qt :: CaseInsensitive ) == 0 )
{
RigActiveCellInfo * activeCellInfo = m_eclipseCase -> activeCellInfo ( matrixOrFracture );
2014-08-08 10:27:29 +02:00
values -> resize ( activeCellInfo -> reservoirActiveCellCount (), 1.0 );
2013-08-26 21:56:40 +02:00
return true ;
}
2013-04-22 14:51:47 +02:00
openInitFile ();
2013-02-27 14:13:37 +01:00
2013-04-22 14:51:47 +02:00
if ( m_ecl_init_file )
{
std :: vector < double > fileValues ;
2013-02-05 10:51:32 +01:00
2013-04-22 14:51:47 +02:00
size_t numOccurrences = ecl_file_get_num_named_kw ( m_ecl_init_file , result . toAscii (). data ());
size_t i ;
for ( i = 0 ; i < numOccurrences ; i ++ )
{
std :: vector < double > partValues ;
RifEclipseOutputFileTools :: keywordData ( m_ecl_init_file , result , i , & partValues );
fileValues . insert ( fileValues . end (), partValues . begin (), partValues . end ());
}
2012-05-18 09:45:23 +02:00
2013-04-22 14:51:47 +02:00
extractResultValuesBasedOnPorosityModel ( matrixOrFracture , values , fileValues );
2012-05-18 09:45:23 +02:00
}
return true ;
}
//--------------------------------------------------------------------------------------------------
/// Get dynamic result at given step index. Will concatenate values for the main grid and all sub grids.
//--------------------------------------------------------------------------------------------------
2013-01-30 14:13:50 +01:00
bool RifReaderEclipseOutput :: dynamicResult ( const QString & result , PorosityModelResultType matrixOrFracture , size_t stepIndex , std :: vector < double >* values )
2012-05-18 09:45:23 +02:00
{
2013-03-05 13:10:26 +01:00
if ( m_dynamicResultsAccess . isNull ())
{
2013-04-10 11:02:10 +02:00
m_dynamicResultsAccess = createDynamicResultsAccess ();
2013-03-05 13:10:26 +01:00
}
2013-04-22 13:24:49 +02:00
if ( m_dynamicResultsAccess . notNull ())
2013-03-05 13:10:26 +01:00
{
2013-04-22 13:24:49 +02:00
std :: vector < double > fileValues ;
if ( ! m_dynamicResultsAccess -> results ( result , stepIndex , m_eclipseCase -> mainGrid () -> gridCount (), & fileValues ))
{
return false ;
}
2013-02-05 10:51:32 +01:00
2013-04-22 13:24:49 +02:00
extractResultValuesBasedOnPorosityModel ( matrixOrFracture , values , fileValues );
2013-02-05 10:51:32 +01:00
}
return true ;
2012-05-18 09:45:23 +02:00
}
2013-08-26 13:56:42 +02:00
2013-08-28 15:36:29 +02:00
//--------------------------------------------------------------------------------------------------
/// Helper struct to store info on how a well-to-grid connection contributes to the position of
/// well segments without any connections.
//--------------------------------------------------------------------------------------------------
2013-08-26 14:56:34 +02:00
struct SegmentPositionContribution
{
SegmentPositionContribution ( int connectionSegmentId ,
cvf :: Vec3d connectionPosition ,
double lengthFromConnection ,
2013-08-26 15:28:34 +02:00
bool isInsolating ,
int segmentIdUnder ,
int segmentIdAbove ,
bool isFromAbove )
2013-08-26 14:56:34 +02:00
: m_connectionSegmentId ( connectionSegmentId ),
m_lengthFromConnection ( lengthFromConnection ),
2013-08-26 15:28:34 +02:00
m_isInsolating ( isInsolating ),
2013-08-26 14:56:34 +02:00
m_connectionPosition ( connectionPosition ),
2013-08-26 15:28:34 +02:00
m_segmentIdUnder ( segmentIdUnder ),
m_segmentIdAbove ( segmentIdAbove ),
m_isFromAbove ( isFromAbove )
2013-08-26 14:56:34 +02:00
{}
int m_connectionSegmentId ;
double m_lengthFromConnection ;
2013-08-26 15:28:34 +02:00
bool m_isInsolating ;
2013-08-26 14:56:34 +02:00
cvf :: Vec3d m_connectionPosition ;
int m_segmentIdUnder ;
2013-08-26 15:28:34 +02:00
int m_segmentIdAbove ;
bool m_isFromAbove ;
2013-08-26 14:56:34 +02:00
};
2013-08-26 14:03:01 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2016-09-08 15:21:40 +02:00
RigWellResultPoint RifReaderEclipseOutput :: createWellResultPoint ( const RigGridBase * grid , const well_conn_type * ert_connection , int ertBranchId , int ertSegmentId , const char * wellName )
2013-08-26 14:03:01 +02:00
{
CVF_ASSERT ( ert_connection );
CVF_ASSERT ( grid );
int cellI = well_conn_get_i ( ert_connection );
int cellJ = well_conn_get_j ( ert_connection );
int cellK = well_conn_get_k ( ert_connection );
bool isCellOpen = well_conn_open ( ert_connection );
2017-02-07 13:47:00 +01:00
double volumeRate = well_conn_get_volume_rate ( ert_connection );
2017-04-18 16:47:37 +02:00
double oilRate = well_conn_get_oil_rate ( ert_connection ) ;
double gasRate = well_conn_get_gas_rate ( ert_connection );
double waterRate = well_conn_get_water_rate ( ert_connection );
2013-08-26 14:03:01 +02:00
// If a well is defined in fracture region, the K-value is from (cellCountK - 1) -> cellCountK*2 - 1
// Adjust K so index is always in valid grid region
if ( cellK >= static_cast < int > ( grid -> cellCountK ()))
{
cellK -= static_cast < int > ( grid -> cellCountK ());
}
2016-09-08 15:21:40 +02:00
// See description for keyword ICON at page 54/55 of Rile Formats Reference Manual 2010.2
/*
Integer completion data array
ICON(NICONZ,NCWMAX,NWELLS) with dimensions
defined by INTEHEAD. The following items are required for each completion in each well:
Item 1 - Well connection index ICON(1,IC,IWELL) = IC (set to -IC if connection is not in current LGR)
Item 2 - I-coordinate (<= 0 if not in this LGR)
Item 3 - J-coordinate (<= 0 if not in this LGR)
Item 4 - K-coordinate (<= 0 if not in this LGR)
Item 6 - Connection status > 0 open, <= 0 shut
Item 14 - Penetration direction (1=x, 2=y, 3=z, 4=fractured in x-direction, 5=fractured in y-direction)
If undefined or zero, assume Z
Item 15 - Segment number containing connection (for multi-segment wells, =0 for ordinary wells)
Undefined items in this array may be set to zero.
*/
2013-08-26 14:03:01 +02:00
// The K value might also be -1. It is not yet known why, or what it is supposed to mean,
// but for now we will interpret as 0.
// TODO: Ask Joakim Haave regarding this.
2016-09-08 15:21:40 +02:00
if ( cellK < 0 )
{
//cvf::Trace::show("Well Connection for grid " + cvf::String(grid->gridName()) + "\n - Detected negative K value (K=" + cvf::String(cellK) + ") for well : " + cvf::String(wellName) + " K clamped to 0");
cellK = 0 ;
}
2016-10-21 08:08:07 +02:00
RigWellResultPoint resultPoint ;
2016-09-08 15:21:40 +02:00
// Introduced based on discussion with Håkon Høgstøl 08.09.2016
2016-09-28 15:07:19 +02:00
if ( cellK >= static_cast < int > ( grid -> cellCountK ()))
2016-09-08 15:21:40 +02:00
{
2017-03-06 11:17:47 +01:00
int maxCellK = static_cast < int > ( grid -> cellCountK ());
cvf :: Trace :: show ( "Well Connection for grid " + cvf :: String ( grid -> gridName ()) + " \n - Ignored connection with invalid K value (K=" + cvf :: String ( cellK ) + ", max K = " + cvf :: String ( maxCellK ) + ") for well : " + cvf :: String ( wellName ));
2016-09-08 15:21:40 +02:00
}
2016-10-21 08:08:07 +02:00
else
{
resultPoint . m_gridIndex = grid -> gridIndex ();
resultPoint . m_gridCellIndex = grid -> cellIndexFromIJK ( cellI , cellJ , cellK );
2013-08-26 14:03:01 +02:00
2016-10-21 08:08:07 +02:00
resultPoint . m_isOpen = isCellOpen ;
2013-08-26 14:03:01 +02:00
2016-10-21 08:08:07 +02:00
resultPoint . m_ertBranchId = ertBranchId ;
resultPoint . m_ertSegmentId = ertSegmentId ;
2017-02-07 13:47:00 +01:00
resultPoint . m_flowRate = volumeRate ;
2017-04-18 16:47:37 +02:00
resultPoint . m_oilRate = oilRate ;
resultPoint . m_waterRate = waterRate ;
2017-05-08 16:02:42 +02:00
2017-05-29 22:52:36 +02:00
/// Unit conversion for use with Well Allocation plots
// Convert Gas to oil equivalents
2017-05-08 16:02:42 +02:00
// If field unit, the Gas is in Mega ft^3 while the others are in [stb] (barrel)
2017-05-29 22:52:36 +02:00
// Unused Gas to Barrel conversion
2017-05-08 16:02:42 +02:00
// we convert gas to stb as well. Based on
// 1 [stb] = 0.15898729492800007 [m^3]
// 1 [ft] = 0.3048 [m]
// megaFt3ToStbFactor = 1.0 / (1.0e-6 * 0.15898729492800007 * ( 1.0 / 0.3048 )^3 )
2017-05-29 22:52:36 +02:00
// double megaFt3ToStbFactor = 178107.60668;
double fieldGasToOilEquivalent = 1.0e6 / 5800 ; // Mega ft^3 to BOE
double metricGasToOilEquivalent = 1.0 / 1.0e3 ; // Sm^3 Gas to Sm^3 oe
2017-06-20 10:40:39 +02:00
if ( m_eclipseCase -> unitsType () == RiaEclipseUnitTools :: UNITS_FIELD ) gasRate = fieldGasToOilEquivalent * gasRate ;
if ( m_eclipseCase -> unitsType () == RiaEclipseUnitTools :: UNITS_METRIC ) gasRate = metricGasToOilEquivalent * gasRate ;
2017-05-08 16:02:42 +02:00
resultPoint . m_gasRate = gasRate ;
2016-10-21 08:08:07 +02:00
}
2013-08-26 14:03:01 +02:00
return resultPoint ;
}
2013-08-26 14:56:34 +02:00
//--------------------------------------------------------------------------------------------------
2013-08-28 15:36:29 +02:00
/// Inverse distance interpolation of the supplied points and distance weights for
/// the contributing points which are closest above, and closest below
2013-08-26 14:56:34 +02:00
//--------------------------------------------------------------------------------------------------
2015-11-27 16:37:26 +01:00
cvf :: Vec3d interpolate3DPosition ( const std :: vector < SegmentPositionContribution >& positions )
2013-08-26 14:56:34 +02:00
{
2013-08-26 15:16:20 +02:00
std :: vector < SegmentPositionContribution > filteredPositions ;
filteredPositions . reserve ( positions . size ());
2013-08-26 15:28:34 +02:00
double minDistFromContribAbove = HUGE_VAL ;
double minDistFromContribBelow = HUGE_VAL ;
std :: vector < SegmentPositionContribution > contrFromAbove ;
std :: vector < SegmentPositionContribution > contrFromBelow ;
2013-08-26 15:16:20 +02:00
for ( size_t i = 0 ; i < positions . size (); i ++ )
{
if ( positions [ i ]. m_connectionPosition != cvf :: Vec3d :: UNDEFINED )
{
2013-08-26 15:28:34 +02:00
if ( positions [ i ]. m_isFromAbove && positions [ i ]. m_lengthFromConnection < minDistFromContribAbove )
{
if ( contrFromAbove . size ()) contrFromAbove [ 0 ] = positions [ i ];
else contrFromAbove . push_back ( positions [ i ]);
minDistFromContribAbove = positions [ i ]. m_lengthFromConnection ;
}
if ( ! positions [ i ]. m_isFromAbove && positions [ i ]. m_lengthFromConnection < minDistFromContribBelow )
{
if ( contrFromBelow . size ()) contrFromBelow [ 0 ] = positions [ i ];
else contrFromBelow . push_back ( positions [ i ]);
minDistFromContribBelow = positions [ i ]. m_lengthFromConnection ;
}
2013-08-26 15:16:20 +02:00
}
}
2013-08-26 15:28:34 +02:00
filteredPositions = contrFromAbove ;
filteredPositions . insert ( filteredPositions . end (), contrFromBelow . begin (), contrFromBelow . end ());
2013-08-26 15:16:20 +02:00
std :: vector < double > nominators ( filteredPositions . size (), 0.0 );
2013-08-26 14:56:34 +02:00
double denominator = 0.0 ;
cvf :: Vec3d interpolatedValue = cvf :: Vec3d :: ZERO ;
2013-08-26 15:16:20 +02:00
for ( size_t i = 0 ; i < filteredPositions . size (); i ++ )
2013-08-26 14:56:34 +02:00
{
#if 0 // Pure average test
nominators[i] = 1.0;
#else
2017-03-06 11:17:47 +01:00
double distance = filteredPositions [ i ]. m_lengthFromConnection ;
2013-08-26 14:56:34 +02:00
if ( distance < 1e-6 )
{
2013-08-26 15:16:20 +02:00
return filteredPositions [ i ]. m_connectionPosition ;
2013-08-26 14:56:34 +02:00
}
2013-08-26 15:22:55 +02:00
else if ( distance < 1.0 )
{
2013-08-26 15:28:34 +02:00
//distance = 1.0;
2013-08-26 15:22:55 +02:00
}
2013-08-26 14:56:34 +02:00
distance = 1.0 / distance ;
nominators [ i ] = distance ;
denominator += distance ;
#endif
}
#if 0 // Pure average test
denominator = positions.size(); // Pure average test
#endif
2013-08-26 15:16:20 +02:00
for ( size_t i = 0 ; i < filteredPositions . size (); i ++ )
2013-08-26 14:56:34 +02:00
{
2013-08-26 15:16:20 +02:00
interpolatedValue += ( nominators [ i ] / denominator ) * filteredPositions [ i ]. m_connectionPosition ;
2013-08-26 14:56:34 +02:00
}
return interpolatedValue ;
}
2013-08-26 15:16:20 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2013-08-26 14:56:34 +02:00
void propagatePosContribDownwards ( std :: map < int , std :: vector < SegmentPositionContribution > > & segmentIdToPositionContrib ,
const well_segment_collection_type * allErtSegments ,
int ertSegmentId ,
std :: vector < SegmentPositionContribution > posContrib )
{
std :: map < int , std :: vector < SegmentPositionContribution > >:: iterator posContribIt ;
posContribIt = segmentIdToPositionContrib . find ( ertSegmentId );
if ( posContribIt != segmentIdToPositionContrib . end ())
{
// Create a set of the segments below this, that has to be followed.
std :: set < int > segmentIdsBelow ;
for ( size_t i = 0 ; i < posContribIt -> second . size (); ++ i )
{
segmentIdsBelow . insert ( posContribIt -> second [ i ]. m_segmentIdUnder );
}
2013-08-26 15:10:34 +02:00
// Get the segment length to add to the contributions
well_segment_type * segment = well_segment_collection_get ( allErtSegments , posContribIt -> first );
double sementLength = well_segment_get_length ( segment );
// If we do not have the contribution represented, add it, and accumulate the length
2013-08-26 14:56:34 +02:00
// If it is already present, do not touch
for ( size_t i = 0 ; i < posContrib . size (); ++ i )
{
bool foundContribution = false ;
for ( size_t j = 0 ; j < posContribIt -> second . size (); ++ j )
{
if ( posContribIt -> second [ j ]. m_connectionSegmentId == posContrib [ i ]. m_connectionSegmentId )
{
foundContribution = true ;
break ;
}
}
if ( ! foundContribution )
{
posContrib [ i ]. m_lengthFromConnection += sementLength ;
2013-08-26 15:28:34 +02:00
posContrib [ i ]. m_isFromAbove = true ;
2013-08-26 15:10:34 +02:00
posContribIt -> second . push_back ( posContrib [ i ]);
2013-08-26 14:56:34 +02:00
}
2013-08-26 15:28:34 +02:00
posContrib [ i ]. m_segmentIdAbove = ertSegmentId ;
2013-08-26 14:56:34 +02:00
}
for ( std :: set < int >:: iterator it = segmentIdsBelow . begin (); it != segmentIdsBelow . end (); ++ it )
{
propagatePosContribDownwards ( segmentIdToPositionContrib , allErtSegments , ( * it ), posContrib );
}
}
}
2013-08-26 13:56:42 +02:00
2012-05-18 09:45:23 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2014-10-24 11:19:54 +02:00
void RifReaderEclipseOutput :: readWellCells ( const ecl_grid_type * mainEclGrid , bool importCompleteMswData )
2012-05-18 09:45:23 +02:00
{
2013-03-08 08:24:40 +01:00
CVF_ASSERT ( m_eclipseCase );
2012-05-18 09:45:23 +02:00
if ( m_dynamicResultsAccess . isNull ()) return ;
2013-08-26 13:56:42 +02:00
well_info_type * ert_well_info = well_info_alloc ( mainEclGrid );
2012-05-18 09:45:23 +02:00
if ( ! ert_well_info ) return ;
2014-10-24 11:19:54 +02:00
m_dynamicResultsAccess -> readWellData ( ert_well_info , importCompleteMswData );
2012-05-18 09:45:23 +02:00
2017-04-26 09:39:17 +02:00
std :: vector < double > daysSinceSimulationStart ;
std :: vector < QDateTime > timeSteps ;
m_dynamicResultsAccess -> timeSteps ( & timeSteps , & daysSinceSimulationStart );
2014-10-29 09:34:57 +01:00
std :: vector < int > reportNumbers = m_dynamicResultsAccess -> reportNumbers ();
2017-01-12 12:04:54 +01:00
2014-10-29 09:34:57 +01:00
bool sameCount = false ;
if ( timeSteps . size () == reportNumbers . size ())
{
sameCount = true ;
}
2012-05-18 09:45:23 +02:00
std :: vector < RigGridBase *> grids ;
2013-02-27 14:13:37 +01:00
m_eclipseCase -> allGrids ( & grids );
2012-05-18 09:45:23 +02:00
2013-03-22 15:43:42 +01:00
cvf :: Collection < RigSingleWellResultsData > wells ;
2013-02-06 13:44:27 +01:00
caf :: ProgressInfo progress ( well_info_get_num_wells ( ert_well_info ), "" );
2012-05-18 09:45:23 +02:00
int wellIdx ;
for ( wellIdx = 0 ; wellIdx < well_info_get_num_wells ( ert_well_info ); wellIdx ++ )
{
const char * wellName = well_info_iget_well_name ( ert_well_info , wellIdx );
CVF_ASSERT ( wellName );
2013-03-22 15:43:42 +01:00
cvf :: ref < RigSingleWellResultsData > wellResults = new RigSingleWellResultsData ;
2012-05-18 09:45:23 +02:00
wellResults -> m_wellName = wellName ;
well_ts_type * ert_well_time_series = well_info_get_ts ( ert_well_info , wellName );
int timeStepCount = well_ts_get_size ( ert_well_time_series );
wellResults -> m_wellCellsTimeSteps . resize ( timeStepCount );
int timeIdx ;
for ( timeIdx = 0 ; timeIdx < timeStepCount ; timeIdx ++ )
{
well_state_type * ert_well_state = well_ts_iget_state ( ert_well_time_series , timeIdx );
RigWellResultFrame & wellResFrame = wellResults -> m_wellCellsTimeSteps [ timeIdx ];
// Build timestamp for well
2014-10-29 09:34:57 +01:00
bool haveFoundTimeStamp = false ;
if ( sameCount )
2012-05-18 09:45:23 +02:00
{
2014-10-29 09:34:57 +01:00
int reportNr = well_state_get_report_nr ( ert_well_state );
for ( size_t i = 0 ; i < reportNumbers . size (); i ++ )
{
if ( reportNumbers [ i ] == reportNr )
{
wellResFrame . m_timestamp = timeSteps [ i ];
haveFoundTimeStamp = true ;
}
}
}
if ( ! haveFoundTimeStamp )
{
// This fallback will not work for timesteps before 1970.
// Also see RifEclipseOutputFileAccess::timeStepsText for accessing time_t structures
2012-05-18 09:45:23 +02:00
time_t stepTime = well_state_get_sim_time ( ert_well_state );
wellResFrame . m_timestamp = QDateTime :: fromTime_t ( stepTime );
}
// Production type
well_type_enum ert_well_type = well_state_get_type ( ert_well_state );
2015-04-14 15:47:51 +02:00
if ( ert_well_type == ERT_PRODUCER )
2012-05-18 09:45:23 +02:00
{
wellResFrame . m_productionType = RigWellResultFrame :: PRODUCER ;
}
2015-04-14 15:47:51 +02:00
else if ( ert_well_type == ERT_WATER_INJECTOR )
2012-05-18 09:45:23 +02:00
{
wellResFrame . m_productionType = RigWellResultFrame :: WATER_INJECTOR ;
}
2015-04-14 15:47:51 +02:00
else if ( ert_well_type == ERT_GAS_INJECTOR )
2012-05-18 09:45:23 +02:00
{
wellResFrame . m_productionType = RigWellResultFrame :: GAS_INJECTOR ;
}
2015-04-14 15:47:51 +02:00
else if ( ert_well_type == ERT_OIL_INJECTOR )
2012-05-18 09:45:23 +02:00
{
wellResFrame . m_productionType = RigWellResultFrame :: OIL_INJECTOR ;
}
else
{
wellResFrame . m_productionType = RigWellResultFrame :: UNDEFINED_PRODUCTION_TYPE ;
}
wellResFrame . m_isOpen = well_state_is_open ( ert_well_state );
2014-10-24 11:19:54 +02:00
if ( importCompleteMswData && well_state_is_MSW ( ert_well_state ))
2013-08-26 14:03:01 +02:00
{
2013-08-26 14:15:27 +02:00
wellResults -> setMultiSegmentWell ( true );
2013-08-26 13:56:42 +02:00
2013-08-26 14:56:34 +02:00
// how do we handle LGR-s ?
// 1. Create separate visual branches for each Grid, with its own wellhead
// 2. Always use the connections to the grid with the highest number (innermost LGR).
// 3. Handle both and switch between them according to visual settings of grid visualization
// Will there ever exist connections to different grids for the same segment ?
2013-08-26 15:28:34 +02:00
// We have currently selected 2.
2013-08-26 14:56:34 +02:00
// Set the wellhead
int lastGridNr = static_cast < int > ( grids . size ()) - 1 ;
for ( int gridNr = lastGridNr ; gridNr >= 0 ; -- gridNr )
{
// If several grids have a wellhead definition for this well, we use the last one.
// (Possibly the innermost LGR)
const well_conn_type * ert_wellhead = well_state_iget_wellhead ( ert_well_state , static_cast < int > ( gridNr ));
if ( ert_wellhead )
{
2016-09-08 15:21:40 +02:00
wellResFrame . m_wellHead = createWellResultPoint ( grids [ gridNr ], ert_wellhead , - 1 , - 1 , wellName );
2016-01-07 14:24:59 +01:00
// HACK: Ert returns open as "this is equally wrong as closed for well heads".
// Well heads are not open jfr mail communication with HHGS and JH Statoil 07.01.2016
wellResFrame . m_wellHead . m_isOpen = false ;
2013-08-26 14:56:34 +02:00
break ;
}
}
well_branch_collection_type * branches = well_state_get_branches ( ert_well_state );
int branchCount = well_branch_collection_get_size ( branches );
wellResFrame . m_wellResultBranches . resize ( branchCount );
std :: map < int , std :: vector < SegmentPositionContribution > > segmentIdToPositionContrib ;
std :: vector < int > upperSegmentIdsOfUnpositionedSegementGroup ;
2013-08-26 15:28:34 +02:00
// For each branch, go from bottom segment upwards and transfer their connections to WellResultpoints.
// If they have no connections, create a resultpoint representing their bottom position, which will
// receive an actual position at a later stage.
// I addition, distribute contributions for calculating segment bottom positions from bottom and up.
2013-08-26 14:56:34 +02:00
for ( int bIdx = 0 ; bIdx < well_branch_collection_get_size ( branches ); bIdx ++ )
{
RigWellResultBranch & wellResultBranch = wellResFrame . m_wellResultBranches [ bIdx ];
const well_segment_type * segment = well_branch_collection_iget_start_segment ( branches , bIdx );
int branchId = well_segment_get_branch_id ( segment );
wellResultBranch . m_ertBranchId = branchId ;
// Data for segment position calculation
int lastConnectionSegmentId = - 1 ;
cvf :: Vec3d lastConnectionPos = cvf :: Vec3d :: UNDEFINED ;
2013-08-28 10:22:30 +02:00
cvf :: Vec3d lastConnectionCellCorner = cvf :: Vec3d :: UNDEFINED ;
2013-08-26 15:28:34 +02:00
double lastConnectionCellSize = 0 ;
2013-08-26 14:56:34 +02:00
double accLengthFromLastConnection = 0 ;
int segmentIdBelow = - 1 ;
bool segmentBelowHasConnections = false ;
while ( segment && branchId == well_segment_get_branch_id ( segment ))
{
// Loop backwards, making us select the connection in the innermost lgr as the truth
bool segmentHasConnections = false ;
for ( int gridNr = lastGridNr ; gridNr >= 0 ; -- gridNr )
{
std :: string gridName = this -> ertGridName ( gridNr );
// If this segment has connections in any grid, transfer the innermost ones
if ( well_segment_has_grid_connections ( segment , gridName . data ()))
{
const well_conn_collection_type * connections = well_segment_get_connections ( segment , gridName . data ());
int connectionCount = well_conn_collection_get_size ( connections );
// Loop backwards to put the deepest connections first in the array. (The segments are also traversed deep to shallow)
for ( int connIdx = connectionCount - 1 ; connIdx >= 0 ; connIdx -- )
{
well_conn_type * ert_connection = well_conn_collection_iget ( connections , connIdx );
wellResultBranch . m_branchResultPoints . push_back (
2016-09-08 15:21:40 +02:00
createWellResultPoint ( grids [ gridNr ], ert_connection , branchId , well_segment_get_id ( segment ), wellName ));
2013-08-26 14:56:34 +02:00
}
segmentHasConnections = true ;
// Prepare data for segment position calculation
well_conn_type * ert_connection = well_conn_collection_iget ( connections , 0 );
2016-09-08 15:21:40 +02:00
RigWellResultPoint point = createWellResultPoint ( grids [ gridNr ], ert_connection , branchId , well_segment_get_id ( segment ), wellName );
2013-08-26 14:56:34 +02:00
lastConnectionPos = grids [ gridNr ] -> cell ( point . m_gridCellIndex ). center ();
2013-08-26 15:28:34 +02:00
cvf :: Vec3d cellVxes [ 8 ];
grids [ gridNr ] -> cellCornerVertices ( point . m_gridCellIndex , cellVxes );
2013-08-28 10:22:30 +02:00
lastConnectionCellCorner = cellVxes [ 0 ];
2013-08-26 15:28:34 +02:00
lastConnectionCellSize = ( lastConnectionPos - cellVxes [ 0 ]). length ();
2013-08-28 10:22:30 +02:00
2013-08-26 14:56:34 +02:00
lastConnectionSegmentId = well_segment_get_id ( segment );
accLengthFromLastConnection = well_segment_get_length ( segment ) / ( connectionCount + 1 );
if ( ! segmentBelowHasConnections ) upperSegmentIdsOfUnpositionedSegementGroup . push_back ( segmentIdBelow );
break ; // Stop looping over grids
}
}
// If the segment did not have connections at all, we need to create a resultpoint representing the bottom of the segment
// and store it as an unpositioned segment
if ( ! segmentHasConnections )
{
RigWellResultPoint data ;
data . m_ertBranchId = branchId ;
data . m_ertSegmentId = well_segment_get_id ( segment );
wellResultBranch . m_branchResultPoints . push_back ( data );
// Store data for segment position calculation
2013-08-26 15:28:34 +02:00
bool isAnInsolationContribution = accLengthFromLastConnection < lastConnectionCellSize ;
2013-08-26 15:10:34 +02:00
2013-08-26 15:28:34 +02:00
2013-08-26 15:10:34 +02:00
segmentIdToPositionContrib [ well_segment_get_id ( segment )]. push_back (
2013-08-26 15:28:34 +02:00
SegmentPositionContribution ( lastConnectionSegmentId , lastConnectionPos , accLengthFromLastConnection , isAnInsolationContribution , segmentIdBelow , - 1 , false ));
2013-08-26 15:10:34 +02:00
accLengthFromLastConnection += well_segment_get_length ( segment );
2013-08-26 14:56:34 +02:00
}
segmentIdBelow = well_segment_get_id ( segment );
segmentBelowHasConnections = segmentHasConnections ;
if ( well_segment_get_outlet_id ( segment ) == - 1 )
{
segment = NULL ;
}
else
{
segment = well_segment_get_outlet ( segment );
}
}
2013-08-26 15:28:34 +02:00
// Add resultpoint representing the outlet segment (bottom), if not the branch ends at the wellhead.
2013-08-26 14:56:34 +02:00
const well_segment_type * outletSegment = segment ;
if ( outletSegment )
{
bool outletSegmentHasConnections = false ;
for ( int gridNr = lastGridNr ; gridNr >= 0 ; -- gridNr )
{
std :: string gridName = this -> ertGridName ( gridNr );
// If this segment has connections in any grid, use the deepest innermost one
if ( well_segment_has_grid_connections ( outletSegment , gridName . data ()))
{
const well_conn_collection_type * connections = well_segment_get_connections ( outletSegment , gridName . data ());
int connectionCount = well_conn_collection_get_size ( connections );
// Select the deepest connection
well_conn_type * ert_connection = well_conn_collection_iget ( connections , connectionCount - 1 );
wellResultBranch . m_branchResultPoints . push_back (
2016-09-08 15:21:40 +02:00
createWellResultPoint ( grids [ gridNr ], ert_connection , branchId , well_segment_get_id ( outletSegment ), wellName ));
2013-08-26 14:56:34 +02:00
outletSegmentHasConnections = true ;
break ; // Stop looping over grids
}
}
if ( ! outletSegmentHasConnections )
{
// Store the result point
RigWellResultPoint data ;
data . m_ertBranchId = well_segment_get_branch_id ( outletSegment );
data . m_ertSegmentId = well_segment_get_id ( outletSegment );
wellResultBranch . m_branchResultPoints . push_back ( data );
2013-08-28 15:36:29 +02:00
// Store data for segment position calculation,
// and propagate it upwards until we meet a segment with connections
2013-08-26 15:28:34 +02:00
2013-08-28 15:36:29 +02:00
bool isAnInsolationContribution = accLengthFromLastConnection < lastConnectionCellSize ;
2013-08-26 15:28:34 +02:00
2013-08-28 15:36:29 +02:00
cvf :: Vec3d lastConnectionPosWOffset = lastConnectionPos ;
if ( isAnInsolationContribution ) lastConnectionPosWOffset += 0.4 * ( lastConnectionCellCorner - lastConnectionPos );
2013-08-26 14:56:34 +02:00
2013-08-28 15:36:29 +02:00
segmentIdToPositionContrib [ well_segment_get_id ( outletSegment )]. push_back (
SegmentPositionContribution ( lastConnectionSegmentId , lastConnectionPosWOffset , accLengthFromLastConnection , isAnInsolationContribution , segmentIdBelow , - 1 , false ));
2013-08-26 14:56:34 +02:00
2013-08-28 15:36:29 +02:00
/// Loop further to add this position contribution until a segment with connections is found
2013-08-26 14:56:34 +02:00
2013-08-28 15:36:29 +02:00
accLengthFromLastConnection += well_segment_get_length ( outletSegment );
segmentIdBelow = well_segment_get_id ( outletSegment );
2013-08-26 14:56:34 +02:00
2013-08-28 15:36:29 +02:00
const well_segment_type * aboveOutletSegment = NULL ;
2013-08-26 14:56:34 +02:00
2013-08-28 15:36:29 +02:00
if ( well_segment_get_outlet_id ( outletSegment ) == - 1 )
{
aboveOutletSegment = NULL ;
}
else
{
aboveOutletSegment = well_segment_get_outlet ( outletSegment );
}
2013-08-26 14:56:34 +02:00
2013-08-28 15:36:29 +02:00
while ( aboveOutletSegment )
{
// Loop backwards, just because we do that the other places
bool segmentHasConnections = false ;
2013-08-26 14:56:34 +02:00
2013-08-28 15:36:29 +02:00
for ( int gridNr = lastGridNr ; gridNr >= 0 ; -- gridNr )
{
std :: string gridName = this -> ertGridName ( gridNr );
2013-08-26 14:56:34 +02:00
2013-08-28 15:36:29 +02:00
// If this segment has connections in any grid, stop traversal
2013-08-26 14:56:34 +02:00
2013-08-28 15:36:29 +02:00
if ( well_segment_has_grid_connections ( aboveOutletSegment , gridName . data ()))
2013-08-26 14:56:34 +02:00
{
2013-08-28 15:36:29 +02:00
segmentHasConnections = true ;
break ;
2013-08-26 14:56:34 +02:00
}
2013-08-28 15:36:29 +02:00
}
if ( ! segmentHasConnections )
{
segmentIdToPositionContrib [ well_segment_get_id ( aboveOutletSegment )]. push_back (
SegmentPositionContribution ( lastConnectionSegmentId , lastConnectionPos , accLengthFromLastConnection , isAnInsolationContribution , segmentIdBelow , - 1 , false ));
accLengthFromLastConnection += well_segment_get_length ( aboveOutletSegment );
}
else
{
break ; // We have found a segment with connections. We do not need to propagate position contributions further
}
2013-08-26 14:56:34 +02:00
2013-08-28 15:36:29 +02:00
segmentIdBelow = well_segment_get_id ( aboveOutletSegment );
2013-08-26 14:56:34 +02:00
2013-08-28 15:36:29 +02:00
if ( well_segment_get_outlet_id ( aboveOutletSegment ) == - 1 )
{
aboveOutletSegment = NULL ;
2013-08-26 14:56:34 +02:00
}
2013-08-28 15:36:29 +02:00
else
{
aboveOutletSegment = well_segment_get_outlet ( aboveOutletSegment );
}
}
2013-08-26 14:56:34 +02:00
}
}
else
{
2013-08-26 15:10:34 +02:00
// Add wellhead as result point Nope. Not Yet, but it is a good idea.
// The centerline calculations would be a bit simpler, I think.
2013-08-26 14:56:34 +02:00
}
// Reverse the order of the resultpoints in this branch, making the deepest come last
std :: reverse ( wellResultBranch . m_branchResultPoints . begin (), wellResultBranch . m_branchResultPoints . end ());
2013-08-28 15:36:29 +02:00
} // End of the branch loop
2013-08-26 14:56:34 +02:00
// Propagate position contributions from connections above unpositioned segments downwards
well_segment_collection_type * allErtSegments = well_state_get_segments ( ert_well_state );
for ( size_t bIdx = 0 ; bIdx < wellResFrame . m_wellResultBranches . size (); ++ bIdx )
{
RigWellResultBranch & wellResultBranch = wellResFrame . m_wellResultBranches [ bIdx ];
bool previousResultPointWasCell = false ;
2013-08-26 15:10:34 +02:00
if ( bIdx == 0 ) previousResultPointWasCell = true ; // Wellhead
2013-08-26 15:28:34 +02:00
// Go downwards until we find a none-cell resultpoint just after a cell-resultpoint
// When we do, start propagating
2013-08-26 14:56:34 +02:00
for ( size_t rpIdx = 0 ; rpIdx < wellResultBranch . m_branchResultPoints . size (); ++ rpIdx )
{
2013-08-26 15:10:34 +02:00
RigWellResultPoint resPoint = wellResultBranch . m_branchResultPoints [ rpIdx ];
if ( resPoint . isCell () )
2013-08-26 14:56:34 +02:00
{
previousResultPointWasCell = true ;
}
2013-08-26 15:10:34 +02:00
else
2013-08-26 14:56:34 +02:00
{
2013-08-26 15:10:34 +02:00
if ( previousResultPointWasCell )
{
RigWellResultPoint prevResPoint ;
if ( bIdx == 0 && rpIdx == 0 )
{
prevResPoint = wellResFrame . m_wellHead ;
}
else
{
prevResPoint = wellResultBranch . m_branchResultPoints [ rpIdx - 1 ];
}
2013-08-26 14:56:34 +02:00
2013-08-26 15:10:34 +02:00
cvf :: Vec3d lastConnectionPos = grids [ prevResPoint . m_gridIndex ] -> cell ( prevResPoint . m_gridCellIndex ). center ();
2013-08-26 14:56:34 +02:00
2013-08-26 15:28:34 +02:00
SegmentPositionContribution posContrib ( prevResPoint . m_ertSegmentId , lastConnectionPos , 0.0 , false , - 1 , prevResPoint . m_ertSegmentId , true );
2013-08-26 14:56:34 +02:00
2013-08-26 15:10:34 +02:00
int ertSegmentId = resPoint . m_ertSegmentId ;
2013-08-26 14:56:34 +02:00
2013-08-26 15:10:34 +02:00
std :: map < int , std :: vector < SegmentPositionContribution > >:: iterator posContribIt ;
posContribIt = segmentIdToPositionContrib . find ( ertSegmentId );
CVF_ASSERT ( posContribIt != segmentIdToPositionContrib . end ());
2013-08-26 14:56:34 +02:00
2013-08-26 15:10:34 +02:00
std :: vector < SegmentPositionContribution > posContributions = posContribIt -> second ;
2013-08-26 15:28:34 +02:00
for ( size_t i = 0 ; i < posContributions . size (); ++ i )
{
posContributions [ i ]. m_segmentIdAbove = prevResPoint . m_ertSegmentId ;
}
2013-08-26 15:10:34 +02:00
posContributions . push_back ( posContrib );
propagatePosContribDownwards ( segmentIdToPositionContrib , allErtSegments , ertSegmentId , posContributions );
}
2013-08-26 14:56:34 +02:00
2013-08-26 15:10:34 +02:00
previousResultPointWasCell = false ;
2013-08-26 14:56:34 +02:00
}
}
}
// Calculate the bottom position of all the unpositioned segments
2013-08-26 15:28:34 +02:00
// Then do the calculation based on the refined contributions
2013-08-26 14:56:34 +02:00
std :: map < int , std :: vector < SegmentPositionContribution > >:: iterator posContribIt = segmentIdToPositionContrib . begin ();
std :: map < int , cvf :: Vec3d > bottomPositions ;
while ( posContribIt != segmentIdToPositionContrib . end ())
{
bottomPositions [ posContribIt -> first ] = interpolate3DPosition ( posContribIt -> second );
2015-11-27 16:37:26 +01:00
++ posContribIt ;
2013-08-26 14:56:34 +02:00
}
// Distribute the positions to the resultpoints stored in the wellResultBranch.m_branchResultPoints
for ( size_t bIdx = 0 ; bIdx < wellResFrame . m_wellResultBranches . size (); ++ bIdx )
{
RigWellResultBranch & wellResultBranch = wellResFrame . m_wellResultBranches [ bIdx ];
for ( size_t rpIdx = 0 ; rpIdx < wellResultBranch . m_branchResultPoints . size (); ++ rpIdx )
{
RigWellResultPoint & resPoint = wellResultBranch . m_branchResultPoints [ rpIdx ];
if ( ! resPoint . isCell () )
{
resPoint . m_bottomPosition = bottomPositions [ resPoint . m_ertSegmentId ];
}
}
}
2013-08-28 15:36:29 +02:00
} // End of the MSW section
2013-08-26 14:15:27 +02:00
else
2013-08-26 14:03:01 +02:00
{
2013-08-26 14:15:27 +02:00
// Code handling None-MSW Wells ... Normal wells that is.
2013-08-26 14:03:01 +02:00
// Loop over all the grids in the model. If we have connections in one, we will discard
// the main grid connections as the well connections are duplicated in the main grid and LGR grids
2013-08-26 14:09:25 +02:00
// Verified on 10 k case JJS. But smarter things could be done, like showing the "main grid well" if turning off the LGR's
2013-08-26 14:03:01 +02:00
bool hasWellConnectionsInLGR = false ;
2013-08-26 14:09:25 +02:00
2013-08-26 14:03:01 +02:00
for ( size_t gridIdx = 1 ; gridIdx < grids . size (); ++ gridIdx )
{
RigGridBase * lgrGrid = m_eclipseCase -> grid ( gridIdx );
if ( well_state_has_grid_connections ( ert_well_state , lgrGrid -> gridName (). data ()))
{
hasWellConnectionsInLGR = true ;
break ;
}
}
2013-08-26 14:09:25 +02:00
2013-08-26 14:03:01 +02:00
size_t gridNr = hasWellConnectionsInLGR ? 1 : 0 ;
for (; gridNr < grids . size (); ++ gridNr )
{
// Wellhead. If several grids have a wellhead definition for this well, we use the last one. (Possibly the innermost LGR)
const well_conn_type * ert_wellhead = well_state_iget_wellhead ( ert_well_state , static_cast < int > ( gridNr ));
if ( ert_wellhead )
{
2016-09-08 15:21:40 +02:00
wellResFrame . m_wellHead = createWellResultPoint ( grids [ gridNr ], ert_wellhead , - 1 , - 1 , wellName );
2016-01-07 14:24:59 +01:00
// HACK: Ert returns open as "this is equally wrong as closed for well heads".
// Well heads are not open jfr mail communication with HHGS and JH Statoil 07.01.2016
wellResFrame . m_wellHead . m_isOpen = false ;
2013-08-26 14:15:27 +02:00
//std::cout << "Wellhead YES at timeIdx: " << timeIdx << " wellIdx: " << wellIdx << " Grid: " << gridNr << std::endl;
2013-08-26 14:03:01 +02:00
}
else
{
2013-08-26 14:15:27 +02:00
// std::cout << "Wellhead NO at timeIdx: " << timeIdx << " wellIdx: " << wellIdx << " Grid: " << gridNr << std::endl;
//CVF_ASSERT(0); // This is just a test assert to see if this condition exists in some files and it does.
// All the grids does not necessarily have a well head definition.
2013-08-26 14:03:01 +02:00
}
2013-08-26 15:10:34 +02:00
const well_conn_collection_type * connections = well_state_get_grid_connections ( ert_well_state , this -> ertGridName ( gridNr ). data ());
2013-08-26 14:03:01 +02:00
// Import all well result cells for all connections
if ( connections )
{
int connectionCount = well_conn_collection_get_size ( connections );
if ( connectionCount )
{
wellResFrame . m_wellResultBranches . push_back ( RigWellResultBranch ());
RigWellResultBranch & wellResultBranch = wellResFrame . m_wellResultBranches . back ();
2013-08-26 15:10:34 +02:00
wellResultBranch . m_ertBranchId = 0 ; // Normal wells have only one branch
2013-08-26 14:03:01 +02:00
size_t existingCellCount = wellResultBranch . m_branchResultPoints . size ();
wellResultBranch . m_branchResultPoints . resize ( existingCellCount + connectionCount );
for ( int connIdx = 0 ; connIdx < connectionCount ; connIdx ++ )
{
well_conn_type * ert_connection = well_conn_collection_iget ( connections , connIdx );
wellResultBranch . m_branchResultPoints [ existingCellCount + connIdx ] =
2016-09-08 15:21:40 +02:00
createWellResultPoint ( grids [ gridNr ], ert_connection , - 1 , - 1 , wellName );
2013-08-26 14:03:01 +02:00
}
}
}
}
}
2012-05-18 09:45:23 +02:00
}
2013-08-26 13:56:42 +02:00
2012-05-18 09:45:23 +02:00
wellResults -> computeMappingFromResultTimeIndicesToWellTimeIndices ( m_timeSteps );
wells . push_back ( wellResults . p ());
2013-02-06 13:44:27 +01:00
progress . incrementProgress ();
2012-05-18 09:45:23 +02:00
}
well_info_free ( ert_well_info );
2013-02-27 14:13:37 +01:00
m_eclipseCase -> setWellResults ( wells );
2012-05-18 09:45:23 +02:00
}
2013-01-25 15:20:41 +01:00
2013-02-05 10:51:32 +01:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2016-08-22 17:00:57 +02:00
QStringList RifReaderEclipseOutput :: validKeywordsForPorosityModel ( const QStringList & keywords ,
const std :: vector < size_t >& keywordDataItemCounts ,
const RigActiveCellInfo * matrixActiveCellInfo ,
const RigActiveCellInfo * fractureActiveCellInfo ,
PorosityModelResultType porosityModel ,
size_t timeStepCount ) const
2013-02-05 10:51:32 +01:00
{
2016-08-12 14:24:41 +02:00
CVF_ASSERT ( matrixActiveCellInfo );
2013-02-12 11:15:36 +01:00
2013-03-02 10:18:27 +01:00
if ( keywords . size () != static_cast < int > ( keywordDataItemCounts . size ()))
2013-02-05 10:51:32 +01:00
{
return QStringList ();
}
2016-07-14 13:35:32 +02:00
if ( porosityModel == RifReaderInterface :: FRACTURE_RESULTS )
2013-02-05 10:51:32 +01:00
{
2014-08-08 10:27:29 +02:00
if ( fractureActiveCellInfo -> reservoirActiveCellCount () == 0 )
2013-02-05 10:51:32 +01:00
{
return QStringList ();
}
}
QStringList keywordsWithCorrectNumberOfDataItems ;
for ( int i = 0 ; i < keywords . size (); i ++ )
{
QString keyword = keywords [ i ];
2016-08-12 14:24:41 +02:00
size_t keywordDataItemCount = keywordDataItemCounts [ i ];
2013-02-05 10:51:32 +01:00
2016-08-12 14:24:41 +02:00
bool validKeyword = false ;
size_t timeStepsAllCellsRest = keywordDataItemCount % matrixActiveCellInfo -> reservoirCellCount ();
if ( timeStepsAllCellsRest == 0 && keywordDataItemCount <= timeStepCount * matrixActiveCellInfo -> reservoirCellCount ())
{
// Found result for all cells for N time steps, usually a static dataset for one time step
validKeyword = true ;
}
else
2013-02-27 11:27:02 +01:00
{
2016-08-12 14:24:41 +02:00
size_t timeStepsMatrixRest = keywordDataItemCount % matrixActiveCellInfo -> reservoirActiveCellCount ();
size_t timeStepsFractureRest = 0 ;
if ( fractureActiveCellInfo -> reservoirActiveCellCount () > 0 )
{
timeStepsFractureRest = keywordDataItemCount % fractureActiveCellInfo -> reservoirActiveCellCount ();
}
2013-10-18 14:26:49 +02:00
2016-08-12 14:24:41 +02:00
size_t sumFractureMatrixActiveCellCount = matrixActiveCellInfo -> reservoirActiveCellCount () + fractureActiveCellInfo -> reservoirActiveCellCount ();
size_t timeStepsMatrixAndFractureRest = keywordDataItemCount % sumFractureMatrixActiveCellCount ;
2013-02-05 10:51:32 +01:00
2016-08-12 14:24:41 +02:00
if ( porosityModel == RifReaderInterface :: MATRIX_RESULTS && timeStepsMatrixRest == 0 )
2013-02-05 10:51:32 +01:00
{
2016-08-12 14:24:41 +02:00
if ( keywordDataItemCount <= timeStepCount * std :: max ( matrixActiveCellInfo -> reservoirActiveCellCount (), sumFractureMatrixActiveCellCount ))
2013-10-18 14:26:49 +02:00
{
2016-08-12 14:24:41 +02:00
validKeyword = true ;
2013-10-18 14:26:49 +02:00
}
2013-02-27 11:27:02 +01:00
}
2016-08-12 14:24:41 +02:00
else if ( porosityModel == RifReaderInterface :: FRACTURE_RESULTS && fractureActiveCellInfo -> reservoirActiveCellCount () > 0 && timeStepsFractureRest == 0 )
2013-02-27 11:27:02 +01:00
{
2016-08-12 14:24:41 +02:00
if ( keywordDataItemCount <= timeStepCount * std :: max ( fractureActiveCellInfo -> reservoirActiveCellCount (), sumFractureMatrixActiveCellCount ))
2013-02-05 10:51:32 +01:00
{
2016-08-12 14:24:41 +02:00
validKeyword = true ;
2013-02-05 10:51:32 +01:00
}
2016-07-14 13:35:32 +02:00
}
2016-08-12 14:24:41 +02:00
else if ( timeStepsMatrixAndFractureRest == 0 )
2016-07-14 13:35:32 +02:00
{
2016-08-12 14:24:41 +02:00
if ( keywordDataItemCount <= timeStepCount * sumFractureMatrixActiveCellCount )
2013-10-18 14:26:49 +02:00
{
2016-08-12 14:24:41 +02:00
validKeyword = true ;
2013-10-18 14:26:49 +02:00
}
2013-02-05 10:51:32 +01:00
}
}
2016-07-14 13:35:32 +02:00
2016-08-22 17:00:57 +02:00
// Check for INIT values that has only values for main grid active cells
if ( ! validKeyword )
{
if ( timeStepCount == 1 )
{
size_t mainGridMatrixActiveCellCount ; matrixActiveCellInfo -> gridActiveCellCounts ( 0 , mainGridMatrixActiveCellCount );
size_t mainGridFractureActiveCellCount ; fractureActiveCellInfo -> gridActiveCellCounts ( 0 , mainGridFractureActiveCellCount );
if ( keywordDataItemCount == mainGridMatrixActiveCellCount
|| keywordDataItemCount == mainGridFractureActiveCellCount
|| keywordDataItemCount == mainGridMatrixActiveCellCount + mainGridFractureActiveCellCount )
{
validKeyword = true ;
}
}
}
2016-08-12 14:24:41 +02:00
if ( validKeyword )
{
keywordsWithCorrectNumberOfDataItems . push_back ( keyword );
2013-02-05 10:51:32 +01:00
}
}
return keywordsWithCorrectNumberOfDataItems ;
}
2013-02-27 11:27:02 +01:00
2013-02-05 10:51:32 +01:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifReaderEclipseOutput :: extractResultValuesBasedOnPorosityModel ( PorosityModelResultType matrixOrFracture , std :: vector < double >* destinationResultValues , const std :: vector < double >& sourceResultValues )
{
2016-08-12 14:24:41 +02:00
if ( sourceResultValues . size () == 0 ) return ;
2013-02-05 10:51:32 +01:00
2016-08-12 14:24:41 +02:00
RigActiveCellInfo * fracActCellInfo = m_eclipseCase -> activeCellInfo ( RifReaderInterface :: FRACTURE_RESULTS );
2013-02-05 10:51:32 +01:00
2014-08-08 10:27:29 +02:00
if ( matrixOrFracture == RifReaderInterface :: MATRIX_RESULTS && fracActCellInfo -> reservoirActiveCellCount () == 0 )
2013-03-13 11:50:31 +01:00
{
destinationResultValues -> insert ( destinationResultValues -> end (), sourceResultValues . begin (), sourceResultValues . end ());
2013-02-05 10:51:32 +01:00
}
else
{
2013-03-13 11:50:31 +01:00
RigActiveCellInfo * actCellInfo = m_eclipseCase -> activeCellInfo ( RifReaderInterface :: MATRIX_RESULTS );
2013-02-05 10:51:32 +01:00
size_t sourceStartPosition = 0 ;
2013-02-27 14:13:37 +01:00
for ( size_t i = 0 ; i < m_eclipseCase -> mainGrid () -> gridCount (); i ++ )
2013-02-05 10:51:32 +01:00
{
2013-02-12 11:15:36 +01:00
size_t matrixActiveCellCount = 0 ;
size_t fractureActiveCellCount = 0 ;
2013-03-13 11:50:31 +01:00
actCellInfo -> gridActiveCellCounts ( i , matrixActiveCellCount );
fracActCellInfo -> gridActiveCellCounts ( i , fractureActiveCellCount );
2013-02-05 10:51:32 +01:00
2013-03-13 11:50:31 +01:00
if ( matrixOrFracture == RifReaderInterface :: MATRIX_RESULTS )
{
destinationResultValues -> insert ( destinationResultValues -> end (),
sourceResultValues . begin () + sourceStartPosition ,
sourceResultValues . begin () + sourceStartPosition + matrixActiveCellCount );
}
else
{
destinationResultValues -> insert ( destinationResultValues -> end (),
sourceResultValues . begin () + sourceStartPosition + matrixActiveCellCount ,
sourceResultValues . begin () + sourceStartPosition + matrixActiveCellCount + fractureActiveCellCount );
}
2013-02-05 10:51:32 +01:00
sourceStartPosition += ( matrixActiveCellCount + fractureActiveCellCount );
}
}
}
2013-02-27 14:13:37 +01:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2013-04-22 14:51:47 +02:00
void RifReaderEclipseOutput :: openInitFile ()
2013-02-27 14:13:37 +01:00
{
if ( m_ecl_init_file )
{
2013-04-22 14:51:47 +02:00
return ;
2013-02-27 14:13:37 +01:00
}
2013-04-10 11:02:10 +02:00
QString initFileName = RifEclipseOutputFileTools :: firstFileNameOfType ( m_filesWithSameBaseName , ECL_INIT_FILE );
2013-02-27 14:13:37 +01:00
if ( initFileName . size () > 0 )
{
2013-04-29 13:13:42 +02:00
m_ecl_init_file = ecl_file_open ( initFileName . toAscii (). data (), ECL_FILE_CLOSE_STREAM );
2013-02-27 14:13:37 +01:00
}
}
2013-03-05 13:10:26 +01:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2013-03-18 11:40:39 +01:00
std :: vector < QDateTime > RifReaderEclipseOutput :: timeSteps ()
2013-03-05 13:10:26 +01:00
{
return m_timeSteps ;
}
2013-05-21 11:10:59 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifReaderEclipseOutput :: transferCoarseningInfo ( const ecl_grid_type * eclGrid , RigGridBase * grid )
{
int coarseGroupCount = ecl_grid_get_num_coarse_groups ( eclGrid );
for ( int i = 0 ; i < coarseGroupCount ; i ++ )
{
ecl_coarse_cell_type * coarse_cell = ecl_grid_iget_coarse_group ( eclGrid , i );
CVF_ASSERT ( coarse_cell );
size_t i1 = static_cast < size_t > ( ecl_coarse_cell_get_i1 ( coarse_cell ));
size_t i2 = static_cast < size_t > ( ecl_coarse_cell_get_i2 ( coarse_cell ));
size_t j1 = static_cast < size_t > ( ecl_coarse_cell_get_j1 ( coarse_cell ));
size_t j2 = static_cast < size_t > ( ecl_coarse_cell_get_j2 ( coarse_cell ));
size_t k1 = static_cast < size_t > ( ecl_coarse_cell_get_k1 ( coarse_cell ));
size_t k2 = static_cast < size_t > ( ecl_coarse_cell_get_k2 ( coarse_cell ));
2013-05-21 21:03:05 +02:00
grid -> addCoarseningBox ( i1 , i2 , j1 , j2 , k1 , k2 );
2013-05-21 11:10:59 +02:00
}
}
2013-08-26 14:56:34 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std :: string RifReaderEclipseOutput :: ertGridName ( size_t gridNr )
{
std :: string gridName ;
if ( gridNr == 0 )
{
gridName = ECL_GRID_GLOBAL_GRID ;
}
else
{
CVF_ASSERT ( m_eclipseCase );
CVF_ASSERT ( m_eclipseCase -> gridCount () > gridNr );
gridName = m_eclipseCase -> grid ( gridNr ) -> gridName ();
}
return gridName ;
}