From 625b927cb67189d1b500f6b48f7869200d414562 Mon Sep 17 00:00:00 2001 From: Kristian Bendiksen Date: Mon, 27 Jun 2022 14:10:28 +0200 Subject: [PATCH] Thermal Fracture: Add visualization of results --- .../RivWellFracturePartMgr.cpp | 33 +- .../RivWellFracturePartMgr.h | 9 +- .../Completions/RimFracture.cpp | 11 +- .../RimThermalFractureTemplate.cpp | 15 +- .../RigThermalFractureDefinition.cpp | 43 +++ .../RigThermalFractureDefinition.h | 10 +- .../RigThermalFractureResultUtil.cpp | 306 +++++++++++++++++- .../RigThermalFractureResultUtil.h | 21 ++ .../UserInterface/RiuViewerCommands.cpp | 4 +- 9 files changed, 409 insertions(+), 43 deletions(-) diff --git a/ApplicationLibCode/ModelVisualization/RivWellFracturePartMgr.cpp b/ApplicationLibCode/ModelVisualization/RivWellFracturePartMgr.cpp index 6727c7b6db..d222405714 100644 --- a/ApplicationLibCode/ModelVisualization/RivWellFracturePartMgr.cpp +++ b/ApplicationLibCode/ModelVisualization/RivWellFracturePartMgr.cpp @@ -34,10 +34,10 @@ #include "RimFractureContainment.h" #include "RimFractureContainmentTools.h" #include "RimFractureTemplate.h" +#include "RimMeshFractureTemplate.h" #include "RimRegularLegendConfig.h" #include "RimSimWellInView.h" #include "RimStimPlanColors.h" -#include "RimStimPlanFractureTemplate.h" #include "RimWellPath.h" #include "RimWellPathCollection.h" @@ -93,9 +93,9 @@ void RivWellFracturePartMgr::appendGeometryPartsToModel( cvf::ModelBasicList* mo double characteristicCellSize = eclView.ownerCase()->characteristicCellSize(); - cvf::Collection parts; - RimStimPlanFractureTemplate* stimPlanFracTemplate = - dynamic_cast( m_rimFracture->fractureTemplate() ); + cvf::Collection parts; + RimMeshFractureTemplate* stimPlanFracTemplate = + dynamic_cast( m_rimFracture->fractureTemplate() ); if ( stimPlanFracTemplate ) { @@ -228,7 +228,7 @@ const QString RivWellFracturePartMgr::resultInfoText( const RimEclipseView& acti if ( m_rimFracture.isNull() ) return text; auto* ellipseFractureTemplate = dynamic_cast( m_rimFracture->fractureTemplate() ); - auto* stimPlanTemplate = dynamic_cast( m_rimFracture->fractureTemplate() ); + auto* stimPlanTemplate = dynamic_cast( m_rimFracture->fractureTemplate() ); if ( ellipseFractureTemplate ) { @@ -285,7 +285,7 @@ const RigFractureCell* RivWellFracturePartMgr::getFractureCellAtDomainCoord( cvf cvf::Mat4d toFractureXf = m_rimFracture->transformMatrix().getInverted(); cvf::Vec3d fractureCoord = domainCoord.getTransformedPoint( toFractureXf ); - auto* stimPlanTempl = dynamic_cast( m_rimFracture->fractureTemplate() ); + auto* stimPlanTempl = dynamic_cast( m_rimFracture->fractureTemplate() ); if ( !stimPlanTempl ) return nullptr; const RigFractureGrid* grid = m_rimFracture->fractureGrid(); @@ -403,8 +403,8 @@ cvf::ref RivWellFracturePartMgr::createEllipseSurfacePart( const RimE cvf::ref RivWellFracturePartMgr::createStimPlanColorInterpolatedSurfacePart( const RimEclipseView& activeView ) { CVF_ASSERT( m_rimFracture ); - RimStimPlanFractureTemplate* stimPlanFracTemplate = - dynamic_cast( m_rimFracture->fractureTemplate() ); + RimMeshFractureTemplate* stimPlanFracTemplate = + dynamic_cast( m_rimFracture->fractureTemplate() ); CVF_ASSERT( stimPlanFracTemplate ); auto displayCoordTransform = activeView.displayCoordTransform(); @@ -542,8 +542,8 @@ cvf::ref RivWellFracturePartMgr::createSingleColorSurfacePart( const cvf::ref RivWellFracturePartMgr::createStimPlanElementColorSurfacePart( const RimEclipseView& activeView ) { CVF_ASSERT( m_rimFracture ); - RimStimPlanFractureTemplate* stimPlanFracTemplate = - dynamic_cast( m_rimFracture->fractureTemplate() ); + RimMeshFractureTemplate* stimPlanFracTemplate = + dynamic_cast( m_rimFracture->fractureTemplate() ); CVF_ASSERT( stimPlanFracTemplate ); if ( !m_rimFracture->fractureGrid() ) return nullptr; @@ -1002,8 +1002,8 @@ cvf::ref RivWellFracturePartMgr::createStimPlanMeshPart( const RimEcl { if ( !m_rimFracture->fractureTemplate() ) return nullptr; - RimStimPlanFractureTemplate* stimPlanFracTemplate = - dynamic_cast( m_rimFracture->fractureTemplate() ); + RimMeshFractureTemplate* stimPlanFracTemplate = + dynamic_cast( m_rimFracture->fractureTemplate() ); if ( !stimPlanFracTemplate ) return nullptr; cvf::ref stimPlanMeshGeo = createStimPlanMeshDrawable( stimPlanFracTemplate, activeView ); @@ -1030,8 +1030,8 @@ cvf::ref RivWellFracturePartMgr::createStimPlanMeshPart( const RimEcl //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RivWellFracturePartMgr::createVisibleFracturePolygons( RimStimPlanFractureTemplate* stimPlanFracTemplate, - const RimEclipseView& activeView ) +void RivWellFracturePartMgr::createVisibleFracturePolygons( RimMeshFractureTemplate* stimPlanFracTemplate, + const RimEclipseView& activeView ) { if ( !m_rimFracture->fractureGrid() ) return; @@ -1060,9 +1060,8 @@ void RivWellFracturePartMgr::createVisibleFracturePolygons( RimStimPlanFractureT //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -cvf::ref - RivWellFracturePartMgr::createStimPlanMeshDrawable( RimStimPlanFractureTemplate* stimPlanFracTemplate, - const RimEclipseView& activeView ) +cvf::ref RivWellFracturePartMgr::createStimPlanMeshDrawable( RimMeshFractureTemplate* stimPlanFracTemplate, + const RimEclipseView& activeView ) { if ( !m_rimFracture->fractureGrid() ) return nullptr; diff --git a/ApplicationLibCode/ModelVisualization/RivWellFracturePartMgr.h b/ApplicationLibCode/ModelVisualization/RivWellFracturePartMgr.h index ac9206c4ce..043a4ba4a1 100644 --- a/ApplicationLibCode/ModelVisualization/RivWellFracturePartMgr.h +++ b/ApplicationLibCode/ModelVisualization/RivWellFracturePartMgr.h @@ -44,7 +44,7 @@ class DisplayCoordTransform; class RimFracture; class RimFractureTemplate; -class RimStimPlanFractureTemplate; +class RimMeshFractureTemplate; class RimEclipseView; class RigFractureCell; @@ -79,11 +79,10 @@ private: void appendFracturePerforationLengthParts( const RimEclipseView& activeView, cvf::ModelBasicList* model ); cvf::ref createStimPlanMeshPart( const RimEclipseView& activeView ); - cvf::ref createStimPlanMeshDrawable( RimStimPlanFractureTemplate* stimPlanFracTemplate, - const RimEclipseView& activeView ); + cvf::ref createStimPlanMeshDrawable( RimMeshFractureTemplate* stimPlanFracTemplate, + const RimEclipseView& activeView ); - void createVisibleFracturePolygons( RimStimPlanFractureTemplate* stimPlanFracTemplate, - const RimEclipseView& activeView ); + void createVisibleFracturePolygons( RimMeshFractureTemplate* stimPlanFracTemplate, const RimEclipseView& activeView ); std::vector fractureBorderPolygon(); diff --git a/ApplicationLibCode/ProjectDataModel/Completions/RimFracture.cpp b/ApplicationLibCode/ProjectDataModel/Completions/RimFracture.cpp index 56219f337a..b0374dc1f8 100644 --- a/ApplicationLibCode/ProjectDataModel/Completions/RimFracture.cpp +++ b/ApplicationLibCode/ProjectDataModel/Completions/RimFracture.cpp @@ -658,12 +658,11 @@ QList RimFracture::calculateValueOptions( const caf::Pdm if ( fractureTemplate() ) { RimFractureTemplate* fracTemplate = fractureTemplate(); - if ( dynamic_cast( fracTemplate ) ) + if ( dynamic_cast( fracTemplate ) ) { - RimStimPlanFractureTemplate* fracTemplateStimPlan = - dynamic_cast( fracTemplate ); - std::vector timeValues = fracTemplateStimPlan->timeSteps(); - int index = 0; + RimMeshFractureTemplate* fracTemplateStimPlan = dynamic_cast( fracTemplate ); + std::vector timeValues = fracTemplateStimPlan->timeSteps(); + int index = 0; for ( double value : timeValues ) { options.push_back( caf::PdmOptionItemInfo( QString::number( value ), index ) ); @@ -750,7 +749,7 @@ void RimFracture::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& ui } RimFractureTemplate* fracTemplate = fractureTemplate(); - if ( dynamic_cast( fracTemplate ) ) + if ( dynamic_cast( fracTemplate ) ) { m_stimPlanTimeIndexToPlot.uiCapability()->setUiHidden( false ); diff --git a/ApplicationLibCode/ProjectDataModel/Completions/RimThermalFractureTemplate.cpp b/ApplicationLibCode/ProjectDataModel/Completions/RimThermalFractureTemplate.cpp index 41ffa0cc48..b992795c23 100644 --- a/ApplicationLibCode/ProjectDataModel/Completions/RimThermalFractureTemplate.cpp +++ b/ApplicationLibCode/ProjectDataModel/Completions/RimThermalFractureTemplate.cpp @@ -163,6 +163,8 @@ void RimThermalFractureTemplate::loadDataAndUpdate() // { // setUnitSystem( m_fractureDefinitionData->unitSet() ); // } + // TODO: handle other units + setUnitSystem( RiaDefines::EclipseUnitSystem::UNITS_METRIC ); if ( !m_userDefinedWellPathDepthAtFracture ) { @@ -200,6 +202,8 @@ void RimThermalFractureTemplate::loadDataAndUpdate() QStringList RimThermalFractureTemplate::conductivityResultNames() const { QStringList resultNames; + if ( !m_fractureDefinitionData ) return resultNames; + for ( auto [name, unit] : m_fractureDefinitionData->getPropertyNamesUnits() ) { resultNames.append( name ); @@ -616,10 +620,12 @@ void RimThermalFractureTemplate::appendDataToResultStatistics( const QString& { if ( m_fractureDefinitionData ) { - // QString fileResultName = mapUiResultNameToFileResultName( uiResultName ); - - // m_fractureDefinitionData->appendDataToResultStatistics( fileResultName, unit, minMaxAccumulator, - // posNegAccumulator ); + QString fileResultName = mapUiResultNameToFileResultName( uiResultName ); + RigThermalFractureResultUtil::appendDataToResultStatistics( m_fractureDefinitionData, + fileResultName, + unit, + minMaxAccumulator, + posNegAccumulator ); } } @@ -633,6 +639,7 @@ void RimThermalFractureTemplate::fractureTriangleGeometry( std::vector( i ); + + return -1; +}; + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RigThermalFractureDefinition::relativeCoordinates( int timeStepIndex ) const +{ + std::vector 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( nodeIndex ), timeStepIndex ), + getPropertyValue( yIndex, static_cast( nodeIndex ), timeStepIndex ), + getPropertyValue( zIndex, static_cast( nodeIndex ), timeStepIndex ) ); + relCoords.push_back( nodePos - centerNode ); + } + + return relCoords; +} diff --git a/ApplicationLibCode/ReservoirDataModel/RigThermalFractureDefinition.h b/ApplicationLibCode/ReservoirDataModel/RigThermalFractureDefinition.h index af58c3113d..106fda121f 100644 --- a/ApplicationLibCode/ReservoirDataModel/RigThermalFractureDefinition.h +++ b/ApplicationLibCode/ReservoirDataModel/RigThermalFractureDefinition.h @@ -20,6 +20,8 @@ #include "RiaDefines.h" +#include "cvfVector3.h" + #include #include @@ -36,8 +38,8 @@ public: { } - QString name() { return m_name; } - QString unit() { return m_unit; } + QString name() const { return m_name; } + QString unit() const { return m_unit; } void appendValue( int nodeIndex, int timeStepIndex, double value ) { @@ -85,6 +87,10 @@ public: double getPropertyValue( int propertyIndex, int nodeIndex, int timeStepIndex ) const; + int getPropertyIndex( const QString& name ) const; + + std::vector relativeCoordinates( int timeStepIndex ) const; + private: QString m_name; diff --git a/ApplicationLibCode/ReservoirDataModel/RigThermalFractureResultUtil.cpp b/ApplicationLibCode/ReservoirDataModel/RigThermalFractureResultUtil.cpp index 6dec60f8f1..87c01a73d5 100644 --- a/ApplicationLibCode/ReservoirDataModel/RigThermalFractureResultUtil.cpp +++ b/ApplicationLibCode/ReservoirDataModel/RigThermalFractureResultUtil.cpp @@ -18,7 +18,20 @@ #include "RigThermalFractureResultUtil.h" +#include "RiaLogging.h" + +#include "RigCellGeometryTools.h" #include "RigFractureGrid.h" +#include "RigStatisticsMath.h" +#include "RigThermalFractureDefinition.h" + +#include "cafAssert.h" +#include "cvfBoundingBox.h" + +#include + +int numSamplesX = 40; +int numSamplesY = 40; //-------------------------------------------------------------------------------------------------- /// @@ -43,7 +56,60 @@ std::vector> const QString& unitName, size_t timeStepIndex ) { - return std::vector>(); + int propertyIndex = fractureDefinition->getPropertyIndex( resultName ); + + std::vector 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 xCoords; + for ( int i = 0; i < static_cast( xCoordsAtNodes.size() ) - 1; i++ ) + xCoords.push_back( ( xCoordsAtNodes[i] + xCoordsAtNodes[i + 1] ) / 2 ); + std::vector depthCoords; + for ( int i = 0; i < static_cast( yCoordsAtNodes.size() ) - 1; i++ ) + depthCoords.push_back( ( yCoordsAtNodes[i] + yCoordsAtNodes[i + 1] ) / 2 ); + + std::vector> vec; + + // Fill with invalid value + for ( int i = 0; i < numSamplesY; i++ ) + { + std::vector 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( xCoords.size() ) - 1; i++ ) + { + for ( int j = 0; j < static_cast( depthCoords.size() ) - 1; j++ ) + { + std::vector 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> //-------------------------------------------------------------------------------------------------- void RigThermalFractureResultUtil::createFractureTriangleGeometry( std::shared_ptr fractureDefinition, + int activeTimeStepIndex, double xScaleFactor, double yScaleFactor, double wellPathIntersectionAtFractureDepth, std::vector* vertices, std::vector* triangleIndices ) { + // Convert to coordinates relative to center node + std::vector 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 adjustedYs = depthCoords; + cvf::uint lenXcoords = static_cast( 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 const QString& unitName, size_t timeStepIndex ) { - return std::vector(); + std::vector fractureGridResults; + const std::vector>& resultValuesAtTimeStep = + getDataAtTimeIndex( fractureDefinition, resultName, unitName, timeStepIndex ); + + for ( int i = 0; i < static_cast( numSamplesX ) - 2; i++ ) + { + for ( int j = 0; j < static_cast( numSamplesY ) - 2; j++ ) + { + if ( j + 1 < static_cast( resultValuesAtTimeStep.size() ) && + i + 1 < static_cast( 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 double wellPathIntersectionAtFractureDepth, RiaDefines::EclipseUnitSystem requiredUnitSet ) { - cvf::ref fractureGrid = new RigFractureGrid; + // Convert to coordinates relative to center node + std::vector points = fractureDefinition->relativeCoordinates( activeTimeStepIndex ); + + QString conductivityUnitTextOnFile; + + std::vector> 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> 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 xCoords; + for ( int i = 0; i < static_cast( xCoordsAtNodes.size() ) - 1; i++ ) + xCoords.push_back( ( xCoordsAtNodes[i] + xCoordsAtNodes[i + 1] ) / 2 ); + std::vector depthCoords; + for ( int i = 0; i < static_cast( yCoordsAtNodes.size() ) - 1; i++ ) + depthCoords.push_back( ( yCoordsAtNodes[i] + yCoordsAtNodes[i + 1] ) / 2 ); + + std::pair wellCenterStimPlanCellIJ = std::make_pair( 0, 0 ); std::vector stimPlanCells; + for ( int i = 0; i < static_cast( xCoords.size() ) - 1; i++ ) + { + for ( int j = 0; j < static_cast( depthCoords.size() ) - 1; j++ ) + { + std::vector 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 fractureGrid = new RigFractureGrid; fractureGrid->setFractureCells( stimPlanCells ); - // fractureGrid->setWellCenterFractureCellIJ( wellCenterStimPlanCellIJ ); - // fractureGrid->setICellCount( this->m_Xs.size() - 2 ); - // fractureGrid->setJCellCount( this->m_Ys.size() - 2 ); - // fractureGrid->ensureCellSearchTreeIsBuilt(); + fractureGrid->setWellCenterFractureCellIJ( wellCenterStimPlanCellIJ ); + fractureGrid->setICellCount( numSamplesX - 2 ); + fractureGrid->setJCellCount( numSamplesY - 2 ); + fractureGrid->ensureCellSearchTreeIsBuilt(); return cvf::cref( fractureGrid.p() ); } + +//-------------------------------------------------------------------------------------------------- +/// TODO: adapted from RimEnsembleFractureStatistics. Maybe extract? +//-------------------------------------------------------------------------------------------------- +std::pair, std::vector> + 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 gridXs; + double sampleDistanceX = linearSampling( minX, maxX, numSamplesX, gridXs ); + + std::vector 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& 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 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 ); + } + } +} diff --git a/ApplicationLibCode/ReservoirDataModel/RigThermalFractureResultUtil.h b/ApplicationLibCode/ReservoirDataModel/RigThermalFractureResultUtil.h index e9f9b719a5..51c17eb53b 100644 --- a/ApplicationLibCode/ReservoirDataModel/RigThermalFractureResultUtil.h +++ b/ApplicationLibCode/ReservoirDataModel/RigThermalFractureResultUtil.h @@ -31,6 +31,14 @@ class RigThermalFractureDefinition; class RigFractureGrid; +class MinMaxAccumulator; +class PosNegAccumulator; + +namespace cvf +{ +class BoundingBox; +}; + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -47,6 +55,7 @@ public: size_t timeStepIndex ); static void createFractureTriangleGeometry( std::shared_ptr fractureDefinition, + int activeTimeStepIndex, double xScaleFactor, double yScaleFactor, double wellPathIntersectionAtFractureDepth, @@ -66,4 +75,16 @@ public: double yScaleFactor, double wellPathIntersectionAtFractureDepth, RiaDefines::EclipseUnitSystem requiredUnitSet ); + + static void appendDataToResultStatistics( std::shared_ptr fractureDefinition, + const QString& resultName, + const QString& unit, + MinMaxAccumulator& minMaxAccumulator, + PosNegAccumulator& posNegAccumulator ); + +private: + static std::pair, std::vector> + generateUniformMesh( const cvf::BoundingBox& bb, int numSamplesX, int numSamplesY ); + + static double linearSampling( double minValue, double maxValue, int numSamples, std::vector& samples ); }; diff --git a/ApplicationLibCode/UserInterface/RiuViewerCommands.cpp b/ApplicationLibCode/UserInterface/RiuViewerCommands.cpp index 2d67366dc6..1c08a703ea 100644 --- a/ApplicationLibCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationLibCode/UserInterface/RiuViewerCommands.cpp @@ -789,8 +789,8 @@ void RiuViewerCommands::handlePickAction( int winPosX, int winPosY, Qt::Keyboard } } - RimStimPlanFractureTemplate* stimPlanTempl = - fracture ? dynamic_cast( fracture->fractureTemplate() ) : nullptr; + RimMeshFractureTemplate* stimPlanTempl = + fracture ? dynamic_cast( fracture->fractureTemplate() ) : nullptr; RimEllipseFractureTemplate* ellipseTempl = fracture ? dynamic_cast( fracture->fractureTemplate() ) : nullptr; if ( stimPlanTempl || ellipseTempl )