From ffb0c5a03fd20310efe0237bc46e99e82ae93242 Mon Sep 17 00:00:00 2001 From: Kristian Bendiksen Date: Mon, 20 Jun 2022 13:08:45 +0200 Subject: [PATCH] Thermal Fracture: add thermal fracture template --- .../Completions/CMakeLists_files.cmake | 2 + .../RimThermalFractureTemplate.cpp | 704 ++++++++++++++++++ .../Completions/RimThermalFractureTemplate.h | 109 +++ .../ReservoirDataModel/CMakeLists_files.cmake | 2 + .../RigThermalFractureResultUtil.cpp | 95 +++ .../RigThermalFractureResultUtil.h | 69 ++ 6 files changed, 981 insertions(+) create mode 100644 ApplicationLibCode/ProjectDataModel/Completions/RimThermalFractureTemplate.cpp create mode 100644 ApplicationLibCode/ProjectDataModel/Completions/RimThermalFractureTemplate.h create mode 100644 ApplicationLibCode/ReservoirDataModel/RigThermalFractureResultUtil.cpp create mode 100644 ApplicationLibCode/ReservoirDataModel/RigThermalFractureResultUtil.h diff --git a/ApplicationLibCode/ProjectDataModel/Completions/CMakeLists_files.cmake b/ApplicationLibCode/ProjectDataModel/Completions/CMakeLists_files.cmake index d682b35963..5d7c8edb1c 100644 --- a/ApplicationLibCode/ProjectDataModel/Completions/CMakeLists_files.cmake +++ b/ApplicationLibCode/ProjectDataModel/Completions/CMakeLists_files.cmake @@ -22,6 +22,7 @@ set(SOURCE_GROUP_HEADER_FILES ${CMAKE_CURRENT_LIST_DIR}/RimSimWellFracture.h ${CMAKE_CURRENT_LIST_DIR}/RimSimWellFractureCollection.h ${CMAKE_CURRENT_LIST_DIR}/RimMeshFractureTemplate.h + ${CMAKE_CURRENT_LIST_DIR}/RimThermalFractureTemplate.h ${CMAKE_CURRENT_LIST_DIR}/RimStimPlanFractureTemplate.h ${CMAKE_CURRENT_LIST_DIR}/RimWellPathFracture.h ${CMAKE_CURRENT_LIST_DIR}/RimWellPathFractureCollection.h @@ -58,6 +59,7 @@ set(SOURCE_GROUP_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/RimSimWellFracture.cpp ${CMAKE_CURRENT_LIST_DIR}/RimSimWellFractureCollection.cpp ${CMAKE_CURRENT_LIST_DIR}/RimMeshFractureTemplate.cpp + ${CMAKE_CURRENT_LIST_DIR}/RimThermalFractureTemplate.cpp ${CMAKE_CURRENT_LIST_DIR}/RimStimPlanFractureTemplate.cpp ${CMAKE_CURRENT_LIST_DIR}/RimWellPathFracture.cpp ${CMAKE_CURRENT_LIST_DIR}/RimWellPathFractureCollection.cpp diff --git a/ApplicationLibCode/ProjectDataModel/Completions/RimThermalFractureTemplate.cpp b/ApplicationLibCode/ProjectDataModel/Completions/RimThermalFractureTemplate.cpp new file mode 100644 index 0000000000..41ffa0cc48 --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/Completions/RimThermalFractureTemplate.cpp @@ -0,0 +1,704 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2022 - Equinor ASA +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimThermalFractureTemplate.h" + +#include "RiaApplication.h" +#include "RiaCompletionTypeCalculationScheduler.h" +#include "RiaEclipseUnitTools.h" +#include "RiaFractureDefines.h" +#include "RiaLogging.h" + +#include "RifThermalFractureReader.h" + +#include "RigFractureCell.h" +#include "RigFractureGrid.h" +#include "RigThermalFractureDefinition.h" +#include "RigThermalFractureResultUtil.h" + +#include "RimEclipseView.h" +#include "RimFracture.h" +#include "RimFractureContainment.h" +#include "RimProject.h" +#include "RimStimPlanColors.h" +#include "RimWellPath.h" + +#include "cafPdmFieldScriptingCapability.h" +#include "cafPdmObject.h" +#include "cafPdmObjectScriptingCapability.h" +#include "cafPdmUiFilePathEditor.h" +#include "cafPdmUiTextEditor.h" + +#include "cvfMath.h" +#include "cvfVector3.h" + +#include + +#include +#include +#include + +CAF_PDM_SOURCE_INIT( RimThermalFractureTemplate, "ThermalFractureTemplate", "RimThermalFractureTemplate" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimThermalFractureTemplate::RimThermalFractureTemplate() +{ + CAF_PDM_InitScriptableObject( "Fracture Template", ":/FractureTemplate16x16.png" ); + + m_readError = false; + + setDeletable( true ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimThermalFractureTemplate::~RimThermalFractureTemplate() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimThermalFractureTemplate::setDefaultsBasedOnFile() +{ + if ( m_fractureDefinitionData ) return; + + computeDepthOfWellPathAtFracture(); + computePerforationLength(); + + RiaLogging::info( QString( "Setting well/fracture intersection depth at %1" ).arg( m_wellPathDepthAtFracture ) ); + + m_activeTimeStepIndex = static_cast( m_fractureDefinitionData->numTimeSteps() - 1 ); + + bool polygonPropertySet = setBorderPolygonResultNameToDefault(); + if ( polygonPropertySet ) + RiaLogging::info( QString( "Calculating polygon outline based on %1 at timestep %2" ) + .arg( m_borderPolygonResultName ) + .arg( m_fractureDefinitionData->timeSteps()[m_activeTimeStepIndex] ) ); + else + RiaLogging::info( QString( "Property for polygon calculation not set." ) ); + + // if ( m_fractureDefinitionData->orientation() == RigStimPlanFractureDefinition::Orientation::TRANSVERSE ) + // { + // m_orientationType = TRANSVERSE_WELL_PATH; + // } + // else if ( m_fractureDefinitionData->orientation() == RigStimPlanFractureDefinition::Orientation::LONGITUDINAL ) + // { + // m_orientationType = ALONG_WELL_PATH; + // } + + QStringList resultNames = conductivityResultNames(); + if ( !resultNames.isEmpty() ) + { + m_conductivityResultNameOnFile = resultNames.front(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimThermalFractureTemplate::setBorderPolygonResultNameToDefault() +{ + // first option: Width + for ( std::pair property : uiResultNamesWithUnit() ) + { + if ( property.first == "WIDTH" ) + { + m_borderPolygonResultName = property.first; + return true; + } + } + + // if width not found, use conductivity + if ( hasConductivity() ) + { + m_borderPolygonResultName = conductivityResultNames().first(); + return true; + } + + // else: Set to first property + if ( !uiResultNamesWithUnit().empty() ) + { + m_borderPolygonResultName = uiResultNamesWithUnit()[0].first; + return true; + } + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimThermalFractureTemplate::loadDataAndUpdate() +{ + if ( m_readError ) return; + + auto [fractureDefinitionData, errorMessage] = + RifThermalFractureReader::readFractureCsvFile( m_stimPlanFileName().path() ); + if ( errorMessage.size() > 0 ) RiaLogging::error( errorMessage ); + + m_fractureDefinitionData = fractureDefinitionData; + if ( m_fractureDefinitionData ) + { + setDefaultConductivityResultIfEmpty(); + + // if ( fractureTemplateUnit() == RiaDefines::EclipseUnitSystem::UNITS_UNKNOWN ) + // { + // setUnitSystem( m_fractureDefinitionData->unitSet() ); + // } + + if ( !m_userDefinedWellPathDepthAtFracture ) + { + computeDepthOfWellPathAtFracture(); + } + + m_readError = false; + } + else + { + m_readError = true; + } + + for ( RimFracture* fracture : fracturesUsingThisTemplate() ) + { + fracture->updateFractureGrid(); + fracture->clearCachedNonDarcyProperties(); + } + + if ( widthResultValues().empty() ) + { + m_fractureWidthType = USER_DEFINED_WIDTH; + } + + // Todo: Must update all views using this fracture template + RimEclipseView* activeView = dynamic_cast( RiaApplication::instance()->activeReservoirView() ); + if ( activeView ) activeView->fractureColors()->loadDataAndUpdate(); + + updateConnectedEditors(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QStringList RimThermalFractureTemplate::conductivityResultNames() const +{ + QStringList resultNames; + for ( auto [name, unit] : m_fractureDefinitionData->getPropertyNamesUnits() ) + { + resultNames.append( name ); + } + + return resultNames; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimThermalFractureTemplate::computeDepthOfWellPathAtFracture() +{ + // if ( !m_fractureDefinitionData.isNull() ) + // { + // double firstTvd = m_fractureDefinitionData->topPerfTvd(); + // double lastTvd = m_fractureDefinitionData->bottomPerfTvd(); + + // if ( firstTvd != HUGE_VAL && lastTvd != HUGE_VAL ) + // { + // m_wellPathDepthAtFracture.setValueWithFieldChanged( ( firstTvd + lastTvd ) / 2 ); + // } + // else + // { + // firstTvd = m_fractureDefinitionData->minDepth(); + // lastTvd = m_fractureDefinitionData->maxDepth(); + // m_wellPathDepthAtFracture.setValueWithFieldChanged( ( firstTvd + lastTvd ) / 2 ); + // } + // } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimThermalFractureTemplate::computePerforationLength() +{ + // if ( !m_fractureDefinitionData.isNull() ) + // { + // double firstTvd = m_fractureDefinitionData->topPerfTvd(); + // double lastTvd = m_fractureDefinitionData->bottomPerfTvd(); + + // if ( firstTvd != HUGE_VAL && lastTvd != HUGE_VAL ) + // { + // m_perforationLength = cvf::Math::abs( firstTvd - lastTvd ); + // } + // } + + // if ( fractureTemplateUnit() == RiaDefines::EclipseUnitSystem::UNITS_METRIC && m_perforationLength < 10 ) + // { + // m_perforationLength = 10; + // } + // else if ( fractureTemplateUnit() == RiaDefines::EclipseUnitSystem::UNITS_FIELD && + // m_perforationLength < RiaEclipseUnitTools::meterToFeet( 10 ) ) + // { + // m_perforationLength = std::round( RiaEclipseUnitTools::meterToFeet( 10 ) ); + // } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector + RimThermalFractureTemplate::fractureGridResultsForUnitSystem( const QString& resultName, + const QString& unitName, + size_t timeStepIndex, + RiaDefines::EclipseUnitSystem requiredUnitSystem ) const +{ + auto resultValues = fractureGridResults( resultName, unitName, m_activeTimeStepIndex ); + + if ( fractureTemplateUnit() == RiaDefines::EclipseUnitSystem::UNITS_METRIC ) + { + for ( auto& v : resultValues ) + { + v = RiaEclipseUnitTools::convertToMeter( v, unitName ); + } + } + else if ( fractureTemplateUnit() == RiaDefines::EclipseUnitSystem::UNITS_FIELD ) + { + for ( auto& v : resultValues ) + { + v = RiaEclipseUnitTools::convertToFeet( v, unitName ); + } + } + + return resultValues; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::pair RimThermalFractureTemplate::widthParameterNameAndUnit() const +{ + return widthParameterNameAndUnit( m_fractureDefinitionData ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::pair + RimThermalFractureTemplate::widthParameterNameAndUnit( std::shared_ptr fractureDefinitionData ) +{ + if ( fractureDefinitionData ) + { + std::vector> propertyNamesUnitsOnFile = + fractureDefinitionData->getPropertyNamesUnits(); + + for ( const auto& nameUnit : propertyNamesUnitsOnFile ) + { + if ( nameUnit.first.contains( "effective width", Qt::CaseInsensitive ) ) + { + return nameUnit; + } + + if ( nameUnit.first.contains( "width", Qt::CaseInsensitive ) ) + { + return nameUnit; + } + } + } + + return std::pair(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::pair RimThermalFractureTemplate::conductivityParameterNameAndUnit() const +{ + if ( m_fractureDefinitionData ) + { + std::vector> propertyNamesUnitsOnFile = + m_fractureDefinitionData->getPropertyNamesUnits(); + + for ( const auto& nameUnit : propertyNamesUnitsOnFile ) + { + if ( nameUnit.first.contains( m_conductivityResultNameOnFile, Qt::CaseInsensitive ) ) + { + return nameUnit; + } + } + } + + return std::pair(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::pair RimThermalFractureTemplate::betaFactorParameterNameAndUnit() const +{ + if ( m_fractureDefinitionData ) + { + std::vector> propertyNamesUnitsOnFile = + m_fractureDefinitionData->getPropertyNamesUnits(); + + for ( const auto& nameUnit : propertyNamesUnitsOnFile ) + { + if ( nameUnit.first.contains( "beta", Qt::CaseInsensitive ) ) + { + return nameUnit; + } + } + } + + return std::pair(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimThermalFractureTemplate::isBetaFactorAvailableOnFile() const +{ + auto nameAndUnit = betaFactorParameterNameAndUnit(); + + return !nameAndUnit.first.isEmpty(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimThermalFractureTemplate::conversionFactorForBetaValues() const +{ + auto nameUnit = betaFactorParameterNameAndUnit(); + + double conversionFactorForBeta = 1.0; + + QString trimmedUnit = nameUnit.second.trimmed().toLower(); + if ( trimmedUnit == "/m" ) + { + conversionFactorForBeta = 1.01325E+08; + } + else if ( trimmedUnit == "/cm" ) + { + conversionFactorForBeta = 1.01325E+06; + } + else if ( trimmedUnit == "/ft" ) + { + conversionFactorForBeta = 3.088386E+07; + } + + return conversionFactorForBeta; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimThermalFractureTemplate::setDefaultConductivityResultIfEmpty() +{ + if ( m_conductivityResultNameOnFile().isEmpty() ) + { + if ( !conductivityResultNames().isEmpty() ) + { + m_conductivityResultNameOnFile = conductivityResultNames().front(); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimThermalFractureTemplate::mapUiResultNameToFileResultName( const QString& uiResultName ) const +{ + QString fileResultName; + + if ( uiResultName == RiaDefines::conductivityResultName() ) + { + fileResultName = m_conductivityResultNameOnFile(); + } + else + { + fileResultName = uiResultName; + } + + return fileResultName; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimThermalFractureTemplate::convertToUnitSystem( RiaDefines::EclipseUnitSystem neededUnit ) +{ + if ( m_fractureTemplateUnit() == neededUnit ) return; + + setUnitSystem( neededUnit ); + RimFractureTemplate::convertToUnitSystem( neededUnit ); + + m_readError = false; + loadDataAndUpdate(); + + if ( !m_fractureDefinitionData ) + { + m_readError = true; + // Force needed unit system when file reading fails to be able to open the project. + setUnitSystem( neededUnit ); + return; + } + + if ( neededUnit == RiaDefines::EclipseUnitSystem::UNITS_FIELD ) + { + m_wellPathDepthAtFracture = RiaEclipseUnitTools::meterToFeet( m_wellPathDepthAtFracture ); + } + else if ( neededUnit == RiaDefines::EclipseUnitSystem::UNITS_METRIC ) + { + m_wellPathDepthAtFracture = RiaEclipseUnitTools::feetToMeter( m_wellPathDepthAtFracture ); + } + + m_activeTimeStepIndex = static_cast( m_fractureDefinitionData->numTimeSteps() - 1 ); + bool polygonPropertySet = setBorderPolygonResultNameToDefault(); + + if ( polygonPropertySet ) + RiaLogging::info( QString( "Calculating polygon outline based on %1 at timestep %2" ) + .arg( m_borderPolygonResultName ) + .arg( m_fractureDefinitionData->timeSteps()[m_activeTimeStepIndex] ) ); + else + RiaLogging::info( QString( "Property for polygon calculation not set." ) ); + + if ( !conductivityResultNames().isEmpty() ) + { + m_conductivityResultNameOnFile = conductivityResultNames().front(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimThermalFractureTemplate::timeSteps() +{ + if ( m_fractureDefinitionData ) + { + return m_fractureDefinitionData->timeSteps(); + } + + return std::vector(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector> RimThermalFractureTemplate::uiResultNamesWithUnit() const +{ + std::vector> propertyNamesAndUnits; + + if ( m_fractureDefinitionData ) + { + QString conductivityUnit = "mD/s"; + + std::vector> tmp; + + std::vector> propertyNamesUnitsOnFile = + m_fractureDefinitionData->getPropertyNamesUnits(); + for ( const auto& nameUnitPair : propertyNamesUnitsOnFile ) + { + if ( nameUnitPair.first.contains( RiaDefines::conductivityResultName(), Qt::CaseInsensitive ) ) + { + conductivityUnit = nameUnitPair.second; + } + else + { + tmp.push_back( nameUnitPair ); + } + } + + propertyNamesAndUnits.push_back( std::make_pair( RiaDefines::conductivityResultName(), conductivityUnit ) ); + + for ( const auto& nameUnitPair : tmp ) + { + propertyNamesAndUnits.push_back( nameUnitPair ); + } + } + + return propertyNamesAndUnits; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector> RimThermalFractureTemplate::resultValues( const QString& uiResultName, + const QString& unitName, + size_t timeStepIndex ) const +{ + if ( m_fractureDefinitionData ) + { + QString fileResultName = mapUiResultNameToFileResultName( uiResultName ); + + return RigThermalFractureResultUtil::getDataAtTimeIndex( m_fractureDefinitionData, + fileResultName, + unitName, + timeStepIndex ); + } + + return std::vector>(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimThermalFractureTemplate::fractureGridResults( const QString& uiResultName, + const QString& unitName, + size_t timeStepIndex ) const +{ + if ( m_fractureDefinitionData ) + { + QString fileResultName = mapUiResultNameToFileResultName( uiResultName ); + + return RigThermalFractureResultUtil::fractureGridResults( m_fractureDefinitionData, + fileResultName, + unitName, + timeStepIndex ); + } + + return std::vector(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimThermalFractureTemplate::hasConductivity() const +{ + return ( m_fractureDefinitionData && !conductivityResultNames().isEmpty() ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimThermalFractureTemplate::resultValueAtIJ( const RigFractureGrid* fractureGrid, + const QString& uiResultName, + const QString& unitName, + size_t timeStepIndex, + size_t i, + size_t j ) +{ + auto values = resultValues( uiResultName, unitName, timeStepIndex ); + + if ( values.empty() ) return HUGE_VAL; + + size_t adjustedI = i + 1; + size_t adjustedJ = j + 1; + + if ( adjustedI >= fractureGrid->iCellCount() || adjustedJ >= fractureGrid->jCellCount() ) + { + return HUGE_VAL; + } + + return values[adjustedJ][adjustedI]; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimThermalFractureTemplate::appendDataToResultStatistics( const QString& uiResultName, + const QString& unit, + MinMaxAccumulator& minMaxAccumulator, + PosNegAccumulator& posNegAccumulator ) const +{ + if ( m_fractureDefinitionData ) + { + // QString fileResultName = mapUiResultNameToFileResultName( uiResultName ); + + // m_fractureDefinitionData->appendDataToResultStatistics( fileResultName, unit, minMaxAccumulator, + // posNegAccumulator ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimThermalFractureTemplate::fractureTriangleGeometry( std::vector* nodeCoords, + std::vector* triangleIndices, + double wellPathDepthAtFracture ) const +{ + if ( m_fractureDefinitionData ) + { + RigThermalFractureResultUtil::createFractureTriangleGeometry( m_fractureDefinitionData, + m_halfLengthScaleFactor(), + m_heightScaleFactor(), + wellPathDepthAtFracture, + nodeCoords, + triangleIndices ); + } +} + +// //-------------------------------------------------------------------------------------------------- +// /// +// //-------------------------------------------------------------------------------------------------- +// void RimThermalFractureTemplate::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) +// { +// RimMeshFractureTemplate::defineUiOrdering( uiConfigName, uiOrdering ); + +// uiOrdering.add( &m_propertiesTable ); + +// // if ( widthResultValues().empty() ) +// // { +// // m_fractureWidthType = USER_DEFINED_WIDTH; +// // } +// } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimThermalFractureTemplate::getFileSelectionFilter() const +{ + return "Reveal Open-Server Files (*.csv);;All Files (*.*)"; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::pair RimThermalFractureTemplate::wellPathDepthAtFractureRange() const +{ + // if ( !m_fractureDefinitionData ) return std::make_pair( 0.0, 1.0 ); + + // return std::make_pair( m_fractureDefinitionData->minDepth(), m_fractureDefinitionData->maxDepth() ); + + return std::make_pair( 0.0, 1.0 ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::cref RimThermalFractureTemplate::createFractureGrid( double wellPathDepthAtFracture ) const +{ + if ( m_fractureDefinitionData ) + { + return RigThermalFractureResultUtil::createFractureGrid( m_fractureDefinitionData, + m_conductivityResultNameOnFile, + m_activeTimeStepIndex, + m_halfLengthScaleFactor(), + m_heightScaleFactor(), + wellPathDepthAtFracture, + m_fractureTemplateUnit() ); + } + + return cvf::cref(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimThermalFractureTemplate::wellPathDepthAtFractureUiName() const +{ + return "Well/Fracture Intersection Depth"; +} diff --git a/ApplicationLibCode/ProjectDataModel/Completions/RimThermalFractureTemplate.h b/ApplicationLibCode/ProjectDataModel/Completions/RimThermalFractureTemplate.h new file mode 100644 index 0000000000..4a1a0e7c2f --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/Completions/RimThermalFractureTemplate.h @@ -0,0 +1,109 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2022 - Equinor ASA +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "RimMeshFractureTemplate.h" + +#include "cafPdmField.h" +#include "cafPdmObject.h" + +#include "cvfVector3.h" + +#include + +class RigThermalFractureDefinition; +class RigFractureCell; +class RigFractureGrid; + +//================================================================================================== +/// +/// +//================================================================================================== +class RimThermalFractureTemplate : public RimMeshFractureTemplate +{ + CAF_PDM_HEADER_INIT; + +public: + RimThermalFractureTemplate(); + ~RimThermalFractureTemplate() override; + + void loadDataAndUpdate() override; + void setDefaultsBasedOnFile() override; + + std::pair wellPathDepthAtFractureRange() const override; + QString wellPathDepthAtFractureUiName() const override; + + // Fracture geometry + cvf::cref createFractureGrid( double wellPathDepthAtFracture ) const override; + + void fractureTriangleGeometry( std::vector* nodeCoords, + std::vector* triangleIndices, + double wellPathDepthAtFracture ) const override; + + // Result Access + + std::vector timeSteps() override; + std::vector> uiResultNamesWithUnit() const override; + std::vector> + resultValues( const QString& uiResultName, const QString& unitName, size_t timeStepIndex ) const override; + std::vector + fractureGridResults( const QString& resultName, const QString& unitName, size_t timeStepIndex ) const override; + bool hasConductivity() const override; + double resultValueAtIJ( const RigFractureGrid* fractureGrid, + const QString& uiResultName, + const QString& unitName, + size_t timeStepIndex, + size_t i, + size_t j ) override; + + void appendDataToResultStatistics( const QString& uiResultName, + const QString& unit, + MinMaxAccumulator& minMaxAccumulator, + PosNegAccumulator& posNegAccumulator ) const override; + + void setDefaultConductivityResultIfEmpty(); + bool setBorderPolygonResultNameToDefault(); + + void computeDepthOfWellPathAtFracture(); + void computePerforationLength(); + + std::vector fractureGridResultsForUnitSystem( const QString& resultName, + const QString& unitName, + size_t timeStepIndex, + RiaDefines::EclipseUnitSystem requiredUnitSystem ) const override; + + std::pair widthParameterNameAndUnit() const override; + std::pair conductivityParameterNameAndUnit() const override; + std::pair betaFactorParameterNameAndUnit() const override; + bool isBetaFactorAvailableOnFile() const override; + + double conversionFactorForBetaValues() const; + + QString mapUiResultNameToFileResultName( const QString& uiResultName ) const; + void convertToUnitSystem( RiaDefines::EclipseUnitSystem neededUnit ) override; + + static std::pair + widthParameterNameAndUnit( std::shared_ptr fractureDefinitionData ); + +protected: + QString getFileSelectionFilter() const override; + QStringList conductivityResultNames() const override; + +private: + std::shared_ptr m_fractureDefinitionData; +}; diff --git a/ApplicationLibCode/ReservoirDataModel/CMakeLists_files.cmake b/ApplicationLibCode/ReservoirDataModel/CMakeLists_files.cmake index 85f9b358ce..f66ae9f408 100644 --- a/ApplicationLibCode/ReservoirDataModel/CMakeLists_files.cmake +++ b/ApplicationLibCode/ReservoirDataModel/CMakeLists_files.cmake @@ -61,6 +61,7 @@ set(SOURCE_GROUP_HEADER_FILES ${CMAKE_CURRENT_LIST_DIR}/RigWellPathFormations.h ${CMAKE_CURRENT_LIST_DIR}/RigStimPlanFractureDefinition.h ${CMAKE_CURRENT_LIST_DIR}/RigThermalFractureDefinition.h + ${CMAKE_CURRENT_LIST_DIR}/RigThermalFractureResultUtil.h ${CMAKE_CURRENT_LIST_DIR}/RigFractureGrid.h ${CMAKE_CURRENT_LIST_DIR}/RigFractureCell.h ${CMAKE_CURRENT_LIST_DIR}/RigWellResultPoint.h @@ -151,6 +152,7 @@ set(SOURCE_GROUP_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/RigWellPathFormations.cpp ${CMAKE_CURRENT_LIST_DIR}/RigStimPlanFractureDefinition.cpp ${CMAKE_CURRENT_LIST_DIR}/RigThermalFractureDefinition.cpp + ${CMAKE_CURRENT_LIST_DIR}/RigThermalFractureResultUtil.cpp ${CMAKE_CURRENT_LIST_DIR}/RigFractureGrid.cpp ${CMAKE_CURRENT_LIST_DIR}/RigFractureCell.cpp ${CMAKE_CURRENT_LIST_DIR}/RigWellResultPoint.cpp diff --git a/ApplicationLibCode/ReservoirDataModel/RigThermalFractureResultUtil.cpp b/ApplicationLibCode/ReservoirDataModel/RigThermalFractureResultUtil.cpp new file mode 100644 index 0000000000..6dec60f8f1 --- /dev/null +++ b/ApplicationLibCode/ReservoirDataModel/RigThermalFractureResultUtil.cpp @@ -0,0 +1,95 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2022 - Equinor ASA +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RigThermalFractureResultUtil.h" + +#include "RigFractureGrid.h" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigThermalFractureResultUtil::RigThermalFractureResultUtil() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigThermalFractureResultUtil::~RigThermalFractureResultUtil() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector> + RigThermalFractureResultUtil::getDataAtTimeIndex( std::shared_ptr fractureDefinition, + const QString& resultName, + const QString& unitName, + size_t timeStepIndex ) +{ + return std::vector>(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigThermalFractureResultUtil::createFractureTriangleGeometry( + std::shared_ptr fractureDefinition, + double xScaleFactor, + double yScaleFactor, + double wellPathIntersectionAtFractureDepth, + std::vector* vertices, + std::vector* triangleIndices ) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector + RigThermalFractureResultUtil::fractureGridResults( std::shared_ptr fractureDefinition, + const QString& resultName, + const QString& unitName, + size_t timeStepIndex ) +{ + return std::vector(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::cref + RigThermalFractureResultUtil::createFractureGrid( std::shared_ptr fractureDefinition, + const QString& resultName, + int activeTimeStepIndex, + double xScaleFactor, + double yScaleFactor, + double wellPathIntersectionAtFractureDepth, + RiaDefines::EclipseUnitSystem requiredUnitSet ) +{ + cvf::ref fractureGrid = new RigFractureGrid; + std::vector stimPlanCells; + fractureGrid->setFractureCells( stimPlanCells ); + // fractureGrid->setWellCenterFractureCellIJ( wellCenterStimPlanCellIJ ); + // fractureGrid->setICellCount( this->m_Xs.size() - 2 ); + // fractureGrid->setJCellCount( this->m_Ys.size() - 2 ); + // fractureGrid->ensureCellSearchTreeIsBuilt(); + + return cvf::cref( fractureGrid.p() ); +} diff --git a/ApplicationLibCode/ReservoirDataModel/RigThermalFractureResultUtil.h b/ApplicationLibCode/ReservoirDataModel/RigThermalFractureResultUtil.h new file mode 100644 index 0000000000..e9f9b719a5 --- /dev/null +++ b/ApplicationLibCode/ReservoirDataModel/RigThermalFractureResultUtil.h @@ -0,0 +1,69 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2022 - Equinor ASA +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RiaDefines.h" + +#include "cvfObject.h" +#include "cvfVector3.h" + +#include + +#include +#include + +class RigThermalFractureDefinition; +class RigFractureGrid; + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +class RigThermalFractureResultUtil +{ +public: + RigThermalFractureResultUtil(); + ~RigThermalFractureResultUtil(); + + static std::vector> + getDataAtTimeIndex( std::shared_ptr fractureDefinition, + const QString& resultName, + const QString& unitName, + size_t timeStepIndex ); + + static void createFractureTriangleGeometry( std::shared_ptr fractureDefinition, + double xScaleFactor, + double yScaleFactor, + double wellPathIntersectionAtFractureDepth, + std::vector* vertices, + std::vector* triangleIndices ); + + static std::vector fractureGridResults( std::shared_ptr fractureDefinition, + const QString& resultName, + const QString& unitName, + size_t timeStepIndex ); + + static cvf::cref + createFractureGrid( std::shared_ptr fractureDefinition, + const QString& resultName, + int activeTimeStepIndex, + double xScaleFactor, + double yScaleFactor, + double wellPathIntersectionAtFractureDepth, + RiaDefines::EclipseUnitSystem requiredUnitSet ); +};