mirror of
https://github.com/OPM/ResInsight.git
synced 2026-11-03 12:50:52 -06:00
Refactor: Extract RicTransmissibilityCalculator from completion export
Move transmissibility calculation logic (TransmissibilityData, connection factor computation, non-Darcy flow calculations) from RicWellPathExportCompletionDataFeatureImpl into a dedicated RicTransmissibilityCalculator class. Add unit tests for the extracted calculator.
This commit is contained in:
1 parent
6bfc46f6b8
commit
05623a3fc6
10 files changed
+687
-456
No files matched your search
@@ -19,8 +19,8 @@
|
|||||||
#include "RiaEclipseUnitTools.h"
|
#include "RiaEclipseUnitTools.h"
|
||||||
|
|
||||||
#include "cafAppEnum.h"
|
#include "cafAppEnum.h"
|
||||||
|
|
||||||
#include "cvfAssert.h"
|
#include "cvfAssert.h"
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@@ -28,7 +28,6 @@
|
|||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
double RiaEclipseUnitTools::darcysConstant( RiaDefines::EclipseUnitSystem unitSystem )
|
double RiaEclipseUnitTools::darcysConstant( RiaDefines::EclipseUnitSystem unitSystem )
|
||||||
{
|
{
|
||||||
// See "Cartesian transmissibility calculations" in the "Eclipse Technical Description"
|
|
||||||
// CDARCY Darcys constant
|
// CDARCY Darcys constant
|
||||||
// = 0.00852702 (E300); 0.008527 (ECLIPSE 100) (METRIC)
|
// = 0.00852702 (E300); 0.008527 (ECLIPSE 100) (METRIC)
|
||||||
// = 0.00112712 (E300); 0.001127 (ECLIPSE 100) (FIELD)
|
// = 0.00112712 (E300); 0.001127 (ECLIPSE 100) (FIELD)
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ set(SOURCE_GROUP_HEADER_FILES
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/RicWellPathExportMswTableData.h
|
${CMAKE_CURRENT_LIST_DIR}/RicWellPathExportMswTableData.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RicMswTableDataTools.h
|
${CMAKE_CURRENT_LIST_DIR}/RicMswTableDataTools.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RicScheduleDataGenerator.h
|
${CMAKE_CURRENT_LIST_DIR}/RicScheduleDataGenerator.h
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/RicTransmissibilityCalculator.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(SOURCE_GROUP_SOURCE_FILES
|
set(SOURCE_GROUP_SOURCE_FILES
|
||||||
@@ -48,6 +49,7 @@ set(SOURCE_GROUP_SOURCE_FILES
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/RicWellPathExportMswTableData.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RicWellPathExportMswTableData.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RicMswTableDataTools.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RicMswTableDataTools.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RicScheduleDataGenerator.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RicScheduleDataGenerator.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/RicTransmissibilityCalculator.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND COMMAND_CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})
|
list(APPEND COMMAND_CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})
|
||||||
|
|||||||
+22
-23
@@ -23,6 +23,7 @@
|
|||||||
#include "RicMswCompletions.h"
|
#include "RicMswCompletions.h"
|
||||||
#include "RicMswExportInfo.h"
|
#include "RicMswExportInfo.h"
|
||||||
#include "RicMswSegment.h"
|
#include "RicMswSegment.h"
|
||||||
|
#include "RicTransmissibilityCalculator.h"
|
||||||
#include "RicWellPathExportCompletionDataFeatureImpl.h"
|
#include "RicWellPathExportCompletionDataFeatureImpl.h"
|
||||||
#include "RicWellPathExportMswTableData.h"
|
#include "RicWellPathExportMswTableData.h"
|
||||||
|
|
||||||
@@ -113,9 +114,9 @@ std::vector<RigCompletionData> RicFishbonesTransmissibilityCalculationFeatureImp
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mainBoreDirection = RicWellPathExportCompletionDataFeatureImpl::calculateCellMainDirection( settings.caseToApply,
|
mainBoreDirection = RicTransmissibilityCalculator::calculateCellMainDirection( settings.caseToApply,
|
||||||
globalCellIndex,
|
globalCellIndex,
|
||||||
wellBorePart.lengthsInCell );
|
wellBorePart.lengthsInCell );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,13 +138,13 @@ std::vector<RigCompletionData> RicFishbonesTransmissibilityCalculationFeatureImp
|
|||||||
{
|
{
|
||||||
// No change in transmissibility for main bore
|
// No change in transmissibility for main bore
|
||||||
auto transmissibilityAndPermeability =
|
auto transmissibilityAndPermeability =
|
||||||
RicWellPathExportCompletionDataFeatureImpl::calculateTransmissibilityData( settings.caseToApply,
|
RicTransmissibilityCalculator::calculateTransmissibilityData( settings.caseToApply,
|
||||||
wellPath,
|
wellPath,
|
||||||
wellBorePart.lengthsInCell,
|
wellBorePart.lengthsInCell,
|
||||||
wellBorePart.skinFactor,
|
wellBorePart.skinFactor,
|
||||||
wellBorePart.wellRadius,
|
wellBorePart.wellRadius,
|
||||||
globalCellIndex,
|
globalCellIndex,
|
||||||
settings.useLateralNTG );
|
settings.useLateralNTG );
|
||||||
|
|
||||||
transmissibility = transmissibilityAndPermeability.connectionFactor();
|
transmissibility = transmissibilityAndPermeability.connectionFactor();
|
||||||
kh = transmissibilityAndPermeability.kh();
|
kh = transmissibilityAndPermeability.kh();
|
||||||
@@ -151,24 +152,22 @@ std::vector<RigCompletionData> RicFishbonesTransmissibilityCalculationFeatureImp
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Adjust transmissibility for fishbone laterals
|
// Adjust transmissibility for fishbone laterals
|
||||||
auto transmissibilityAndPermeability =
|
auto transmissibilityAndPermeability = RicTransmissibilityCalculator::calculateTransmissibilityData( settings.caseToApply,
|
||||||
RicWellPathExportCompletionDataFeatureImpl::calculateTransmissibilityData( settings.caseToApply,
|
wellPath,
|
||||||
wellPath,
|
wellBorePart.lengthsInCell,
|
||||||
wellBorePart.lengthsInCell,
|
wellBorePart.skinFactor,
|
||||||
wellBorePart.skinFactor,
|
wellBorePart.wellRadius,
|
||||||
wellBorePart.wellRadius,
|
globalCellIndex,
|
||||||
globalCellIndex,
|
settings.useLateralNTG,
|
||||||
settings.useLateralNTG,
|
numberOfLaterals,
|
||||||
numberOfLaterals,
|
mainBoreDirection );
|
||||||
mainBoreDirection );
|
|
||||||
|
|
||||||
transmissibility = transmissibilityAndPermeability.connectionFactor();
|
transmissibility = transmissibilityAndPermeability.connectionFactor();
|
||||||
kh = transmissibilityAndPermeability.kh();
|
kh = transmissibilityAndPermeability.kh();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto direction = RicWellPathExportCompletionDataFeatureImpl::calculateCellMainDirection( settings.caseToApply,
|
auto direction =
|
||||||
globalCellIndex,
|
RicTransmissibilityCalculator::calculateCellMainDirection( settings.caseToApply, globalCellIndex, wellBorePart.lengthsInCell );
|
||||||
wellBorePart.lengthsInCell );
|
|
||||||
|
|
||||||
completion.setTransAndWPImultBackgroundDataFromFishbone( transmissibility,
|
completion.setTransAndWPImultBackgroundDataFromFishbone( transmissibility,
|
||||||
wellBorePart.skinFactor,
|
wellBorePart.skinFactor,
|
||||||
|
|||||||
+316
@@ -0,0 +1,316 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (C) 2026 Equinor ASA
|
||||||
|
//
|
||||||
|
// ResInsight is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
//
|
||||||
|
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||||
|
// for more details.
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "RicTransmissibilityCalculator.h"
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
#include "RiaEclipseUnitTools.h"
|
||||||
|
#include "RiaFractureDefines.h"
|
||||||
|
|
||||||
|
#include "RigCaseCellResultsData.h"
|
||||||
|
#include "RigEclipseCaseData.h"
|
||||||
|
#include "RigEclipseResultAddress.h"
|
||||||
|
#include "RigMainGrid.h"
|
||||||
|
#include "RigPerforationTransmissibilityEquations.h"
|
||||||
|
#include "RigResultAccessorFactory.h"
|
||||||
|
#include "RigTransmissibilityEquations.h"
|
||||||
|
|
||||||
|
#include "RimEclipseCase.h"
|
||||||
|
#include "RimNonDarcyPerforationParameters.h"
|
||||||
|
#include "RimWellPath.h"
|
||||||
|
|
||||||
|
namespace internal
|
||||||
|
{
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
RiaDefines::PorosityModelType porosityModel( RimEclipseCase* eclipseCase )
|
||||||
|
{
|
||||||
|
if ( eclipseCase && eclipseCase->eclipseCaseData() && eclipseCase->eclipseCaseData()->mainGrid() &&
|
||||||
|
eclipseCase->eclipseCaseData()->mainGrid()->isDualPorosity() )
|
||||||
|
{
|
||||||
|
return RiaDefines::PorosityModelType::FRACTURE_MODEL;
|
||||||
|
}
|
||||||
|
return RiaDefines::PorosityModelType::MATRIX_MODEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
cvf::ref<RigResultAccessor> loadResultAccessor( RimEclipseCase* eclipseCase, const QString& resultName )
|
||||||
|
{
|
||||||
|
if ( !eclipseCase || !eclipseCase->eclipseCaseData() ) return nullptr;
|
||||||
|
|
||||||
|
auto porModel = porosityModel( eclipseCase );
|
||||||
|
|
||||||
|
auto* results = eclipseCase->results( porModel );
|
||||||
|
if ( !results ) return nullptr;
|
||||||
|
|
||||||
|
results->ensureKnownResultLoaded( RigEclipseResultAddress( resultName ) );
|
||||||
|
return RigResultAccessorFactory::createFromResultAddress( eclipseCase->eclipseCaseData(), 0, porModel, 0, RigEclipseResultAddress( resultName ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
struct CellProperties
|
||||||
|
{
|
||||||
|
double dx, dy, dz;
|
||||||
|
double permx, permy, permz;
|
||||||
|
};
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
std::optional<CellProperties> loadCellProperties( RimEclipseCase* eclipseCase, size_t globalCellIndex )
|
||||||
|
{
|
||||||
|
auto dxAcc = loadResultAccessor( eclipseCase, "DX" );
|
||||||
|
auto dyAcc = loadResultAccessor( eclipseCase, "DY" );
|
||||||
|
auto dzAcc = loadResultAccessor( eclipseCase, "DZ" );
|
||||||
|
auto permxAcc = loadResultAccessor( eclipseCase, "PERMX" );
|
||||||
|
auto permyAcc = loadResultAccessor( eclipseCase, "PERMY" );
|
||||||
|
auto permzAcc = loadResultAccessor( eclipseCase, "PERMZ" );
|
||||||
|
|
||||||
|
if ( dxAcc.isNull() || dyAcc.isNull() || dzAcc.isNull() || permxAcc.isNull() || permyAcc.isNull() || permzAcc.isNull() )
|
||||||
|
{
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
CellProperties props;
|
||||||
|
props.dx = dxAcc->cellScalarGlobIdx( globalCellIndex );
|
||||||
|
props.dy = dyAcc->cellScalarGlobIdx( globalCellIndex );
|
||||||
|
props.dz = dzAcc->cellScalarGlobIdx( globalCellIndex );
|
||||||
|
props.permx = permxAcc->cellScalarGlobIdx( globalCellIndex );
|
||||||
|
props.permy = permyAcc->cellScalarGlobIdx( globalCellIndex );
|
||||||
|
props.permz = permzAcc->cellScalarGlobIdx( globalCellIndex );
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
double loadNtg( RimEclipseCase* eclipseCase, size_t globalCellIndex )
|
||||||
|
{
|
||||||
|
auto ntgAcc = loadResultAccessor( eclipseCase, "NTG" );
|
||||||
|
if ( ntgAcc.notNull() ) return ntgAcc->cellScalarGlobIdx( globalCellIndex );
|
||||||
|
return 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
RigCompletionData::CellDirection RicTransmissibilityCalculator::calculateCellMainDirection( RimEclipseCase* eclipseCase,
|
||||||
|
size_t globalCellIndex,
|
||||||
|
const cvf::Vec3d& lengthsInCell )
|
||||||
|
{
|
||||||
|
if ( !eclipseCase || !eclipseCase->eclipseCaseData() ) return RigCompletionData::CellDirection::DIR_K;
|
||||||
|
|
||||||
|
auto props = internal::loadCellProperties( eclipseCase, globalCellIndex );
|
||||||
|
if ( !props ) return RigCompletionData::CellDirection::DIR_K;
|
||||||
|
|
||||||
|
double xLengthFraction = fabs( lengthsInCell.x() / props->dx );
|
||||||
|
double yLengthFraction = fabs( lengthsInCell.y() / props->dy );
|
||||||
|
double zLengthFraction = fabs( lengthsInCell.z() / props->dz );
|
||||||
|
|
||||||
|
if ( xLengthFraction > yLengthFraction && xLengthFraction > zLengthFraction )
|
||||||
|
{
|
||||||
|
return RigCompletionData::CellDirection::DIR_I;
|
||||||
|
}
|
||||||
|
else if ( yLengthFraction > xLengthFraction && yLengthFraction > zLengthFraction )
|
||||||
|
{
|
||||||
|
return RigCompletionData::CellDirection::DIR_J;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return RigCompletionData::CellDirection::DIR_K;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
TransmissibilityData RicTransmissibilityCalculator::calculateTransmissibilityData( RimEclipseCase* eclipseCase,
|
||||||
|
const RimWellPath* wellPath,
|
||||||
|
const cvf::Vec3d& internalCellLengths,
|
||||||
|
double skinFactor,
|
||||||
|
double wellRadius,
|
||||||
|
size_t globalCellIndex,
|
||||||
|
bool useLateralNTG,
|
||||||
|
size_t volumeScaleConstant,
|
||||||
|
RigCompletionData::CellDirection directionForVolumeScaling )
|
||||||
|
{
|
||||||
|
if ( !eclipseCase || !eclipseCase->eclipseCaseData() || !wellPath ) return TransmissibilityData();
|
||||||
|
|
||||||
|
auto props = internal::loadCellProperties( eclipseCase, globalCellIndex );
|
||||||
|
if ( !props )
|
||||||
|
{
|
||||||
|
return TransmissibilityData();
|
||||||
|
}
|
||||||
|
|
||||||
|
double ntg = internal::loadNtg( eclipseCase, globalCellIndex );
|
||||||
|
double latNtg = useLateralNTG ? ntg : 1.0;
|
||||||
|
|
||||||
|
const double totalKh = RigTransmissibilityEquations::totalKh( props->permx, props->permy, props->permz, internalCellLengths, latNtg, ntg );
|
||||||
|
const double effectiveK =
|
||||||
|
RigTransmissibilityEquations::effectiveK( props->permx, props->permy, props->permz, internalCellLengths, latNtg, ntg );
|
||||||
|
const double effectiveH = RigTransmissibilityEquations::effectiveH( internalCellLengths, latNtg, ntg );
|
||||||
|
|
||||||
|
double darcy = RiaEclipseUnitTools::darcysConstant( wellPath->unitSystem() );
|
||||||
|
|
||||||
|
double dx = props->dx;
|
||||||
|
double dy = props->dy;
|
||||||
|
double dz = props->dz;
|
||||||
|
if ( volumeScaleConstant != 1 )
|
||||||
|
{
|
||||||
|
if ( directionForVolumeScaling == RigCompletionData::CellDirection::DIR_I ) dx = dx / volumeScaleConstant;
|
||||||
|
if ( directionForVolumeScaling == RigCompletionData::CellDirection::DIR_J ) dy = dy / volumeScaleConstant;
|
||||||
|
if ( directionForVolumeScaling == RigCompletionData::CellDirection::DIR_K ) dz = dz / volumeScaleConstant;
|
||||||
|
}
|
||||||
|
|
||||||
|
const double transx = RigTransmissibilityEquations::wellBoreTransmissibilityComponent( internalCellLengths.x() * latNtg,
|
||||||
|
props->permy,
|
||||||
|
props->permz,
|
||||||
|
dy,
|
||||||
|
dz,
|
||||||
|
wellRadius,
|
||||||
|
skinFactor,
|
||||||
|
darcy );
|
||||||
|
const double transy = RigTransmissibilityEquations::wellBoreTransmissibilityComponent( internalCellLengths.y() * latNtg,
|
||||||
|
props->permx,
|
||||||
|
props->permz,
|
||||||
|
dx,
|
||||||
|
dz,
|
||||||
|
wellRadius,
|
||||||
|
skinFactor,
|
||||||
|
darcy );
|
||||||
|
const double transz = RigTransmissibilityEquations::wellBoreTransmissibilityComponent( internalCellLengths.z() * ntg,
|
||||||
|
props->permy,
|
||||||
|
props->permx,
|
||||||
|
dy,
|
||||||
|
dx,
|
||||||
|
wellRadius,
|
||||||
|
skinFactor,
|
||||||
|
darcy );
|
||||||
|
|
||||||
|
const double totalConnectionFactor = RigTransmissibilityEquations::totalConnectionFactor( transx, transy, transz );
|
||||||
|
|
||||||
|
TransmissibilityData trData;
|
||||||
|
trData.setData( effectiveH, effectiveK, totalConnectionFactor, totalKh );
|
||||||
|
return trData;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
double RicTransmissibilityCalculator::calculateDFactor( RimEclipseCase* eclipseCase,
|
||||||
|
double effectiveH,
|
||||||
|
size_t globalCellIndex,
|
||||||
|
const RimNonDarcyPerforationParameters* nonDarcyParameters,
|
||||||
|
const double effectivePermeability )
|
||||||
|
{
|
||||||
|
using EQ = RigPerforationTransmissibilityEquations;
|
||||||
|
|
||||||
|
if ( !eclipseCase || !eclipseCase->eclipseCaseData() )
|
||||||
|
{
|
||||||
|
return std::numeric_limits<double>::infinity();
|
||||||
|
}
|
||||||
|
|
||||||
|
double porosity = 0.0;
|
||||||
|
{
|
||||||
|
auto poroAcc = internal::loadResultAccessor( eclipseCase, "PORO" );
|
||||||
|
if ( poroAcc.notNull() )
|
||||||
|
{
|
||||||
|
porosity = poroAcc->cellScalar( globalCellIndex );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const double betaFactor = EQ::betaFactor( nonDarcyParameters->inertialCoefficientBeta0(),
|
||||||
|
effectivePermeability,
|
||||||
|
nonDarcyParameters->permeabilityScalingFactor(),
|
||||||
|
porosity,
|
||||||
|
nonDarcyParameters->porosityScalingFactor() );
|
||||||
|
|
||||||
|
const double alpha = RiaDefines::nonDarcyFlowAlpha( eclipseCase->eclipseCaseData()->unitsType() );
|
||||||
|
|
||||||
|
return EQ::dFactor( alpha,
|
||||||
|
betaFactor,
|
||||||
|
effectivePermeability,
|
||||||
|
effectiveH,
|
||||||
|
nonDarcyParameters->wellRadius(),
|
||||||
|
nonDarcyParameters->relativeGasDensity(),
|
||||||
|
nonDarcyParameters->gasViscosity() );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
double RicTransmissibilityCalculator::calculateTransmissibilityAsEclipseDoes( RimEclipseCase* eclipseCase,
|
||||||
|
double skinFactor,
|
||||||
|
double wellRadius,
|
||||||
|
size_t globalCellIndex,
|
||||||
|
RigCompletionData::CellDirection direction )
|
||||||
|
{
|
||||||
|
if ( !eclipseCase || !eclipseCase->eclipseCaseData() ) return cvf::UNDEFINED_DOUBLE;
|
||||||
|
|
||||||
|
auto props = internal::loadCellProperties( eclipseCase, globalCellIndex );
|
||||||
|
if ( !props ) return cvf::UNDEFINED_DOUBLE;
|
||||||
|
|
||||||
|
double ntg = internal::loadNtg( eclipseCase, globalCellIndex );
|
||||||
|
double darcy = RiaEclipseUnitTools::darcysConstant( eclipseCase->eclipseCaseData()->unitsType() );
|
||||||
|
|
||||||
|
double trans = cvf::UNDEFINED_DOUBLE;
|
||||||
|
if ( direction == RigCompletionData::CellDirection::DIR_I )
|
||||||
|
{
|
||||||
|
trans = RigTransmissibilityEquations::wellBoreTransmissibilityComponent( props->dx,
|
||||||
|
props->permy,
|
||||||
|
props->permz,
|
||||||
|
props->dy,
|
||||||
|
props->dz,
|
||||||
|
wellRadius,
|
||||||
|
skinFactor,
|
||||||
|
darcy );
|
||||||
|
}
|
||||||
|
else if ( direction == RigCompletionData::CellDirection::DIR_J )
|
||||||
|
{
|
||||||
|
trans = RigTransmissibilityEquations::wellBoreTransmissibilityComponent( props->dy,
|
||||||
|
props->permx,
|
||||||
|
props->permz,
|
||||||
|
props->dx,
|
||||||
|
props->dz,
|
||||||
|
wellRadius,
|
||||||
|
skinFactor,
|
||||||
|
darcy );
|
||||||
|
}
|
||||||
|
else if ( direction == RigCompletionData::CellDirection::DIR_K )
|
||||||
|
{
|
||||||
|
trans = RigTransmissibilityEquations::wellBoreTransmissibilityComponent( props->dz * ntg,
|
||||||
|
props->permy,
|
||||||
|
props->permx,
|
||||||
|
props->dy,
|
||||||
|
props->dx,
|
||||||
|
wellRadius,
|
||||||
|
skinFactor,
|
||||||
|
darcy );
|
||||||
|
}
|
||||||
|
|
||||||
|
return trans;
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (C) 2026 Equinor ASA
|
||||||
|
//
|
||||||
|
// ResInsight is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
//
|
||||||
|
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||||
|
// for more details.
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "RigCompletionData.h"
|
||||||
|
|
||||||
|
#include "cvfVector3.h"
|
||||||
|
|
||||||
|
class RimEclipseCase;
|
||||||
|
class RimNonDarcyPerforationParameters;
|
||||||
|
class RimWellPath;
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
///
|
||||||
|
//==================================================================================================
|
||||||
|
class TransmissibilityData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TransmissibilityData()
|
||||||
|
: m_isValid( false )
|
||||||
|
, m_effectiveH( 0.0 )
|
||||||
|
, m_effectiveK( 0.0 )
|
||||||
|
, m_connectionFactor( 0.0 )
|
||||||
|
, m_kh( 0.0 )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isValid() const { return m_isValid; }
|
||||||
|
|
||||||
|
void setData( double effectiveH, double effectiveK, double connectionFactor, double kh )
|
||||||
|
{
|
||||||
|
m_isValid = true;
|
||||||
|
|
||||||
|
m_effectiveH = effectiveH;
|
||||||
|
m_effectiveK = effectiveK;
|
||||||
|
m_connectionFactor = connectionFactor;
|
||||||
|
m_kh = kh;
|
||||||
|
}
|
||||||
|
|
||||||
|
double effectiveH() const { return m_effectiveH; }
|
||||||
|
|
||||||
|
double effectiveK() const { return m_effectiveK; }
|
||||||
|
double connectionFactor() const { return m_connectionFactor; }
|
||||||
|
double kh() const { return m_kh; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_isValid;
|
||||||
|
double m_effectiveH;
|
||||||
|
double m_effectiveK;
|
||||||
|
double m_connectionFactor;
|
||||||
|
double m_kh;
|
||||||
|
};
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
///
|
||||||
|
//==================================================================================================
|
||||||
|
class RicTransmissibilityCalculator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static RigCompletionData::CellDirection
|
||||||
|
calculateCellMainDirection( RimEclipseCase* eclipseCase, size_t globalCellIndex, const cvf::Vec3d& lengthsInCell );
|
||||||
|
|
||||||
|
static TransmissibilityData
|
||||||
|
calculateTransmissibilityData( RimEclipseCase* eclipseCase,
|
||||||
|
const RimWellPath* wellPath,
|
||||||
|
const cvf::Vec3d& internalCellLengths,
|
||||||
|
double skinFactor,
|
||||||
|
double wellRadius,
|
||||||
|
size_t globalCellIndex,
|
||||||
|
bool useLateralNTG,
|
||||||
|
size_t volumeScaleConstant = 1,
|
||||||
|
RigCompletionData::CellDirection directionForVolumeScaling = RigCompletionData::CellDirection::DIR_I );
|
||||||
|
|
||||||
|
static double calculateDFactor( RimEclipseCase* eclipseCase,
|
||||||
|
double effectiveH,
|
||||||
|
size_t globalCellIndex,
|
||||||
|
const RimNonDarcyPerforationParameters* nonDarcyParameters,
|
||||||
|
const double effectivePermeability );
|
||||||
|
|
||||||
|
static double calculateTransmissibilityAsEclipseDoes( RimEclipseCase* eclipseCase,
|
||||||
|
double skinFactor,
|
||||||
|
double wellRadius,
|
||||||
|
size_t globalCellIndex,
|
||||||
|
RigCompletionData::CellDirection direction );
|
||||||
|
};
|
||||||
+23
-366
@@ -18,9 +18,6 @@
|
|||||||
|
|
||||||
#include "RicWellPathExportCompletionDataFeatureImpl.h"
|
#include "RicWellPathExportCompletionDataFeatureImpl.h"
|
||||||
|
|
||||||
#include "RiaEclipseUnitTools.h"
|
|
||||||
#include "RiaFilePathTools.h"
|
|
||||||
#include "RiaFractureDefines.h"
|
|
||||||
#include "RiaLogging.h"
|
#include "RiaLogging.h"
|
||||||
#include "RiaPreferencesSystem.h"
|
#include "RiaPreferencesSystem.h"
|
||||||
#include "RiaWeightedMeanCalculator.h"
|
#include "RiaWeightedMeanCalculator.h"
|
||||||
@@ -28,9 +25,9 @@
|
|||||||
|
|
||||||
#include "ExportCommands/RicExportLgrFeature.h"
|
#include "ExportCommands/RicExportLgrFeature.h"
|
||||||
#include "RicExportCompletionDataSettingsUi.h"
|
#include "RicExportCompletionDataSettingsUi.h"
|
||||||
#include "RicExportFeatureImpl.h"
|
|
||||||
#include "RicExportFractureCompletionsImpl.h"
|
#include "RicExportFractureCompletionsImpl.h"
|
||||||
#include "RicFishbonesTransmissibilityCalculationFeatureImp.h"
|
#include "RicFishbonesTransmissibilityCalculationFeatureImp.h"
|
||||||
|
#include "RicTransmissibilityCalculator.h"
|
||||||
#include "RicWellPathExportCompletionsFileTools.h"
|
#include "RicWellPathExportCompletionsFileTools.h"
|
||||||
#include "RicWellPathExportMswCompletionsImpl.h"
|
#include "RicWellPathExportMswCompletionsImpl.h"
|
||||||
#include "RicWellPathFractureReportItem.h"
|
#include "RicWellPathFractureReportItem.h"
|
||||||
@@ -40,46 +37,26 @@
|
|||||||
#include "RifThermalToStimPlanFractureXmlOutput.h"
|
#include "RifThermalToStimPlanFractureXmlOutput.h"
|
||||||
|
|
||||||
#include "RigActiveCellInfo.h"
|
#include "RigActiveCellInfo.h"
|
||||||
#include "RigCaseCellResultsData.h"
|
|
||||||
#include "RigEclipseCaseData.h"
|
#include "RigEclipseCaseData.h"
|
||||||
#include "RigEclipseResultAddress.h"
|
|
||||||
#include "RigMainGrid.h"
|
#include "RigMainGrid.h"
|
||||||
#include "RigPerforationTransmissibilityEquations.h"
|
|
||||||
#include "RigResultAccessorFactory.h"
|
|
||||||
#include "RigTransmissibilityEquations.h"
|
|
||||||
#include "RigVirtualPerforationTransmissibilities.h"
|
|
||||||
#include "Well/RigWellLogExtractionTools.h"
|
|
||||||
#include "Well/RigWellLogExtractor.h"
|
#include "Well/RigWellLogExtractor.h"
|
||||||
#include "Well/RigWellPath.h"
|
#include "Well/RigWellPath.h"
|
||||||
#include "Well/RigWellPathIntersectionTools.h"
|
#include "Well/RigWellPathIntersectionTools.h"
|
||||||
|
|
||||||
#include "RimEclipseCase.h"
|
#include "RimEclipseCase.h"
|
||||||
#include "RimFileWellPath.h"
|
|
||||||
#include "RimFishbones.h"
|
|
||||||
#include "RimFishbonesCollection.h"
|
#include "RimFishbonesCollection.h"
|
||||||
#include "RimFractureTemplate.h"
|
|
||||||
#include "RimNonDarcyPerforationParameters.h"
|
#include "RimNonDarcyPerforationParameters.h"
|
||||||
#include "RimPerforationCollection.h"
|
#include "RimPerforationCollection.h"
|
||||||
#include "RimPerforationInterval.h"
|
#include "RimPerforationInterval.h"
|
||||||
#include "RimProject.h"
|
|
||||||
#include "RimSimWellInView.h"
|
|
||||||
#include "RimThermalFractureTemplate.h"
|
#include "RimThermalFractureTemplate.h"
|
||||||
#include "RimWellPath.h"
|
#include "RimWellPath.h"
|
||||||
#include "RimWellPathCollection.h"
|
|
||||||
#include "RimWellPathCompletions.h"
|
#include "RimWellPathCompletions.h"
|
||||||
#include "RimWellPathFracture.h"
|
#include "RimWellPathFracture.h"
|
||||||
#include "RimWellPathFractureCollection.h"
|
#include "RimWellPathFractureCollection.h"
|
||||||
#include "RimWellPathValve.h"
|
|
||||||
|
|
||||||
#include "Riu3DMainWindowTools.h"
|
#include "Riu3DMainWindowTools.h"
|
||||||
#include "RiuMainWindow.h"
|
|
||||||
|
|
||||||
#include "cafPdmUiPropertyViewDialog.h"
|
|
||||||
#include "cafProgressInfo.h"
|
#include "cafProgressInfo.h"
|
||||||
#include "cafSelectionManager.h"
|
|
||||||
#include "cafUtils.h"
|
|
||||||
|
|
||||||
#include "cvfPlane.h"
|
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
|
||||||
@@ -551,11 +528,11 @@ RigCompletionData RicWellPathExportCompletionDataFeatureImpl::combineEclipseCell
|
|||||||
{
|
{
|
||||||
// calculate trans for main bore - but as Eclipse will do it!
|
// calculate trans for main bore - but as Eclipse will do it!
|
||||||
double transmissibilityEclipseCalculation =
|
double transmissibilityEclipseCalculation =
|
||||||
RicWellPathExportCompletionDataFeatureImpl::calculateTransmissibilityAsEclipseDoes( settings.caseToApply(),
|
RicTransmissibilityCalculator::calculateTransmissibilityAsEclipseDoes( settings.caseToApply(),
|
||||||
combinedSkinFactor,
|
combinedSkinFactor,
|
||||||
combinedDiameter / 2,
|
combinedDiameter / 2,
|
||||||
cellIndexIJK.globalCellIndex(),
|
cellIndexIJK.globalCellIndex(),
|
||||||
cellDirection );
|
cellDirection );
|
||||||
|
|
||||||
double defaultKh = RigCompletionData::defaultValue();
|
double defaultKh = RigCompletionData::defaultValue();
|
||||||
double wpimult = combinedTrans / transmissibilityEclipseCalculation;
|
double wpimult = combinedTrans / transmissibilityEclipseCalculation;
|
||||||
@@ -1201,20 +1178,23 @@ std::vector<RigCompletionData>
|
|||||||
cell.startMD );
|
cell.startMD );
|
||||||
|
|
||||||
RigCompletionData::CellDirection direction =
|
RigCompletionData::CellDirection direction =
|
||||||
calculateCellMainDirection( settings.caseToApply, cell.globCellIndex, cell.intersectionLengthsInCellCS );
|
RicTransmissibilityCalculator::calculateCellMainDirection( settings.caseToApply,
|
||||||
|
cell.globCellIndex,
|
||||||
|
cell.intersectionLengthsInCellCS );
|
||||||
|
|
||||||
double transmissibility = 0.0;
|
double transmissibility = 0.0;
|
||||||
double kh = RigCompletionData::defaultValue();
|
double kh = RigCompletionData::defaultValue();
|
||||||
double dFactor = RigCompletionData::defaultValue();
|
double dFactor = RigCompletionData::defaultValue();
|
||||||
|
|
||||||
{
|
{
|
||||||
auto transmissibilityData = calculateTransmissibilityData( settings.caseToApply,
|
auto transmissibilityData =
|
||||||
wellPath,
|
RicTransmissibilityCalculator::calculateTransmissibilityData( settings.caseToApply,
|
||||||
cell.intersectionLengthsInCellCS,
|
wellPath,
|
||||||
interval->skinFactor(),
|
cell.intersectionLengthsInCellCS,
|
||||||
interval->diameter( unitSystem ) / 2,
|
interval->skinFactor(),
|
||||||
cell.globCellIndex,
|
interval->diameter( unitSystem ) / 2,
|
||||||
settings.useLateralNTG );
|
cell.globCellIndex,
|
||||||
|
settings.useLateralNTG );
|
||||||
|
|
||||||
transmissibility = transmissibilityData.connectionFactor();
|
transmissibility = transmissibilityData.connectionFactor();
|
||||||
kh = transmissibilityData.kh();
|
kh = transmissibilityData.kh();
|
||||||
@@ -1226,11 +1206,12 @@ std::vector<RigCompletionData>
|
|||||||
const double effectivePermeability =
|
const double effectivePermeability =
|
||||||
nonDarcyParameters->gridPermeabilityScalingFactor() * transmissibilityData.effectiveK();
|
nonDarcyParameters->gridPermeabilityScalingFactor() * transmissibilityData.effectiveK();
|
||||||
|
|
||||||
dFactor = calculateDFactor( settings.caseToApply,
|
dFactor =
|
||||||
effectiveH,
|
RicTransmissibilityCalculator::calculateDFactor( settings.caseToApply,
|
||||||
cell.globCellIndex,
|
effectiveH,
|
||||||
wellPath->perforationIntervalCollection()->nonDarcyParameters(),
|
cell.globCellIndex,
|
||||||
effectivePermeability );
|
wellPath->perforationIntervalCollection()->nonDarcyParameters(),
|
||||||
|
effectivePermeability );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1297,330 +1278,6 @@ void RicWellPathExportCompletionDataFeatureImpl::appendCompletionData( std::map<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
///
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
RigCompletionData::CellDirection RicWellPathExportCompletionDataFeatureImpl::calculateCellMainDirection( RimEclipseCase* eclipseCase,
|
|
||||||
size_t globalCellIndex,
|
|
||||||
const cvf::Vec3d& lengthsInCell )
|
|
||||||
{
|
|
||||||
RigEclipseCaseData* eclipseCaseData = eclipseCase->eclipseCaseData();
|
|
||||||
|
|
||||||
eclipseCase->results( RiaDefines::PorosityModelType::MATRIX_MODEL )->ensureKnownResultLoaded( RigEclipseResultAddress( "DX" ) );
|
|
||||||
cvf::ref<RigResultAccessor> dxAccessObject = RigResultAccessorFactory::createFromResultAddress( eclipseCaseData,
|
|
||||||
0,
|
|
||||||
RiaDefines::PorosityModelType::MATRIX_MODEL,
|
|
||||||
0,
|
|
||||||
RigEclipseResultAddress( "DX" ) );
|
|
||||||
eclipseCase->results( RiaDefines::PorosityModelType::MATRIX_MODEL )->ensureKnownResultLoaded( RigEclipseResultAddress( "DY" ) );
|
|
||||||
cvf::ref<RigResultAccessor> dyAccessObject = RigResultAccessorFactory::createFromResultAddress( eclipseCaseData,
|
|
||||||
0,
|
|
||||||
RiaDefines::PorosityModelType::MATRIX_MODEL,
|
|
||||||
0,
|
|
||||||
RigEclipseResultAddress( "DY" ) );
|
|
||||||
eclipseCase->results( RiaDefines::PorosityModelType::MATRIX_MODEL )->ensureKnownResultLoaded( RigEclipseResultAddress( "DZ" ) );
|
|
||||||
cvf::ref<RigResultAccessor> dzAccessObject = RigResultAccessorFactory::createFromResultAddress( eclipseCaseData,
|
|
||||||
0,
|
|
||||||
RiaDefines::PorosityModelType::MATRIX_MODEL,
|
|
||||||
0,
|
|
||||||
RigEclipseResultAddress( "DZ" ) );
|
|
||||||
|
|
||||||
double xLengthFraction = fabs( lengthsInCell.x() / dxAccessObject->cellScalarGlobIdx( globalCellIndex ) );
|
|
||||||
double yLengthFraction = fabs( lengthsInCell.y() / dyAccessObject->cellScalarGlobIdx( globalCellIndex ) );
|
|
||||||
double zLengthFraction = fabs( lengthsInCell.z() / dzAccessObject->cellScalarGlobIdx( globalCellIndex ) );
|
|
||||||
|
|
||||||
if ( xLengthFraction > yLengthFraction && xLengthFraction > zLengthFraction )
|
|
||||||
{
|
|
||||||
return RigCompletionData::CellDirection::DIR_I;
|
|
||||||
}
|
|
||||||
else if ( yLengthFraction > xLengthFraction && yLengthFraction > zLengthFraction )
|
|
||||||
{
|
|
||||||
return RigCompletionData::CellDirection::DIR_J;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return RigCompletionData::CellDirection::DIR_K;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
///
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
TransmissibilityData
|
|
||||||
RicWellPathExportCompletionDataFeatureImpl::calculateTransmissibilityData( RimEclipseCase* eclipseCase,
|
|
||||||
const RimWellPath* wellPath,
|
|
||||||
const cvf::Vec3d& internalCellLengths,
|
|
||||||
double skinFactor,
|
|
||||||
double wellRadius,
|
|
||||||
size_t globalCellIndex,
|
|
||||||
bool useLateralNTG,
|
|
||||||
size_t volumeScaleConstant,
|
|
||||||
RigCompletionData::CellDirection directionForVolumeScaling )
|
|
||||||
{
|
|
||||||
RigEclipseCaseData* eclipseCaseData = eclipseCase->eclipseCaseData();
|
|
||||||
|
|
||||||
eclipseCase->results( RiaDefines::PorosityModelType::MATRIX_MODEL )->ensureKnownResultLoaded( RigEclipseResultAddress( "DX" ) );
|
|
||||||
cvf::ref<RigResultAccessor> dxAccessObject = RigResultAccessorFactory::createFromResultAddress( eclipseCaseData,
|
|
||||||
0,
|
|
||||||
RiaDefines::PorosityModelType::MATRIX_MODEL,
|
|
||||||
0,
|
|
||||||
RigEclipseResultAddress( "DX" ) );
|
|
||||||
eclipseCase->results( RiaDefines::PorosityModelType::MATRIX_MODEL )->ensureKnownResultLoaded( RigEclipseResultAddress( "DY" ) );
|
|
||||||
cvf::ref<RigResultAccessor> dyAccessObject = RigResultAccessorFactory::createFromResultAddress( eclipseCaseData,
|
|
||||||
0,
|
|
||||||
RiaDefines::PorosityModelType::MATRIX_MODEL,
|
|
||||||
0,
|
|
||||||
RigEclipseResultAddress( "DY" ) );
|
|
||||||
eclipseCase->results( RiaDefines::PorosityModelType::MATRIX_MODEL )->ensureKnownResultLoaded( RigEclipseResultAddress( "DZ" ) );
|
|
||||||
cvf::ref<RigResultAccessor> dzAccessObject = RigResultAccessorFactory::createFromResultAddress( eclipseCaseData,
|
|
||||||
0,
|
|
||||||
RiaDefines::PorosityModelType::MATRIX_MODEL,
|
|
||||||
0,
|
|
||||||
RigEclipseResultAddress( "DZ" ) );
|
|
||||||
|
|
||||||
eclipseCase->results( RiaDefines::PorosityModelType::MATRIX_MODEL )->ensureKnownResultLoaded( RigEclipseResultAddress( "PERMX" ) );
|
|
||||||
cvf::ref<RigResultAccessor> permxAccessObject =
|
|
||||||
RigResultAccessorFactory::createFromResultAddress( eclipseCaseData,
|
|
||||||
0,
|
|
||||||
RiaDefines::PorosityModelType::MATRIX_MODEL,
|
|
||||||
0,
|
|
||||||
RigEclipseResultAddress( "PERMX" ) );
|
|
||||||
eclipseCase->results( RiaDefines::PorosityModelType::MATRIX_MODEL )->ensureKnownResultLoaded( RigEclipseResultAddress( "PERMY" ) );
|
|
||||||
cvf::ref<RigResultAccessor> permyAccessObject =
|
|
||||||
RigResultAccessorFactory::createFromResultAddress( eclipseCaseData,
|
|
||||||
0,
|
|
||||||
RiaDefines::PorosityModelType::MATRIX_MODEL,
|
|
||||||
0,
|
|
||||||
RigEclipseResultAddress( "PERMY" ) );
|
|
||||||
eclipseCase->results( RiaDefines::PorosityModelType::MATRIX_MODEL )->ensureKnownResultLoaded( RigEclipseResultAddress( "PERMZ" ) );
|
|
||||||
cvf::ref<RigResultAccessor> permzAccessObject =
|
|
||||||
RigResultAccessorFactory::createFromResultAddress( eclipseCaseData,
|
|
||||||
0,
|
|
||||||
RiaDefines::PorosityModelType::MATRIX_MODEL,
|
|
||||||
0,
|
|
||||||
RigEclipseResultAddress( "PERMZ" ) );
|
|
||||||
|
|
||||||
if ( dxAccessObject.isNull() || dyAccessObject.isNull() || dzAccessObject.isNull() || permxAccessObject.isNull() ||
|
|
||||||
permyAccessObject.isNull() || permzAccessObject.isNull() )
|
|
||||||
{
|
|
||||||
return TransmissibilityData();
|
|
||||||
}
|
|
||||||
|
|
||||||
double ntg = 1.0;
|
|
||||||
{
|
|
||||||
// Trigger loading from file
|
|
||||||
eclipseCase->results( RiaDefines::PorosityModelType::MATRIX_MODEL )->ensureKnownResultLoaded( RigEclipseResultAddress( "NTG" ) );
|
|
||||||
|
|
||||||
cvf::ref<RigResultAccessor> ntgAccessObject =
|
|
||||||
RigResultAccessorFactory::createFromResultAddress( eclipseCaseData,
|
|
||||||
0,
|
|
||||||
RiaDefines::PorosityModelType::MATRIX_MODEL,
|
|
||||||
0,
|
|
||||||
RigEclipseResultAddress( "NTG" ) );
|
|
||||||
|
|
||||||
if ( ntgAccessObject.notNull() )
|
|
||||||
{
|
|
||||||
ntg = ntgAccessObject->cellScalarGlobIdx( globalCellIndex );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
double latNtg = useLateralNTG ? ntg : 1.0;
|
|
||||||
|
|
||||||
double dx = dxAccessObject->cellScalarGlobIdx( globalCellIndex );
|
|
||||||
double dy = dyAccessObject->cellScalarGlobIdx( globalCellIndex );
|
|
||||||
double dz = dzAccessObject->cellScalarGlobIdx( globalCellIndex );
|
|
||||||
double permx = permxAccessObject->cellScalarGlobIdx( globalCellIndex );
|
|
||||||
double permy = permyAccessObject->cellScalarGlobIdx( globalCellIndex );
|
|
||||||
double permz = permzAccessObject->cellScalarGlobIdx( globalCellIndex );
|
|
||||||
|
|
||||||
const double totalKh = RigTransmissibilityEquations::totalKh( permx, permy, permz, internalCellLengths, latNtg, ntg );
|
|
||||||
|
|
||||||
const double effectiveK = RigTransmissibilityEquations::effectiveK( permx, permy, permz, internalCellLengths, latNtg, ntg );
|
|
||||||
const double effectiveH = RigTransmissibilityEquations::effectiveH( internalCellLengths, latNtg, ntg );
|
|
||||||
|
|
||||||
double darcy = RiaEclipseUnitTools::darcysConstant( wellPath->unitSystem() );
|
|
||||||
|
|
||||||
if ( volumeScaleConstant != 1 )
|
|
||||||
{
|
|
||||||
if ( directionForVolumeScaling == RigCompletionData::CellDirection::DIR_I ) dx = dx / volumeScaleConstant;
|
|
||||||
if ( directionForVolumeScaling == RigCompletionData::CellDirection::DIR_J ) dy = dy / volumeScaleConstant;
|
|
||||||
if ( directionForVolumeScaling == RigCompletionData::CellDirection::DIR_K ) dz = dz / volumeScaleConstant;
|
|
||||||
}
|
|
||||||
|
|
||||||
const double transx = RigTransmissibilityEquations::wellBoreTransmissibilityComponent( internalCellLengths.x() * latNtg,
|
|
||||||
permy,
|
|
||||||
permz,
|
|
||||||
dy,
|
|
||||||
dz,
|
|
||||||
wellRadius,
|
|
||||||
skinFactor,
|
|
||||||
darcy );
|
|
||||||
const double transy = RigTransmissibilityEquations::wellBoreTransmissibilityComponent( internalCellLengths.y() * latNtg,
|
|
||||||
permx,
|
|
||||||
permz,
|
|
||||||
dx,
|
|
||||||
dz,
|
|
||||||
wellRadius,
|
|
||||||
skinFactor,
|
|
||||||
darcy );
|
|
||||||
const double transz = RigTransmissibilityEquations::wellBoreTransmissibilityComponent( internalCellLengths.z() * ntg,
|
|
||||||
permy,
|
|
||||||
permx,
|
|
||||||
dy,
|
|
||||||
dx,
|
|
||||||
wellRadius,
|
|
||||||
skinFactor,
|
|
||||||
darcy );
|
|
||||||
|
|
||||||
const double totalConnectionFactor = RigTransmissibilityEquations::totalConnectionFactor( transx, transy, transz );
|
|
||||||
|
|
||||||
TransmissibilityData trData;
|
|
||||||
trData.setData( effectiveH, effectiveK, totalConnectionFactor, totalKh );
|
|
||||||
return trData;
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
///
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
double RicWellPathExportCompletionDataFeatureImpl::calculateDFactor( RimEclipseCase* eclipseCase,
|
|
||||||
double effectiveH,
|
|
||||||
size_t globalCellIndex,
|
|
||||||
const RimNonDarcyPerforationParameters* nonDarcyParameters,
|
|
||||||
const double effectivePermeability )
|
|
||||||
{
|
|
||||||
using EQ = RigPerforationTransmissibilityEquations;
|
|
||||||
|
|
||||||
if ( !eclipseCase || !eclipseCase->eclipseCaseData() )
|
|
||||||
{
|
|
||||||
return std::numeric_limits<double>::infinity();
|
|
||||||
}
|
|
||||||
|
|
||||||
RigEclipseCaseData* eclipseCaseData = eclipseCase->eclipseCaseData();
|
|
||||||
|
|
||||||
double porosity = 0.0;
|
|
||||||
{
|
|
||||||
eclipseCase->results( RiaDefines::PorosityModelType::MATRIX_MODEL )->ensureKnownResultLoaded( RigEclipseResultAddress( "PORO" ) );
|
|
||||||
cvf::ref<RigResultAccessor> poroAccessObject =
|
|
||||||
RigResultAccessorFactory::createFromResultAddress( eclipseCaseData,
|
|
||||||
0,
|
|
||||||
RiaDefines::PorosityModelType::MATRIX_MODEL,
|
|
||||||
0,
|
|
||||||
RigEclipseResultAddress( "PORO" ) );
|
|
||||||
|
|
||||||
if ( poroAccessObject.notNull() )
|
|
||||||
{
|
|
||||||
porosity = poroAccessObject->cellScalar( globalCellIndex );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const double betaFactor = EQ::betaFactor( nonDarcyParameters->inertialCoefficientBeta0(),
|
|
||||||
effectivePermeability,
|
|
||||||
nonDarcyParameters->permeabilityScalingFactor(),
|
|
||||||
porosity,
|
|
||||||
nonDarcyParameters->porosityScalingFactor() );
|
|
||||||
|
|
||||||
const double alpha = RiaDefines::nonDarcyFlowAlpha( eclipseCaseData->unitsType() );
|
|
||||||
|
|
||||||
return EQ::dFactor( alpha,
|
|
||||||
betaFactor,
|
|
||||||
effectivePermeability,
|
|
||||||
effectiveH,
|
|
||||||
nonDarcyParameters->wellRadius(),
|
|
||||||
nonDarcyParameters->relativeGasDensity(),
|
|
||||||
nonDarcyParameters->gasViscosity() );
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
///
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
double RicWellPathExportCompletionDataFeatureImpl::calculateTransmissibilityAsEclipseDoes( RimEclipseCase* eclipseCase,
|
|
||||||
double skinFactor,
|
|
||||||
double wellRadius,
|
|
||||||
size_t globalCellIndex,
|
|
||||||
RigCompletionData::CellDirection direction )
|
|
||||||
{
|
|
||||||
RigEclipseCaseData* eclipseCaseData = eclipseCase->eclipseCaseData();
|
|
||||||
|
|
||||||
eclipseCase->results( RiaDefines::PorosityModelType::MATRIX_MODEL )->ensureKnownResultLoaded( RigEclipseResultAddress( "DX" ) );
|
|
||||||
cvf::ref<RigResultAccessor> dxAccessObject = RigResultAccessorFactory::createFromResultAddress( eclipseCaseData,
|
|
||||||
0,
|
|
||||||
RiaDefines::PorosityModelType::MATRIX_MODEL,
|
|
||||||
0,
|
|
||||||
RigEclipseResultAddress( "DX" ) );
|
|
||||||
eclipseCase->results( RiaDefines::PorosityModelType::MATRIX_MODEL )->ensureKnownResultLoaded( RigEclipseResultAddress( "DY" ) );
|
|
||||||
cvf::ref<RigResultAccessor> dyAccessObject = RigResultAccessorFactory::createFromResultAddress( eclipseCaseData,
|
|
||||||
0,
|
|
||||||
RiaDefines::PorosityModelType::MATRIX_MODEL,
|
|
||||||
0,
|
|
||||||
RigEclipseResultAddress( "DY" ) );
|
|
||||||
eclipseCase->results( RiaDefines::PorosityModelType::MATRIX_MODEL )->ensureKnownResultLoaded( RigEclipseResultAddress( "DZ" ) );
|
|
||||||
cvf::ref<RigResultAccessor> dzAccessObject = RigResultAccessorFactory::createFromResultAddress( eclipseCaseData,
|
|
||||||
0,
|
|
||||||
RiaDefines::PorosityModelType::MATRIX_MODEL,
|
|
||||||
0,
|
|
||||||
RigEclipseResultAddress( "DZ" ) );
|
|
||||||
|
|
||||||
eclipseCase->results( RiaDefines::PorosityModelType::MATRIX_MODEL )->ensureKnownResultLoaded( RigEclipseResultAddress( "PERMX" ) );
|
|
||||||
cvf::ref<RigResultAccessor> permxAccessObject =
|
|
||||||
RigResultAccessorFactory::createFromResultAddress( eclipseCaseData,
|
|
||||||
0,
|
|
||||||
RiaDefines::PorosityModelType::MATRIX_MODEL,
|
|
||||||
0,
|
|
||||||
RigEclipseResultAddress( "PERMX" ) );
|
|
||||||
eclipseCase->results( RiaDefines::PorosityModelType::MATRIX_MODEL )->ensureKnownResultLoaded( RigEclipseResultAddress( "PERMY" ) );
|
|
||||||
cvf::ref<RigResultAccessor> permyAccessObject =
|
|
||||||
RigResultAccessorFactory::createFromResultAddress( eclipseCaseData,
|
|
||||||
0,
|
|
||||||
RiaDefines::PorosityModelType::MATRIX_MODEL,
|
|
||||||
0,
|
|
||||||
RigEclipseResultAddress( "PERMY" ) );
|
|
||||||
eclipseCase->results( RiaDefines::PorosityModelType::MATRIX_MODEL )->ensureKnownResultLoaded( RigEclipseResultAddress( "PERMZ" ) );
|
|
||||||
cvf::ref<RigResultAccessor> permzAccessObject =
|
|
||||||
RigResultAccessorFactory::createFromResultAddress( eclipseCaseData,
|
|
||||||
0,
|
|
||||||
RiaDefines::PorosityModelType::MATRIX_MODEL,
|
|
||||||
0,
|
|
||||||
RigEclipseResultAddress( "PERMZ" ) );
|
|
||||||
|
|
||||||
double ntg = 1.0;
|
|
||||||
if ( eclipseCase->results( RiaDefines::PorosityModelType::MATRIX_MODEL )->ensureKnownResultLoaded( RigEclipseResultAddress( "NTG" ) ) )
|
|
||||||
{
|
|
||||||
cvf::ref<RigResultAccessor> ntgAccessObject =
|
|
||||||
RigResultAccessorFactory::createFromResultAddress( eclipseCaseData,
|
|
||||||
0,
|
|
||||||
RiaDefines::PorosityModelType::MATRIX_MODEL,
|
|
||||||
0,
|
|
||||||
RigEclipseResultAddress( "NTG" ) );
|
|
||||||
ntg = ntgAccessObject->cellScalarGlobIdx( globalCellIndex );
|
|
||||||
}
|
|
||||||
|
|
||||||
double dx = dxAccessObject->cellScalarGlobIdx( globalCellIndex );
|
|
||||||
double dy = dyAccessObject->cellScalarGlobIdx( globalCellIndex );
|
|
||||||
double dz = dzAccessObject->cellScalarGlobIdx( globalCellIndex );
|
|
||||||
double permx = permxAccessObject->cellScalarGlobIdx( globalCellIndex );
|
|
||||||
double permy = permyAccessObject->cellScalarGlobIdx( globalCellIndex );
|
|
||||||
double permz = permzAccessObject->cellScalarGlobIdx( globalCellIndex );
|
|
||||||
|
|
||||||
RiaDefines::EclipseUnitSystem units = eclipseCaseData->unitsType();
|
|
||||||
double darcy = RiaEclipseUnitTools::darcysConstant( units );
|
|
||||||
|
|
||||||
double trans = cvf::UNDEFINED_DOUBLE;
|
|
||||||
if ( direction == RigCompletionData::CellDirection::DIR_I )
|
|
||||||
{
|
|
||||||
trans = RigTransmissibilityEquations::wellBoreTransmissibilityComponent( dx, permy, permz, dy, dz, wellRadius, skinFactor, darcy );
|
|
||||||
}
|
|
||||||
else if ( direction == RigCompletionData::CellDirection::DIR_J )
|
|
||||||
{
|
|
||||||
trans = RigTransmissibilityEquations::wellBoreTransmissibilityComponent( dy, permx, permz, dx, dz, wellRadius, skinFactor, darcy );
|
|
||||||
}
|
|
||||||
else if ( direction == RigCompletionData::CellDirection::DIR_K )
|
|
||||||
{
|
|
||||||
trans =
|
|
||||||
RigTransmissibilityEquations::wellBoreTransmissibilityComponent( dz * ntg, permy, permx, dy, dx, wellRadius, skinFactor, darcy );
|
|
||||||
}
|
|
||||||
|
|
||||||
return trans;
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
-64
@@ -54,70 +54,12 @@ class SubSegmentIntersectionInfo;
|
|||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
using QFilePtr = std::shared_ptr<QFile>;
|
using QFilePtr = std::shared_ptr<QFile>;
|
||||||
|
|
||||||
class TransmissibilityData
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
TransmissibilityData()
|
|
||||||
: m_isValid( false )
|
|
||||||
, m_effectiveH( 0.0 )
|
|
||||||
, m_effectiveK( 0.0 )
|
|
||||||
, m_connectionFactor( 0.0 )
|
|
||||||
, m_kh( 0.0 )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isValid() const { return m_isValid; }
|
|
||||||
|
|
||||||
void setData( double effectiveH, double effectiveK, double connectionFactor, double kh )
|
|
||||||
{
|
|
||||||
m_isValid = true;
|
|
||||||
|
|
||||||
m_effectiveH = effectiveH;
|
|
||||||
m_effectiveK = effectiveK;
|
|
||||||
m_connectionFactor = connectionFactor;
|
|
||||||
m_kh = kh;
|
|
||||||
}
|
|
||||||
|
|
||||||
double effectiveH() const { return m_effectiveH; }
|
|
||||||
|
|
||||||
double effectiveK() const { return m_effectiveK; }
|
|
||||||
double connectionFactor() const { return m_connectionFactor; }
|
|
||||||
double kh() const { return m_kh; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool m_isValid;
|
|
||||||
double m_effectiveH;
|
|
||||||
double m_effectiveK;
|
|
||||||
double m_connectionFactor;
|
|
||||||
double m_kh;
|
|
||||||
};
|
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
///
|
///
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
class RicWellPathExportCompletionDataFeatureImpl
|
class RicWellPathExportCompletionDataFeatureImpl
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static RigCompletionData::CellDirection
|
|
||||||
calculateCellMainDirection( RimEclipseCase* eclipseCase, size_t globalCellIndex, const cvf::Vec3d& lengthsInCell );
|
|
||||||
|
|
||||||
static TransmissibilityData
|
|
||||||
calculateTransmissibilityData( RimEclipseCase* eclipseCase,
|
|
||||||
const RimWellPath* wellPath,
|
|
||||||
const cvf::Vec3d& internalCellLengths,
|
|
||||||
double skinFactor,
|
|
||||||
double wellRadius,
|
|
||||||
size_t globalCellIndex,
|
|
||||||
bool useLateralNTG,
|
|
||||||
size_t volumeScaleConstant = 1,
|
|
||||||
RigCompletionData::CellDirection directionForVolumeScaling = RigCompletionData::CellDirection::DIR_I );
|
|
||||||
|
|
||||||
static double calculateDFactor( RimEclipseCase* eclipseCase,
|
|
||||||
double effectiveH,
|
|
||||||
size_t globalCellIndex,
|
|
||||||
const RimNonDarcyPerforationParameters* nonDarcyParameters,
|
|
||||||
const double effectivePermeability );
|
|
||||||
|
|
||||||
static void exportCompletions( const std::vector<RimWellPath*>& wellPaths, const RicExportCompletionDataSettingsUi& exportSettings );
|
static void exportCompletions( const std::vector<RimWellPath*>& wellPaths, const RicExportCompletionDataSettingsUi& exportSettings );
|
||||||
|
|
||||||
static std::vector<RigCompletionData> computeStaticCompletionsForWellPath( RimWellPath* wellPath, RimEclipseCase* eclipseCase );
|
static std::vector<RigCompletionData> computeStaticCompletionsForWellPath( RimWellPath* wellPath, RimEclipseCase* eclipseCase );
|
||||||
@@ -140,12 +82,6 @@ private:
|
|||||||
const RicExportCompletionDataSettingsUi& settings,
|
const RicExportCompletionDataSettingsUi& settings,
|
||||||
const std::optional<QDateTime>& exportDate = std::nullopt );
|
const std::optional<QDateTime>& exportDate = std::nullopt );
|
||||||
|
|
||||||
static double calculateTransmissibilityAsEclipseDoes( RimEclipseCase* eclipseCase,
|
|
||||||
double skinFactor,
|
|
||||||
double wellRadius,
|
|
||||||
size_t globalCellIndex,
|
|
||||||
RigCompletionData::CellDirection direction );
|
|
||||||
|
|
||||||
static RigCompletionData combineEclipseCellCompletions( const std::vector<RigCompletionData>& completions,
|
static RigCompletionData combineEclipseCellCompletions( const std::vector<RigCompletionData>& completions,
|
||||||
const RicExportCompletionDataSettingsUi& settings );
|
const RicExportCompletionDataSettingsUi& settings );
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,6 @@
|
|||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
namespace RifEclipseSummaryAddressDefines
|
namespace RifEclipseSummaryAddressDefines
|
||||||
{
|
{
|
||||||
// Based on list in ecl_smspec.c and list of types taken from Eclipse Reference Manual ecl_rm_2011.1.pdf
|
|
||||||
enum class SummaryCategory
|
enum class SummaryCategory
|
||||||
{
|
{
|
||||||
SUMMARY_INVALID,
|
SUMMARY_INVALID,
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ set(SOURCE_UNITTEST_FILES
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/RifSurfio-Test.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RifSurfio-Test.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RifRmsWellPathReader-Test.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RifRmsWellPathReader-Test.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RiaAngleUtils-Test.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RiaAngleUtils-Test.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/RicTransmissibilityCalculator-Test.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/cafVecIjk-Test.cpp
|
${CMAKE_CURRENT_LIST_DIR}/cafVecIjk-Test.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RiaSummaryAddressCollectionTools-Test.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RiaSummaryAddressCollectionTools-Test.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RimMockSummaryCase.h
|
${CMAKE_CURRENT_LIST_DIR}/RimMockSummaryCase.h
|
||||||
|
|||||||
@@ -0,0 +1,221 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (C) 2026 Equinor ASA
|
||||||
|
//
|
||||||
|
// ResInsight is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
//
|
||||||
|
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||||
|
// for more details.
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
#include "CompletionExportCommands/RicTransmissibilityCalculator.h"
|
||||||
|
|
||||||
|
#include "RifReaderMockModel.h"
|
||||||
|
|
||||||
|
#include "RigActiveCellInfo.h"
|
||||||
|
#include "RigCaseCellResultsData.h"
|
||||||
|
#include "RigEclipseCaseData.h"
|
||||||
|
#include "RigEclipseResultAddress.h"
|
||||||
|
#include "RigEclipseResultInfo.h"
|
||||||
|
#include "RigMainGrid.h"
|
||||||
|
|
||||||
|
#include "RimEclipseCase.h"
|
||||||
|
#include "RimEclipseResultCase.h"
|
||||||
|
#include "RimWellPath.h"
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
/// Helper: Register a STATIC_NATIVE result with a uniform value for all cells
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
static void addStaticResult( RigCaseCellResultsData* cellResults, const QString& name, size_t cellCount, double value )
|
||||||
|
{
|
||||||
|
RigEclipseResultAddress address( RiaDefines::ResultCatType::STATIC_NATIVE, name );
|
||||||
|
cellResults->createResultEntry( address, false );
|
||||||
|
|
||||||
|
auto timeStepInfo = RigEclipseTimeStepInfo( QDateTime(), 0, 0.0 );
|
||||||
|
cellResults->setTimeStepInfos( address, { timeStepInfo } );
|
||||||
|
|
||||||
|
auto* timesteps = cellResults->modifiableCellScalarResultTimesteps( address );
|
||||||
|
timesteps->resize( 1 );
|
||||||
|
( *timesteps )[0].assign( cellCount, value );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
/// Helper: Create a RimEclipseCase with mock grid and populated result data
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
static RimEclipseCase*
|
||||||
|
createMockEclipseCase( double dxVal, double dyVal, double dzVal, double permxVal, double permyVal, double permzVal, double ntgVal )
|
||||||
|
{
|
||||||
|
auto* eclipseCase = new RimEclipseResultCase;
|
||||||
|
|
||||||
|
cvf::ref<RigEclipseCaseData> caseData = new RigEclipseCaseData( eclipseCase );
|
||||||
|
|
||||||
|
{
|
||||||
|
cvf::ref<RifReaderMockModel> mockReader = new RifReaderMockModel;
|
||||||
|
mockReader->setWorldCoordinates( cvf::Vec3d( 0, 0, 0 ), cvf::Vec3d( 100, 100, 100 ) );
|
||||||
|
mockReader->setCellCounts( cvf::Vec3st( 2, 2, 2 ) );
|
||||||
|
mockReader->enableWellData( false );
|
||||||
|
mockReader->open( "", caseData.p() );
|
||||||
|
caseData->mainGrid()->computeCachedData();
|
||||||
|
}
|
||||||
|
|
||||||
|
eclipseCase->setReservoirData( caseData.p() );
|
||||||
|
|
||||||
|
size_t cellCount = caseData->mainGrid()->totalCellCount();
|
||||||
|
RigCaseCellResultsData* cellResults = caseData->results( RiaDefines::PorosityModelType::MATRIX_MODEL );
|
||||||
|
|
||||||
|
addStaticResult( cellResults, "DX", cellCount, dxVal );
|
||||||
|
addStaticResult( cellResults, "DY", cellCount, dyVal );
|
||||||
|
addStaticResult( cellResults, "DZ", cellCount, dzVal );
|
||||||
|
addStaticResult( cellResults, "PERMX", cellCount, permxVal );
|
||||||
|
addStaticResult( cellResults, "PERMY", cellCount, permyVal );
|
||||||
|
addStaticResult( cellResults, "PERMZ", cellCount, permzVal );
|
||||||
|
addStaticResult( cellResults, "NTG", cellCount, ntgVal );
|
||||||
|
|
||||||
|
return eclipseCase;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
TEST( RicTransmissibilityCalculator, CalculateCellMainDirection_DirectionI )
|
||||||
|
{
|
||||||
|
RimEclipseCase* eclipseCase = createMockEclipseCase( 10.0, 20.0, 30.0, 100.0, 100.0, 10.0, 1.0 );
|
||||||
|
|
||||||
|
// lengthsInCell = (8, 3, 2) → fractions: x=0.8, y=0.15, z=0.067 → DIR_I
|
||||||
|
cvf::Vec3d lengthsInCell( 8.0, 3.0, 2.0 );
|
||||||
|
|
||||||
|
auto direction = RicTransmissibilityCalculator::calculateCellMainDirection( eclipseCase, 0, lengthsInCell );
|
||||||
|
|
||||||
|
EXPECT_EQ( RigCompletionData::CellDirection::DIR_I, direction );
|
||||||
|
|
||||||
|
delete eclipseCase;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
TEST( RicTransmissibilityCalculator, CalculateCellMainDirection_DirectionK )
|
||||||
|
{
|
||||||
|
RimEclipseCase* eclipseCase = createMockEclipseCase( 10.0, 20.0, 30.0, 100.0, 100.0, 10.0, 1.0 );
|
||||||
|
|
||||||
|
// lengthsInCell = (1, 1, 25) → fractions: x=0.1, y=0.05, z=0.833 → DIR_K
|
||||||
|
cvf::Vec3d lengthsInCell( 1.0, 1.0, 25.0 );
|
||||||
|
|
||||||
|
auto direction = RicTransmissibilityCalculator::calculateCellMainDirection( eclipseCase, 0, lengthsInCell );
|
||||||
|
|
||||||
|
EXPECT_EQ( RigCompletionData::CellDirection::DIR_K, direction );
|
||||||
|
|
||||||
|
delete eclipseCase;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
TEST( RicTransmissibilityCalculator, CalculateTransmissibilityData_Valid )
|
||||||
|
{
|
||||||
|
RimEclipseCase* eclipseCase = createMockEclipseCase( 100.0, 100.0, 10.0, 100.0, 100.0, 10.0, 1.0 );
|
||||||
|
|
||||||
|
RimWellPath wellPath;
|
||||||
|
wellPath.setUnitSystem( RiaDefines::EclipseUnitSystem::UNITS_METRIC );
|
||||||
|
|
||||||
|
cvf::Vec3d internalCellLengths( 50.0, 50.0, 5.0 );
|
||||||
|
double skinFactor = 0.0;
|
||||||
|
double wellRadius = 0.1;
|
||||||
|
|
||||||
|
auto result =
|
||||||
|
RicTransmissibilityCalculator::calculateTransmissibilityData( eclipseCase, &wellPath, internalCellLengths, skinFactor, wellRadius, 0, false );
|
||||||
|
|
||||||
|
EXPECT_TRUE( result.isValid() );
|
||||||
|
EXPECT_GT( result.connectionFactor(), 0.0 );
|
||||||
|
EXPECT_GT( result.kh(), 0.0 );
|
||||||
|
EXPECT_GT( result.effectiveH(), 0.0 );
|
||||||
|
EXPECT_GT( result.effectiveK(), 0.0 );
|
||||||
|
|
||||||
|
delete eclipseCase;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
TEST( RicTransmissibilityCalculator, CalculateTransmissibilityAsEclipseDoes_DirectionK )
|
||||||
|
{
|
||||||
|
RimEclipseCase* eclipseCase = createMockEclipseCase( 100.0, 100.0, 10.0, 100.0, 100.0, 10.0, 1.0 );
|
||||||
|
|
||||||
|
double skinFactor = 0.0;
|
||||||
|
double wellRadius = 0.1;
|
||||||
|
|
||||||
|
double trans = RicTransmissibilityCalculator::calculateTransmissibilityAsEclipseDoes( eclipseCase,
|
||||||
|
skinFactor,
|
||||||
|
wellRadius,
|
||||||
|
0,
|
||||||
|
RigCompletionData::CellDirection::DIR_K );
|
||||||
|
|
||||||
|
EXPECT_GT( trans, 0.0 );
|
||||||
|
|
||||||
|
delete eclipseCase;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
/// Helper: Set up fracture active cell info and enable dual porosity
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
static void enableDualPorosity( RigEclipseCaseData* caseData )
|
||||||
|
{
|
||||||
|
size_t cellCount = caseData->mainGrid()->totalCellCount();
|
||||||
|
|
||||||
|
RigActiveCellInfo* fractureActiveCellInfo = caseData->activeCellInfo( RiaDefines::PorosityModelType::FRACTURE_MODEL );
|
||||||
|
fractureActiveCellInfo->setReservoirCellCount( cellCount );
|
||||||
|
for ( size_t i = 0; i < cellCount; i++ )
|
||||||
|
{
|
||||||
|
fractureActiveCellInfo->setCellResultIndex( i, i );
|
||||||
|
}
|
||||||
|
fractureActiveCellInfo->setGridCount( 1 );
|
||||||
|
fractureActiveCellInfo->setGridActiveCellCounts( 0, cellCount );
|
||||||
|
fractureActiveCellInfo->computeDerivedData();
|
||||||
|
|
||||||
|
caseData->mainGrid()->setDualPorosity( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
TEST( RicTransmissibilityCalculator, CalculateCellMainDirection_DualPorosity_UsesFractureProperties )
|
||||||
|
{
|
||||||
|
// Matrix: DX=10, DY=20, DZ=30. Fracture: DX=100, DY=20, DZ=30.
|
||||||
|
// lengthsInCell = (8, 3, 2)
|
||||||
|
// Matrix fracs: x=8/10=0.8, y=3/20=0.15, z=2/30=0.067 → DIR_I
|
||||||
|
// Fracture fracs: x=8/100=0.08, y=3/20=0.15, z=2/30=0.067 → DIR_J
|
||||||
|
RimEclipseCase* eclipseCase = createMockEclipseCase( 10.0, 20.0, 30.0, 100.0, 100.0, 10.0, 1.0 );
|
||||||
|
|
||||||
|
RigEclipseCaseData* caseData = eclipseCase->eclipseCaseData();
|
||||||
|
size_t cellCount = caseData->mainGrid()->totalCellCount();
|
||||||
|
|
||||||
|
enableDualPorosity( caseData );
|
||||||
|
|
||||||
|
// Populate fracture results with different DX
|
||||||
|
RigCaseCellResultsData* fractureResults = caseData->results( RiaDefines::PorosityModelType::FRACTURE_MODEL );
|
||||||
|
addStaticResult( fractureResults, "DX", cellCount, 100.0 );
|
||||||
|
addStaticResult( fractureResults, "DY", cellCount, 20.0 );
|
||||||
|
addStaticResult( fractureResults, "DZ", cellCount, 30.0 );
|
||||||
|
addStaticResult( fractureResults, "PERMX", cellCount, 100.0 );
|
||||||
|
addStaticResult( fractureResults, "PERMY", cellCount, 100.0 );
|
||||||
|
addStaticResult( fractureResults, "PERMZ", cellCount, 10.0 );
|
||||||
|
|
||||||
|
cvf::Vec3d lengthsInCell( 8.0, 3.0, 2.0 );
|
||||||
|
|
||||||
|
auto direction = RicTransmissibilityCalculator::calculateCellMainDirection( eclipseCase, 0, lengthsInCell );
|
||||||
|
|
||||||
|
// With matrix properties this would be DIR_I, but with fracture properties it should be DIR_J
|
||||||
|
EXPECT_EQ( RigCompletionData::CellDirection::DIR_J, direction );
|
||||||
|
|
||||||
|
delete eclipseCase;
|
||||||
|
}
|
||||||
Reference in new issue
Block a user