2017-05-15 16:04:11 +02:00
/////////////////////////////////////////////////////////////////////////////////
//
2017-05-16 14:50:54 +02:00
// Copyright (C) 2017 Statoil ASA
2017-05-15 16:04:11 +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.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RicWellPathExportCompletionDataFeature.h"
#include "RiaApplication.h"
#include "RiaLogging.h"
2017-06-28 10:13:59 +02:00
#include "RicExportCompletionDataSettingsUi.h"
#include "RicExportFeatureImpl.h"
#include "RicFishbonesTransmissibilityCalculationFeatureImp.h"
#include "RigActiveCellInfo.h"
#include "RigEclipseCaseData.h"
#include "RigMainGrid.h"
#include "RigResultAccessorFactory.h"
#include "RigTransmissibilityEquations.h"
#include "RigWellLogExtractionTools.h"
#include "RigWellPath.h"
#include "RigWellPathIntersectionTools.h"
2017-05-30 09:26:45 +02:00
#include "RimFishboneWellPath.h"
#include "RimFishboneWellPathCollection.h"
2017-06-28 10:13:59 +02:00
#include "RimFishbonesCollection.h"
#include "RimFishbonesMultipleSubs.h"
2017-05-29 13:13:25 +02:00
#include "RimPerforationCollection.h"
2017-06-28 10:13:59 +02:00
#include "RimPerforationInterval.h"
#include "RimProject.h"
2017-06-07 16:04:34 +02:00
#include "RimReservoirCellResultsStorage.h"
2017-06-28 10:13:59 +02:00
#include "RimWellPath.h"
#include "RimWellPathCollection.h"
2017-06-14 13:43:56 +02:00
#include "RimWellPathCompletions.h"
2017-06-07 16:04:34 +02:00
2017-05-15 16:04:11 +02:00
#include "RiuMainWindow.h"
#include "cafPdmUiPropertyViewDialog.h"
2017-06-28 10:13:59 +02:00
#include "cafSelectionManager.h"
2017-05-15 16:04:11 +02:00
2017-05-19 11:28:02 +02:00
#include "cvfPlane.h"
2017-05-15 16:04:11 +02:00
#include <QAction>
2017-07-03 15:02:24 +02:00
#include <QDir>
2017-05-15 16:04:11 +02:00
#include <QFileDialog>
#include <QMessageBox>
2017-05-16 14:50:54 +02:00
CAF_CMD_SOURCE_INIT ( RicWellPathExportCompletionDataFeature , "RicWellPathExportCompletionDataFeature" );
2017-05-15 16:04:11 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicWellPathExportCompletionDataFeature :: isCommandEnabled ()
{
2017-05-29 15:52:35 +02:00
return ! selectedWellPaths (). empty ();
2017-05-15 16:04:11 +02:00
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicWellPathExportCompletionDataFeature :: onActionTriggered ( bool isChecked )
{
2017-05-29 15:52:35 +02:00
std :: vector < RimWellPath *> wellPaths = selectedWellPaths ();
2017-05-15 16:04:11 +02:00
2017-05-29 15:52:35 +02:00
CVF_ASSERT ( wellPaths . size () > 0 );
2017-05-15 16:04:11 +02:00
RiaApplication * app = RiaApplication :: instance ();
QString projectFolder = app -> currentProjectPath ();
QString defaultDir = RiaApplication :: instance () -> lastUsedDialogDirectoryWithFallback ( "COMPLETIONS" , projectFolder );
2017-06-22 13:39:30 +02:00
bool onlyWellPathCollectionSelected = noWellPathsSelectedDirectly ();
2017-05-15 16:04:11 +02:00
2017-06-22 13:39:30 +02:00
RicExportCompletionDataSettingsUi exportSettings ( onlyWellPathCollectionSelected );
2017-05-19 11:09:36 +02:00
std :: vector < RimCase *> cases ;
app -> project () -> allCases ( cases );
for ( auto c : cases )
{
RimEclipseCase * eclipseCase = dynamic_cast < RimEclipseCase *> ( c );
if ( eclipseCase != nullptr )
{
exportSettings . caseToApply = eclipseCase ;
break ;
}
}
2017-05-15 16:04:11 +02:00
2017-06-15 11:21:37 +02:00
exportSettings . folder = defaultDir ;
2017-05-15 16:04:11 +02:00
caf :: PdmUiPropertyViewDialog propertyDialog ( RiuMainWindow :: instance (), & exportSettings , "Export Completion Data" , "" );
2017-06-28 10:13:59 +02:00
RicExportFeatureImpl :: configureForExport ( & propertyDialog );
2017-05-15 16:04:11 +02:00
if ( propertyDialog . exec () == QDialog :: Accepted )
{
2017-06-22 13:39:30 +02:00
RiaApplication :: instance () -> setLastUsedDialogDirectory ( "COMPLETIONS" , exportSettings . folder );
2017-05-15 16:04:11 +02:00
2017-05-29 15:52:35 +02:00
exportCompletions ( wellPaths , exportSettings );
2017-05-15 16:04:11 +02:00
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicWellPathExportCompletionDataFeature :: setupActionLook ( QAction * actionToSetup )
{
actionToSetup -> setText ( "Export Completion Data" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-05-29 15:52:35 +02:00
std :: vector < RimWellPath *> RicWellPathExportCompletionDataFeature :: selectedWellPaths ()
{
std :: vector < RimWellPath *> wellPaths ;
caf :: SelectionManager :: instance () -> objectsByType ( & wellPaths );
2017-06-22 14:34:49 +02:00
if ( wellPaths . empty ())
2017-05-29 15:52:35 +02:00
{
2017-06-22 14:34:49 +02:00
std :: vector < RimWellPathCollection *> wellPathCollections ;
caf :: SelectionManager :: instance () -> objectsByType ( & wellPathCollections );
for ( auto wellPathCollection : wellPathCollections )
2017-05-29 15:52:35 +02:00
{
2017-06-22 14:34:49 +02:00
for ( auto wellPath : wellPathCollection -> wellPaths ())
{
wellPaths . push_back ( wellPath );
}
2017-05-29 15:52:35 +02:00
}
}
std :: set < RimWellPath *> uniqueWellPaths ( wellPaths . begin (), wellPaths . end ());
wellPaths . assign ( uniqueWellPaths . begin (), uniqueWellPaths . end ());
return wellPaths ;
}
2017-06-22 13:39:30 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicWellPathExportCompletionDataFeature :: noWellPathsSelectedDirectly ()
{
std :: vector < RimWellPath *> wellPaths ;
caf :: SelectionManager :: instance () -> objectsByType ( & wellPaths );
if ( wellPaths . empty ()) return true ;
else return false ;
}
2017-05-29 15:52:35 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-06-20 08:26:53 +02:00
void RicWellPathExportCompletionDataFeature :: exportCompletions ( const std :: vector < RimWellPath *>& wellPaths ,
const RicExportCompletionDataSettingsUi & exportSettings )
2017-05-15 16:04:11 +02:00
{
2017-05-16 09:43:41 +02:00
2017-05-19 16:45:07 +02:00
if ( exportSettings . caseToApply () == nullptr )
2017-05-16 09:43:41 +02:00
{
RiaLogging :: error ( "Export Completions Data: Cannot export completions data without specified eclipse case" );
return ;
}
2017-05-16 15:17:19 +02:00
2017-06-15 11:37:00 +02:00
std :: vector < RimWellPath *> usedWellPaths ;
2017-06-22 13:39:30 +02:00
if ( exportSettings . wellSelection == RicExportCompletionDataSettingsUi :: ALL_WELLS
|| exportSettings . wellSelection == RicExportCompletionDataSettingsUi :: SELECTED_WELLS )
2017-06-15 11:37:00 +02:00
{
usedWellPaths = wellPaths ;
}
2017-06-22 14:34:49 +02:00
else if ( exportSettings . wellSelection == RicExportCompletionDataSettingsUi :: CHECKED_WELLS )
2017-06-15 11:37:00 +02:00
{
for ( auto wellPath : wellPaths )
{
if ( wellPath -> showWellPath )
{
usedWellPaths . push_back ( wellPath );
}
}
}
2017-06-08 12:59:12 +02:00
{
bool unitSystemMismatch = false ;
2017-06-15 11:37:00 +02:00
for ( const RimWellPath * wellPath : usedWellPaths )
2017-06-08 12:59:12 +02:00
{
2017-06-20 10:40:39 +02:00
if ( wellPath -> unitSystem () != exportSettings . caseToApply -> eclipseCaseData () -> unitsType ())
2017-06-08 12:59:12 +02:00
{
unitSystemMismatch = true ;
break ;
}
}
if ( unitSystemMismatch )
{
RiaLogging :: error ( "Well path unit systems must match unit system of chosen eclipse case." );
return ;
}
}
2017-06-20 08:26:53 +02:00
std :: map < IJKCellIndex , std :: vector < RigCompletionData > > completionsPerEclipseCell ;
2017-06-01 17:21:46 +02:00
2017-06-15 11:37:00 +02:00
for ( auto wellPath : usedWellPaths )
2017-05-29 13:13:25 +02:00
{
2017-05-29 15:52:35 +02:00
// Generate completion data
2017-05-19 16:45:07 +02:00
2017-05-29 15:52:35 +02:00
if ( exportSettings . includePerforations )
{
std :: vector < RigCompletionData > perforationCompletionData = generatePerforationsCompdatValues ( wellPath , exportSettings );
2017-06-20 08:26:53 +02:00
appendCompletionData ( & completionsPerEclipseCell , perforationCompletionData );
2017-05-29 15:52:35 +02:00
}
if ( exportSettings . includeFishbones )
{
2017-06-14 14:58:39 +02:00
std :: vector < RigCompletionData > fishbonesCompletionData = RicFishbonesTransmissibilityCalculationFeatureImp :: generateFishboneCompdatValuesUsingAdjustedCellVolume ( wellPath , exportSettings );
2017-06-20 08:26:53 +02:00
appendCompletionData ( & completionsPerEclipseCell , fishbonesCompletionData );
2017-05-29 15:52:35 +02:00
}
2017-06-01 17:21:46 +02:00
}
2017-05-19 16:45:07 +02:00
2017-06-01 17:21:46 +02:00
std :: vector < RigCompletionData > completions ;
2017-06-20 08:26:53 +02:00
//std::map < IJKCellIndex, std::map<QString, RigCompletionData >> combinedCompletionDataPerEclipseCell;
//Should be moved to map instead of vector
for ( auto & data : completionsPerEclipseCell )
2017-06-01 17:21:46 +02:00
{
2017-06-20 08:26:53 +02:00
completions . push_back ( combineEclipseCellCompletions ( data . second , exportSettings ));
2017-06-01 17:21:46 +02:00
}
2017-06-15 11:21:37 +02:00
const QString eclipseCaseName = exportSettings . caseToApply -> caseUserDescription ();
if ( exportSettings . fileSplit == RicExportCompletionDataSettingsUi :: UNIFIED_FILE )
{
const QString fileName = QString ( "UnifiedCompletions_%1" ). arg ( eclipseCaseName );
2017-06-21 10:58:02 +02:00
printCompletionsToFile ( exportSettings . folder , fileName , completions , exportSettings . compdatExport );
2017-06-15 11:21:37 +02:00
}
else if ( exportSettings . fileSplit == RicExportCompletionDataSettingsUi :: SPLIT_ON_WELL )
{
2017-06-15 11:37:00 +02:00
for ( auto wellPath : usedWellPaths )
2017-06-15 11:21:37 +02:00
{
std :: vector < RigCompletionData > wellCompletions ;
for ( auto completion : completions )
{
if ( completion . wellName () == wellPath -> completions () -> wellNameForExport ())
{
wellCompletions . push_back ( completion );
}
}
QString fileName = QString ( "%1_unifiedCompletions_%2" ). arg ( wellPath -> name ()). arg ( eclipseCaseName );
2017-06-21 10:58:02 +02:00
printCompletionsToFile ( exportSettings . folder , fileName , wellCompletions , exportSettings . compdatExport );
2017-06-15 11:21:37 +02:00
}
}
else if ( exportSettings . fileSplit == RicExportCompletionDataSettingsUi :: SPLIT_ON_WELL_AND_COMPLETION_TYPE )
{
2017-06-15 11:37:00 +02:00
for ( auto wellPath : usedWellPaths )
2017-06-15 11:21:37 +02:00
{
{
std :: vector < RigCompletionData > fishbonesCompletions = getCompletionsForWellAndCompletionType ( completions , wellPath -> completions () -> wellNameForExport (), RigCompletionData :: FISHBONES );
QString fileName = QString ( "%1_Fishbones_%2" ). arg ( wellPath -> name ()). arg ( eclipseCaseName );
2017-06-21 10:58:02 +02:00
printCompletionsToFile ( exportSettings . folder , fileName , fishbonesCompletions , exportSettings . compdatExport );
2017-06-15 11:21:37 +02:00
}
{
std :: vector < RigCompletionData > perforationCompletions = getCompletionsForWellAndCompletionType ( completions , wellPath -> completions () -> wellNameForExport (), RigCompletionData :: PERFORATION );
QString fileName = QString ( "%1_Perforations_%2" ). arg ( wellPath -> name ()). arg ( eclipseCaseName );
2017-06-21 10:58:02 +02:00
printCompletionsToFile ( exportSettings . folder , fileName , perforationCompletions , exportSettings . compdatExport );
2017-06-15 11:21:37 +02:00
}
}
}
}
2017-06-20 08:26:53 +02:00
//==================================================================================================
///
//==================================================================================================
RigCompletionData RicWellPathExportCompletionDataFeature :: combineEclipseCellCompletions ( const std :: vector < RigCompletionData >& completions ,
const RicExportCompletionDataSettingsUi & settings )
{
CVF_ASSERT ( ! completions . empty ());
QString wellName = completions [ 0 ]. wellName ();
IJKCellIndex cellIndexIJK = completions [ 0 ]. cellIndex ();
RigMainGrid * grid = settings . caseToApply -> eclipseCaseData () -> mainGrid ();
size_t cellIndex = grid -> cellIndexFromIJK ( cellIndexIJK . i , cellIndexIJK . j , cellIndexIJK . k );
RigCompletionData :: CompletionType completionType = completions [ 0 ]. completionType ();
//completion type, skin factor, well bore diameter and cell direction are taken from (first) main bore,
//if no main bore they are taken from first completion
double skinfactor = completions [ 0 ]. skinFactor ();
double wellBoreDiameter = completions [ 0 ]. diameter ();
CellDirection cellDirection = completions [ 0 ]. direction ();
for ( const RigCompletionData & completion : completions )
{
if ( completion . isMainBore ())
{
skinfactor = completion . skinFactor ();
wellBoreDiameter = completion . diameter ();
cellDirection = completion . direction ();
break ;
}
}
RigCompletionData resultCompletion ( wellName , cellIndexIJK );
double totalTrans = 0.0 ;
for ( const RigCompletionData & completion : completions )
{
if ( completion . completionType () != completions [ 0 ]. completionType ())
{
RiaLogging :: error ( QString ( "Cannot combine completions of different types in same cell [%1, %2, %3]" ). arg ( cellIndexIJK . i ). arg ( cellIndexIJK . j ). arg ( cellIndexIJK . k ));
return resultCompletion ; //Returning empty completion, should not be exported
}
if ( completion . wellName () != completions [ 0 ]. wellName ())
{
RiaLogging :: error ( QString ( "Cannot combine completions from different wells in same cell [%1, %2, %3]" ). arg ( cellIndexIJK . i ). arg ( cellIndexIJK . j ). arg ( cellIndexIJK . k ));
return resultCompletion ; //Returning empty completion, should not be exported
}
if ( completion . transmissibility () == HUGE_VAL )
{
RiaLogging :: error ( QString ( "Transmissibility calculation has failed for cell [%1, %2, %3]" ). arg ( cellIndexIJK . i ). arg ( cellIndexIJK . j ). arg ( cellIndexIJK . k ));
return resultCompletion ; //Returning empty completion, should not be exported
}
2017-06-20 13:48:46 +02:00
2017-06-21 15:54:18 +02:00
if ( settings . excludeMainBoreForFishbones && completionType == RigCompletionData :: FISHBONES && completion . isMainBore ())
{
continue ;
}
2017-06-20 08:26:53 +02:00
totalTrans = totalTrans + completion . transmissibility ();
2017-06-20 13:48:46 +02:00
resultCompletion . m_metadata . reserve ( resultCompletion . m_metadata . size () + completion . m_metadata . size ());
resultCompletion . m_metadata . insert ( resultCompletion . m_metadata . end (), completion . m_metadata . begin (), completion . m_metadata . end ());
2017-06-20 08:26:53 +02:00
}
2017-06-21 10:58:02 +02:00
if ( settings . compdatExport == RicExportCompletionDataSettingsUi :: TRANSMISSIBILITIES )
2017-06-20 08:26:53 +02:00
{
resultCompletion . setCombinedValuesExplicitTrans ( totalTrans , completionType );
}
2017-06-21 10:58:02 +02:00
if ( settings . compdatExport == RicExportCompletionDataSettingsUi :: WPIMULT_AND_DEFAULT_CONNECTION_FACTORS )
2017-06-20 08:26:53 +02:00
{
//calculate trans for main bore - but as Eclipse will do it!
double transmissibilityEclipseCalculation = RicWellPathExportCompletionDataFeature :: calculateTransmissibilityAsEclipseDoes ( settings . caseToApply (),
skinfactor ,
wellBoreDiameter / 2 ,
cellIndex ,
cellDirection );
double wpimult = totalTrans / transmissibilityEclipseCalculation ;
resultCompletion . setCombinedValuesImplicitTransWPImult ( wpimult , cellDirection , skinfactor , wellBoreDiameter , completionType );
}
return resultCompletion ;
}
2017-06-15 11:21:37 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-07-03 15:02:24 +02:00
void RicWellPathExportCompletionDataFeature :: printCompletionsToFile ( const QString & folderName , const QString & fileName , std :: vector < RigCompletionData >& completions , RicExportCompletionDataSettingsUi :: CompdatExportType exportType )
2017-06-15 11:21:37 +02:00
{
2017-06-20 08:26:53 +02:00
//TODO: Check that completion is ready for export
2017-07-03 15:02:24 +02:00
QDir exportFolder = QDir ( folderName );
if ( ! exportFolder . exists ())
{
bool createdPath = exportFolder . mkpath ( folderName );
if ( createdPath ) RiaLogging :: info ( "Created export folder " + folderName );
else RiaLogging :: error ( "Selected output folder does not exist, and could not be created." );
}
QString filePath = exportFolder . filePath ( fileName );
2017-06-15 11:21:37 +02:00
QFile exportFile ( filePath );
2017-07-03 15:02:24 +02:00
if ( ! exportFile . open ( QIODevice :: WriteOnly ))
2017-06-15 11:21:37 +02:00
{
RiaLogging :: error ( QString ( "Export Completions Data: Could not open the file: %1" ). arg ( filePath ));
return ;
}
QTextStream stream ( & exportFile );
RifEclipseDataTableFormatter formatter ( stream );
2017-06-01 17:21:46 +02:00
// Sort by well name / cell index
std :: sort ( completions . begin (), completions . end ());
2017-06-15 11:21:37 +02:00
2017-06-01 17:21:46 +02:00
// Print completion data
generateCompdatTable ( formatter , completions );
2017-06-20 08:26:53 +02:00
2017-06-21 10:58:02 +02:00
if ( exportType == RicExportCompletionDataSettingsUi :: WPIMULT_AND_DEFAULT_CONNECTION_FACTORS )
2017-06-01 17:21:46 +02:00
{
generateWpimultTable ( formatter , completions );
2017-05-16 15:17:19 +02:00
}
2017-06-08 11:56:06 +02:00
2017-06-15 11:21:37 +02:00
RiaLogging :: info ( QString ( "Successfully exported completion data to %1" ). arg ( filePath ));
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std :: vector < RigCompletionData > RicWellPathExportCompletionDataFeature :: getCompletionsForWellAndCompletionType ( const std :: vector < RigCompletionData >& completions ,
const QString & wellName ,
RigCompletionData :: CompletionType completionType )
{
std :: vector < RigCompletionData > filteredCompletions ;
for ( auto completion : completions )
{
if ( completion . wellName () == wellName && completion . completionType () == completionType )
{
filteredCompletions . push_back ( completion );
}
}
return filteredCompletions ;
2017-05-19 16:45:07 +02:00
}
2017-05-15 16:04:11 +02:00
2017-05-19 16:45:07 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-05-30 15:00:14 +02:00
void RicWellPathExportCompletionDataFeature :: generateCompdatTable ( RifEclipseDataTableFormatter & formatter , const std :: vector < RigCompletionData >& completionData )
2017-05-19 16:45:07 +02:00
{
std :: vector < RifEclipseOutputTableColumn > header = {
2017-05-29 13:13:25 +02:00
RifEclipseOutputTableColumn ( "Well" ),
RifEclipseOutputTableColumn ( "I" ),
RifEclipseOutputTableColumn ( "J" ),
RifEclipseOutputTableColumn ( "K1" ),
RifEclipseOutputTableColumn ( "K2" ),
RifEclipseOutputTableColumn ( "Status" ),
RifEclipseOutputTableColumn ( "SAT" ),
2017-06-21 16:25:41 +02:00
RifEclipseOutputTableColumn ( "TR" , RifEclipseOutputTableDoubleFormatting ( RifEclipseOutputTableDoubleFormat :: SCIENTIFIC )),
2017-05-29 13:13:25 +02:00
RifEclipseOutputTableColumn ( "DIAM" ),
RifEclipseOutputTableColumn ( "KH" ),
RifEclipseOutputTableColumn ( "S" ),
RifEclipseOutputTableColumn ( "Df" ),
RifEclipseOutputTableColumn ( "DIR" ),
RifEclipseOutputTableColumn ( "r0" )
2017-05-19 16:45:07 +02:00
};
formatter . keyword ( "COMPDAT" );
formatter . header ( header );
2017-05-29 13:13:25 +02:00
for ( const RigCompletionData & data : completionData )
{
2017-06-21 15:54:18 +02:00
if ( data . transmissibility () == 0.0 || data . wpimult () == 0.0 )
{
//Don't export completions without transmissibility
continue ;
}
2017-05-29 13:13:25 +02:00
for ( const RigCompletionMetaData & metadata : data . metadata ())
{
formatter . comment ( QString ( "%1 : %2" ). arg ( metadata . name ). arg ( metadata . comment ));
}
formatter . add ( data . wellName ());
formatter . addZeroBasedCellIndex ( data . cellIndex (). i ). addZeroBasedCellIndex ( data . cellIndex (). j ). addZeroBasedCellIndex ( data . cellIndex (). k ). addZeroBasedCellIndex ( data . cellIndex (). k );
switch ( data . connectionState ())
{
case OPEN :
formatter . add ( "OPEN" );
break ;
case SHUT :
formatter . add ( "SHUT" );
break ;
case AUTO :
formatter . add ( "AUTO" );
break ;
}
if ( RigCompletionData :: isDefaultValue ( data . saturation ())) formatter . add ( "1*" ); else formatter . add ( data . saturation ());
if ( RigCompletionData :: isDefaultValue ( data . transmissibility ()))
{
formatter . add ( "1*" ); // Transmissibility
if ( RigCompletionData :: isDefaultValue ( data . diameter ())) formatter . add ( "1*" ); else formatter . add ( data . diameter ());
if ( RigCompletionData :: isDefaultValue ( data . kh ())) formatter . add ( "1*" ); else formatter . add ( data . kh ());
if ( RigCompletionData :: isDefaultValue ( data . skinFactor ())) formatter . add ( "1*" ); else formatter . add ( data . skinFactor ());
if ( RigCompletionData :: isDefaultValue ( data . dFactor ())) formatter . add ( "1*" ); else formatter . add ( data . dFactor ());
switch ( data . direction ())
{
case DIR_I :
formatter . add ( "'X'" );
break ;
case DIR_J :
formatter . add ( "'Y'" );
break ;
case DIR_K :
formatter . add ( "'Z'" );
break ;
default :
formatter . add ( "'Z'" );
break ;
}
}
else
{
formatter . add ( data . transmissibility ());
}
formatter . rowCompleted ();
}
formatter . tableCompleted ();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-05-30 15:00:14 +02:00
void RicWellPathExportCompletionDataFeature :: generateWpimultTable ( RifEclipseDataTableFormatter & formatter , const std :: vector < RigCompletionData >& completionData )
2017-05-29 13:13:25 +02:00
{
std :: vector < RifEclipseOutputTableColumn > header = {
RifEclipseOutputTableColumn ( "Well" ),
RifEclipseOutputTableColumn ( "Mult" ),
RifEclipseOutputTableColumn ( "I" ),
RifEclipseOutputTableColumn ( "J" ),
RifEclipseOutputTableColumn ( "K" ),
};
formatter . keyword ( "WPIMULT" );
formatter . header ( header );
for ( auto & completion : completionData )
{
2017-06-21 15:54:18 +02:00
if ( completion . wpimult () == 0.0 )
{
continue ;
}
2017-05-29 13:13:25 +02:00
formatter . add ( completion . wellName ());
2017-06-21 15:54:18 +02:00
formatter . add ( completion . wpimult ());
2017-05-29 13:13:25 +02:00
formatter . addZeroBasedCellIndex ( completion . cellIndex (). i ). addZeroBasedCellIndex ( completion . cellIndex (). j ). addZeroBasedCellIndex ( completion . cellIndex (). k );
formatter . rowCompleted ();
}
formatter . tableCompleted ();
}
//--------------------------------------------------------------------------------------------------
2017-05-19 16:45:07 +02:00
///
//--------------------------------------------------------------------------------------------------
2017-05-30 14:37:51 +02:00
std :: vector < RigCompletionData > RicWellPathExportCompletionDataFeature :: generatePerforationsCompdatValues ( const RimWellPath * wellPath , const RicExportCompletionDataSettingsUi & settings )
2017-05-19 16:45:07 +02:00
{
2017-06-20 10:40:39 +02:00
RiaEclipseUnitTools :: UnitSystem unitSystem = settings . caseToApply -> eclipseCaseData () -> unitsType ();
2017-05-29 13:13:25 +02:00
std :: vector < RigCompletionData > completionData ;
2017-06-20 10:18:20 +02:00
const RigActiveCellInfo * activeCellInfo = settings . caseToApply -> eclipseCaseData () -> activeCellInfo ( RifReaderInterface :: MATRIX_RESULTS );
2017-05-19 16:45:07 +02:00
2017-05-29 13:13:25 +02:00
for ( const RimPerforationInterval * interval : wellPath -> perforationIntervalCollection () -> perforations ())
2017-05-19 16:45:07 +02:00
{
2017-05-30 15:42:05 +02:00
if ( ! interval -> isActiveOnDate ( settings . caseToApply -> timeStepDates ()[ settings . timeStep ])) continue ;
2017-05-29 13:13:25 +02:00
std :: vector < cvf :: Vec3d > perforationPoints = wellPath -> wellPathGeometry () -> clippedPointSubset ( interval -> startMD (), interval -> endMD ());
std :: vector < WellPathCellIntersectionInfo > intersectedCells = RigWellPathIntersectionTools :: findCellsIntersectedByPath ( settings . caseToApply -> eclipseCaseData (), perforationPoints );
for ( auto & cell : intersectedCells )
{
2017-06-20 10:18:20 +02:00
bool cellIsActive = activeCellInfo -> isActive ( cell . cellIndex );
if ( ! cellIsActive ) continue ;
2017-05-29 13:13:25 +02:00
size_t i , j , k ;
settings . caseToApply -> eclipseCaseData () -> mainGrid () -> ijkFromCellIndex ( cell . cellIndex , & i , & j , & k );
2017-06-14 13:43:56 +02:00
RigCompletionData completion ( wellPath -> completions () -> wellNameForExport (), IJKCellIndex ( i , j , k ));
2017-06-07 16:04:34 +02:00
CellDirection direction = calculateDirectionInCell ( settings . caseToApply , cell . cellIndex , cell . internalCellLengths );
2017-06-20 10:18:20 +02:00
double transmissibility = RicWellPathExportCompletionDataFeature :: calculateTransmissibility ( settings . caseToApply ,
wellPath ,
cell . internalCellLengths ,
interval -> skinFactor (),
2017-06-20 10:40:39 +02:00
interval -> diameter ( unitSystem ) / 2 ,
2017-06-20 10:18:20 +02:00
cell . cellIndex );
completion . setTransAndWPImultBackgroundDataFromPerforation ( transmissibility ,
interval -> skinFactor (),
2017-06-20 10:40:39 +02:00
interval -> diameter ( unitSystem ),
2017-06-20 10:18:20 +02:00
direction );
2017-06-22 15:20:16 +02:00
completion . addMetadata ( "Perforation" , QString ( "StartMD: %1 - EndMD: %2" ). arg ( interval -> startMD ()). arg ( interval -> endMD ()) + QString ( " : " ) + QString :: number ( transmissibility ));
2017-05-29 13:13:25 +02:00
completionData . push_back ( completion );
}
2017-05-19 16:45:07 +02:00
}
2017-05-29 13:13:25 +02:00
return completionData ;
2017-05-19 16:45:07 +02:00
}
2017-05-15 16:04:11 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std :: vector < size_t > RicWellPathExportCompletionDataFeature :: findIntersectingCells ( const RigEclipseCaseData * caseData , const std :: vector < cvf :: Vec3d >& coords )
{
2017-05-16 14:50:54 +02:00
std :: set < size_t > cells ;
2017-05-15 16:04:11 +02:00
2017-05-29 13:13:25 +02:00
std :: vector < HexIntersectionInfo > intersections = RigWellPathIntersectionTools :: getIntersectedCells ( caseData -> mainGrid (), coords );
2017-05-19 11:28:02 +02:00
for ( auto intersection : intersections )
{
cells . insert ( intersection . m_hexIndex );
}
// Ensure only unique cells are included
std :: vector < size_t > cellsVector ;
cellsVector . assign ( cells . begin (), cells . end ());
// Sort cells
std :: sort ( cellsVector . begin (), cellsVector . end ());
return cellsVector ;
}
2017-05-15 16:04:11 +02:00
//--------------------------------------------------------------------------------------------------
2017-05-16 14:50:54 +02:00
///
2017-05-15 16:04:11 +02:00
//--------------------------------------------------------------------------------------------------
2017-05-19 16:45:07 +02:00
void RicWellPathExportCompletionDataFeature :: markWellPathCells ( const std :: vector < size_t >& wellPathCells , std :: vector < WellSegmentLocation >* locations )
2017-05-15 16:04:11 +02:00
{
2017-05-19 16:45:07 +02:00
std :: set < size_t > wellPathCellSet ( wellPathCells . begin (), wellPathCells . end ());
for ( WellSegmentLocation & location : * locations )
2017-05-16 09:43:41 +02:00
{
2017-05-19 16:45:07 +02:00
for ( WellSegmentLateral & lateral : location . laterals )
2017-05-16 09:43:41 +02:00
{
2017-05-19 16:45:07 +02:00
for ( WellSegmentLateralIntersection & intersection : lateral . intersections )
{
if ( wellPathCellSet . find ( intersection . cellIndex ) != wellPathCellSet . end ())
{
intersection . mainBoreCell = true ;
}
}
2017-05-16 09:43:41 +02:00
}
}
}
2017-05-19 11:28:02 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicWellPathExportCompletionDataFeature :: wellSegmentLocationOrdering ( const WellSegmentLocation & first , const WellSegmentLocation & second )
{
return first . measuredDepth < second . measuredDepth ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-06-14 10:32:24 +02:00
bool RicWellPathExportCompletionDataFeature :: isPointBetween ( const cvf :: Vec3d & startPoint , const cvf :: Vec3d & endPoint , const cvf :: Vec3d & pointToCheck )
2017-05-19 11:28:02 +02:00
{
cvf :: Plane plane ;
2017-06-14 10:32:24 +02:00
plane . setFromPointAndNormal ( pointToCheck , endPoint - startPoint );
return plane . side ( startPoint ) != plane . side ( endPoint );
2017-05-19 11:28:02 +02:00
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-05-29 13:13:25 +02:00
std :: vector < WellSegmentLocation > RicWellPathExportCompletionDataFeature :: findWellSegmentLocations ( const RimEclipseCase * caseToApply , const RimWellPath * wellPath )
2017-05-19 11:28:02 +02:00
{
2017-05-29 15:39:37 +02:00
std :: vector < RimFishbonesMultipleSubs *> fishbonesSubs ;
2017-05-19 15:44:32 +02:00
for ( RimFishbonesMultipleSubs * subs : wellPath -> fishbonesCollection () -> fishbonesSubs ())
2017-05-29 15:39:37 +02:00
{
fishbonesSubs . push_back ( subs );
}
return findWellSegmentLocations ( caseToApply , wellPath , fishbonesSubs );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std :: vector < WellSegmentLocation > RicWellPathExportCompletionDataFeature :: findWellSegmentLocations ( const RimEclipseCase * caseToApply , const RimWellPath * wellPath , const std :: vector < RimFishbonesMultipleSubs *>& fishbonesSubs )
{
std :: vector < WellSegmentLocation > wellSegmentLocations ;
for ( RimFishbonesMultipleSubs * subs : fishbonesSubs )
2017-05-19 11:28:02 +02:00
{
2017-06-02 10:16:16 +02:00
for ( auto & sub : subs -> installedLateralIndices ())
2017-05-19 11:28:02 +02:00
{
2017-06-02 10:16:16 +02:00
double measuredDepth = subs -> measuredDepth ( sub . subIndex );
2017-05-19 11:28:02 +02:00
cvf :: Vec3d position = wellPath -> wellPathGeometry () -> interpolatedPointAlongWellPath ( measuredDepth );
2017-06-02 10:16:16 +02:00
WellSegmentLocation location = WellSegmentLocation ( subs , measuredDepth , - position . z (), sub . subIndex );
for ( size_t lateralIndex : sub . lateralIndices )
2017-05-19 11:28:02 +02:00
{
location . laterals . push_back ( WellSegmentLateral ( lateralIndex ));
}
wellSegmentLocations . push_back ( location );
}
}
std :: sort ( wellSegmentLocations . begin (), wellSegmentLocations . end (), wellSegmentLocationOrdering );
2017-05-19 16:45:07 +02:00
assignBranchAndSegmentNumbers ( caseToApply , & wellSegmentLocations );
2017-05-19 11:28:02 +02:00
return wellSegmentLocations ;
}
2017-05-19 16:45:07 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicWellPathExportCompletionDataFeature :: calculateLateralIntersections ( const RimEclipseCase * caseToApply , WellSegmentLocation * location , int * branchNum , int * segmentNum )
{
for ( WellSegmentLateral & lateral : location -> laterals )
{
lateral . branchNumber = ++ ( * branchNum );
2017-06-14 10:32:24 +02:00
std :: vector < cvf :: Vec3d > lateralCoords = location -> fishbonesSubs -> coordsForLateral ( location -> subIndex , lateral . lateralIndex );
std :: vector < WellPathCellIntersectionInfo > intersections = RigWellPathIntersectionTools :: findCellsIntersectedByPath ( caseToApply -> eclipseCaseData (), lateralCoords );
2017-05-19 16:45:07 +02:00
2017-05-29 13:13:25 +02:00
auto intersection = intersections . cbegin ();
double length = 0 ;
double depth = 0 ;
2017-06-14 10:32:24 +02:00
cvf :: Vec3d startPoint = lateralCoords [ 0 ];
2017-06-02 12:50:16 +02:00
int attachedSegmentNumber = location -> icdSegmentNumber ;
2017-05-19 16:45:07 +02:00
2017-06-14 10:32:24 +02:00
for ( size_t i = 1 ; i < lateralCoords . size () && intersection != intersections . cend (); ++ i )
2017-05-19 16:45:07 +02:00
{
2017-06-14 10:32:24 +02:00
if ( isPointBetween ( startPoint , lateralCoords [ i ], intersection -> endPoint ))
2017-05-19 16:45:07 +02:00
{
2017-05-29 13:13:25 +02:00
length += ( intersection -> endPoint - startPoint ). length ();
depth += intersection -> endPoint . z () - startPoint . z ();
WellSegmentLateralIntersection lateralIntersection ( ++ ( * segmentNum ), attachedSegmentNumber , intersection -> cellIndex , length , depth );
2017-06-07 16:04:34 +02:00
lateralIntersection . lengthsInCell = intersection -> internalCellLengths ;
2017-05-29 13:13:25 +02:00
lateral . intersections . push_back ( lateralIntersection );
length = 0 ;
depth = 0 ;
2017-06-02 11:43:03 +02:00
startPoint = intersection -> endPoint ;
2017-05-29 13:13:25 +02:00
attachedSegmentNumber = * segmentNum ;
++ intersection ;
}
else
{
2017-06-14 10:32:24 +02:00
length += ( lateralCoords [ i ] - startPoint ). length ();
depth += lateralCoords [ i ]. z () - startPoint . z ();
startPoint = lateralCoords [ i ];
2017-05-19 16:45:07 +02:00
}
2017-05-22 13:23:48 +02:00
}
2017-05-19 16:45:07 +02:00
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicWellPathExportCompletionDataFeature :: assignBranchAndSegmentNumbers ( const RimEclipseCase * caseToApply , std :: vector < WellSegmentLocation >* locations )
{
int segmentNumber = 1 ;
int branchNumber = 1 ;
// First loop over the locations so that each segment on the main stem is an incremental number
for ( WellSegmentLocation & location : * locations )
{
location . segmentNumber = ++ segmentNumber ;
2017-06-02 12:50:16 +02:00
location . icdBranchNumber = ++ branchNumber ;
location . icdSegmentNumber = ++ segmentNumber ;
2017-05-19 16:45:07 +02:00
}
// Then assign branch and segment numbers to each lateral parts
for ( WellSegmentLocation & location : * locations )
{
calculateLateralIntersections ( caseToApply , & location , & branchNumber , & segmentNumber );
}
}
2017-05-22 13:23:48 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-06-15 09:11:55 +02:00
void RicWellPathExportCompletionDataFeature :: appendCompletionData ( std :: map < IJKCellIndex , std :: vector < RigCompletionData > >* completionData , const std :: vector < RigCompletionData >& data )
2017-05-22 13:23:48 +02:00
{
2017-05-29 13:13:25 +02:00
for ( auto & completion : data )
2017-05-22 13:23:48 +02:00
{
2017-05-29 13:13:25 +02:00
auto it = completionData -> find ( completion . cellIndex ());
if ( it != completionData -> end ())
2017-05-22 13:23:48 +02:00
{
2017-06-15 09:11:55 +02:00
it -> second . push_back ( completion );
2017-05-22 13:23:48 +02:00
}
2017-05-29 13:13:25 +02:00
else
2017-05-22 13:23:48 +02:00
{
2017-06-15 09:11:55 +02:00
completionData -> insert ( std :: pair < IJKCellIndex , std :: vector < RigCompletionData > > ( completion . cellIndex (), std :: vector < RigCompletionData > { completion }));
2017-05-22 13:23:48 +02:00
}
}
}
2017-05-30 09:26:45 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-06-07 16:04:34 +02:00
CellDirection RicWellPathExportCompletionDataFeature :: calculateDirectionInCell ( RimEclipseCase * eclipseCase , size_t cellIndex , const cvf :: Vec3d & lengthsInCell )
2017-05-30 09:26:45 +02:00
{
2017-06-07 16:04:34 +02:00
RigEclipseCaseData * eclipseCaseData = eclipseCase -> eclipseCaseData ();
2017-06-13 15:41:52 +02:00
eclipseCase -> results ( RifReaderInterface :: MATRIX_RESULTS ) -> findOrLoadScalarResult ( RiaDefines :: STATIC_NATIVE , "DX" );
2017-06-07 16:04:34 +02:00
cvf :: ref < RigResultAccessor > dxAccessObject = RigResultAccessorFactory :: createFromUiResultName ( eclipseCaseData , 0 , RifReaderInterface :: MATRIX_RESULTS , 0 , "DX" );
2017-06-13 15:41:52 +02:00
eclipseCase -> results ( RifReaderInterface :: MATRIX_RESULTS ) -> findOrLoadScalarResult ( RiaDefines :: STATIC_NATIVE , "DY" );
2017-06-07 16:04:34 +02:00
cvf :: ref < RigResultAccessor > dyAccessObject = RigResultAccessorFactory :: createFromUiResultName ( eclipseCaseData , 0 , RifReaderInterface :: MATRIX_RESULTS , 0 , "DY" );
2017-06-13 15:41:52 +02:00
eclipseCase -> results ( RifReaderInterface :: MATRIX_RESULTS ) -> findOrLoadScalarResult ( RiaDefines :: STATIC_NATIVE , "DZ" );
2017-06-07 16:04:34 +02:00
cvf :: ref < RigResultAccessor > dzAccessObject = RigResultAccessorFactory :: createFromUiResultName ( eclipseCaseData , 0 , RifReaderInterface :: MATRIX_RESULTS , 0 , "DZ" );
double xLengthFraction = abs ( lengthsInCell . x () / dxAccessObject -> cellScalarGlobIdx ( cellIndex ));
double yLengthFraction = abs ( lengthsInCell . y () / dyAccessObject -> cellScalarGlobIdx ( cellIndex ));
double zLengthFraction = abs ( lengthsInCell . z () / dzAccessObject -> cellScalarGlobIdx ( cellIndex ));
if ( xLengthFraction > yLengthFraction && xLengthFraction > zLengthFraction )
2017-05-30 09:26:45 +02:00
{
2017-05-30 09:31:37 +02:00
return CellDirection :: DIR_I ;
2017-06-07 16:04:34 +02:00
}
else if ( yLengthFraction > xLengthFraction && yLengthFraction > zLengthFraction )
{
2017-05-30 09:31:37 +02:00
return CellDirection :: DIR_J ;
2017-06-07 16:04:34 +02:00
}
else
{
2017-05-30 09:31:37 +02:00
return CellDirection :: DIR_K ;
2017-05-30 09:26:45 +02:00
}
}
2017-06-08 10:40:56 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-06-13 15:37:06 +02:00
double RicWellPathExportCompletionDataFeature :: calculateTransmissibility ( RimEclipseCase * eclipseCase ,
const RimWellPath * wellPath ,
const cvf :: Vec3d & internalCellLengths ,
double skinFactor ,
double wellRadius ,
size_t cellIndex ,
size_t volumeScaleConstant ,
2017-06-20 09:46:25 +02:00
CellDirection directionForVolumeScaling )
2017-06-08 10:40:56 +02:00
{
RigEclipseCaseData * eclipseCaseData = eclipseCase -> eclipseCaseData ();
2017-06-13 15:41:52 +02:00
eclipseCase -> results ( RifReaderInterface :: MATRIX_RESULTS ) -> findOrLoadScalarResult ( RiaDefines :: STATIC_NATIVE , "DX" );
2017-06-08 10:40:56 +02:00
cvf :: ref < RigResultAccessor > dxAccessObject = RigResultAccessorFactory :: createFromUiResultName ( eclipseCaseData , 0 , RifReaderInterface :: MATRIX_RESULTS , 0 , "DX" );
2017-06-13 15:41:52 +02:00
eclipseCase -> results ( RifReaderInterface :: MATRIX_RESULTS ) -> findOrLoadScalarResult ( RiaDefines :: STATIC_NATIVE , "DY" );
2017-06-08 10:40:56 +02:00
cvf :: ref < RigResultAccessor > dyAccessObject = RigResultAccessorFactory :: createFromUiResultName ( eclipseCaseData , 0 , RifReaderInterface :: MATRIX_RESULTS , 0 , "DY" );
2017-06-13 15:41:52 +02:00
eclipseCase -> results ( RifReaderInterface :: MATRIX_RESULTS ) -> findOrLoadScalarResult ( RiaDefines :: STATIC_NATIVE , "DZ" );
2017-06-08 10:40:56 +02:00
cvf :: ref < RigResultAccessor > dzAccessObject = RigResultAccessorFactory :: createFromUiResultName ( eclipseCaseData , 0 , RifReaderInterface :: MATRIX_RESULTS , 0 , "DZ" );
2017-06-13 15:41:52 +02:00
eclipseCase -> results ( RifReaderInterface :: MATRIX_RESULTS ) -> findOrLoadScalarResult ( RiaDefines :: STATIC_NATIVE , "PERMX" );
2017-06-08 10:40:56 +02:00
cvf :: ref < RigResultAccessor > permxAccessObject = RigResultAccessorFactory :: createFromUiResultName ( eclipseCaseData , 0 , RifReaderInterface :: MATRIX_RESULTS , 0 , "PERMX" );
2017-06-13 15:41:52 +02:00
eclipseCase -> results ( RifReaderInterface :: MATRIX_RESULTS ) -> findOrLoadScalarResult ( RiaDefines :: STATIC_NATIVE , "PERMY" );
2017-06-08 10:40:56 +02:00
cvf :: ref < RigResultAccessor > permyAccessObject = RigResultAccessorFactory :: createFromUiResultName ( eclipseCaseData , 0 , RifReaderInterface :: MATRIX_RESULTS , 0 , "PERMY" );
2017-06-13 15:41:52 +02:00
eclipseCase -> results ( RifReaderInterface :: MATRIX_RESULTS ) -> findOrLoadScalarResult ( RiaDefines :: STATIC_NATIVE , "PERMZ" );
2017-06-08 10:40:56 +02:00
cvf :: ref < RigResultAccessor > permzAccessObject = RigResultAccessorFactory :: createFromUiResultName ( eclipseCaseData , 0 , RifReaderInterface :: MATRIX_RESULTS , 0 , "PERMZ" );
double dx = dxAccessObject -> cellScalarGlobIdx ( cellIndex );
double dy = dyAccessObject -> cellScalarGlobIdx ( cellIndex );
double dz = dzAccessObject -> cellScalarGlobIdx ( cellIndex );
double permx = permxAccessObject -> cellScalarGlobIdx ( cellIndex );
double permy = permxAccessObject -> cellScalarGlobIdx ( cellIndex );
double permz = permxAccessObject -> cellScalarGlobIdx ( cellIndex );
2017-06-13 15:22:12 +02:00
double darcy = RiaEclipseUnitTools :: darcysConstant ( wellPath -> unitSystem ());
2017-06-08 10:40:56 +02:00
2017-06-13 15:37:06 +02:00
if ( volumeScaleConstant != 1 )
{
2017-06-20 09:46:25 +02:00
if ( directionForVolumeScaling == CellDirection :: DIR_I ) dx = dx / volumeScaleConstant ;
if ( directionForVolumeScaling == CellDirection :: DIR_J ) dy = dy / volumeScaleConstant ;
if ( directionForVolumeScaling == CellDirection :: DIR_K ) dz = dz / volumeScaleConstant ;
2017-06-13 15:37:06 +02:00
}
2017-06-08 10:40:56 +02:00
double transx = RigTransmissibilityEquations :: wellBoreTransmissibilityComponent ( internalCellLengths . x (), permy , permz , dy , dz , wellRadius , skinFactor , darcy );
double transy = RigTransmissibilityEquations :: wellBoreTransmissibilityComponent ( internalCellLengths . y (), permx , permz , dx , dz , wellRadius , skinFactor , darcy );
double transz = RigTransmissibilityEquations :: wellBoreTransmissibilityComponent ( internalCellLengths . z (), permy , permx , dy , dx , wellRadius , skinFactor , darcy );
return RigTransmissibilityEquations :: totalConnectionFactor ( transx , transy , transz );
}
2017-06-20 08:26:53 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RicWellPathExportCompletionDataFeature :: calculateTransmissibilityAsEclipseDoes ( RimEclipseCase * eclipseCase ,
double skinFactor ,
double wellRadius ,
size_t cellIndex ,
CellDirection direction )
{
RigEclipseCaseData * eclipseCaseData = eclipseCase -> eclipseCaseData ();
eclipseCase -> results ( RifReaderInterface :: MATRIX_RESULTS ) -> findOrLoadScalarResult ( RiaDefines :: STATIC_NATIVE , "DX" );
cvf :: ref < RigResultAccessor > dxAccessObject = RigResultAccessorFactory :: createFromUiResultName ( eclipseCaseData , 0 , RifReaderInterface :: MATRIX_RESULTS , 0 , "DX" );
eclipseCase -> results ( RifReaderInterface :: MATRIX_RESULTS ) -> findOrLoadScalarResult ( RiaDefines :: STATIC_NATIVE , "DY" );
cvf :: ref < RigResultAccessor > dyAccessObject = RigResultAccessorFactory :: createFromUiResultName ( eclipseCaseData , 0 , RifReaderInterface :: MATRIX_RESULTS , 0 , "DY" );
eclipseCase -> results ( RifReaderInterface :: MATRIX_RESULTS ) -> findOrLoadScalarResult ( RiaDefines :: STATIC_NATIVE , "DZ" );
cvf :: ref < RigResultAccessor > dzAccessObject = RigResultAccessorFactory :: createFromUiResultName ( eclipseCaseData , 0 , RifReaderInterface :: MATRIX_RESULTS , 0 , "DZ" );
eclipseCase -> results ( RifReaderInterface :: MATRIX_RESULTS ) -> findOrLoadScalarResult ( RiaDefines :: STATIC_NATIVE , "PERMX" );
cvf :: ref < RigResultAccessor > permxAccessObject = RigResultAccessorFactory :: createFromUiResultName ( eclipseCaseData , 0 , RifReaderInterface :: MATRIX_RESULTS , 0 , "PERMX" );
eclipseCase -> results ( RifReaderInterface :: MATRIX_RESULTS ) -> findOrLoadScalarResult ( RiaDefines :: STATIC_NATIVE , "PERMY" );
cvf :: ref < RigResultAccessor > permyAccessObject = RigResultAccessorFactory :: createFromUiResultName ( eclipseCaseData , 0 , RifReaderInterface :: MATRIX_RESULTS , 0 , "PERMY" );
eclipseCase -> results ( RifReaderInterface :: MATRIX_RESULTS ) -> findOrLoadScalarResult ( RiaDefines :: STATIC_NATIVE , "PERMZ" );
cvf :: ref < RigResultAccessor > permzAccessObject = RigResultAccessorFactory :: createFromUiResultName ( eclipseCaseData , 0 , RifReaderInterface :: MATRIX_RESULTS , 0 , "PERMZ" );
double dx = dxAccessObject -> cellScalarGlobIdx ( cellIndex );
double dy = dyAccessObject -> cellScalarGlobIdx ( cellIndex );
double dz = dzAccessObject -> cellScalarGlobIdx ( cellIndex );
double permx = permxAccessObject -> cellScalarGlobIdx ( cellIndex );
double permy = permxAccessObject -> cellScalarGlobIdx ( cellIndex );
double permz = permxAccessObject -> cellScalarGlobIdx ( cellIndex );
2017-06-20 10:40:39 +02:00
RiaEclipseUnitTools :: UnitSystem units = eclipseCaseData -> unitsType ();
2017-06-20 08:26:53 +02:00
double darcy = RiaEclipseUnitTools :: darcysConstant ( units );
double trans = cvf :: UNDEFINED_DOUBLE ;
if ( direction == CellDirection :: DIR_I )
{
trans = RigTransmissibilityEquations :: wellBoreTransmissibilityComponent ( dx , permy , permz , dy , dz , wellRadius , skinFactor , darcy );
}
else if ( direction == CellDirection :: DIR_J )
{
trans = RigTransmissibilityEquations :: wellBoreTransmissibilityComponent ( dy , permx , permz , dx , dz , wellRadius , skinFactor , darcy );
}
else if ( direction == CellDirection :: DIR_K )
{
trans = RigTransmissibilityEquations :: wellBoreTransmissibilityComponent ( dz , permy , permx , dy , dx , wellRadius , skinFactor , darcy );
}
return trans ;
}