#6064 Compute stress and stress gradients for fracture model plot.

This commit is contained in:
Kristian Bendiksen
2020-06-16 19:22:43 +02:00
parent e23cee8124
commit f2696b003d
14 changed files with 422 additions and 73 deletions

View File

@@ -108,6 +108,13 @@ RimFractureModel::RimFractureModel()
CAF_PDM_InitField( &m_defaultPorosity, "DefaultPorosity", 0.0, "Default Porosity", "", "", "" );
CAF_PDM_InitField( &m_defaultPermeability, "DefaultPermeability", 10.0e-6, "Default Permeability", "", "", "" );
// Stress unit: bar
// Stress gradient unit: bar/m
// Depth is meter
CAF_PDM_InitField( &m_verticalStress, "VerticalStress", 879.0, "Vertical Stress", "", "", "" );
CAF_PDM_InitField( &m_verticalStressGradient, "VerticalStressGradient", 0.238, "Vertical Stress Gradient", "", "", "" );
CAF_PDM_InitField( &m_stressDepth, "StressDepth", 1000.0, "Stress Depth", "", "", "" );
CAF_PDM_InitFieldNoDefault( &m_elasticProperties, "ElasticProperties", "Elastic Properties", "", "", "" );
m_elasticProperties.uiCapability()->setUiHidden( true );
m_elasticProperties.uiCapability()->setUiTreeHidden( true );
@@ -522,3 +529,27 @@ double RimFractureModel::getDefaultForMissingValue( const QString& keyword ) con
return std::numeric_limits<double>::infinity();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimFractureModel::verticalStress() const
{
return m_verticalStress;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimFractureModel::verticalStressGradient() const
{
return m_verticalStressGradient;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimFractureModel::stressDepth() const
{
return m_stressDepth;
}

View File

@@ -63,6 +63,10 @@ public:
double defaultPorosity() const;
double defaultPermeability() const;
double verticalStress() const;
double verticalStressGradient() const;
double stressDepth() const;
// RimWellPathCompletionsInterface overrides.
RiaDefines::WellPathComponentType componentType() const override;
QString componentLabel() const override;
@@ -105,4 +109,7 @@ protected:
caf::PdmChildField<RimElasticProperties*> m_elasticProperties;
caf::PdmField<double> m_defaultPorosity;
caf::PdmField<double> m_defaultPermeability;
caf::PdmField<double> m_verticalStress;
caf::PdmField<double> m_verticalStressGradient;
caf::PdmField<double> m_stressDepth;
};

View File

@@ -130,6 +130,8 @@ QString RimElasticProperties::generatePropertiesTable()
" <th>Poisson's<br>Ratio</th>"
" <th>K-Ic</th>"
" <th>Proppant<br>Embedment</th>"
" <th>Biot<br>Coefficient</th>"
" <th>k0</th>"
" </tr>"
" </thead>"
" <tbody>" );
@@ -143,6 +145,8 @@ QString RimElasticProperties::generatePropertiesTable()
const std::vector<double>& poissonsRatio = prop.second.poissonsRatio();
const std::vector<double>& K_Ic = prop.second.K_Ic();
const std::vector<double>& proppantEmbedment = prop.second.proppantEmbedment();
const std::vector<double>& biotCoefficient = prop.second.biotCoefficient();
const std::vector<double>& k0 = prop.second.k0();
for ( size_t i = 0; i < porosity.size(); i++ )
{
@@ -155,6 +159,8 @@ QString RimElasticProperties::generatePropertiesTable()
" <td align=right>%6</td>"
" <td align=right>%7</td>"
" <td align=right>%8</td>"
" <td align=right>%9</td>"
" <td align=right>%10</td>"
"</tr>" );
QString line = format.arg( fieldName )
@@ -164,7 +170,9 @@ QString RimElasticProperties::generatePropertiesTable()
.arg( youngsModulus[i] )
.arg( poissonsRatio[i] )
.arg( K_Ic[i] )
.arg( proppantEmbedment[i] );
.arg( proppantEmbedment[i] )
.arg( biotCoefficient[i] )
.arg( k0[i] );
body.append( line );
}

View File

@@ -67,6 +67,8 @@ void AppEnum<RimElasticPropertiesCurve::PropertyType>::setUp()
addItem( RimElasticPropertiesCurve::PropertyType::POISSONS_RATIO, "POISSONS_RATIO", "Poisson's Ratio" );
addItem( RimElasticPropertiesCurve::PropertyType::K_IC, "K_IC", "K-Ic" );
addItem( RimElasticPropertiesCurve::PropertyType::PROPPANT_EMBEDMENT, "PROPPANT_EMBEDMENT", "Proppant Embedment" );
addItem( RimElasticPropertiesCurve::PropertyType::BIOT_COEFFICIENT, "BIOT_COEFFICIENT", "Biot Coefficient" );
addItem( RimElasticPropertiesCurve::PropertyType::K0, "K0", "k0" );
setDefault( RimElasticPropertiesCurve::PropertyType::YOUNGS_MODULUS );
}
}; // namespace caf
@@ -255,6 +257,16 @@ void RimElasticPropertiesCurve::performDataExtraction( bool* isUsingPseudoLength
double val = rigElasticProperties.getProppantEmbedment( porosity );
values.push_back( val );
}
else if ( m_propertyType() == PropertyType::BIOT_COEFFICIENT )
{
double val = rigElasticProperties.getBiotCoefficient( porosity );
values.push_back( val );
}
else if ( m_propertyType() == PropertyType::K0 )
{
double val = rigElasticProperties.getK0( porosity );
values.push_back( val );
}
}
else
{

View File

@@ -45,7 +45,9 @@ public:
YOUNGS_MODULUS,
POISSONS_RATIO,
K_IC,
PROPPANT_EMBEDMENT
PROPPANT_EMBEDMENT,
BIOT_COEFFICIENT,
K0
};
RimElasticPropertiesCurve();

View File

@@ -18,6 +18,8 @@
#include "RimFractureModelPlot.h"
#include "RiaDefines.h"
#include "RiaLogging.h"
#include "RicfCommandObject.h"
#include "RimEclipseCase.h"
@@ -40,6 +42,18 @@ CAF_PDM_SOURCE_INIT( RimFractureModelPlot, "FractureModelPlot" );
RimFractureModelPlot::RimFractureModelPlot()
{
CAF_PDM_InitScriptableObject( "Fracture Model Plot", "", "", "A fracture model plot" );
CAF_PDM_InitFieldNoDefault( &m_fractureModel, "FractureModel", "Fracture Model", "", "", "" );
m_fractureModel.uiCapability()->setUiTreeChildrenHidden( true );
m_fractureModel.uiCapability()->setUiHidden( true );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimFractureModelPlot::setFractureModel( RimFractureModel* fractureModel )
{
m_fractureModel = fractureModel;
}
//--------------------------------------------------------------------------------------------------
@@ -75,6 +89,30 @@ void RimFractureModelPlot::applyDataSource()
this->updateConnectedEditors();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimFractureModelPlot::convertToPsiPerFeetFromBarPerMeter( double value )
{
return value * 4.42075;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimFractureModelPlot::convertToFeetFromMeter( double value )
{
return value * 3.28084;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimFractureModelPlot::convertToPsiFromBar( double value )
{
return value * 14.5038;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -122,11 +160,30 @@ void RimFractureModelPlot::calculateLayers( std::vector<std::pair<double, double
{
layerBoundaryDepths.push_back( std::make_pair( depths[startIndex], depths[i] ) );
layerBoundaryIndexes.push_back( std::make_pair( startIndex, i ) );
startIndex = i + 1;
startIndex = i;
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimFractureModelPlot::computeValueAtDepth( const std::vector<double>& values,
std::vector<std::pair<double, double>>& layerBoundaryDepths,
double depth )
{
for ( size_t i = 0; i < layerBoundaryDepths.size(); i++ )
{
if ( layerBoundaryDepths[i].first <= depth && layerBoundaryDepths[i].second >= depth )
{
return values[i];
}
}
RiaLogging::error( QString( "Failed to compute value at depth: %1" ).arg( depth ) );
return std::numeric_limits<double>::infinity();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -180,11 +237,10 @@ std::vector<double> RimFractureModelPlot::calculateTrueVerticalDepth() const
std::vector<double> tvdTopZone;
for ( auto p : layerBoundaryDepths )
{
std::cout << "Layer boundaries: " << p.first << " - " << p.second << std::endl;
tvdTopZone.push_back( p.first );
double depthInFeet = convertToFeetFromMeter( p.first );
tvdTopZone.push_back( depthInFeet );
}
// TODO: convert to feet!!!!
return tvdTopZone;
}
@@ -196,7 +252,7 @@ std::vector<double> RimFractureModelPlot::findCurveAndComputeLayeredAverage( con
RimWellLogExtractionCurve* curve = findCurveByName( curveName );
if ( !curve )
{
std::cerr << "NO " << curveName.toStdString() << " FOUND!!!" << std::endl;
RiaLogging::error( QString( "No curve named '%1' found" ).arg( curveName ) );
return std::vector<double>();
}
@@ -248,7 +304,139 @@ std::vector<double> RimFractureModelPlot::calculateVerticalPermeability() const
//--------------------------------------------------------------------------------------------------
std::vector<double> RimFractureModelPlot::calculateStress() const
{
return std::vector<double>();
std::vector<double> stress;
std::vector<double> stressGradients;
calculateStressWithGradients( stress, stressGradients );
return stress;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimFractureModelPlot::calculateStressWithGradients( std::vector<double>& stress,
std::vector<double>& stressGradients ) const
{
// Reference stress
const double verticalStressRef = m_fractureModel->verticalStress();
const double verticalStressGradientRef = m_fractureModel->verticalStressGradient();
const double stressDepthRef = m_fractureModel->stressDepth();
std::vector<std::pair<double, double>> layerBoundaryDepths;
std::vector<std::pair<size_t, size_t>> layerBoundaryIndexes;
calculateLayers( layerBoundaryDepths, layerBoundaryIndexes );
// Biot coefficient
RimWellLogExtractionCurve* biotCurve = findCurveByName( "Biot Coefficient" );
if ( !biotCurve )
{
RiaLogging::error( "Biot coefficient data not found." );
return false;
}
std::vector<double> biotData = biotCurve->curveData()->xValues();
// Biot coefficient
RimWellLogExtractionCurve* k0Curve = findCurveByName( "k0" );
if ( !k0Curve )
{
RiaLogging::error( "k0 data not found." );
return false;
}
std::vector<double> k0Data = k0Curve->curveData()->xValues();
// Pressure at the give time step
RimWellLogExtractionCurve* timeStepPressureCurve = findCurveByName( "PRESSURE" );
if ( !timeStepPressureCurve )
{
RiaLogging::error( "Pressure data for time step not found." );
return false;
}
std::vector<double> timeStepPressureData = timeStepPressureCurve->curveData()->xValues();
// Initial pressure
RimWellLogExtractionCurve* initialPressureCurve = findCurveByName( "INITIAL PRESSURE" );
if ( !initialPressureCurve )
{
RiaLogging::error( "Initial pressure data not found." );
return false;
}
std::vector<double> initialPressureData = initialPressureCurve->curveData()->xValues();
// Poissons ratio
RimWellLogExtractionCurve* poissonsRatioCurve = findCurveByName( "Poisson's Ratio" );
if ( !poissonsRatioCurve )
{
RiaLogging::error( "Poisson's ratio data not found." );
return false;
}
std::vector<double> poissonsRatioData = poissonsRatioCurve->curveData()->xValues();
std::vector<double> stressForGradients;
std::vector<double> pressureForGradients;
std::vector<double> depthForGradients;
// Calculate the stress
for ( size_t i = 0; i < layerBoundaryDepths.size(); i++ )
{
double depthTopOfZone = layerBoundaryDepths[i].first;
double depthBottomOfZone = layerBoundaryDepths[i].second;
// Data from curves at the top zone depth
double k0 = computeValueAtDepth( k0Data, layerBoundaryDepths, depthTopOfZone );
double biot = computeValueAtDepth( biotData, layerBoundaryDepths, depthTopOfZone );
double poissonsRatio = computeValueAtDepth( poissonsRatioData, layerBoundaryDepths, depthTopOfZone );
double initialPressure = computeValueAtDepth( initialPressureData, layerBoundaryDepths, depthTopOfZone );
double timeStepPressure = computeValueAtDepth( timeStepPressureData, layerBoundaryDepths, depthTopOfZone );
// Vertical stress
// Use difference between reference depth and depth of top of zone
double depthDiff = depthTopOfZone - stressDepthRef;
double Sv = verticalStressRef + verticalStressGradientRef * depthDiff;
double Sh_init = k0 * Sv + initialPressure * ( 1.0 - k0 );
double pressureDiff = timeStepPressure - initialPressure;
// Vertical stress diff assumed to be zero
double Sv_diff = 0.0;
double deltaHorizontalStress = poissonsRatio / ( 1.0 - poissonsRatio ) * ( Sv_diff - biot * pressureDiff ) +
( biot * pressureDiff );
double depletionStress = Sh_init + deltaHorizontalStress;
stress.push_back( convertToPsiFromBar( depletionStress ) );
// Cache some results for the gradients calculation
stressForGradients.push_back( Sv );
pressureForGradients.push_back( initialPressure );
depthForGradients.push_back( depthTopOfZone );
if ( i == layerBoundaryDepths.size() - 1 )
{
// Use the bottom of the last layer to compute gradient for last layer
double bottomInitialPressure =
computeValueAtDepth( initialPressureData, layerBoundaryDepths, depthBottomOfZone );
double bottomDepthDiff = depthBottomOfZone - stressDepthRef;
double bottomSv = verticalStressRef + verticalStressGradientRef * bottomDepthDiff;
stressForGradients.push_back( bottomSv );
pressureForGradients.push_back( bottomInitialPressure );
depthForGradients.push_back( depthBottomOfZone );
}
}
assert( stressForGradients.size() == layerBoundaryDepths.size() + 1 );
assert( pressureForGradients.size() == layerBoundaryDepths.size() + 1 );
assert( depthForGradients.size() == layerBoundaryDepths.size() + 1 );
// Second pass to calculate the stress gradients
for ( size_t i = 0; i < layerBoundaryDepths.size(); i++ )
{
double diffStress = stressForGradients[i + 1] - stressForGradients[i];
double diffPressure = pressureForGradients[i + 1] - pressureForGradients[i];
double diffDepth = depthForGradients[i + 1] - depthForGradients[i];
double k0 = computeValueAtDepth( k0Data, layerBoundaryDepths, depthForGradients[i] );
double gradient = ( diffStress * k0 + diffPressure * ( 1.0 - k0 ) ) / diffDepth;
stressGradients.push_back( convertToPsiPerFeetFromBarPerMeter( gradient ) );
}
return true;
}
//--------------------------------------------------------------------------------------------------
@@ -256,7 +444,10 @@ std::vector<double> RimFractureModelPlot::calculateStress() const
//--------------------------------------------------------------------------------------------------
std::vector<double> RimFractureModelPlot::calculateStressGradient() const
{
return std::vector<double>();
std::vector<double> stress;
std::vector<double> stressGradients;
calculateStressWithGradients( stress, stressGradients );
return stressGradients;
}
//--------------------------------------------------------------------------------------------------

View File

@@ -25,6 +25,7 @@
#include <vector>
class RimWellLogExtractionCurve;
class RimFractureModel;
class RimFractureModelPlot : public RimDepthTrackPlot
{
@@ -33,6 +34,8 @@ class RimFractureModelPlot : public RimDepthTrackPlot
public:
RimFractureModelPlot();
void setFractureModel( RimFractureModel* fractureModel );
void getPorosityValues( std::vector<double>& values ) const;
std::vector<double> calculateTrueVerticalDepth() const;
@@ -54,9 +57,17 @@ protected:
void calculateLayers( std::vector<std::pair<double, double>>& layerBoundaryDepths,
std::vector<std::pair<size_t, size_t>>& layerBoundaryIndexes ) const;
RimWellLogExtractionCurve* findCurveByName( const QString& curveName ) const;
static void computeAverageByLayer( const std::vector<std::pair<size_t, size_t>>& layerBoundaryIndexes,
const std::vector<double>& inputVector,
std::vector<double>& result );
bool calculateStressWithGradients( std::vector<double>& stress, std::vector<double>& stressGradients ) const;
static double computeValueAtDepth( const std::vector<double>& values,
std::vector<std::pair<double, double>>& layerBoundaryDepths,
double depth );
static void computeAverageByLayer( const std::vector<std::pair<size_t, size_t>>& layerBoundaryIndexes,
const std::vector<double>& inputVector,
std::vector<double>& result );
static double convertToPsiPerFeetFromBarPerMeter( double value );
static double convertToFeetFromMeter( double value );
static double convertToPsiFromBar( double value );
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
@@ -64,4 +75,6 @@ protected:
private:
void applyDataSource();
caf::PdmPtrField<RimFractureModel*> m_fractureModel;
};