Thermal Fracture: add relative and absolute filter-cake pressure drop calculation.

This commit is contained in:
Kristian Bendiksen 2022-09-26 18:31:46 +02:00
parent da2b183d0e
commit 8ed349f859
9 changed files with 258 additions and 46 deletions

View File

@ -774,3 +774,11 @@ void RimThermalFractureTemplate::defineUiOrdering( QString uiConfigName, caf::Pd
uiOrdering.add( &m_filterCakePressureDropType );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimThermalFractureTemplate::FilterCakePressureDrop RimThermalFractureTemplate::filterCakePressureDropType() const
{
return m_filterCakePressureDropType.value();
}

View File

@ -111,6 +111,8 @@ public:
const RigThermalFractureDefinition* fractureDefinition() const;
FilterCakePressureDrop filterCakePressureDropType() const;
protected:
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;

View File

@ -2,6 +2,7 @@ set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RigCompletionData.h
${CMAKE_CURRENT_LIST_DIR}/RigCompletionDataGridCell.h
${CMAKE_CURRENT_LIST_DIR}/RigEclipseToStimPlanCellTransmissibilityCalculator.h
${CMAKE_CURRENT_LIST_DIR}/RigEclipseToThermalCellTransmissibilityCalculator.h
${CMAKE_CURRENT_LIST_DIR}/RigTransmissibilityCondenser.h
${CMAKE_CURRENT_LIST_DIR}/RigFractureTransmissibilityEquations.h
${CMAKE_CURRENT_LIST_DIR}/RigWellPathStimplanIntersector.h
@ -14,6 +15,7 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RigCompletionData.cpp
${CMAKE_CURRENT_LIST_DIR}/RigCompletionDataGridCell.cpp
${CMAKE_CURRENT_LIST_DIR}/RigEclipseToStimPlanCellTransmissibilityCalculator.cpp
${CMAKE_CURRENT_LIST_DIR}/RigEclipseToThermalCellTransmissibilityCalculator.cpp
${CMAKE_CURRENT_LIST_DIR}/RigTransmissibilityCondenser.cpp
${CMAKE_CURRENT_LIST_DIR}/RigFractureTransmissibilityEquations.cpp
${CMAKE_CURRENT_LIST_DIR}/RigWellPathStimplanIntersector.cpp

View File

@ -19,11 +19,14 @@
#include "RigEclipseToStimPlanCalculator.h"
#include "RiaLogging.h"
#include "RiaWeightedMeanCalculator.h"
#include "RigActiveCellInfo.h"
#include "RigCaseCellResultsData.h"
#include "RigCellGeometryTools.h"
#include "RigEclipseCaseData.h"
#include "RigEclipseToStimPlanCellTransmissibilityCalculator.h"
#include "RigEclipseToThermalCellTransmissibilityCalculator.h"
#include "RigFractureCell.h"
#include "RigFractureGrid.h"
#include "RigFractureTransmissibilityEquations.h"
@ -32,12 +35,12 @@
#include "RigResultAccessorFactory.h"
#include "RigTransmissibilityCondenser.h"
#include "RiaWeightedMeanCalculator.h"
#include "RimEclipseCase.h"
#include "RimEllipseFractureTemplate.h"
#include "RimFracture.h"
#include "RimFractureContainmentTools.h"
#include "RimMeshFractureTemplate.h"
#include "RimThermalFractureTemplate.h"
//--------------------------------------------------------------------------------------------------
///
@ -71,20 +74,68 @@ void RigEclipseToStimPlanCalculator::computeValues()
const RigFractureCell& fractureCell = m_fractureGrid.fractureCells()[i];
if ( !fractureCell.hasNonZeroConductivity() ) continue;
RigEclipseToStimPlanCellTransmissibilityCalculator eclToFractureTransCalc( m_case,
m_fractureTransform,
m_fractureSkinFactor,
m_cDarcy,
fractureCell,
reservoirCellIndicesOpenForFlow,
m_fracture );
std::unique_ptr<RigEclipseToStimPlanCellTransmissibilityCalculator> eclToFractureTransCalc;
if ( dynamic_cast<RimThermalFractureTemplate*>( m_fracture->fractureTemplate() ) != nullptr )
{
RimThermalFractureTemplate* thermalFractureTemplate =
dynamic_cast<RimThermalFractureTemplate*>( m_fracture->fractureTemplate() );
size_t timeStep = thermalFractureTemplate->activeTimeStepIndex();
int cellI = fractureCell.getI();
int cellJ = fractureCell.getJ();
double injectivityDecline = thermalFractureTemplate->resultValueAtIJ( &m_fractureGrid,
"InjectivityDecline",
"factor",
timeStep,
cellI,
cellJ );
double viscosity =
thermalFractureTemplate->resultValueAtIJ( &m_fractureGrid, "Viscosity", "mPa.s", timeStep, cellI, cellJ );
double filterCakeMobility = thermalFractureTemplate->resultValueAtIJ( &m_fractureGrid,
"FilterCakeMobility",
"m/day/bar",
timeStep,
cellI,
cellJ );
// Assumed value
double relativePermeability = 1.0;
auto filterPressureDropType = thermalFractureTemplate->filterCakePressureDropType();
eclToFractureTransCalc =
std::make_unique<RigEclipseToThermalCellTransmissibilityCalculator>( m_case,
m_fractureTransform,
m_fractureSkinFactor,
m_cDarcy,
fractureCell,
m_fracture,
filterPressureDropType,
injectivityDecline,
filterCakeMobility,
viscosity,
relativePermeability );
}
else
{
eclToFractureTransCalc =
std::make_unique<RigEclipseToStimPlanCellTransmissibilityCalculator>( m_case,
m_fractureTransform,
m_fractureSkinFactor,
m_cDarcy,
fractureCell,
m_fracture );
}
eclToFractureTransCalc->computeValues( reservoirCellIndicesOpenForFlow );
const std::vector<size_t>& fractureCellContributingEclipseCells =
eclToFractureTransCalc.globalIndiciesToContributingEclipseCells();
eclToFractureTransCalc->globalIndiciesToContributingEclipseCells();
if ( !fractureCellContributingEclipseCells.empty() )
{
m_singleFractureCellCalculators.emplace( i, eclToFractureTransCalc );
m_singleFractureCellCalculators.emplace( i, std::move( eclToFractureTransCalc ) );
}
}
}
@ -100,10 +151,10 @@ void RigEclipseToStimPlanCalculator::appendDataToTransmissibilityCondenser( bool
for ( const auto& eclToFractureTransCalc : m_singleFractureCellCalculators )
{
const std::vector<size_t>& fractureCellContributingEclipseCells =
eclToFractureTransCalc.second.globalIndiciesToContributingEclipseCells();
eclToFractureTransCalc.second->globalIndiciesToContributingEclipseCells();
const std::vector<double>& fractureCellContributingEclipseCellTransmissibilities =
eclToFractureTransCalc.second.contributingEclipseCellTransmissibilities();
eclToFractureTransCalc.second->contributingEclipseCellTransmissibilities();
size_t stimPlanCellIndex = eclToFractureTransCalc.first;
@ -138,7 +189,7 @@ double RigEclipseToStimPlanCalculator::totalEclipseAreaOpenForFlow() const
for ( const auto& singleCellCalc : m_singleFractureCellCalculators )
{
double cellArea = singleCellCalc.second.areaOpenForFlow();
double cellArea = singleCellCalc.second->areaOpenForFlow();
area += cellArea;
}
@ -153,20 +204,16 @@ double RigEclipseToStimPlanCalculator::areaWeightedMatrixPermeability() const
{
RiaWeightedMeanCalculator<double> calc;
for ( const auto& singleCellCalc : m_singleFractureCellCalculators )
{
for ( const auto& singleCellCalc : m_singleFractureCellCalculators )
const std::vector<double>& areas = singleCellCalc.second->contributingEclipseCellIntersectionAreas();
const std::vector<double>& permeabilities = singleCellCalc.second->contributingEclipseCellPermeabilities();
if ( areas.size() == permeabilities.size() )
{
const RigEclipseToStimPlanCellTransmissibilityCalculator& calulator = singleCellCalc.second;
const std::vector<double>& areas = calulator.contributingEclipseCellIntersectionAreas();
const std::vector<double>& permeabilities = calulator.contributingEclipseCellPermeabilities();
if ( areas.size() == permeabilities.size() )
for ( size_t i = 0; i < areas.size(); i++ )
{
for ( size_t i = 0; i < areas.size(); i++ )
{
calc.addValueAndWeight( permeabilities[i], areas[i] );
}
calc.addValueAndWeight( permeabilities[i], areas[i] );
}
}
}
@ -197,7 +244,7 @@ double RigEclipseToStimPlanCalculator::areaWeightedWidth() const
for ( const auto& singleCellCalc : m_singleFractureCellCalculators )
{
double cellArea = singleCellCalc.second.areaOpenForFlow();
double cellArea = singleCellCalc.second->areaOpenForFlow();
size_t globalStimPlanCellIndex = singleCellCalc.first;
double widthValue = widthValues[globalStimPlanCellIndex];
@ -228,9 +275,9 @@ double RigEclipseToStimPlanCalculator::areaWeightedConductivity() const
for ( const auto& singleCellCalc : m_singleFractureCellCalculators )
{
double cellArea = singleCellCalc.second.areaOpenForFlow();
double cellArea = singleCellCalc.second->areaOpenForFlow();
double conductivity = singleCellCalc.second.fractureCell().getConductivityValue();
double conductivity = singleCellCalc.second->fractureCell().getConductivityValue();
if ( !std::isinf( conductivity ) && !std::isnan( conductivity ) )
{
calc.addValueAndWeight( conductivity, cellArea );
@ -260,7 +307,7 @@ double RigEclipseToStimPlanCalculator::longestYSectionOpenForFlow() const
auto calculatorForCell = m_singleFractureCellCalculators.find( globalStimPlanCellIndex );
if ( calculatorForCell != m_singleFractureCellCalculators.end() )
{
currentAggregatedDistanceY += calculatorForCell->second.fractureCell().cellSizeZ();
currentAggregatedDistanceY += calculatorForCell->second->fractureCell().cellSizeZ();
}
else
{

View File

@ -25,6 +25,7 @@
#include "cvfMatrix4.h"
#include <map>
#include <memory>
class QString;
@ -69,5 +70,5 @@ private:
cvf::Mat4d m_fractureTransform;
const RigFractureGrid& m_fractureGrid;
std::map<size_t, RigEclipseToStimPlanCellTransmissibilityCalculator> m_singleFractureCellCalculators;
std::map<size_t, std::unique_ptr<RigEclipseToStimPlanCellTransmissibilityCalculator>> m_singleFractureCellCalculators;
};

View File

@ -39,19 +39,22 @@
///
//--------------------------------------------------------------------------------------------------
RigEclipseToStimPlanCellTransmissibilityCalculator::RigEclipseToStimPlanCellTransmissibilityCalculator(
const RimEclipseCase* caseToApply,
cvf::Mat4d fractureTransform,
double skinFactor,
double cDarcy,
const RigFractureCell& stimPlanCell,
const std::set<size_t>& reservoirCellIndicesOpenForFlow,
const RimFracture* fracture )
const RimEclipseCase* caseToApply,
cvf::Mat4d fractureTransform,
double skinFactor,
double cDarcy,
const RigFractureCell& stimPlanCell,
const RimFracture* fracture )
: m_case( caseToApply )
, m_fractureTransform( fractureTransform )
, m_fractureSkinFactor( skinFactor )
, m_cDarcy( cDarcy )
, m_stimPlanCell( stimPlanCell )
, m_fracture( fracture )
{
}
void RigEclipseToStimPlanCellTransmissibilityCalculator::computeValues( const std::set<size_t>& reservoirCellIndicesOpenForFlow )
{
calculateStimPlanCellsMatrixTransmissibility( reservoirCellIndicesOpenForFlow );
}
@ -328,8 +331,8 @@ void RigEclipseToStimPlanCellTransmissibilityCalculator::calculateStimPlanCellsM
fractureAreaWeightedlength,
m_cDarcy );
transmissibility = sqrt( transmissibility_X * transmissibility_X + transmissibility_Y * transmissibility_Y +
transmissibility_Z * transmissibility_Z );
cvf::Vec3d transmissibilityVector( transmissibility_X, transmissibility_Y, transmissibility_Z );
transmissibility = calculateTransmissibility( transmissibilityVector, fractureArea );
matrixPermeability = RigFractureTransmissibilityEquations::matrixPermeability( permX, permY, NTG );
}
@ -390,3 +393,12 @@ cvf::ref<RigResultAccessor>
0,
RigEclipseResultAddress( uiResultName ) );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RigEclipseToStimPlanCellTransmissibilityCalculator::calculateTransmissibility( const cvf::Vec3d& transmissibilityVector,
double fractureArea )
{
return transmissibilityVector.length();
}

View File

@ -42,13 +42,13 @@ class RimFracture;
class RigEclipseToStimPlanCellTransmissibilityCalculator
{
public:
explicit RigEclipseToStimPlanCellTransmissibilityCalculator( const RimEclipseCase* caseToApply,
cvf::Mat4d fractureTransform,
double skinFactor,
double cDarcy,
const RigFractureCell& stimPlanCell,
const std::set<size_t>& reservoirCellIndicesOpenForFlow,
const RimFracture* fracture );
explicit RigEclipseToStimPlanCellTransmissibilityCalculator( const RimEclipseCase* caseToApply,
cvf::Mat4d fractureTransform,
double skinFactor,
double cDarcy,
const RigFractureCell& stimPlanCell,
const RimFracture* fracture );
void computeValues( const std::set<size_t>& reservoirCellIndicesOpenForFlow );
// These three vectors have the same size
const std::vector<size_t>& globalIndiciesToContributingEclipseCells() const;
@ -65,12 +65,14 @@ public:
private:
void calculateStimPlanCellsMatrixTransmissibility( const std::set<size_t>& reservoirCellIndicesOpenForFlow );
virtual double calculateTransmissibility( const cvf::Vec3d& transmissibilityVector, double fractureArea );
std::vector<size_t> getPotentiallyFracturedCellsForPolygon( const std::vector<cvf::Vec3d>& polygon ) const;
static cvf::ref<RigResultAccessor> createResultAccessor( const RimEclipseCase* eclipseCase,
const QString& uiResultName );
private:
protected:
const RimEclipseCase* m_case;
const RimFracture* m_fracture;

View File

@ -0,0 +1,70 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2022 Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RigEclipseToThermalCellTransmissibilityCalculator.h"
#include "RimEclipseCase.h"
#include "RimFracture.h"
#include "RimThermalFractureTemplate.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RigEclipseToThermalCellTransmissibilityCalculator::RigEclipseToThermalCellTransmissibilityCalculator(
const RimEclipseCase* caseToApply,
cvf::Mat4d fractureTransform,
double skinFactor,
double cDarcy,
const RigFractureCell& stimPlanCell,
const RimFracture* fracture,
RimThermalFractureTemplate::FilterCakePressureDrop filterCakePressureDrop,
double injectivityDecline,
double filterCakeMobility,
double viscosity,
double relativePermeability )
: RigEclipseToStimPlanCellTransmissibilityCalculator( caseToApply, fractureTransform, skinFactor, cDarcy, stimPlanCell, fracture )
, m_filterCakePressureDrop( filterCakePressureDrop )
, m_injectivityDecline( injectivityDecline )
, m_filterCakeMobility( filterCakeMobility )
, m_viscosity( viscosity )
, m_relativePermeability( relativePermeability )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RigEclipseToThermalCellTransmissibilityCalculator::calculateTransmissibility( const cvf::Vec3d& transmissibilityVector,
double fractureArea )
{
double fractureMatrixTransimissibility = transmissibilityVector.length();
if ( m_filterCakePressureDrop == RimThermalFractureTemplate::FilterCakePressureDrop::RELATIVE )
{
return m_injectivityDecline * fractureMatrixTransimissibility;
}
else
{
CAF_ASSERT( m_filterCakePressureDrop == RimThermalFractureTemplate::FilterCakePressureDrop::ABSOLUTE );
double filterCakeTransmissibility = ( m_viscosity / m_relativePermeability ) * fractureArea * m_filterCakeMobility;
// Harmonic mean
return ( fractureMatrixTransimissibility * filterCakeTransmissibility ) /
( fractureMatrixTransimissibility + filterCakeTransmissibility );
}
}

View File

@ -0,0 +1,68 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2022 Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RigEclipseToStimPlanCellTransmissibilityCalculator.h"
#include "cvfMatrix4.h"
#include "cvfObject.h"
#include "RimThermalFractureTemplate.h"
#include <vector>
class QString;
class RimEclipseCase;
class RigFractureCell;
class RigResultAccessor;
class RimFracture;
//==================================================================================================
///
/// Calculator used to compute the intersection areas between one Thermal RigFractureCell and Eclipse cells
/// Both active and inactive Eclipse cells are included. The transmissibility value for inactive cells are set to zero.
/// Eclipse reservoir cells open for flow is defined by reservoirCellIndicesOpenForFlow
///
//==================================================================================================
class RigEclipseToThermalCellTransmissibilityCalculator : public RigEclipseToStimPlanCellTransmissibilityCalculator
{
public:
explicit RigEclipseToThermalCellTransmissibilityCalculator(
const RimEclipseCase* caseToApply,
cvf::Mat4d fractureTransform,
double skinFactor,
double cDarcy,
const RigFractureCell& stimPlanCell,
const RimFracture* fracture,
RimThermalFractureTemplate::FilterCakePressureDrop filterCakePressureDrop,
double injectvityDecline,
double filterCakeMobility,
double viscosity,
double relativePermeability );
protected:
double calculateTransmissibility( const cvf::Vec3d& transmissibilityVector, double fractureArea ) override;
RimThermalFractureTemplate::FilterCakePressureDrop m_filterCakePressureDrop;
double m_injectivityDecline;
double m_filterCakeMobility;
double m_viscosity;
double m_relativePermeability;
};