From fcc0f710d54fd2339db03006b90206d3907a61c3 Mon Sep 17 00:00:00 2001 From: Kristian Bendiksen Date: Mon, 6 Jul 2020 10:42:21 +0200 Subject: [PATCH 1/5] #6213 GeoMech: Add calculation of Mud Weight Window. --- .../GeoMech/GeoMechDataModel/CMakeLists.txt | 2 + ...FemPartResultCalculatorMudWeightWindow.cpp | 323 ++++++++++++++++++ ...igFemPartResultCalculatorMudWeightWindow.h | 53 +++ .../RigFemPartResultsCollection.cpp | 13 + .../RigGeoMechWellLogExtractor.h | 5 +- 5 files changed, 394 insertions(+), 2 deletions(-) create mode 100644 ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultCalculatorMudWeightWindow.cpp create mode 100644 ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultCalculatorMudWeightWindow.h diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/CMakeLists.txt b/ApplicationCode/GeoMech/GeoMechDataModel/CMakeLists.txt index 407677f59e..0b1ad06d9e 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/CMakeLists.txt +++ b/ApplicationCode/GeoMech/GeoMechDataModel/CMakeLists.txt @@ -96,6 +96,8 @@ add_library( ${PROJECT_NAME} RigFemPartResultCalculatorPoreCompressibility.cpp RigFemPartResultCalculatorPorosityPermeability.h RigFemPartResultCalculatorPorosityPermeability.cpp + RigFemPartResultCalculatorMudWeightWindow.h + RigFemPartResultCalculatorMudWeightWindow.cpp RimGeoMechGeometrySelectionItem.h RimGeoMechGeometrySelectionItem.cpp ) diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultCalculatorMudWeightWindow.cpp b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultCalculatorMudWeightWindow.cpp new file mode 100644 index 0000000000..414de8b7f9 --- /dev/null +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultCalculatorMudWeightWindow.cpp @@ -0,0 +1,323 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2020- 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 "RigFemPartResultCalculatorMudWeightWindow.h" + +#include "RigFemPart.h" +#include "RigFemPartCollection.h" +#include "RigFemPartGrid.h" +#include "RigFemPartResultsCollection.h" +#include "RigFemResultAddress.h" +#include "RigFemScalarResultFrames.h" +#include "RigGeoMechBoreHoleStressCalculator.h" +#include "RigGeoMechWellLogExtractor.h" + +#include "RiaOffshoreSphericalCoords.h" + +#include "cafProgressInfo.h" + +#include "cvfBoundingBox.h" + +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigFemPartResultCalculatorMudWeightWindow::RigFemPartResultCalculatorMudWeightWindow( RigFemPartResultsCollection& collection ) + : RigFemPartResultCalculator( collection ) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigFemPartResultCalculatorMudWeightWindow::~RigFemPartResultCalculatorMudWeightWindow() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RigFemPartResultCalculatorMudWeightWindow::isMatching( const RigFemResultAddress& resVarAddr ) const +{ + return ( resVarAddr.fieldName == "MUD-WEIGHT" && + ( resVarAddr.componentName == "MWW" || resVarAddr.componentName == "MWM" || + resVarAddr.componentName == "UMWL" || resVarAddr.componentName == "LMWL" ) ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigFemScalarResultFrames* RigFemPartResultCalculatorMudWeightWindow::calculate( int partIndex, + const RigFemResultAddress& resVarAddr ) +{ + CVF_ASSERT( isMatching( resVarAddr ) ); + + caf::ProgressInfo frameCountProgress( m_resultCollection->frameCount() * 4, "" ); + frameCountProgress.setProgressDescription( "Calculating Mud Weight Window" ); + + double wellPathDeviation = 12.3; + double wellPathAzimuth = 32.4; + double ucsBar = 3.4; + double poissonsRatio = 0.45; + double K0_FG = 0.445; + double airGap = 123.0; + + UpperLimitParameter upperLimitParameter = UpperLimitParameter::FG; + LowerLimitParameter lowerLimitParameter = LowerLimitParameter::MAX_OF_PORE_PRESSURE_AND_SFG; + + // Pore pressure + frameCountProgress.setNextProgressIncrement( m_resultCollection->frameCount() ); + RigFemScalarResultFrames* porePressureDataFrames = + m_resultCollection->findOrLoadScalarResult( partIndex, RigFemResultAddress( RIG_NODAL, "POR-Bar", "" ) ); + frameCountProgress.incrementProgress(); + + // Stress (ST.S3) + frameCountProgress.setNextProgressIncrement( m_resultCollection->frameCount() ); + RigFemScalarResultFrames* stressDataFrames = + m_resultCollection->findOrLoadScalarResult( partIndex, RigFemResultAddress( resVarAddr.resultPosType, "ST", "S3" ) ); + frameCountProgress.incrementProgress(); + + frameCountProgress.setNextProgressIncrement( m_resultCollection->frameCount() ); + + RigFemScalarResultFrames* mudWeightWindowFrames = + m_resultCollection->createScalarResult( partIndex, + RigFemResultAddress( resVarAddr.resultPosType, resVarAddr.fieldName, "MWW" ) ); + RigFemScalarResultFrames* mudWeightMiddleFrames = + m_resultCollection->createScalarResult( partIndex, + RigFemResultAddress( resVarAddr.resultPosType, resVarAddr.fieldName, "MWM" ) ); + RigFemScalarResultFrames* upperMudWeightLimitFrames = + m_resultCollection->createScalarResult( partIndex, + RigFemResultAddress( resVarAddr.resultPosType, resVarAddr.fieldName, "UMWL" ) ); + RigFemScalarResultFrames* lowerMudWeightLimitFrames = + m_resultCollection->createScalarResult( partIndex, + RigFemResultAddress( resVarAddr.resultPosType, resVarAddr.fieldName, "LMWL" ) ); + frameCountProgress.incrementProgress(); + + const RigFemPart* femPart = m_resultCollection->parts()->part( partIndex ); + const RigFemPartGrid* femPartGrid = femPart->getOrCreateStructGrid(); + + float inf = std::numeric_limits::infinity(); + + frameCountProgress.setNextProgressIncrement( 1u ); + + int frameCount = stressDataFrames->frameCount(); + for ( int fIdx = 0; fIdx < frameCount; ++fIdx ) + { + const std::vector& porFrameData = porePressureDataFrames->frameData( fIdx ); + const std::vector& stressFrameData = stressDataFrames->frameData( fIdx ); + + std::vector& mudWeightWindowFrameData = mudWeightWindowFrames->frameData( fIdx ); + std::vector& mudWeightMiddleFrameData = mudWeightMiddleFrames->frameData( fIdx ); + std::vector& upperMudWeightLimitFrameData = upperMudWeightLimitFrames->frameData( fIdx ); + std::vector& lowerMudWeightLimitFrameData = lowerMudWeightLimitFrames->frameData( fIdx ); + + size_t valCount = stressFrameData.size(); + mudWeightWindowFrameData.resize( valCount ); + mudWeightMiddleFrameData.resize( valCount ); + upperMudWeightLimitFrameData.resize( valCount ); + lowerMudWeightLimitFrameData.resize( valCount ); + + int elementCount = femPart->elementCount(); + + // Load stress + RigFemResultAddress stressResAddr( RIG_ELEMENT_NODAL, "ST", "" ); + std::vector vertexStressesFloat = m_resultCollection->tensors( stressResAddr, partIndex, fIdx ); + + std::vector vertexStresses; + vertexStresses.reserve( vertexStressesFloat.size() ); + for ( const caf::Ten3f& floatTensor : vertexStressesFloat ) + { + vertexStresses.push_back( caf::Ten3d( floatTensor ) ); + } + +#pragma omp parallel for + for ( int elmIdx = 0; elmIdx < elementCount; ++elmIdx ) + { + RigElementType elmType = femPart->elementType( elmIdx ); + + int elmNodeCount = RigFemTypes::elementNodeCount( femPart->elementType( elmIdx ) ); + + if ( elmType == HEX8P ) + { + for ( int elmNodIdx = 0; elmNodIdx < elmNodeCount; ++elmNodIdx ) + { + // Use hydrostatic pressure from cell centroid. + // Use centroid to avoid intra-element differences + cvf::Vec3d cellCentroid = femPartGrid->cellCentroid( elmIdx ); + double cellCentroidTvdRKB = std::abs( cellCentroid.z() ) + airGap; + double cellCenterHydroStaticPressure = + RiaWellLogUnitTools::hydrostaticPorePressureBar( cellCentroidTvdRKB ); + + size_t elmNodResIdx = femPart->elementNodeResultIdx( elmIdx, elmNodIdx ); + if ( elmNodResIdx < stressFrameData.size() ) + { + int nodeIdx = femPart->nodeIdxFromElementNodeResultIdx( elmNodResIdx ); + + // Pore pressure (unit: Bar) + double porePressureBar = porFrameData[nodeIdx]; + + // FG is for sands, SFG for shale. Sands has valid PP, shale does not. + bool isSand = ( porePressureBar != inf ); + + caf::Ten3d segmentStress = caf::Ten3d( vertexStressesFloat[nodeIdx] ); + + cvf::Vec3d wellPathTangent = calculateWellPathTangent( wellPathAzimuth, wellPathDeviation ); + caf::Ten3d wellPathStressFloat = + RigGeoMechWellLogExtractor::transformTensorToWellPathOrientation( wellPathTangent, + segmentStress ); + caf::Ten3d wellPathStressDouble( wellPathStressFloat ); + + RigGeoMechBoreHoleStressCalculator sigmaCalculator( wellPathStressDouble, + porePressureBar, + poissonsRatio, + ucsBar, + 32 ); + + // Calculate upper limit + float upperLimit = inf; + if ( upperLimitParameter == UpperLimitParameter::FG ) + { + upperLimit = sigmaCalculator.solveFractureGradient(); + } + else if ( upperLimitParameter == UpperLimitParameter::SH_MIN ) + { + upperLimit = stressFrameData[elmNodResIdx]; + } + + // Calculate lower limit + float lowerLimit = inf; + if ( lowerLimitParameter == LowerLimitParameter::PORE_PRESSURE ) + { + lowerLimit = porePressureBar; + } + else if ( lowerLimitParameter == LowerLimitParameter::MAX_OF_PORE_PRESSURE_AND_SFG ) + { + if ( isSand ) + { + lowerLimit = porePressureBar; + } + else + { + double SFG = sigmaCalculator.solveStassiDalia(); + lowerLimit = std::max( porePressureBar, SFG ); + } + } + + // Normalize by hydrostatic pore pressure + upperMudWeightLimitFrameData[elmNodResIdx] = upperLimit / cellCenterHydroStaticPressure; + lowerMudWeightLimitFrameData[elmNodResIdx] = lowerLimit / cellCenterHydroStaticPressure; + } + } + } + else + { + for ( int elmNodIdx = 0; elmNodIdx < elmNodeCount; ++elmNodIdx ) + { + size_t elmNodResIdx = femPart->elementNodeResultIdx( elmIdx, elmNodIdx ); + if ( elmNodResIdx < stressFrameData.size() ) + { + mudWeightWindowFrameData[elmNodResIdx] = inf; + mudWeightMiddleFrameData[elmNodResIdx] = inf; + upperMudWeightLimitFrameData[elmNodResIdx] = inf; + lowerMudWeightLimitFrameData[elmNodResIdx] = inf; + } + } + } + } + + size_t kRefLayer = 28; // resVarAddr.refKLayerIndex; + +#pragma omp parallel for + for ( int elmIdx = 0; elmIdx < elementCount; ++elmIdx ) + { + RigElementType elmType = femPart->elementType( elmIdx ); + + int elmNodeCount = RigFemTypes::elementNodeCount( femPart->elementType( elmIdx ) ); + + size_t i, j, k; + bool validIndex = femPartGrid->ijkFromCellIndex( elmIdx, &i, &j, &k ); + size_t kMin = std::min( k, kRefLayer ); + size_t kMax = std::max( k, kRefLayer ); + + if ( elmType == HEX8P && validIndex ) + { + for ( int elmNodIdx = 0; elmNodIdx < elmNodeCount; ++elmNodIdx ) + { + size_t elmNodResIdx = femPart->elementNodeResultIdx( elmIdx, elmNodIdx ); + + float maxLowerMudWeightLimit = 0.0; + float minUpperMudWeightLimit = 0.0; + if ( kMin == kMax ) + { + maxLowerMudWeightLimit = lowerMudWeightLimitFrameData[elmNodResIdx]; + minUpperMudWeightLimit = upperMudWeightLimitFrameData[elmNodResIdx]; + } + else + { + for ( size_t currentK = kMin; currentK < kMax; currentK++ ) + { + size_t kElmIdx = femPartGrid->cellIndexFromIJK( i, j, currentK ); + if ( kElmIdx != cvf::UNDEFINED_SIZE_T && femPart->elementType( kElmIdx ) == HEX8P ) + { + size_t kElmNodResIdx = femPart->elementNodeResultIdx( kElmIdx, elmNodIdx ); + + float currentLowerMudWeightLimit = lowerMudWeightLimitFrameData[kElmNodResIdx]; + if ( currentLowerMudWeightLimit > maxLowerMudWeightLimit ) + { + maxLowerMudWeightLimit = currentLowerMudWeightLimit; + } + + float currentUpperMudWeightLimit = upperMudWeightLimitFrameData[kElmNodResIdx]; + if ( currentUpperMudWeightLimit > minUpperMudWeightLimit ) + { + minUpperMudWeightLimit = currentUpperMudWeightLimit; + } + } + } + } + + float mudWeightWindow = minUpperMudWeightLimit - maxLowerMudWeightLimit; + mudWeightWindowFrameData[elmNodResIdx] = mudWeightWindow; + + float mudWeightMiddle = inf; + if ( mudWeightWindow > 0.0 ) + { + mudWeightMiddle = maxLowerMudWeightLimit + mudWeightWindow / 2.0; + } + mudWeightMiddleFrameData[elmNodResIdx] = mudWeightMiddle; + } + } + } + + frameCountProgress.incrementProgress(); + } + + RigFemScalarResultFrames* requestedResultFrames = m_resultCollection->findOrLoadScalarResult( partIndex, resVarAddr ); + return requestedResultFrames; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec3d RigFemPartResultCalculatorMudWeightWindow::calculateWellPathTangent( double azimuth, double inclination ) +{ + double aziRad = cvf::Math::toRadians( azimuth ); + double incRad = cvf::Math::toRadians( inclination ); + return RiaOffshoreSphericalCoords::unitVectorFromAziInc( aziRad, incRad ); +} diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultCalculatorMudWeightWindow.h b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultCalculatorMudWeightWindow.h new file mode 100644 index 0000000000..3ef1db8926 --- /dev/null +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultCalculatorMudWeightWindow.h @@ -0,0 +1,53 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2020- 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 "RigFemPartResultCalculator.h" + +class RigFemPartResultsCollection; +class RigFemScalarResultFrames; +class RigFemResultAddress; + +#include "cvfVector3.h" + +//================================================================================================== +/// +//================================================================================================== +class RigFemPartResultCalculatorMudWeightWindow : public RigFemPartResultCalculator +{ +public: + enum class UpperLimitParameter + { + FG, + SH_MIN + }; + + enum class LowerLimitParameter + { + PORE_PRESSURE, + MAX_OF_PORE_PRESSURE_AND_SFG + }; + + explicit RigFemPartResultCalculatorMudWeightWindow( RigFemPartResultsCollection& collection ); + virtual ~RigFemPartResultCalculatorMudWeightWindow(); + bool isMatching( const RigFemResultAddress& resVarAddr ) const override; + RigFemScalarResultFrames* calculate( int partIndex, const RigFemResultAddress& resVarAddr ) override; + + cvf::Vec3d calculateWellPathTangent( double azimuth, double inclination ); +}; diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.cpp b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.cpp index c75a68cdce..adeb75e045 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.cpp +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.cpp @@ -39,6 +39,7 @@ #include "RigFemPartResultCalculatorFOS.h" #include "RigFemPartResultCalculatorFormationIndices.h" #include "RigFemPartResultCalculatorGamma.h" +#include "RigFemPartResultCalculatorMudWeightWindow.h" #include "RigFemPartResultCalculatorNE.h" #include "RigFemPartResultCalculatorNodalGradients.h" #include "RigFemPartResultCalculatorNormalSE.h" @@ -173,6 +174,8 @@ RigFemPartResultsCollection::RigFemPartResultsCollection( RifGeoMechReaderInterf std::unique_ptr( new RigFemPartResultCalculatorPoreCompressibility( *this ) ) ); m_resultCalculators.push_back( std::unique_ptr( new RigFemPartResultCalculatorPorosityPermeability( *this ) ) ); + m_resultCalculators.push_back( + std::unique_ptr( new RigFemPartResultCalculatorMudWeightWindow( *this ) ) ); m_resultCalculators.push_back( std::unique_ptr( new RigFemPartResultCalculatorFormationIndices( *this ) ) ); } @@ -707,6 +710,11 @@ std::map> fieldCompNames["PORO-PERM"].push_back( "PHI" ); fieldCompNames["PORO-PERM"].push_back( "DPHI" ); fieldCompNames["PORO-PERM"].push_back( "PERM" ); + + fieldCompNames["MUD-WEIGHT"].push_back( "MWW" ); + fieldCompNames["MUD-WEIGHT"].push_back( "MWM" ); + fieldCompNames["MUD-WEIGHT"].push_back( "UMWL" ); + fieldCompNames["MUD-WEIGHT"].push_back( "LMWL" ); } else if ( resPos == RIG_INTEGRATION_POINT ) { @@ -790,6 +798,11 @@ std::map> fieldCompNames["PORO-PERM"].push_back( "PHI" ); fieldCompNames["PORO-PERM"].push_back( "DPHI" ); fieldCompNames["PORO-PERM"].push_back( "PERM" ); + + fieldCompNames["MUD-WEIGHT"].push_back( "MWW" ); + fieldCompNames["MUD-WEIGHT"].push_back( "MWM" ); + fieldCompNames["MUD-WEIGHT"].push_back( "UMWL" ); + fieldCompNames["MUD-WEIGHT"].push_back( "LMWL" ); } else if ( resPos == RIG_ELEMENT_NODAL_FACE ) { diff --git a/ApplicationCode/ReservoirDataModel/RigGeoMechWellLogExtractor.h b/ApplicationCode/ReservoirDataModel/RigGeoMechWellLogExtractor.h index be63f47ee8..342827ba60 100644 --- a/ApplicationCode/ReservoirDataModel/RigGeoMechWellLogExtractor.h +++ b/ApplicationCode/ReservoirDataModel/RigGeoMechWellLogExtractor.h @@ -81,6 +81,9 @@ public: std::vector poissonSourceRegions( int frameIndex ); std::vector ucsSourceRegions( int frameIndex ); + static caf::Ten3d transformTensorToWellPathOrientation( const cvf::Vec3d& wellPathTangent, + const caf::Ten3d& wellPathTensor ); + private: enum WellPathTangentCalculation { @@ -122,8 +125,6 @@ private: cvf::Vec3d calculateLengthInCell( size_t cellIndex, const cvf::Vec3d& startPoint, const cvf::Vec3d& endPoint ) const override; cvf::Vec3d calculateWellPathTangent( int64_t intersectionIdx, WellPathTangentCalculation calculationType ) const; - static caf::Ten3d transformTensorToWellPathOrientation( const cvf::Vec3d& wellPathTangent, - const caf::Ten3d& wellPathTensor ); cvf::Vec3f cellCentroid( size_t intersectionIdx ) const; double getWellLogIntersectionValue( size_t intersectionIdx, From 5d99526d985d4670a6709d228f92a63e6539de11 Mon Sep 17 00:00:00 2001 From: Kristian Bendiksen Date: Mon, 3 Aug 2020 14:06:59 +0200 Subject: [PATCH 2/5] #6213 Add UI for configuring "mud-weight window" calculation. --- ...FemPartResultCalculatorMudWeightWindow.cpp | 149 +++++- ...igFemPartResultCalculatorMudWeightWindow.h | 37 +- .../RigFemPartResultsCollection.cpp | 119 +++++ .../RigFemPartResultsCollection.h | 26 + .../ProjectDataModel/CMakeLists_files.cmake | 2 + .../ProjectDataModel/RimGeoMechCase.cpp | 20 + .../ProjectDataModel/RimGeoMechCase.h | 23 +- .../RimMudWeightWindowParameters.cpp | 483 ++++++++++++++++++ .../RimMudWeightWindowParameters.h | 136 +++++ 9 files changed, 958 insertions(+), 37 deletions(-) create mode 100644 ApplicationCode/ProjectDataModel/RimMudWeightWindowParameters.cpp create mode 100644 ApplicationCode/ProjectDataModel/RimMudWeightWindowParameters.h diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultCalculatorMudWeightWindow.cpp b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultCalculatorMudWeightWindow.cpp index 414de8b7f9..b8f61d8ed5 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultCalculatorMudWeightWindow.cpp +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultCalculatorMudWeightWindow.cpp @@ -68,18 +68,31 @@ RigFemScalarResultFrames* RigFemPartResultCalculatorMudWeightWindow::calculate( { CVF_ASSERT( isMatching( resVarAddr ) ); - caf::ProgressInfo frameCountProgress( m_resultCollection->frameCount() * 4, "" ); + const std::vector parameterTypes = + {RimMudWeightWindowParameters::ParameterType::WELL_DEVIATION, + RimMudWeightWindowParameters::ParameterType::WELL_AZIMUTH, + RimMudWeightWindowParameters::ParameterType::UCS, + RimMudWeightWindowParameters::ParameterType::POISSONS_RATIO, + RimMudWeightWindowParameters::ParameterType::K0_FG}; + + caf::ProgressInfo frameCountProgress( m_resultCollection->frameCount() * ( 4 + parameterTypes.size() ), "" ); frameCountProgress.setProgressDescription( "Calculating Mud Weight Window" ); - double wellPathDeviation = 12.3; - double wellPathAzimuth = 32.4; - double ucsBar = 3.4; - double poissonsRatio = 0.45; - double K0_FG = 0.445; - double airGap = 123.0; + std::map parameterFrames; + std::map parameterValues; - UpperLimitParameter upperLimitParameter = UpperLimitParameter::FG; - LowerLimitParameter lowerLimitParameter = LowerLimitParameter::MAX_OF_PORE_PRESSURE_AND_SFG; + for ( auto parameterType : parameterTypes ) + { + frameCountProgress.setNextProgressIncrement( m_resultCollection->frameCount() ); + loadParameterFramesOrValue( parameterType, partIndex, parameterFrames, parameterValues ); + frameCountProgress.incrementProgress(); + } + + double airGap = m_resultCollection->airGapMudWeightWindow(); + RimMudWeightWindowParameters::UpperLimitType upperLimitParameter = + m_resultCollection->upperLimitParameterMudWeightWindow(); + RimMudWeightWindowParameters::LowerLimitType lowerLimitParameter = + m_resultCollection->lowerLimitParameterMudWeightWindow(); // Pore pressure frameCountProgress.setNextProgressIncrement( m_resultCollection->frameCount() ); @@ -135,6 +148,12 @@ RigFemScalarResultFrames* RigFemPartResultCalculatorMudWeightWindow::calculate( int elementCount = femPart->elementCount(); + std::map> parameterFrameData; + for ( auto parameterType : parameterTypes ) + { + parameterFrameData[parameterType] = loadDataForFrame( parameterType, parameterFrames, fIdx ); + } + // Load stress RigFemResultAddress stressResAddr( RIG_ELEMENT_NODAL, "ST", "" ); std::vector vertexStressesFloat = m_resultCollection->tensors( stressResAddr, partIndex, fIdx ); @@ -151,6 +170,31 @@ RigFemScalarResultFrames* RigFemPartResultCalculatorMudWeightWindow::calculate( { RigElementType elmType = femPart->elementType( elmIdx ); + double wellPathDeviation = getValueForElement( RimMudWeightWindowParameters::ParameterType::WELL_DEVIATION, + parameterFrameData, + parameterValues, + elmIdx ); + + double wellPathAzimuth = getValueForElement( RimMudWeightWindowParameters::ParameterType::WELL_AZIMUTH, + parameterFrameData, + parameterValues, + elmIdx ); + + double ucsBar = getValueForElement( RimMudWeightWindowParameters::ParameterType::UCS, + parameterFrameData, + parameterValues, + elmIdx ); + + double poissonsRatio = getValueForElement( RimMudWeightWindowParameters::ParameterType::POISSONS_RATIO, + parameterFrameData, + parameterValues, + elmIdx ); + + double K0_FG = getValueForElement( RimMudWeightWindowParameters::ParameterType::K0_FG, + parameterFrameData, + parameterValues, + elmIdx ); + int elmNodeCount = RigFemTypes::elementNodeCount( femPart->elementType( elmIdx ) ); if ( elmType == HEX8P ) @@ -191,22 +235,23 @@ RigFemScalarResultFrames* RigFemPartResultCalculatorMudWeightWindow::calculate( // Calculate upper limit float upperLimit = inf; - if ( upperLimitParameter == UpperLimitParameter::FG ) + if ( upperLimitParameter == RimMudWeightWindowParameters::UpperLimitType::FG ) { upperLimit = sigmaCalculator.solveFractureGradient(); } - else if ( upperLimitParameter == UpperLimitParameter::SH_MIN ) + else if ( upperLimitParameter == RimMudWeightWindowParameters::UpperLimitType::SH_MIN ) { upperLimit = stressFrameData[elmNodResIdx]; } // Calculate lower limit float lowerLimit = inf; - if ( lowerLimitParameter == LowerLimitParameter::PORE_PRESSURE ) + if ( lowerLimitParameter == RimMudWeightWindowParameters::LowerLimitType::PORE_PRESSURE ) { lowerLimit = porePressureBar; } - else if ( lowerLimitParameter == LowerLimitParameter::MAX_OF_PORE_PRESSURE_AND_SFG ) + else if ( lowerLimitParameter == + RimMudWeightWindowParameters::LowerLimitType::MAX_OF_PORE_PRESSURE_AND_SFG ) { if ( isSand ) { @@ -241,7 +286,7 @@ RigFemScalarResultFrames* RigFemPartResultCalculatorMudWeightWindow::calculate( } } - size_t kRefLayer = 28; // resVarAddr.refKLayerIndex; + size_t kRefLayer = m_resultCollection->referenceLayerMudWeightWindow(); #pragma omp parallel for for ( int elmIdx = 0; elmIdx < elementCount; ++elmIdx ) @@ -321,3 +366,79 @@ cvf::Vec3d RigFemPartResultCalculatorMudWeightWindow::calculateWellPathTangent( double incRad = cvf::Math::toRadians( inclination ); return RiaOffshoreSphericalCoords::unitVectorFromAziInc( aziRad, incRad ); } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFemPartResultCalculatorMudWeightWindow::loadParameterFramesOrValue( + RimMudWeightWindowParameters::ParameterType parameterType, + size_t partIndex, + std::map& parameterFrames, + std::map& parameterValues ) +{ + RigFemScalarResultFrames* resultFrames = nullptr; + + QString resultAddress = m_resultCollection->getCalculationParameterAddress( parameterType ); + if ( !resultAddress.isEmpty() ) + { + resultFrames = + m_resultCollection->findOrLoadScalarResult( partIndex, + RigFemResultAddress( RIG_ELEMENT, resultAddress.toStdString(), "" ) ); + parameterFrames[parameterType] = resultFrames; + } + + parameterValues[parameterType] = m_resultCollection->getCalculationParameterValue( parameterType ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RigFemPartResultCalculatorMudWeightWindow::loadDataForFrame( + RimMudWeightWindowParameters::ParameterType parameterType, + std::map& parameterFrames, + int frameIndex ) +{ + auto it = parameterFrames.find( parameterType ); + if ( it != parameterFrames.end() ) + { + RigFemScalarResultFrames* frame = it->second; + std::vector dataForFrame = frame->frameData( frameIndex ); + return dataForFrame; + } + else + { + return std::vector(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +float RigFemPartResultCalculatorMudWeightWindow::getValueForElement( + RimMudWeightWindowParameters::ParameterType parameterType, + const std::map>& parameterFrameData, + const std::map parameterValues, + int elmIdx ) +{ + // Use data per element if available + auto it = parameterFrameData.find( parameterType ); + if ( it != parameterFrameData.end() ) + { + if ( !it->second.empty() && static_cast( elmIdx ) < it->second.size() ) + { + return it->second[elmIdx]; + } + } + + // Use fixed value + auto value = parameterValues.find( parameterType ); + if ( value != parameterValues.end() ) + { + return value->second; + } + else + { + // No value found (should not happen) + return std::numeric_limits::infinity(); + } +} diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultCalculatorMudWeightWindow.h b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultCalculatorMudWeightWindow.h index 3ef1db8926..14ae16f5ec 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultCalculatorMudWeightWindow.h +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultCalculatorMudWeightWindow.h @@ -20,34 +20,43 @@ #include "RigFemPartResultCalculator.h" +#include "RimMudWeightWindowParameters.h" + +#include "cvfVector3.h" + +#include + class RigFemPartResultsCollection; class RigFemScalarResultFrames; class RigFemResultAddress; -#include "cvfVector3.h" - //================================================================================================== /// //================================================================================================== class RigFemPartResultCalculatorMudWeightWindow : public RigFemPartResultCalculator { public: - enum class UpperLimitParameter - { - FG, - SH_MIN - }; - - enum class LowerLimitParameter - { - PORE_PRESSURE, - MAX_OF_PORE_PRESSURE_AND_SFG - }; - explicit RigFemPartResultCalculatorMudWeightWindow( RigFemPartResultsCollection& collection ); virtual ~RigFemPartResultCalculatorMudWeightWindow(); bool isMatching( const RigFemResultAddress& resVarAddr ) const override; RigFemScalarResultFrames* calculate( int partIndex, const RigFemResultAddress& resVarAddr ) override; cvf::Vec3d calculateWellPathTangent( double azimuth, double inclination ); + +private: + void loadParameterFramesOrValue( RimMudWeightWindowParameters::ParameterType parameterType, + size_t partIndex, + std::map& parameterFrames, + std::map& parameterValues ); + + static std::vector + loadDataForFrame( RimMudWeightWindowParameters::ParameterType parameterType, + std::map& parameterFrames, + int frameIndex ); + + static float + getValueForElement( RimMudWeightWindowParameters::ParameterType parameterType, + const std::map>& parameterFrameData, + const std::map parameterValues, + int elmIdx ); }; diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.cpp b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.cpp index adeb75e045..43e3bdc726 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.cpp +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.cpp @@ -119,6 +119,9 @@ RigFemPartResultsCollection::RigFemPartResultsCollection( RifGeoMechReaderInterf m_initialPermeabilityResultAddress = ""; m_permeabilityExponent = 1.0; + m_airGapMudWeightWindow = 0.0; + m_referenceLayerMudWeightWindow = 0; + m_resultCalculators.push_back( std::unique_ptr( new RigFemPartResultCalculatorTimeLapse( *this ) ) ); m_resultCalculators.push_back( @@ -1338,6 +1341,23 @@ std::set RigFemPartResultsCollection::referenceCaseDependen return results; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::set RigFemPartResultsCollection::mudWeightWindowResults() +{ + std::set results; + for ( auto elmType : {RIG_ELEMENT_NODAL, RIG_INTEGRATION_POINT} ) + { + results.insert( RigFemResultAddress( elmType, "MUD-WEIGHT", "MWW", RigFemResultAddress::allTimeLapsesValue() ) ); + results.insert( RigFemResultAddress( elmType, "MUD-WEIGHT", "MWM", RigFemResultAddress::allTimeLapsesValue() ) ); + results.insert( RigFemResultAddress( elmType, "MUD-WEIGHT", "UMWL", RigFemResultAddress::allTimeLapsesValue() ) ); + results.insert( RigFemResultAddress( elmType, "MUD-WEIGHT", "LMWL", RigFemResultAddress::allTimeLapsesValue() ) ); + } + + return results; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -1619,3 +1639,102 @@ bool RigFemPartResultsCollection::isValidBiotData( const std::vector& bio return true; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFemPartResultsCollection::setCalculationParameters( RimMudWeightWindowParameters::ParameterType parameterType, + const QString& address, + double value ) +{ + parameterAddresses[parameterType] = address; + parameterValues[parameterType] = value; + + // Invalidate dependent results + for ( auto result : mudWeightWindowResults() ) + { + this->deleteResult( result ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RigFemPartResultsCollection::getCalculationParameterValue( RimMudWeightWindowParameters::ParameterType parameterType ) const +{ + auto it = parameterValues.find( parameterType ); + if ( it != parameterValues.end() ) + return it->second; + else + { + // TODO: log error maybe? + return 1.0; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RigFemPartResultsCollection::getCalculationParameterAddress( RimMudWeightWindowParameters::ParameterType parameterType ) const +{ + auto it = parameterAddresses.find( parameterType ); + if ( it != parameterAddresses.end() ) + return it->second; + else + { + // TODO: log error maybe? + return QString(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RigFemPartResultsCollection::airGapMudWeightWindow() const +{ + return m_airGapMudWeightWindow; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimMudWeightWindowParameters::UpperLimitType RigFemPartResultsCollection::upperLimitParameterMudWeightWindow() const +{ + return m_upperLimitParameterMudWeightWindow; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimMudWeightWindowParameters::LowerLimitType RigFemPartResultsCollection::lowerLimitParameterMudWeightWindow() const +{ + return m_lowerLimitParameterMudWeightWindow; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t RigFemPartResultsCollection::referenceLayerMudWeightWindow() const +{ + return m_referenceLayerMudWeightWindow; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFemPartResultsCollection::setMudWeightWindowParameters( double airGap, + RimMudWeightWindowParameters::UpperLimitType upperLimit, + RimMudWeightWindowParameters::LowerLimitType lowerLimit, + int referenceLayer ) +{ + m_airGapMudWeightWindow = airGap; + m_upperLimitParameterMudWeightWindow = upperLimit; + m_lowerLimitParameterMudWeightWindow = lowerLimit; + m_referenceLayerMudWeightWindow = referenceLayer; + + // Invalidate dependent results + for ( auto result : mudWeightWindowResults() ) + { + this->deleteResult( result ); + } +} diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.h b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.h index 0d877fefbb..f5bcea04f5 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.h +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.h @@ -21,6 +21,8 @@ #include "RigFemResultAddress.h" +#include "RimMudWeightWindowParameters.h" + #include "cafTensor3.h" #include "cvfCollection.h" @@ -80,6 +82,21 @@ public: QString initialPermeabilityAddress() const; double permeabilityExponent() const; + void setCalculationParameters( RimMudWeightWindowParameters::ParameterType parameterType, + const QString& address, + double value ); + double getCalculationParameterValue( RimMudWeightWindowParameters::ParameterType ) const; + QString getCalculationParameterAddress( RimMudWeightWindowParameters::ParameterType ) const; + + void setMudWeightWindowParameters( double airGap, + RimMudWeightWindowParameters::UpperLimitType upperLimit, + RimMudWeightWindowParameters::LowerLimitType lowerLimit, + int referenceLayer ); + double airGapMudWeightWindow() const; + RimMudWeightWindowParameters::UpperLimitType upperLimitParameterMudWeightWindow() const; + RimMudWeightWindowParameters::LowerLimitType lowerLimitParameterMudWeightWindow() const; + size_t referenceLayerMudWeightWindow() const; + std::map> scalarFieldAndComponentNames( RigFemResultPosEnum resPos ); std::vector filteredStepNames() const; bool assertResultsLoaded( const RigFemResultAddress& resVarAddr ); @@ -144,6 +161,7 @@ public: static bool isReferenceCaseDependentResult( const RigFemResultAddress& result ); static std::set initialPermeabilityDependentResults(); + static std::set mudWeightWindowResults(); RigFemScalarResultFrames* findOrLoadScalarResult( int partIndex, const RigFemResultAddress& resVarAddr ); RigFemScalarResultFrames* createScalarResult( int partIndex, const RigFemResultAddress& resVarAddr ); @@ -178,6 +196,14 @@ private: int m_referenceTimeStep; + double m_airGapMudWeightWindow; + int m_referenceLayerMudWeightWindow; + RimMudWeightWindowParameters::UpperLimitType m_upperLimitParameterMudWeightWindow; + RimMudWeightWindowParameters::LowerLimitType m_lowerLimitParameterMudWeightWindow; + + std::map parameterAddresses; + std::map parameterValues; + std::vector> m_resultCalculators; RigStatisticsDataCache* statistics( const RigFemResultAddress& resVarAddr ); diff --git a/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake b/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake index 0638c13aed..4967eb6d3e 100644 --- a/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake +++ b/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake @@ -138,6 +138,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RimEclipseContourMapViewCollection.h ${CMAKE_CURRENT_LIST_DIR}/RimGeoMechContourMapProjection.h ${CMAKE_CURRENT_LIST_DIR}/RimGeoMechContourMapView.h ${CMAKE_CURRENT_LIST_DIR}/RimGeoMechContourMapViewCollection.h +${CMAKE_CURRENT_LIST_DIR}/RimMudWeightWindowParameters.h ${CMAKE_CURRENT_LIST_DIR}/RimViewNameConfig.h ${CMAKE_CURRENT_LIST_DIR}/RimReloadCaseTools.h ${CMAKE_CURRENT_LIST_DIR}/RimPlotAxisPropertiesInterface.h @@ -231,6 +232,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RimGeoMechPropertyFilter.cpp ${CMAKE_CURRENT_LIST_DIR}/RimGeoMechPropertyFilterCollection.cpp ${CMAKE_CURRENT_LIST_DIR}/RimGeoMechResultDefinition.cpp ${CMAKE_CURRENT_LIST_DIR}/RimGeoMechCellColors.cpp +${CMAKE_CURRENT_LIST_DIR}/RimMudWeightWindowParameters.cpp ${CMAKE_CURRENT_LIST_DIR}/RimViewWindow.cpp ${CMAKE_CURRENT_LIST_DIR}/Rim3dView.cpp ${CMAKE_CURRENT_LIST_DIR}/RimGridView.cpp diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechCase.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechCase.cpp index 4d73afa76c..1473b3de96 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechCase.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechCase.cpp @@ -44,6 +44,7 @@ #include "RimGeoMechView.h" #include "RimIntersectionCollection.h" #include "RimMainPlotCollection.h" +#include "RimMudWeightWindowParameters.h" #include "RimProject.h" #include "RimTimeStepFilter.h" #include "RimTools.h" @@ -179,6 +180,15 @@ RimGeoMechCase::RimGeoMechCase( void ) CAF_PDM_InitFieldNoDefault( &m_contourMapCollection, "ContourMaps", "2d Contour Maps", "", "", "" ); m_contourMapCollection = new RimGeoMechContourMapViewCollection; m_contourMapCollection.uiCapability()->setUiTreeHidden( true ); + + CAF_PDM_InitFieldNoDefault( &m_mudWeightWindowParameters, + "MudWeightWindowParameters", + "Mud Weight Window Parameters", + "", + "", + "" ); + m_mudWeightWindowParameters = new RimMudWeightWindowParameters; + m_mudWeightWindowParameters.uiCapability()->setUiTreeHidden( true ); } //-------------------------------------------------------------------------------------------------- @@ -406,6 +416,8 @@ std::vector RimGeoMechCase::allSpecialViews() const //-------------------------------------------------------------------------------------------------- void RimGeoMechCase::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName /*= ""*/ ) { + uiTreeOrdering.add( &m_mudWeightWindowParameters ); + std::vector children; geoMechViews.childObjects( &children ); @@ -1250,3 +1262,11 @@ std::vector RimGeoMechCase::possibleElementPropertyFieldNames() } return fieldNames; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimGeoMechCase::elementPropertyFileNames() const +{ + return m_elementPropertyFileNames(); +} diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechCase.h b/ApplicationCode/ProjectDataModel/RimGeoMechCase.h index d9793441f8..1c528aff17 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechCase.h +++ b/ApplicationCode/ProjectDataModel/RimGeoMechCase.h @@ -36,6 +36,7 @@ class RigGeoMechCaseData; class RifGeoMechReaderInterface; class RimGeoMechContourMapView; class RimGeoMechContourMapViewCollection; +class RimMudWeightWindowParameters; //================================================================================================== /// @@ -111,6 +112,14 @@ public: QString initialPermeabilityAddress() const; double permeabilityExponent() const; + std::vector possibleElementPropertyFieldNames(); + std::vector elementPropertyFileNames() const; + + QString findFileNameForElementProperty( const std::string& elementProperty, + const std::map addressesInFiles ) const; + + void updateConnectedViews(); + private: cvf::Vec3d displayModelOffset() const override; static std::vector vectorOfValidDateTimesFromTimeStepStrings( const QStringList& timeStepStrings ); @@ -125,20 +134,15 @@ private: QList calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions, bool* useOptionsOnly ) override; - QString findFileNameForElementProperty( const std::string& elementProperty, - const std::map addressesInFiles ) const; - void updateFormationNamesData() override; void initAfterRead() override; static QString subStringOfDigits( const QString& timeStepString, int numberOfDigitsToFind ); - void importElementPropertyFile(); - void closeSelectedElementPropertyFiles(); - void reloadSelectedElementPropertyFiles(); - std::vector allSpecialViews() const override; - void updateConnectedViews(); - std::vector possibleElementPropertyFieldNames(); + void importElementPropertyFile(); + void closeSelectedElementPropertyFiles(); + void reloadSelectedElementPropertyFiles(); + std::vector allSpecialViews() const override; private: cvf::ref m_geoMechCaseData; @@ -160,6 +164,7 @@ private: caf::PdmField m_permeabilityExponent; caf::PdmChildField m_contourMapCollection; + caf::PdmChildField m_mudWeightWindowParameters; bool m_applyTimeFilter; }; diff --git a/ApplicationCode/ProjectDataModel/RimMudWeightWindowParameters.cpp b/ApplicationCode/ProjectDataModel/RimMudWeightWindowParameters.cpp new file mode 100644 index 0000000000..9252348642 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimMudWeightWindowParameters.cpp @@ -0,0 +1,483 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2020- 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 "RimMudWeightWindowParameters.h" + +#include "RiaLogging.h" + +#include "RigFemPartResultsCollection.h" +#include "RigGeoMechCaseData.h" + +#include "RimGeoMechCase.h" + +#include "cafPdmFieldIOScriptability.h" +#include "cafPdmObjectScriptability.h" +#include "cafPdmUiDoubleValueEditor.h" +#include "cafPdmUiListEditor.h" +#include "cafPdmUiPropertyViewDialog.h" +#include "cafPdmUiTreeOrdering.h" + +CAF_PDM_SOURCE_INIT( RimMudWeightWindowParameters, "RimMudWeightWindowParameters" ); + +namespace caf +{ +template <> +void caf::AppEnum::setUp() +{ + addItem( RimMudWeightWindowParameters::SourceType::FIXED, "FIXED", "Fixed" ); + addItem( RimMudWeightWindowParameters::SourceType::PER_ELEMENT, "PER_ELEMENT", "From element properties" ); + setDefault( RimMudWeightWindowParameters::SourceType::FIXED ); +} + +template <> +void caf::AppEnum::setUp() +{ + addItem( RimMudWeightWindowParameters::ParameterType::WELL_DEVIATION, "WELL_DEVIATION", "Well Deviation" ); + addItem( RimMudWeightWindowParameters::ParameterType::WELL_AZIMUTH, "WELL_AZIMUTH", "Well Azimuth" ); + addItem( RimMudWeightWindowParameters::ParameterType::UCS, "UCS", "UCS" ); + addItem( RimMudWeightWindowParameters::ParameterType::POISSONS_RATIO, "POISSONS_RARIO", "Poisson's Ratio" ); + addItem( RimMudWeightWindowParameters::ParameterType::K0_FG, "K0_FG", "K0 FG" ); + setDefault( RimMudWeightWindowParameters::ParameterType::WELL_DEVIATION ); +} + +template <> +void caf::AppEnum::setUp() +{ + addItem( RimMudWeightWindowParameters::UpperLimitType::FG, "FG", "Fracture Gradient" ); + addItem( RimMudWeightWindowParameters::UpperLimitType::SH_MIN, "SH_MIN", "Minimum Horizontal Stress" ); + setDefault( RimMudWeightWindowParameters::UpperLimitType::FG ); +} + +template <> +void caf::AppEnum::setUp() +{ + addItem( RimMudWeightWindowParameters::LowerLimitType::PORE_PRESSURE, "PORE_PRESSURE", "Pore Pressure" ); + addItem( RimMudWeightWindowParameters::LowerLimitType::MAX_OF_PORE_PRESSURE_AND_SFG, + "MAX_OF_PORE_PRESSURE_AND_SFG", + "Maximum of Pore Pressure and SFG" ); + setDefault( RimMudWeightWindowParameters::LowerLimitType::PORE_PRESSURE ); +} + +} // End namespace caf + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimMudWeightWindowParameters::RimMudWeightWindowParameters( void ) +{ + CAF_PDM_InitScriptableObjectWithNameAndComment( "Mud Weight Window Parameters", + "", + "", + "The Mud Weight Window Calculation Parameters", + "MudWeightWindowParameters", + "" ); + + caf::AppEnum defaultSourceType = RimMudWeightWindowParameters::SourceType::FIXED; + + CAF_PDM_InitField( &m_wellDeviationType, "WellDeviationSourceType", defaultSourceType, "Well Deviation", "", "", "" ); + CAF_PDM_InitField( &m_wellDeviationFixed, "WellDeviationFixed", 0.0, "Fixed", "", "", "" ); + m_wellDeviationFixed.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() ); + + CAF_PDM_InitField( &m_wellDeviationAddress, "WellDeviationAddress", QString( "" ), "Value", "", "", "" ); + m_wellDeviationAddress.uiCapability()->setUiEditorTypeName( caf::PdmUiListEditor::uiEditorTypeName() ); + + CAF_PDM_InitField( &m_wellAzimuthType, "WellAzimuthSourceType", defaultSourceType, "Well Azimuth", "", "", "" ); + CAF_PDM_InitField( &m_wellAzimuthFixed, "WellAzimuthFixed", 0.0, "Fixed", "", "", "" ); + m_wellAzimuthFixed.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() ); + + CAF_PDM_InitField( &m_wellAzimuthAddress, "WellAzimuthAddress", QString( "" ), "Value", "", "", "" ); + m_wellAzimuthAddress.uiCapability()->setUiEditorTypeName( caf::PdmUiListEditor::uiEditorTypeName() ); + + CAF_PDM_InitField( &m_UCSType, "UCSSourceType", defaultSourceType, "UCS", "", "", "" ); + CAF_PDM_InitField( &m_UCSFixed, "UCSFixed", 1.0, "Fixed", "", "", "" ); + m_UCSFixed.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() ); + + CAF_PDM_InitField( &m_UCSAddress, "UCSAddress", QString( "" ), "Value", "", "", "" ); + m_UCSAddress.uiCapability()->setUiEditorTypeName( caf::PdmUiListEditor::uiEditorTypeName() ); + + CAF_PDM_InitField( &m_poissonsRatioType, "PoissonsRatioSourceType", defaultSourceType, "Poisson's Ratio", "", "", "" ); + CAF_PDM_InitField( &m_poissonsRatioFixed, "PoissonsRatioFixed", 0.3, "Fixed", "", "", "" ); + m_poissonsRatioFixed.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() ); + + CAF_PDM_InitField( &m_poissonsRatioAddress, "PoissonsRatioAddress", QString( "" ), "Value", "", "", "" ); + m_poissonsRatioAddress.uiCapability()->setUiEditorTypeName( caf::PdmUiListEditor::uiEditorTypeName() ); + + CAF_PDM_InitField( &m_K0_FGType, "K0_FGSourceType", defaultSourceType, "K0 FG", "", "", "" ); + CAF_PDM_InitField( &m_K0_FGFixed, "K0_FGFixed", 1.0, "Fixed", "", "", "" ); + m_K0_FGFixed.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() ); + + CAF_PDM_InitField( &m_K0_FGAddress, "K0_FGAddress", QString( "" ), "Value", "", "", "" ); + m_K0_FGAddress.uiCapability()->setUiEditorTypeName( caf::PdmUiListEditor::uiEditorTypeName() ); + + CAF_PDM_InitField( &m_airGap, "AirGap", 0.0, "Air Gap", "", "", "" ); + + caf::AppEnum defaultUpperLimitType = RimMudWeightWindowParameters::UpperLimitType::FG; + CAF_PDM_InitField( &m_upperLimitType, "UpperLimitType", defaultUpperLimitType, "Upper Limit Type", "", "", "" ); + + caf::AppEnum defaultLowerLimitType = + RimMudWeightWindowParameters::LowerLimitType::MAX_OF_PORE_PRESSURE_AND_SFG; + CAF_PDM_InitField( &m_lowerLimitType, "LowerLimitType", defaultLowerLimitType, "Lower Limit Type", "", "", "" ); + + CAF_PDM_InitField( &m_referenceLayer, "ReferenceLayer", 0, "Reference Layer", "", "", "" ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimMudWeightWindowParameters::SourceType RimMudWeightWindowParameters::wellDeviationType() const +{ + return m_wellDeviationType(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimMudWeightWindowParameters::wellDeviation() const +{ + return m_wellDeviationFixed; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimMudWeightWindowParameters::wellDeviationAddress() const +{ + return m_wellDeviationAddress; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimMudWeightWindowParameters::SourceType RimMudWeightWindowParameters::wellAzimuthType() const +{ + return m_wellAzimuthType(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimMudWeightWindowParameters::wellAzimuth() const +{ + return m_wellAzimuthFixed; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimMudWeightWindowParameters::wellAzimuthAddress() const +{ + return m_wellAzimuthAddress; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimMudWeightWindowParameters::SourceType RimMudWeightWindowParameters::ucsType() const +{ + return m_UCSType(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimMudWeightWindowParameters::ucs() const +{ + return m_UCSFixed; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimMudWeightWindowParameters::ucsAddress() const +{ + return m_UCSAddress; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimMudWeightWindowParameters::SourceType RimMudWeightWindowParameters::poissonsRatioType() const +{ + return m_poissonsRatioType(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimMudWeightWindowParameters::poissonsRatio() const +{ + return m_poissonsRatioFixed(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimMudWeightWindowParameters::poissonsRatioAddress() const +{ + return m_poissonsRatioAddress; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimMudWeightWindowParameters::SourceType RimMudWeightWindowParameters::K0_FG_Type() const +{ + return m_K0_FGType(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimMudWeightWindowParameters::K0_FG() const +{ + return m_K0_FGFixed; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimMudWeightWindowParameters::K0_FGAddress() const +{ + return m_K0_FGAddress; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimMudWeightWindowParameters::airGap() const +{ + return m_airGap; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimMudWeightWindowParameters::fieldChangedByUi( const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue ) +{ + RimGeoMechCase* geoMechCase = nullptr; + firstAncestorOrThisOfType( geoMechCase ); + if ( !geoMechCase ) + { + return; + } + + if ( changedField == &m_wellDeviationFixed || changedField == &m_wellDeviationType || + changedField == &m_wellDeviationAddress ) + { + handleFieldChanged( geoMechCase, + ParameterType::WELL_DEVIATION, + &m_wellDeviationType, + &m_wellDeviationFixed, + &m_wellDeviationAddress, + changedField == &m_wellDeviationType ); + } + else if ( changedField == &m_wellAzimuthFixed || changedField == &m_wellAzimuthType || + changedField == &m_wellAzimuthAddress ) + { + handleFieldChanged( geoMechCase, + ParameterType::WELL_AZIMUTH, + &m_wellAzimuthType, + &m_wellAzimuthFixed, + &m_wellAzimuthAddress, + changedField == &m_wellAzimuthType ); + } + + else if ( changedField == &m_UCSFixed || changedField == &m_UCSType || changedField == &m_UCSAddress ) + { + handleFieldChanged( geoMechCase, ParameterType::UCS, &m_UCSType, &m_UCSFixed, &m_UCSAddress, changedField == &m_UCSType ); + } + + else if ( changedField == &m_poissonsRatioFixed || changedField == &m_poissonsRatioType || + changedField == &m_poissonsRatioAddress ) + { + handleFieldChanged( geoMechCase, + ParameterType::POISSONS_RATIO, + &m_poissonsRatioType, + &m_poissonsRatioFixed, + &m_poissonsRatioAddress, + changedField == &m_poissonsRatioType ); + } + + else if ( changedField == &m_K0_FGFixed || changedField == &m_K0_FGType || changedField == &m_K0_FGAddress ) + { + handleFieldChanged( geoMechCase, + ParameterType::K0_FG, + &m_K0_FGType, + &m_K0_FGFixed, + &m_K0_FGAddress, + changedField == &m_K0_FGType ); + } + else if ( changedField == &m_airGap || changedField == &m_upperLimitType || changedField == &m_lowerLimitType || + changedField == &m_referenceLayer ) + { + RigGeoMechCaseData* rigCaseData = geoMechCase->geoMechData(); + if ( rigCaseData && rigCaseData->femPartResults() ) + { + rigCaseData->femPartResults()->setMudWeightWindowParameters( m_airGap, + m_upperLimitType.value(), + m_lowerLimitType.value(), + m_referenceLayer ); + geoMechCase->updateConnectedViews(); + } + } +} + +void RimMudWeightWindowParameters::handleFieldChanged( RimGeoMechCase* geoMechCase, + ParameterType parameterType, + caf::PdmField>* typeField, + caf::PdmField* fixedField, + caf::PdmField* addressField, + bool typeFieldChanged ) + +{ + RigGeoMechCaseData* rigCaseData = geoMechCase->geoMechData(); + + if ( rigCaseData && rigCaseData->femPartResults() ) + { + if ( typeField->value() == RimMudWeightWindowParameters::SourceType::FIXED ) + { + rigCaseData->femPartResults()->setCalculationParameters( parameterType, "", fixedField->value() ); + } + else if ( typeField->value() == RimMudWeightWindowParameters::SourceType::PER_ELEMENT ) + { + if ( typeFieldChanged ) + { + // Show info message to user when selecting "from file" option before + // an element property has been imported + std::vector elementProperties = geoMechCase->possibleElementPropertyFieldNames(); + if ( elementProperties.empty() ) + { + QString title = caf::AppEnum::uiText( parameterType ); + QString importMessage = + QString( "Please import '%1' from file by " + "selecting 'Import Element Property Table' on the Geomechanical Model." ) + .arg( title ); + RiaLogging::info( importMessage ); + // Set back to default value + *typeField = RimMudWeightWindowParameters::SourceType::FIXED; + return; + } + } + + if ( addressField->value().isEmpty() ) + { + // Automatically select the first available property element if empty + std::vector elementProperties = geoMechCase->possibleElementPropertyFieldNames(); + if ( !elementProperties.empty() ) + { + *addressField = QString::fromStdString( elementProperties[0] ); + } + } + + rigCaseData->femPartResults()->setCalculationParameters( parameterType, + addressField->value(), + fixedField->value() ); + } + } + + geoMechCase->updateConnectedViews(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimMudWeightWindowParameters::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) +{ + defineGroup( uiOrdering, "Well Deviation", &m_wellDeviationType, &m_wellDeviationFixed, &m_wellDeviationAddress ); + defineGroup( uiOrdering, "Well Azimuth", &m_wellAzimuthType, &m_wellAzimuthFixed, &m_wellAzimuthAddress ); + defineGroup( uiOrdering, "UCS", &m_UCSType, &m_UCSFixed, &m_UCSAddress ); + defineGroup( uiOrdering, "Poisson's Ratio", &m_poissonsRatioType, &m_poissonsRatioFixed, &m_poissonsRatioAddress ); + defineGroup( uiOrdering, "K0 for Fracture Gradient Factor for Shale", &m_K0_FGType, &m_K0_FGFixed, &m_K0_FGAddress ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimMudWeightWindowParameters::defineGroup( caf::PdmUiOrdering& uiOrdering, + const QString& title, + caf::PdmField>* typeField, + caf::PdmField* fixedField, + caf::PdmField* addressField ) +{ + caf::PdmUiGroup* group = uiOrdering.addNewGroup( title ); + group->add( typeField ); + group->add( fixedField ); + group->add( addressField ); + + fixedField->uiCapability()->setUiHidden( *typeField != RimMudWeightWindowParameters::SourceType::FIXED ); + addressField->uiCapability()->setUiHidden( *typeField != RimMudWeightWindowParameters::SourceType::PER_ELEMENT ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimMudWeightWindowParameters::defineEditorAttribute( const caf::PdmFieldHandle* field, + QString uiConfigName, + caf::PdmUiEditorAttribute* attribute ) +{ + if ( field == &m_wellDeviationFixed || field == &m_wellAzimuthFixed ) + { + auto uiDoubleValueEditorAttr = dynamic_cast( attribute ); + if ( uiDoubleValueEditorAttr ) + { + uiDoubleValueEditorAttr->m_validator = new QDoubleValidator( 0.0, 360.0, 3 ); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QList + RimMudWeightWindowParameters::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions, + bool* useOptionsOnly ) +{ + QList options; + + RimGeoMechCase* geoMechCase = nullptr; + firstAncestorOrThisOfType( geoMechCase ); + + if ( geoMechCase != nullptr && + ( fieldNeedingOptions == &m_wellDeviationAddress || fieldNeedingOptions == &m_wellAzimuthAddress || + fieldNeedingOptions == &m_UCSAddress || fieldNeedingOptions == &m_poissonsRatioAddress || + fieldNeedingOptions == &m_K0_FGAddress ) ) + { + std::vector elementProperties = geoMechCase->possibleElementPropertyFieldNames(); + + std::vector elementPropertyFileNames = geoMechCase->elementPropertyFileNames(); + std::vector paths; + for ( auto path : elementPropertyFileNames ) + { + paths.push_back( path.path() ); + } + + std::map addressesInFile = + geoMechCase->geoMechData()->femPartResults()->addressesInElementPropertyFiles( paths ); + + for ( const std::string elementProperty : elementProperties ) + { + QString result = QString::fromStdString( elementProperty ); + QString filename = geoMechCase->findFileNameForElementProperty( elementProperty, addressesInFile ); + options.push_back( caf::PdmOptionItemInfo( result + " (" + filename + ")", result ) ); + } + } + + return options; +} diff --git a/ApplicationCode/ProjectDataModel/RimMudWeightWindowParameters.h b/ApplicationCode/ProjectDataModel/RimMudWeightWindowParameters.h new file mode 100644 index 0000000000..d6c4306748 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimMudWeightWindowParameters.h @@ -0,0 +1,136 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2020- 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 "cafPdmField.h" +#include "cafPdmObject.h" + +class RimGeoMechCase; + +//================================================================================================== +/// +/// +//================================================================================================== +class RimMudWeightWindowParameters : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; + +public: + enum class SourceType + { + FIXED = 0, + PER_ELEMENT + }; + + enum class ParameterType + { + WELL_DEVIATION, + WELL_AZIMUTH, + UCS, + POISSONS_RATIO, + K0_FG + }; + + enum class UpperLimitType + { + FG, + SH_MIN + }; + + enum class LowerLimitType + { + PORE_PRESSURE, + MAX_OF_PORE_PRESSURE_AND_SFG + }; + + RimMudWeightWindowParameters( void ); + + SourceType wellDeviationType() const; + double wellDeviation() const; + QString wellDeviationAddress() const; + + SourceType wellAzimuthType() const; + double wellAzimuth() const; + QString wellAzimuthAddress() const; + + SourceType ucsType() const; + double ucs() const; + QString ucsAddress() const; + + SourceType poissonsRatioType() const; + double poissonsRatio() const; + QString poissonsRatioAddress() const; + + SourceType K0_FG_Type() const; + double K0_FG() const; + QString K0_FGAddress() const; + + double airGap() const; + +private: + void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override; + void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override; + void defineEditorAttribute( const caf::PdmFieldHandle* field, + QString uiConfigName, + caf::PdmUiEditorAttribute* attribute ) override; + + QList calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions, + bool* useOptionsOnly ) override; + + void defineGroup( caf::PdmUiOrdering& uiOrdering, + const QString& title, + caf::PdmField>* typeField, + caf::PdmField* fixedField, + caf::PdmField* addressField ); + + void handleFieldChanged( RimGeoMechCase* geoMechCase, + ParameterType parameterType, + caf::PdmField>* typeField, + caf::PdmField* fixedField, + caf::PdmField* addressField, + bool typeFieldChanged ); + +private: + caf::PdmField> m_wellDeviationType; + caf::PdmField m_wellDeviationFixed; + caf::PdmField m_wellDeviationAddress; + + caf::PdmField> m_wellAzimuthType; + caf::PdmField m_wellAzimuthFixed; + caf::PdmField m_wellAzimuthAddress; + + caf::PdmField> m_UCSType; + caf::PdmField m_UCSFixed; + caf::PdmField m_UCSAddress; + + caf::PdmField> m_poissonsRatioType; + caf::PdmField m_poissonsRatioFixed; + caf::PdmField m_poissonsRatioAddress; + + caf::PdmField> m_K0_FGType; + caf::PdmField m_K0_FGFixed; + caf::PdmField m_K0_FGAddress; + + caf::PdmField m_airGap; + + caf::PdmField> m_upperLimitType; + caf::PdmField> m_lowerLimitType; + + caf::PdmField m_referenceLayer; +}; From 91410c4434b87f91217e182107c45eddec1c1057 Mon Sep 17 00:00:00 2001 From: Kristian Bendiksen Date: Thu, 6 Aug 2020 06:54:29 +0200 Subject: [PATCH 3/5] #6213 Improve UI for selecting mud weight window reference layer. --- .../RimMudWeightWindowParameters.cpp | 69 ++++++++++++++----- 1 file changed, 50 insertions(+), 19 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimMudWeightWindowParameters.cpp b/ApplicationCode/ProjectDataModel/RimMudWeightWindowParameters.cpp index 9252348642..72ed3356e6 100644 --- a/ApplicationCode/ProjectDataModel/RimMudWeightWindowParameters.cpp +++ b/ApplicationCode/ProjectDataModel/RimMudWeightWindowParameters.cpp @@ -20,6 +20,8 @@ #include "RiaLogging.h" +#include "RigFemPartCollection.h" +#include "RigFemPartGrid.h" #include "RigFemPartResultsCollection.h" #include "RigGeoMechCaseData.h" @@ -133,7 +135,7 @@ RimMudWeightWindowParameters::RimMudWeightWindowParameters( void ) RimMudWeightWindowParameters::LowerLimitType::MAX_OF_PORE_PRESSURE_AND_SFG; CAF_PDM_InitField( &m_lowerLimitType, "LowerLimitType", defaultLowerLimitType, "Lower Limit Type", "", "", "" ); - CAF_PDM_InitField( &m_referenceLayer, "ReferenceLayer", 0, "Reference Layer", "", "", "" ); + CAF_PDM_InitField( &m_referenceLayer, "ReferenceLayer", -1, "Reference Layer", "", "", "" ); } //-------------------------------------------------------------------------------------------------- @@ -405,6 +407,21 @@ void RimMudWeightWindowParameters::defineUiOrdering( QString uiConfigName, caf:: defineGroup( uiOrdering, "UCS", &m_UCSType, &m_UCSFixed, &m_UCSAddress ); defineGroup( uiOrdering, "Poisson's Ratio", &m_poissonsRatioType, &m_poissonsRatioFixed, &m_poissonsRatioAddress ); defineGroup( uiOrdering, "K0 for Fracture Gradient Factor for Shale", &m_K0_FGType, &m_K0_FGFixed, &m_K0_FGAddress ); + + RimGeoMechCase* geoMechCase = nullptr; + firstAncestorOrThisOfType( geoMechCase ); + if ( !geoMechCase ) + { + return; + } + + RigGeoMechCaseData* rigCaseData = geoMechCase->geoMechData(); + + if ( rigCaseData && m_referenceLayer == -1 ) + { + m_referenceLayer = + (int)rigCaseData->femParts()->part( 0 )->getOrCreateStructGrid()->reservoirIJKBoundingBox().first.z(); + } } //-------------------------------------------------------------------------------------------------- @@ -454,28 +471,42 @@ QList RimGeoMechCase* geoMechCase = nullptr; firstAncestorOrThisOfType( geoMechCase ); - if ( geoMechCase != nullptr && - ( fieldNeedingOptions == &m_wellDeviationAddress || fieldNeedingOptions == &m_wellAzimuthAddress || - fieldNeedingOptions == &m_UCSAddress || fieldNeedingOptions == &m_poissonsRatioAddress || - fieldNeedingOptions == &m_K0_FGAddress ) ) + if ( geoMechCase != nullptr ) { - std::vector elementProperties = geoMechCase->possibleElementPropertyFieldNames(); - - std::vector elementPropertyFileNames = geoMechCase->elementPropertyFileNames(); - std::vector paths; - for ( auto path : elementPropertyFileNames ) + if ( fieldNeedingOptions == &m_wellDeviationAddress || fieldNeedingOptions == &m_wellAzimuthAddress || + fieldNeedingOptions == &m_UCSAddress || fieldNeedingOptions == &m_poissonsRatioAddress || + fieldNeedingOptions == &m_K0_FGAddress ) { - paths.push_back( path.path() ); + std::vector elementProperties = geoMechCase->possibleElementPropertyFieldNames(); + + std::vector elementPropertyFileNames = geoMechCase->elementPropertyFileNames(); + std::vector paths; + for ( auto path : elementPropertyFileNames ) + { + paths.push_back( path.path() ); + } + + std::map addressesInFile = + geoMechCase->geoMechData()->femPartResults()->addressesInElementPropertyFiles( paths ); + + for ( const std::string elementProperty : elementProperties ) + { + QString result = QString::fromStdString( elementProperty ); + QString filename = geoMechCase->findFileNameForElementProperty( elementProperty, addressesInFile ); + options.push_back( caf::PdmOptionItemInfo( result + " (" + filename + ")", result ) ); + } } - - std::map addressesInFile = - geoMechCase->geoMechData()->femPartResults()->addressesInElementPropertyFiles( paths ); - - for ( const std::string elementProperty : elementProperties ) + else if ( fieldNeedingOptions == &m_referenceLayer ) { - QString result = QString::fromStdString( elementProperty ); - QString filename = geoMechCase->findFileNameForElementProperty( elementProperty, addressesInFile ); - options.push_back( caf::PdmOptionItemInfo( result + " (" + filename + ")", result ) ); + if ( geoMechCase->geoMechData() ) + { + size_t kCount = + geoMechCase->geoMechData()->femParts()->part( 0 )->getOrCreateStructGrid()->gridPointCountK() - 1; + for ( size_t layerIdx = 0; layerIdx < kCount; ++layerIdx ) + { + options.push_back( caf::PdmOptionItemInfo( QString::number( layerIdx + 1 ), (int)layerIdx ) ); + } + } } } From fee4318b92bc313710983b7b2f921a88ea587555 Mon Sep 17 00:00:00 2001 From: Kristian Bendiksen Date: Thu, 6 Aug 2020 11:36:12 +0200 Subject: [PATCH 4/5] #6213 Fix comparison of lower limit, and simplify initialization. --- ...FemPartResultCalculatorMudWeightWindow.cpp | 39 ++++++++----------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultCalculatorMudWeightWindow.cpp b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultCalculatorMudWeightWindow.cpp index b8f61d8ed5..955247b8b1 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultCalculatorMudWeightWindow.cpp +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultCalculatorMudWeightWindow.cpp @@ -306,33 +306,26 @@ RigFemScalarResultFrames* RigFemPartResultCalculatorMudWeightWindow::calculate( { size_t elmNodResIdx = femPart->elementNodeResultIdx( elmIdx, elmNodIdx ); - float maxLowerMudWeightLimit = 0.0; - float minUpperMudWeightLimit = 0.0; - if ( kMin == kMax ) + float maxLowerMudWeightLimit = lowerMudWeightLimitFrameData[elmNodResIdx]; + float minUpperMudWeightLimit = upperMudWeightLimitFrameData[elmNodResIdx]; + + for ( size_t currentK = kMin; currentK < kMax; currentK++ ) { - maxLowerMudWeightLimit = lowerMudWeightLimitFrameData[elmNodResIdx]; - minUpperMudWeightLimit = upperMudWeightLimitFrameData[elmNodResIdx]; - } - else - { - for ( size_t currentK = kMin; currentK < kMax; currentK++ ) + size_t kElmIdx = femPartGrid->cellIndexFromIJK( i, j, currentK ); + if ( kElmIdx != cvf::UNDEFINED_SIZE_T && femPart->elementType( kElmIdx ) == HEX8P ) { - size_t kElmIdx = femPartGrid->cellIndexFromIJK( i, j, currentK ); - if ( kElmIdx != cvf::UNDEFINED_SIZE_T && femPart->elementType( kElmIdx ) == HEX8P ) + size_t kElmNodResIdx = femPart->elementNodeResultIdx( kElmIdx, elmNodIdx ); + + float currentLowerMudWeightLimit = lowerMudWeightLimitFrameData[kElmNodResIdx]; + if ( currentLowerMudWeightLimit > maxLowerMudWeightLimit ) { - size_t kElmNodResIdx = femPart->elementNodeResultIdx( kElmIdx, elmNodIdx ); + maxLowerMudWeightLimit = currentLowerMudWeightLimit; + } - float currentLowerMudWeightLimit = lowerMudWeightLimitFrameData[kElmNodResIdx]; - if ( currentLowerMudWeightLimit > maxLowerMudWeightLimit ) - { - maxLowerMudWeightLimit = currentLowerMudWeightLimit; - } - - float currentUpperMudWeightLimit = upperMudWeightLimitFrameData[kElmNodResIdx]; - if ( currentUpperMudWeightLimit > minUpperMudWeightLimit ) - { - minUpperMudWeightLimit = currentUpperMudWeightLimit; - } + float currentUpperMudWeightLimit = upperMudWeightLimitFrameData[kElmNodResIdx]; + if ( currentUpperMudWeightLimit < minUpperMudWeightLimit ) + { + minUpperMudWeightLimit = currentUpperMudWeightLimit; } } } From 372df1e407c4240ec0a7e70e7369e43cc97ec163 Mon Sep 17 00:00:00 2001 From: Kristian Bendiksen Date: Thu, 6 Aug 2020 14:44:04 +0200 Subject: [PATCH 5/5] #6213 Make input fields and default values more similar to WBS plot. --- .../RimMudWeightWindowParameters.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimMudWeightWindowParameters.cpp b/ApplicationCode/ProjectDataModel/RimMudWeightWindowParameters.cpp index 72ed3356e6..e0c34b24f1 100644 --- a/ApplicationCode/ProjectDataModel/RimMudWeightWindowParameters.cpp +++ b/ApplicationCode/ProjectDataModel/RimMudWeightWindowParameters.cpp @@ -92,35 +92,35 @@ RimMudWeightWindowParameters::RimMudWeightWindowParameters( void ) caf::AppEnum defaultSourceType = RimMudWeightWindowParameters::SourceType::FIXED; CAF_PDM_InitField( &m_wellDeviationType, "WellDeviationSourceType", defaultSourceType, "Well Deviation", "", "", "" ); - CAF_PDM_InitField( &m_wellDeviationFixed, "WellDeviationFixed", 0.0, "Fixed", "", "", "" ); + CAF_PDM_InitField( &m_wellDeviationFixed, "WellDeviationFixed", 0.0, "Fixed Well Deviation", "", "", "" ); m_wellDeviationFixed.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() ); CAF_PDM_InitField( &m_wellDeviationAddress, "WellDeviationAddress", QString( "" ), "Value", "", "", "" ); m_wellDeviationAddress.uiCapability()->setUiEditorTypeName( caf::PdmUiListEditor::uiEditorTypeName() ); CAF_PDM_InitField( &m_wellAzimuthType, "WellAzimuthSourceType", defaultSourceType, "Well Azimuth", "", "", "" ); - CAF_PDM_InitField( &m_wellAzimuthFixed, "WellAzimuthFixed", 0.0, "Fixed", "", "", "" ); + CAF_PDM_InitField( &m_wellAzimuthFixed, "WellAzimuthFixed", 0.0, "Fixed Well Azimuth", "", "", "" ); m_wellAzimuthFixed.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() ); CAF_PDM_InitField( &m_wellAzimuthAddress, "WellAzimuthAddress", QString( "" ), "Value", "", "", "" ); m_wellAzimuthAddress.uiCapability()->setUiEditorTypeName( caf::PdmUiListEditor::uiEditorTypeName() ); - CAF_PDM_InitField( &m_UCSType, "UCSSourceType", defaultSourceType, "UCS", "", "", "" ); - CAF_PDM_InitField( &m_UCSFixed, "UCSFixed", 1.0, "Fixed", "", "", "" ); + CAF_PDM_InitField( &m_UCSType, "UCSSourceType", defaultSourceType, "UCS [Bar]", "", "", "" ); + CAF_PDM_InitField( &m_UCSFixed, "UCSFixed", 100.0, "Fixed UCS [Bar]", "", "", "" ); m_UCSFixed.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() ); CAF_PDM_InitField( &m_UCSAddress, "UCSAddress", QString( "" ), "Value", "", "", "" ); m_UCSAddress.uiCapability()->setUiEditorTypeName( caf::PdmUiListEditor::uiEditorTypeName() ); CAF_PDM_InitField( &m_poissonsRatioType, "PoissonsRatioSourceType", defaultSourceType, "Poisson's Ratio", "", "", "" ); - CAF_PDM_InitField( &m_poissonsRatioFixed, "PoissonsRatioFixed", 0.3, "Fixed", "", "", "" ); + CAF_PDM_InitField( &m_poissonsRatioFixed, "PoissonsRatioFixed", 0.35, "Fixed Possion's Ratio", "", "", "" ); m_poissonsRatioFixed.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() ); CAF_PDM_InitField( &m_poissonsRatioAddress, "PoissonsRatioAddress", QString( "" ), "Value", "", "", "" ); m_poissonsRatioAddress.uiCapability()->setUiEditorTypeName( caf::PdmUiListEditor::uiEditorTypeName() ); CAF_PDM_InitField( &m_K0_FGType, "K0_FGSourceType", defaultSourceType, "K0 FG", "", "", "" ); - CAF_PDM_InitField( &m_K0_FGFixed, "K0_FGFixed", 1.0, "Fixed", "", "", "" ); + CAF_PDM_InitField( &m_K0_FGFixed, "K0_FGFixed", 0.75, "Fixed K0_FG", "", "", "" ); m_K0_FGFixed.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() ); CAF_PDM_InitField( &m_K0_FGAddress, "K0_FGAddress", QString( "" ), "Value", "", "", "" ); @@ -433,10 +433,9 @@ void RimMudWeightWindowParameters::defineGroup( caf::PdmUiOrdering& caf::PdmField* fixedField, caf::PdmField* addressField ) { - caf::PdmUiGroup* group = uiOrdering.addNewGroup( title ); - group->add( typeField ); - group->add( fixedField ); - group->add( addressField ); + uiOrdering.add( typeField ); + uiOrdering.add( fixedField ); + uiOrdering.add( addressField ); fixedField->uiCapability()->setUiHidden( *typeField != RimMudWeightWindowParameters::SourceType::FIXED ); addressField->uiCapability()->setUiHidden( *typeField != RimMudWeightWindowParameters::SourceType::PER_ELEMENT );