Thermal Fracture: Add visualization of results

This commit is contained in:
Kristian Bendiksen
2022-06-27 14:10:28 +02:00
parent cb0bc1392d
commit 625b927cb6
9 changed files with 409 additions and 43 deletions

View File

@@ -34,10 +34,10 @@
#include "RimFractureContainment.h" #include "RimFractureContainment.h"
#include "RimFractureContainmentTools.h" #include "RimFractureContainmentTools.h"
#include "RimFractureTemplate.h" #include "RimFractureTemplate.h"
#include "RimMeshFractureTemplate.h"
#include "RimRegularLegendConfig.h" #include "RimRegularLegendConfig.h"
#include "RimSimWellInView.h" #include "RimSimWellInView.h"
#include "RimStimPlanColors.h" #include "RimStimPlanColors.h"
#include "RimStimPlanFractureTemplate.h"
#include "RimWellPath.h" #include "RimWellPath.h"
#include "RimWellPathCollection.h" #include "RimWellPathCollection.h"
@@ -93,9 +93,9 @@ void RivWellFracturePartMgr::appendGeometryPartsToModel( cvf::ModelBasicList* mo
double characteristicCellSize = eclView.ownerCase()->characteristicCellSize(); double characteristicCellSize = eclView.ownerCase()->characteristicCellSize();
cvf::Collection<cvf::Part> parts; cvf::Collection<cvf::Part> parts;
RimStimPlanFractureTemplate* stimPlanFracTemplate = RimMeshFractureTemplate* stimPlanFracTemplate =
dynamic_cast<RimStimPlanFractureTemplate*>( m_rimFracture->fractureTemplate() ); dynamic_cast<RimMeshFractureTemplate*>( m_rimFracture->fractureTemplate() );
if ( stimPlanFracTemplate ) if ( stimPlanFracTemplate )
{ {
@@ -228,7 +228,7 @@ const QString RivWellFracturePartMgr::resultInfoText( const RimEclipseView& acti
if ( m_rimFracture.isNull() ) return text; if ( m_rimFracture.isNull() ) return text;
auto* ellipseFractureTemplate = dynamic_cast<RimEllipseFractureTemplate*>( m_rimFracture->fractureTemplate() ); auto* ellipseFractureTemplate = dynamic_cast<RimEllipseFractureTemplate*>( m_rimFracture->fractureTemplate() );
auto* stimPlanTemplate = dynamic_cast<RimStimPlanFractureTemplate*>( m_rimFracture->fractureTemplate() ); auto* stimPlanTemplate = dynamic_cast<RimMeshFractureTemplate*>( m_rimFracture->fractureTemplate() );
if ( ellipseFractureTemplate ) if ( ellipseFractureTemplate )
{ {
@@ -285,7 +285,7 @@ const RigFractureCell* RivWellFracturePartMgr::getFractureCellAtDomainCoord( cvf
cvf::Mat4d toFractureXf = m_rimFracture->transformMatrix().getInverted(); cvf::Mat4d toFractureXf = m_rimFracture->transformMatrix().getInverted();
cvf::Vec3d fractureCoord = domainCoord.getTransformedPoint( toFractureXf ); cvf::Vec3d fractureCoord = domainCoord.getTransformedPoint( toFractureXf );
auto* stimPlanTempl = dynamic_cast<RimStimPlanFractureTemplate*>( m_rimFracture->fractureTemplate() ); auto* stimPlanTempl = dynamic_cast<RimMeshFractureTemplate*>( m_rimFracture->fractureTemplate() );
if ( !stimPlanTempl ) return nullptr; if ( !stimPlanTempl ) return nullptr;
const RigFractureGrid* grid = m_rimFracture->fractureGrid(); const RigFractureGrid* grid = m_rimFracture->fractureGrid();
@@ -403,8 +403,8 @@ cvf::ref<cvf::Part> RivWellFracturePartMgr::createEllipseSurfacePart( const RimE
cvf::ref<cvf::Part> RivWellFracturePartMgr::createStimPlanColorInterpolatedSurfacePart( const RimEclipseView& activeView ) cvf::ref<cvf::Part> RivWellFracturePartMgr::createStimPlanColorInterpolatedSurfacePart( const RimEclipseView& activeView )
{ {
CVF_ASSERT( m_rimFracture ); CVF_ASSERT( m_rimFracture );
RimStimPlanFractureTemplate* stimPlanFracTemplate = RimMeshFractureTemplate* stimPlanFracTemplate =
dynamic_cast<RimStimPlanFractureTemplate*>( m_rimFracture->fractureTemplate() ); dynamic_cast<RimMeshFractureTemplate*>( m_rimFracture->fractureTemplate() );
CVF_ASSERT( stimPlanFracTemplate ); CVF_ASSERT( stimPlanFracTemplate );
auto displayCoordTransform = activeView.displayCoordTransform(); auto displayCoordTransform = activeView.displayCoordTransform();
@@ -542,8 +542,8 @@ cvf::ref<cvf::Part> RivWellFracturePartMgr::createSingleColorSurfacePart( const
cvf::ref<cvf::Part> RivWellFracturePartMgr::createStimPlanElementColorSurfacePart( const RimEclipseView& activeView ) cvf::ref<cvf::Part> RivWellFracturePartMgr::createStimPlanElementColorSurfacePart( const RimEclipseView& activeView )
{ {
CVF_ASSERT( m_rimFracture ); CVF_ASSERT( m_rimFracture );
RimStimPlanFractureTemplate* stimPlanFracTemplate = RimMeshFractureTemplate* stimPlanFracTemplate =
dynamic_cast<RimStimPlanFractureTemplate*>( m_rimFracture->fractureTemplate() ); dynamic_cast<RimMeshFractureTemplate*>( m_rimFracture->fractureTemplate() );
CVF_ASSERT( stimPlanFracTemplate ); CVF_ASSERT( stimPlanFracTemplate );
if ( !m_rimFracture->fractureGrid() ) return nullptr; if ( !m_rimFracture->fractureGrid() ) return nullptr;
@@ -1002,8 +1002,8 @@ cvf::ref<cvf::Part> RivWellFracturePartMgr::createStimPlanMeshPart( const RimEcl
{ {
if ( !m_rimFracture->fractureTemplate() ) return nullptr; if ( !m_rimFracture->fractureTemplate() ) return nullptr;
RimStimPlanFractureTemplate* stimPlanFracTemplate = RimMeshFractureTemplate* stimPlanFracTemplate =
dynamic_cast<RimStimPlanFractureTemplate*>( m_rimFracture->fractureTemplate() ); dynamic_cast<RimMeshFractureTemplate*>( m_rimFracture->fractureTemplate() );
if ( !stimPlanFracTemplate ) return nullptr; if ( !stimPlanFracTemplate ) return nullptr;
cvf::ref<cvf::DrawableGeo> stimPlanMeshGeo = createStimPlanMeshDrawable( stimPlanFracTemplate, activeView ); cvf::ref<cvf::DrawableGeo> stimPlanMeshGeo = createStimPlanMeshDrawable( stimPlanFracTemplate, activeView );
@@ -1030,8 +1030,8 @@ cvf::ref<cvf::Part> RivWellFracturePartMgr::createStimPlanMeshPart( const RimEcl
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
void RivWellFracturePartMgr::createVisibleFracturePolygons( RimStimPlanFractureTemplate* stimPlanFracTemplate, void RivWellFracturePartMgr::createVisibleFracturePolygons( RimMeshFractureTemplate* stimPlanFracTemplate,
const RimEclipseView& activeView ) const RimEclipseView& activeView )
{ {
if ( !m_rimFracture->fractureGrid() ) return; if ( !m_rimFracture->fractureGrid() ) return;
@@ -1060,9 +1060,8 @@ void RivWellFracturePartMgr::createVisibleFracturePolygons( RimStimPlanFractureT
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
cvf::ref<cvf::DrawableGeo> cvf::ref<cvf::DrawableGeo> RivWellFracturePartMgr::createStimPlanMeshDrawable( RimMeshFractureTemplate* stimPlanFracTemplate,
RivWellFracturePartMgr::createStimPlanMeshDrawable( RimStimPlanFractureTemplate* stimPlanFracTemplate, const RimEclipseView& activeView )
const RimEclipseView& activeView )
{ {
if ( !m_rimFracture->fractureGrid() ) return nullptr; if ( !m_rimFracture->fractureGrid() ) return nullptr;

View File

@@ -44,7 +44,7 @@ class DisplayCoordTransform;
class RimFracture; class RimFracture;
class RimFractureTemplate; class RimFractureTemplate;
class RimStimPlanFractureTemplate; class RimMeshFractureTemplate;
class RimEclipseView; class RimEclipseView;
class RigFractureCell; class RigFractureCell;
@@ -79,11 +79,10 @@ private:
void appendFracturePerforationLengthParts( const RimEclipseView& activeView, cvf::ModelBasicList* model ); void appendFracturePerforationLengthParts( const RimEclipseView& activeView, cvf::ModelBasicList* model );
cvf::ref<cvf::Part> createStimPlanMeshPart( const RimEclipseView& activeView ); cvf::ref<cvf::Part> createStimPlanMeshPart( const RimEclipseView& activeView );
cvf::ref<cvf::DrawableGeo> createStimPlanMeshDrawable( RimStimPlanFractureTemplate* stimPlanFracTemplate, cvf::ref<cvf::DrawableGeo> createStimPlanMeshDrawable( RimMeshFractureTemplate* stimPlanFracTemplate,
const RimEclipseView& activeView ); const RimEclipseView& activeView );
void createVisibleFracturePolygons( RimStimPlanFractureTemplate* stimPlanFracTemplate, void createVisibleFracturePolygons( RimMeshFractureTemplate* stimPlanFracTemplate, const RimEclipseView& activeView );
const RimEclipseView& activeView );
std::vector<cvf::Vec3d> fractureBorderPolygon(); std::vector<cvf::Vec3d> fractureBorderPolygon();

View File

@@ -658,12 +658,11 @@ QList<caf::PdmOptionItemInfo> RimFracture::calculateValueOptions( const caf::Pdm
if ( fractureTemplate() ) if ( fractureTemplate() )
{ {
RimFractureTemplate* fracTemplate = fractureTemplate(); RimFractureTemplate* fracTemplate = fractureTemplate();
if ( dynamic_cast<RimStimPlanFractureTemplate*>( fracTemplate ) ) if ( dynamic_cast<RimMeshFractureTemplate*>( fracTemplate ) )
{ {
RimStimPlanFractureTemplate* fracTemplateStimPlan = RimMeshFractureTemplate* fracTemplateStimPlan = dynamic_cast<RimMeshFractureTemplate*>( fracTemplate );
dynamic_cast<RimStimPlanFractureTemplate*>( fracTemplate ); std::vector<double> timeValues = fracTemplateStimPlan->timeSteps();
std::vector<double> timeValues = fracTemplateStimPlan->timeSteps(); int index = 0;
int index = 0;
for ( double value : timeValues ) for ( double value : timeValues )
{ {
options.push_back( caf::PdmOptionItemInfo( QString::number( value ), index ) ); options.push_back( caf::PdmOptionItemInfo( QString::number( value ), index ) );
@@ -750,7 +749,7 @@ void RimFracture::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& ui
} }
RimFractureTemplate* fracTemplate = fractureTemplate(); RimFractureTemplate* fracTemplate = fractureTemplate();
if ( dynamic_cast<RimStimPlanFractureTemplate*>( fracTemplate ) ) if ( dynamic_cast<RimMeshFractureTemplate*>( fracTemplate ) )
{ {
m_stimPlanTimeIndexToPlot.uiCapability()->setUiHidden( false ); m_stimPlanTimeIndexToPlot.uiCapability()->setUiHidden( false );

View File

@@ -163,6 +163,8 @@ void RimThermalFractureTemplate::loadDataAndUpdate()
// { // {
// setUnitSystem( m_fractureDefinitionData->unitSet() ); // setUnitSystem( m_fractureDefinitionData->unitSet() );
// } // }
// TODO: handle other units
setUnitSystem( RiaDefines::EclipseUnitSystem::UNITS_METRIC );
if ( !m_userDefinedWellPathDepthAtFracture ) if ( !m_userDefinedWellPathDepthAtFracture )
{ {
@@ -200,6 +202,8 @@ void RimThermalFractureTemplate::loadDataAndUpdate()
QStringList RimThermalFractureTemplate::conductivityResultNames() const QStringList RimThermalFractureTemplate::conductivityResultNames() const
{ {
QStringList resultNames; QStringList resultNames;
if ( !m_fractureDefinitionData ) return resultNames;
for ( auto [name, unit] : m_fractureDefinitionData->getPropertyNamesUnits() ) for ( auto [name, unit] : m_fractureDefinitionData->getPropertyNamesUnits() )
{ {
resultNames.append( name ); resultNames.append( name );
@@ -616,10 +620,12 @@ void RimThermalFractureTemplate::appendDataToResultStatistics( const QString&
{ {
if ( m_fractureDefinitionData ) if ( m_fractureDefinitionData )
{ {
// QString fileResultName = mapUiResultNameToFileResultName( uiResultName ); QString fileResultName = mapUiResultNameToFileResultName( uiResultName );
RigThermalFractureResultUtil::appendDataToResultStatistics( m_fractureDefinitionData,
// m_fractureDefinitionData->appendDataToResultStatistics( fileResultName, unit, minMaxAccumulator, fileResultName,
// posNegAccumulator ); unit,
minMaxAccumulator,
posNegAccumulator );
} }
} }
@@ -633,6 +639,7 @@ void RimThermalFractureTemplate::fractureTriangleGeometry( std::vector<cvf::Vec3
if ( m_fractureDefinitionData ) if ( m_fractureDefinitionData )
{ {
RigThermalFractureResultUtil::createFractureTriangleGeometry( m_fractureDefinitionData, RigThermalFractureResultUtil::createFractureTriangleGeometry( m_fractureDefinitionData,
m_activeTimeStepIndex,
m_halfLengthScaleFactor(), m_halfLengthScaleFactor(),
m_heightScaleFactor(), m_heightScaleFactor(),
wellPathDepthAtFracture, wellPathDepthAtFracture,

View File

@@ -125,3 +125,46 @@ double RigThermalFractureDefinition::getPropertyValue( int propertyIndex, int no
{ {
return m_results[propertyIndex].getValue( nodeIndex, timeStepIndex ); return m_results[propertyIndex].getValue( nodeIndex, timeStepIndex );
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int RigThermalFractureDefinition::getPropertyIndex( const QString& name ) const
{
for ( size_t i = 0; i < m_results.size(); i++ )
if ( name == m_results[i].name() ) return static_cast<int>( i );
return -1;
};
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<cvf::Vec3d> RigThermalFractureDefinition::relativeCoordinates( int timeStepIndex ) const
{
std::vector<cvf::Vec3d> relCoords;
int xIndex = getPropertyIndex( "XCoord" );
int yIndex = getPropertyIndex( "YCoord" );
int zIndex = getPropertyIndex( "ZCoord" );
if ( xIndex == -1 || yIndex == -1 || zIndex == -1 )
{
return relCoords;
}
// The first node is the center node
int centerNodeIndex = 0;
cvf::Vec3d centerNode( getPropertyValue( xIndex, centerNodeIndex, timeStepIndex ),
getPropertyValue( yIndex, centerNodeIndex, timeStepIndex ),
getPropertyValue( zIndex, centerNodeIndex, timeStepIndex ) );
for ( size_t nodeIndex = 0; nodeIndex < numNodes(); nodeIndex++ )
{
cvf::Vec3d nodePos( getPropertyValue( xIndex, static_cast<int>( nodeIndex ), timeStepIndex ),
getPropertyValue( yIndex, static_cast<int>( nodeIndex ), timeStepIndex ),
getPropertyValue( zIndex, static_cast<int>( nodeIndex ), timeStepIndex ) );
relCoords.push_back( nodePos - centerNode );
}
return relCoords;
}

View File

@@ -20,6 +20,8 @@
#include "RiaDefines.h" #include "RiaDefines.h"
#include "cvfVector3.h"
#include <QString> #include <QString>
#include <vector> #include <vector>
@@ -36,8 +38,8 @@ public:
{ {
} }
QString name() { return m_name; } QString name() const { return m_name; }
QString unit() { return m_unit; } QString unit() const { return m_unit; }
void appendValue( int nodeIndex, int timeStepIndex, double value ) void appendValue( int nodeIndex, int timeStepIndex, double value )
{ {
@@ -85,6 +87,10 @@ public:
double getPropertyValue( int propertyIndex, int nodeIndex, int timeStepIndex ) const; double getPropertyValue( int propertyIndex, int nodeIndex, int timeStepIndex ) const;
int getPropertyIndex( const QString& name ) const;
std::vector<cvf::Vec3d> relativeCoordinates( int timeStepIndex ) const;
private: private:
QString m_name; QString m_name;

View File

@@ -18,7 +18,20 @@
#include "RigThermalFractureResultUtil.h" #include "RigThermalFractureResultUtil.h"
#include "RiaLogging.h"
#include "RigCellGeometryTools.h"
#include "RigFractureGrid.h" #include "RigFractureGrid.h"
#include "RigStatisticsMath.h"
#include "RigThermalFractureDefinition.h"
#include "cafAssert.h"
#include "cvfBoundingBox.h"
#include <cmath>
int numSamplesX = 40;
int numSamplesY = 40;
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
@@ -43,7 +56,60 @@ std::vector<std::vector<double>>
const QString& unitName, const QString& unitName,
size_t timeStepIndex ) size_t timeStepIndex )
{ {
return std::vector<std::vector<double>>(); int propertyIndex = fractureDefinition->getPropertyIndex( resultName );
std::vector<cvf::Vec3d> relativePos = fractureDefinition->relativeCoordinates( timeStepIndex );
CAF_ASSERT( relativePos.size() == fractureDefinition->numNodes() );
// Create bounding box
cvf::BoundingBox boundingBox;
for ( auto p : relativePos )
boundingBox.add( p );
// Generate a uniform mesh
auto [xCoordsAtNodes, yCoordsAtNodes] = generateUniformMesh( boundingBox, numSamplesX, numSamplesY );
// Find center points
std::vector<double> xCoords;
for ( int i = 0; i < static_cast<int>( xCoordsAtNodes.size() ) - 1; i++ )
xCoords.push_back( ( xCoordsAtNodes[i] + xCoordsAtNodes[i + 1] ) / 2 );
std::vector<double> depthCoords;
for ( int i = 0; i < static_cast<int>( yCoordsAtNodes.size() ) - 1; i++ )
depthCoords.push_back( ( yCoordsAtNodes[i] + yCoordsAtNodes[i + 1] ) / 2 );
std::vector<std::vector<double>> vec;
// Fill with invalid value
for ( int i = 0; i < numSamplesY; i++ )
{
std::vector<double> junk( numSamplesX, HUGE_VAL );
vec.push_back( junk );
}
// Loop through each polygon and check if point is inside.
for ( int i = 0; i < static_cast<int>( xCoords.size() ) - 1; i++ )
{
for ( int j = 0; j < static_cast<int>( depthCoords.size() ) - 1; j++ )
{
std::vector<cvf::Vec3d> cellPolygon;
cellPolygon.push_back( cvf::Vec3d( xCoords[i], depthCoords[j], 0.0 ) );
cellPolygon.push_back( cvf::Vec3d( xCoords[i + 1], depthCoords[j], 0.0 ) );
cellPolygon.push_back( cvf::Vec3d( xCoords[i + 1], depthCoords[j + 1], 0.0 ) );
cellPolygon.push_back( cvf::Vec3d( xCoords[i], depthCoords[j + 1], 0.0 ) );
for ( size_t nodeIndex = 0; nodeIndex < fractureDefinition->numNodes(); nodeIndex++ )
{
if ( RigCellGeometryTools::pointInsidePolygon2D( relativePos[nodeIndex], cellPolygon ) )
{
double value = fractureDefinition->getPropertyValue( propertyIndex, nodeIndex, timeStepIndex );
vec[j][i] = value;
}
}
}
}
return vec;
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -51,12 +117,64 @@ std::vector<std::vector<double>>
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
void RigThermalFractureResultUtil::createFractureTriangleGeometry( void RigThermalFractureResultUtil::createFractureTriangleGeometry(
std::shared_ptr<const RigThermalFractureDefinition> fractureDefinition, std::shared_ptr<const RigThermalFractureDefinition> fractureDefinition,
int activeTimeStepIndex,
double xScaleFactor, double xScaleFactor,
double yScaleFactor, double yScaleFactor,
double wellPathIntersectionAtFractureDepth, double wellPathIntersectionAtFractureDepth,
std::vector<cvf::Vec3f>* vertices, std::vector<cvf::Vec3f>* vertices,
std::vector<cvf::uint>* triangleIndices ) std::vector<cvf::uint>* triangleIndices )
{ {
// Convert to coordinates relative to center node
std::vector<cvf::Vec3d> points = fractureDefinition->relativeCoordinates( activeTimeStepIndex );
// Create bounding box
cvf::BoundingBox boundingBox;
for ( auto p : points )
boundingBox.add( p );
// Generate a uniform mesh
auto [xCoords, depthCoords] = generateUniformMesh( boundingBox, numSamplesX, numSamplesY );
// Code adapted from RigStimPlanFractureDefinition
std::vector<double> adjustedYs = depthCoords;
cvf::uint lenXcoords = static_cast<cvf::uint>( xCoords.size() );
for ( cvf::uint k = 0; k < adjustedYs.size(); k++ )
{
for ( cvf::uint i = 0; i < lenXcoords; i++ )
{
cvf::Vec3f node = cvf::Vec3f( xCoords[i], adjustedYs[k], 0 );
vertices->push_back( node );
if ( i < lenXcoords - 1 && k < adjustedYs.size() - 1 )
{
double THRESHOLD_VALUE = 1e-5;
if ( xCoords[i] < THRESHOLD_VALUE )
{
// Upper triangle
triangleIndices->push_back( i + k * lenXcoords );
triangleIndices->push_back( ( i + 1 ) + k * lenXcoords );
triangleIndices->push_back( ( i + 1 ) + ( k + 1 ) * lenXcoords );
// Lower triangle
triangleIndices->push_back( i + k * lenXcoords );
triangleIndices->push_back( ( i + 1 ) + ( k + 1 ) * lenXcoords );
triangleIndices->push_back( ( i ) + ( k + 1 ) * lenXcoords );
}
else
{
// Upper triangle
triangleIndices->push_back( i + k * lenXcoords );
triangleIndices->push_back( ( i + 1 ) + k * lenXcoords );
triangleIndices->push_back( ( i ) + ( k + 1 ) * lenXcoords );
// Lower triangle
triangleIndices->push_back( ( i + 1 ) + k * lenXcoords );
triangleIndices->push_back( ( i + 1 ) + ( k + 1 ) * lenXcoords );
triangleIndices->push_back( ( i ) + ( k + 1 ) * lenXcoords );
}
}
}
}
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -68,7 +186,27 @@ std::vector<double>
const QString& unitName, const QString& unitName,
size_t timeStepIndex ) size_t timeStepIndex )
{ {
return std::vector<double>(); std::vector<double> fractureGridResults;
const std::vector<std::vector<double>>& resultValuesAtTimeStep =
getDataAtTimeIndex( fractureDefinition, resultName, unitName, timeStepIndex );
for ( int i = 0; i < static_cast<int>( numSamplesX ) - 2; i++ )
{
for ( int j = 0; j < static_cast<int>( numSamplesY ) - 2; j++ )
{
if ( j + 1 < static_cast<int>( resultValuesAtTimeStep.size() ) &&
i + 1 < static_cast<int>( resultValuesAtTimeStep[j + 1].size() ) )
{
fractureGridResults.push_back( resultValuesAtTimeStep[j + 1][i + 1] );
}
else
{
fractureGridResults.push_back( HUGE_VAL );
}
}
}
return fractureGridResults;
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -83,13 +221,167 @@ cvf::cref<RigFractureGrid>
double wellPathIntersectionAtFractureDepth, double wellPathIntersectionAtFractureDepth,
RiaDefines::EclipseUnitSystem requiredUnitSet ) RiaDefines::EclipseUnitSystem requiredUnitSet )
{ {
cvf::ref<RigFractureGrid> fractureGrid = new RigFractureGrid; // Convert to coordinates relative to center node
std::vector<cvf::Vec3d> points = fractureDefinition->relativeCoordinates( activeTimeStepIndex );
QString conductivityUnitTextOnFile;
std::vector<std::pair<QString, QString>> propertyNamesUnitsOnFile = fractureDefinition->getPropertyNamesUnits();
for ( auto properyNameUnit : propertyNamesUnitsOnFile )
{
if ( resultName == properyNameUnit.first )
{
conductivityUnitTextOnFile = properyNameUnit.second;
}
}
CAF_ASSERT( !conductivityUnitTextOnFile.isEmpty() );
if ( conductivityUnitTextOnFile.isEmpty() )
{
RiaLogging::error( "Did not find unit for conductivity on file" );
return nullptr;
}
std::vector<std::vector<double>> conductivityValues =
getDataAtTimeIndex( fractureDefinition, resultName, conductivityUnitTextOnFile, activeTimeStepIndex );
if ( conductivityValues.empty() )
{
RiaLogging::error( QString( "No conductivity values found for result: %1" ).arg( resultName ) );
return nullptr;
}
// Create bounding box
cvf::BoundingBox boundingBox;
for ( auto p : points )
boundingBox.add( p );
// Generate a uniform mesh
auto [xCoordsAtNodes, yCoordsAtNodes] = generateUniformMesh( boundingBox, numSamplesX, numSamplesY );
// Find center points
std::vector<double> xCoords;
for ( int i = 0; i < static_cast<int>( xCoordsAtNodes.size() ) - 1; i++ )
xCoords.push_back( ( xCoordsAtNodes[i] + xCoordsAtNodes[i + 1] ) / 2 );
std::vector<double> depthCoords;
for ( int i = 0; i < static_cast<int>( yCoordsAtNodes.size() ) - 1; i++ )
depthCoords.push_back( ( yCoordsAtNodes[i] + yCoordsAtNodes[i + 1] ) / 2 );
std::pair<size_t, size_t> wellCenterStimPlanCellIJ = std::make_pair( 0, 0 );
std::vector<RigFractureCell> stimPlanCells; std::vector<RigFractureCell> stimPlanCells;
for ( int i = 0; i < static_cast<int>( xCoords.size() ) - 1; i++ )
{
for ( int j = 0; j < static_cast<int>( depthCoords.size() ) - 1; j++ )
{
std::vector<cvf::Vec3d> cellPolygon;
cellPolygon.push_back( cvf::Vec3d( xCoords[i], depthCoords[j], 0.0 ) );
cellPolygon.push_back( cvf::Vec3d( xCoords[i + 1], depthCoords[j], 0.0 ) );
cellPolygon.push_back( cvf::Vec3d( xCoords[i + 1], depthCoords[j + 1], 0.0 ) );
cellPolygon.push_back( cvf::Vec3d( xCoords[i], depthCoords[j + 1], 0.0 ) );
RigFractureCell stimPlanCell( cellPolygon, i, j );
if ( !conductivityValues.empty() ) // Assuming vector to be of correct length, or no values
{
stimPlanCell.setConductivityValue( conductivityValues[j + 1][i + 1] );
}
else
{
stimPlanCell.setConductivityValue( cvf::UNDEFINED_DOUBLE );
}
// The well path is intersecting the fracture at origo in the fracture coordinate system
// Find the Stimplan cell where the well path is intersecting
if ( cellPolygon[0].x() <= 0.0 && cellPolygon[1].x() >= 0.0 )
{
if ( cellPolygon[1].y() >= 0.0 && cellPolygon[2].y() <= 0.0 )
{
wellCenterStimPlanCellIJ = std::make_pair( stimPlanCell.getI(), stimPlanCell.getJ() );
}
}
stimPlanCells.push_back( stimPlanCell );
}
}
cvf::ref<RigFractureGrid> fractureGrid = new RigFractureGrid;
fractureGrid->setFractureCells( stimPlanCells ); fractureGrid->setFractureCells( stimPlanCells );
// fractureGrid->setWellCenterFractureCellIJ( wellCenterStimPlanCellIJ ); fractureGrid->setWellCenterFractureCellIJ( wellCenterStimPlanCellIJ );
// fractureGrid->setICellCount( this->m_Xs.size() - 2 ); fractureGrid->setICellCount( numSamplesX - 2 );
// fractureGrid->setJCellCount( this->m_Ys.size() - 2 ); fractureGrid->setJCellCount( numSamplesY - 2 );
// fractureGrid->ensureCellSearchTreeIsBuilt(); fractureGrid->ensureCellSearchTreeIsBuilt();
return cvf::cref<RigFractureGrid>( fractureGrid.p() ); return cvf::cref<RigFractureGrid>( fractureGrid.p() );
} }
//--------------------------------------------------------------------------------------------------
/// TODO: adapted from RimEnsembleFractureStatistics. Maybe extract?
//--------------------------------------------------------------------------------------------------
std::pair<std::vector<double>, std::vector<double>>
RigThermalFractureResultUtil::generateUniformMesh( const cvf::BoundingBox& bb, int numSamplesX, int numSamplesY )
{
CAF_ASSERT( numSamplesX > 0 );
CAF_ASSERT( numSamplesY > 0 );
double minX = bb.min().x();
double maxX = bb.max().x();
double minY = bb.min().y();
double maxY = bb.max().y();
std::vector<double> gridXs;
double sampleDistanceX = linearSampling( minX, maxX, numSamplesX, gridXs );
std::vector<double> gridYs;
double sampleDistanceY = linearSampling( minY, maxY, numSamplesY, gridYs );
RiaLogging::info( QString( "Uniform Mesh. Output size: %1x%2. Sampling Distance X = %3 Sampling Distance Y = %4" )
.arg( numSamplesX )
.arg( numSamplesY )
.arg( sampleDistanceX )
.arg( sampleDistanceY ) );
return std::make_pair( gridXs, gridYs );
}
//--------------------------------------------------------------------------------------------------
/// TODO: duplicated from RimEnsembleFractureStatistics. Extract to util.
//--------------------------------------------------------------------------------------------------
double RigThermalFractureResultUtil::linearSampling( double minValue,
double maxValue,
int numSamples,
std::vector<double>& samples )
{
CAF_ASSERT( numSamples > 0 );
double sampleDistance = ( maxValue - minValue ) / numSamples;
for ( int s = 0; s < numSamples; s++ )
{
double pos = minValue + s * sampleDistance + sampleDistance * 0.5;
samples.push_back( pos );
}
return sampleDistance;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigThermalFractureResultUtil::appendDataToResultStatistics( std::shared_ptr<const RigThermalFractureDefinition> fractureDefinition,
const QString& resultName,
const QString& unit,
MinMaxAccumulator& minMaxAccumulator,
PosNegAccumulator& posNegAccumulator )
{
int propertyIndex = fractureDefinition->getPropertyIndex( resultName );
size_t maxTs = fractureDefinition->timeSteps().size();
for ( size_t ts = 0; ts < maxTs; ts++ )
{
for ( size_t nodeIndex = 0; nodeIndex < fractureDefinition->numNodes(); nodeIndex++ )
{
double value = fractureDefinition->getPropertyValue( propertyIndex, nodeIndex, ts );
minMaxAccumulator.addValue( value );
posNegAccumulator.addValue( value );
}
}
}

View File

@@ -31,6 +31,14 @@
class RigThermalFractureDefinition; class RigThermalFractureDefinition;
class RigFractureGrid; class RigFractureGrid;
class MinMaxAccumulator;
class PosNegAccumulator;
namespace cvf
{
class BoundingBox;
};
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -47,6 +55,7 @@ public:
size_t timeStepIndex ); size_t timeStepIndex );
static void createFractureTriangleGeometry( std::shared_ptr<const RigThermalFractureDefinition> fractureDefinition, static void createFractureTriangleGeometry( std::shared_ptr<const RigThermalFractureDefinition> fractureDefinition,
int activeTimeStepIndex,
double xScaleFactor, double xScaleFactor,
double yScaleFactor, double yScaleFactor,
double wellPathIntersectionAtFractureDepth, double wellPathIntersectionAtFractureDepth,
@@ -66,4 +75,16 @@ public:
double yScaleFactor, double yScaleFactor,
double wellPathIntersectionAtFractureDepth, double wellPathIntersectionAtFractureDepth,
RiaDefines::EclipseUnitSystem requiredUnitSet ); RiaDefines::EclipseUnitSystem requiredUnitSet );
static void appendDataToResultStatistics( std::shared_ptr<const RigThermalFractureDefinition> fractureDefinition,
const QString& resultName,
const QString& unit,
MinMaxAccumulator& minMaxAccumulator,
PosNegAccumulator& posNegAccumulator );
private:
static std::pair<std::vector<double>, std::vector<double>>
generateUniformMesh( const cvf::BoundingBox& bb, int numSamplesX, int numSamplesY );
static double linearSampling( double minValue, double maxValue, int numSamples, std::vector<double>& samples );
}; };

View File

@@ -789,8 +789,8 @@ void RiuViewerCommands::handlePickAction( int winPosX, int winPosY, Qt::Keyboard
} }
} }
RimStimPlanFractureTemplate* stimPlanTempl = RimMeshFractureTemplate* stimPlanTempl =
fracture ? dynamic_cast<RimStimPlanFractureTemplate*>( fracture->fractureTemplate() ) : nullptr; fracture ? dynamic_cast<RimMeshFractureTemplate*>( fracture->fractureTemplate() ) : nullptr;
RimEllipseFractureTemplate* ellipseTempl = RimEllipseFractureTemplate* ellipseTempl =
fracture ? dynamic_cast<RimEllipseFractureTemplate*>( fracture->fractureTemplate() ) : nullptr; fracture ? dynamic_cast<RimEllipseFractureTemplate*>( fracture->fractureTemplate() ) : nullptr;
if ( stimPlanTempl || ellipseTempl ) if ( stimPlanTempl || ellipseTempl )