diff --git a/ApplicationLibCode/Application/RiaStimPlanModelDefines.cpp b/ApplicationLibCode/Application/RiaStimPlanModelDefines.cpp index 5da5e98d36..10090bd9db 100644 --- a/ApplicationLibCode/Application/RiaStimPlanModelDefines.cpp +++ b/ApplicationLibCode/Application/RiaStimPlanModelDefines.cpp @@ -57,6 +57,7 @@ void AppEnum::setUp() addItem( RiaDefines::CurveProperty::POROSITY_UNSCALED, "POROSITY_UNSCALED", "Porosity (Unscaled)" ); addItem( RiaDefines::CurveProperty::EQLNUM, "EQLNUM", "Equilibration Number" ); addItem( RiaDefines::CurveProperty::PRESSURE_GRADIENT, "PRESSURE_GRADIENT", "Pressure Gradient" ); + addItem( RiaDefines::CurveProperty::FORMATIONS, "FORMATIONS", "Formations" ); setDefault( RiaDefines::CurveProperty::UNDEFINED ); } diff --git a/ApplicationLibCode/Application/RiaStimPlanModelDefines.h b/ApplicationLibCode/Application/RiaStimPlanModelDefines.h index 833ff779c9..58e03c985c 100644 --- a/ApplicationLibCode/Application/RiaStimPlanModelDefines.h +++ b/ApplicationLibCode/Application/RiaStimPlanModelDefines.h @@ -52,6 +52,7 @@ enum class CurveProperty POROSITY_UNSCALED, EQLNUM, PRESSURE_GRADIENT, + FORMATIONS }; double defaultPorosity(); diff --git a/ApplicationLibCode/FileInterface/RifStimPlanModelGeologicalFrkExporter.cpp b/ApplicationLibCode/FileInterface/RifStimPlanModelGeologicalFrkExporter.cpp index 4ca4c09e04..cb921fa19f 100644 --- a/ApplicationLibCode/FileInterface/RifStimPlanModelGeologicalFrkExporter.cpp +++ b/ApplicationLibCode/FileInterface/RifStimPlanModelGeologicalFrkExporter.cpp @@ -18,10 +18,13 @@ #include "RifStimPlanModelGeologicalFrkExporter.h" +#include "RiaEclipseUnitTools.h" #include "RiaLogging.h" #include "RiaPreferences.h" #include "RifCsvDataTableFormatter.h" +#include "RifStimPlanModelPerfsFrkExporter.h" +#include "RifTextDataTableFormatter.h" #include "RimStimPlanModel.h" #include "RimStimPlanModelCalculator.h" @@ -140,15 +143,33 @@ bool RifStimPlanModelGeologicalFrkExporter::writeToFile( RimStimPlanModel* stimP values["zonePoroElas"] = stimPlanModel->calculator()->calculatePoroElasticConstant(); values["zoneThermalExp"] = stimPlanModel->calculator()->calculateThermalExpansionCoefficient(); + auto [faciesIndex, faciesNames] = stimPlanModel->calculator()->calculateFacies(); + values["faciesIdx"] = faciesIndex; + if ( faciesIndex.size() != tvd.size() || faciesNames.size() != tvd.size() ) return false; + + auto [formationIndex, formationNames] = stimPlanModel->calculator()->calculateFormation(); + values["formationIdx"] = formationIndex; + if ( formationIndex.size() != tvd.size() || formationNames.size() != tvd.size() ) return false; + // Special values for csv export - auto [depthStart, depthEnd] = createDepthRanges( tvd ); - values["dpthstart"] = depthStart; - values["dpthend"] = depthEnd; - std::vector csvLabels = { "dpthstart", "dpthend" }; + auto [depthStart, depthEnd] = createDepthRanges( tvd ); + values["dpthstart"] = depthStart; + values["dpthend"] = depthEnd; + + auto [perforationTop, perforationBottom] = + RifStimPlanModelPerfsFrkExporter::calculateTopAndBottomMeasuredDepth( stimPlanModel, stimPlanModel->wellPath() ); + + values["perfs"] = createPerforationValues( depthStart, + depthEnd, + RiaEclipseUnitTools::meterToFeet( perforationTop ), + RiaEclipseUnitTools::meterToFeet( perforationBottom ) ); + + std::vector csvLabels = { "dpthstart", "dpthend", "faciesIdx", "formationIdx", "perfs" }; for ( const QString& label : labels ) csvLabels.push_back( label ); - return writeToFrkFile( filepath, labels, values ) && writeToCsvFile( filepath, csvLabels, values ); + return writeToFrkFile( filepath, labels, values ) && + writeToCsvFile( filepath, csvLabels, values, faciesNames, formationNames ); } //-------------------------------------------------------------------------------------------------- @@ -187,8 +208,9 @@ bool RifStimPlanModelGeologicalFrkExporter::writeToFrkFile( const QString& //-------------------------------------------------------------------------------------------------- bool RifStimPlanModelGeologicalFrkExporter::writeToCsvFile( const QString& filepath, const std::vector& labels, - const std::map>& values ) - + const std::map>& values, + const std::vector& faciesNames, + const std::vector& formationNames ) { // Create the csv in the same directory as the frk file QFileInfo fi( filepath ); @@ -210,6 +232,8 @@ bool RifStimPlanModelGeologicalFrkExporter::writeToCsvFile( const QString& { header.push_back( RifTextDataTableColumn( label, RifTextDataTableDoubleFormat::RIF_FLOAT ) ); } + header.push_back( RifTextDataTableColumn( "Facies" ) ); + header.push_back( RifTextDataTableColumn( "Formation" ) ); formatter.header( header ); // The length of the vectors are assumed to be equal @@ -230,6 +254,11 @@ bool RifStimPlanModelGeologicalFrkExporter::writeToCsvFile( const QString& formatter.add( vals->second[idx] ); } } + if ( !isDone ) + { + formatter.add( faciesNames[idx] ); + formatter.add( formationNames[idx] ); + } formatter.rowCompleted(); idx++; } @@ -374,3 +403,25 @@ std::pair, std::vector> return std::make_pair( startTvd, endTvd ); } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RifStimPlanModelGeologicalFrkExporter::createPerforationValues( const std::vector& depthStart, + const std::vector& depthEnd, + double perforationTop, + double perforationBottom ) +{ + std::vector perfs; + for ( size_t idx = 0; idx < depthStart.size(); idx++ ) + { + double top = depthStart[idx]; + double bottom = depthEnd[idx]; + + // Layer is perforation if end points are inside the perforation interval + bool isPerforation = !( bottom < perforationTop || top > perforationBottom ); + perfs.push_back( static_cast( isPerforation ) ); + } + + return perfs; +} diff --git a/ApplicationLibCode/FileInterface/RifStimPlanModelGeologicalFrkExporter.h b/ApplicationLibCode/FileInterface/RifStimPlanModelGeologicalFrkExporter.h index aadb08a9cc..717beec3e1 100644 --- a/ApplicationLibCode/FileInterface/RifStimPlanModelGeologicalFrkExporter.h +++ b/ApplicationLibCode/FileInterface/RifStimPlanModelGeologicalFrkExporter.h @@ -44,7 +44,9 @@ private: const std::map>& values ); static bool writeToCsvFile( const QString& filepath, const std::vector& labels, - const std::map>& values ); + const std::map>& values, + const std::vector& faciesNames, + const std::vector& formationNames ); static void appendHeaderToStream( QTextStream& stream ); static void appendToStream( QTextStream& stream, const QString& label, const std::vector& values ); @@ -59,4 +61,9 @@ private: static bool warnOnInvalidData( const QString& label, const std::vector& values ); static bool hasInvalidData( const std::vector& values ); + + static std::vector createPerforationValues( const std::vector& depthStart, + const std::vector& depthEnd, + double perforationTop, + double perforationBottom ); }; diff --git a/ApplicationLibCode/FileInterface/RifStimPlanModelPerfsFrkExporter.cpp b/ApplicationLibCode/FileInterface/RifStimPlanModelPerfsFrkExporter.cpp index 9df42a1975..901ca11efb 100644 --- a/ApplicationLibCode/FileInterface/RifStimPlanModelPerfsFrkExporter.cpp +++ b/ApplicationLibCode/FileInterface/RifStimPlanModelPerfsFrkExporter.cpp @@ -59,12 +59,7 @@ bool RifStimPlanModelPerfsFrkExporter::writeToFile( RimStimPlanModel* stimPlanMo appendFractureOrientationToStream( stream, isTransverse ); // Unit: meter - double perforationLength = stimPlanModel->perforationLength(); - - double anchorPositionMD = computeMeasuredDepthForPosition( wellPath, stimPlanModel->anchorPosition() ); - double topMD = anchorPositionMD - ( perforationLength / 2.0 ); - double bottomMD = anchorPositionMD + ( perforationLength / 2.0 ); - + auto [topMD, bottomMD] = calculateTopAndBottomMeasuredDepth( stimPlanModel, wellPath ); appendPerforationToStream( stream, 1, RiaEclipseUnitTools::meterToFeet( topMD ), @@ -158,3 +153,19 @@ double RifStimPlanModelPerfsFrkExporter::computeMeasuredDepthForPosition( const return -1.0; } } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::pair + RifStimPlanModelPerfsFrkExporter::calculateTopAndBottomMeasuredDepth( RimStimPlanModel* stimPlanModel, + RimWellPath* wellPath ) +{ + double perforationLength = stimPlanModel->perforationLength(); + + double anchorPositionMD = computeMeasuredDepthForPosition( wellPath, stimPlanModel->anchorPosition() ); + double topMD = anchorPositionMD - ( perforationLength / 2.0 ); + double bottomMD = anchorPositionMD + ( perforationLength / 2.0 ); + + return std::make_pair( topMD, bottomMD ); +} diff --git a/ApplicationLibCode/FileInterface/RifStimPlanModelPerfsFrkExporter.h b/ApplicationLibCode/FileInterface/RifStimPlanModelPerfsFrkExporter.h index fc5000c4b1..e4c1b5bfba 100644 --- a/ApplicationLibCode/FileInterface/RifStimPlanModelPerfsFrkExporter.h +++ b/ApplicationLibCode/FileInterface/RifStimPlanModelPerfsFrkExporter.h @@ -20,6 +20,8 @@ #include "cvfVector3.h" +#include + class RimStimPlanModel; class RimWellPath; @@ -34,10 +36,14 @@ class RifStimPlanModelPerfsFrkExporter public: static bool writeToFile( RimStimPlanModel* stimPlanModel, const QString& filepath ); -private: - static void appendHeaderToStream( QTextStream& stream ); - static void appendFractureOrientationToStream( QTextStream& stream, bool isTranseverse ); - static void appendPerforationToStream( QTextStream& stream, int index, double topMd, double bottomMd ); - static void appendFooterToStream( QTextStream& stream ); + static std::pair calculateTopAndBottomMeasuredDepth( RimStimPlanModel* stimPlanModel, + RimWellPath* wellPath ); + static double computeMeasuredDepthForPosition( const RimWellPath* wellPath, const cvf::Vec3d& position ); + +private: + static void appendHeaderToStream( QTextStream& stream ); + static void appendFractureOrientationToStream( QTextStream& stream, bool isTranseverse ); + static void appendPerforationToStream( QTextStream& stream, int index, double topMd, double bottomMd ); + static void appendFooterToStream( QTextStream& stream ); }; diff --git a/ApplicationLibCode/ProjectDataModel/StimPlanModel/RimStimPlanModelCalculator.cpp b/ApplicationLibCode/ProjectDataModel/StimPlanModel/RimStimPlanModelCalculator.cpp index 7b8ef268af..351f256506 100644 --- a/ApplicationLibCode/ProjectDataModel/StimPlanModel/RimStimPlanModelCalculator.cpp +++ b/ApplicationLibCode/ProjectDataModel/StimPlanModel/RimStimPlanModelCalculator.cpp @@ -24,7 +24,10 @@ #include "RigEclipseCaseData.h" +#include "RimColorLegend.h" +#include "RimEclipseCase.h" #include "RimEclipseResultDefinition.h" +#include "RimFaciesProperties.h" #include "RimStimPlanModel.h" #include "RimStimPlanModelCalculator.h" #include "RimStimPlanModelElasticPropertyCalculator.h" @@ -32,7 +35,9 @@ #include "RimStimPlanModelPressureCalculator.h" #include "RimStimPlanModelPropertyCalculator.h" #include "RimStimPlanModelStressCalculator.h" +#include "RimStimPlanModelTemplate.h" #include "RimStimPlanModelWellLogCalculator.h" +#include "RimWellLogTrack.h" #include @@ -707,6 +712,66 @@ double RimStimPlanModelCalculator::calculateStressAtDepth( double depth, return stress; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::pair, std::vector> RimStimPlanModelCalculator::calculateFacies() const +{ + std::vector values = findCurveAndComputeTopOfLayer( RiaDefines::CurveProperty::FACIES ); + std::vector faciesNames; + + RimStimPlanModelTemplate* stimPlanModelTemplate = m_stimPlanModel->stimPlanModelTemplate(); + if ( !stimPlanModelTemplate ) + { + RiaLogging::error( QString( "No fracture model template found" ) ); + return std::make_pair( values, faciesNames ); + } + + RimFaciesProperties* faciesProperties = stimPlanModelTemplate->faciesProperties(); + if ( !faciesProperties ) + { + RiaLogging::error( QString( "No facies properties found when extracting elastic properties." ) ); + return std::make_pair( values, faciesNames ); + } + + RimColorLegend* colorLegend = faciesProperties->colorLegend(); + if ( !colorLegend ) + { + RiaLogging::error( QString( "No color legend found when extracting elastic properties." ) ); + return std::make_pair( values, faciesNames ); + } + + for ( auto value : values ) + { + faciesNames.push_back( RimStimPlanModelElasticPropertyCalculator::findFaciesName( *colorLegend, value ) ); + } + + return std::make_pair( values, faciesNames ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::pair, std::vector> RimStimPlanModelCalculator::calculateFormation() const +{ + std::vector values = findCurveAndComputeTopOfLayer( RiaDefines::CurveProperty::FORMATIONS ); + + RimEclipseCase* eclipseCase = m_stimPlanModel->eclipseCaseForProperty( RiaDefines::CurveProperty::FACIES ); + std::vector formationNamesVector = RimWellLogTrack::formationNamesVector( eclipseCase ); + + std::vector formationNames; + for ( auto value : values ) + { + int idx = static_cast( value ); + if ( idx < static_cast( formationNamesVector.size() ) ) + formationNames.push_back( formationNamesVector[idx] ); + else + formationNames.push_back( "_" ); + } + + return std::make_pair( values, formationNames ); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/ProjectDataModel/StimPlanModel/RimStimPlanModelCalculator.h b/ApplicationLibCode/ProjectDataModel/StimPlanModel/RimStimPlanModelCalculator.h index 73577965c8..2fb9656783 100644 --- a/ApplicationLibCode/ProjectDataModel/StimPlanModel/RimStimPlanModelCalculator.h +++ b/ApplicationLibCode/ProjectDataModel/StimPlanModel/RimStimPlanModelCalculator.h @@ -65,6 +65,9 @@ public: std::vector calculatePoroElasticConstant() const; std::vector calculateThermalExpansionCoefficient() const; + std::pair, std::vector> calculateFacies() const; + std::pair, std::vector> calculateFormation() const; + void calculateTemperature( std::vector& temperatures ) const; void clearCache(); diff --git a/ApplicationLibCode/ProjectDataModel/StimPlanModel/RimStimPlanModelElasticPropertyCalculator.h b/ApplicationLibCode/ProjectDataModel/StimPlanModel/RimStimPlanModelElasticPropertyCalculator.h index 91b0ccbb4c..c49231a485 100644 --- a/ApplicationLibCode/ProjectDataModel/StimPlanModel/RimStimPlanModelElasticPropertyCalculator.h +++ b/ApplicationLibCode/ProjectDataModel/StimPlanModel/RimStimPlanModelElasticPropertyCalculator.h @@ -44,6 +44,8 @@ public: bool isMatching( RiaDefines::CurveProperty curveProperty ) const override; + static QString findFaciesName( const RimColorLegend& colorLegend, double value ); + protected: static void addOverburden( std::vector& formationNames, std::vector& formationValues, @@ -59,8 +61,6 @@ protected: double underburdenHeight, const QString& formationName ); - static QString findFaciesName( const RimColorLegend& colorLegend, double value ); - private: RimStimPlanModelCalculator* m_stimPlanModelCalculator; }; diff --git a/ApplicationLibCode/ProjectDataModel/StimPlanModel/RimStimPlanModelLayerCalculator.cpp b/ApplicationLibCode/ProjectDataModel/StimPlanModel/RimStimPlanModelLayerCalculator.cpp index 30fa66bb94..fa81f7f4ce 100644 --- a/ApplicationLibCode/ProjectDataModel/StimPlanModel/RimStimPlanModelLayerCalculator.cpp +++ b/ApplicationLibCode/ProjectDataModel/StimPlanModel/RimStimPlanModelLayerCalculator.cpp @@ -54,7 +54,7 @@ RimStimPlanModelLayerCalculator::RimStimPlanModelLayerCalculator( RimStimPlanMod //-------------------------------------------------------------------------------------------------- bool RimStimPlanModelLayerCalculator::isMatching( RiaDefines::CurveProperty curveProperty ) const { - return curveProperty == RiaDefines::CurveProperty::LAYERS; + return ( curveProperty == RiaDefines::CurveProperty::LAYERS || curveProperty == RiaDefines::CurveProperty::FORMATIONS ); } //-------------------------------------------------------------------------------------------------- @@ -165,7 +165,16 @@ bool RimStimPlanModelLayerCalculator::calculate( RiaDefines::CurveProperty curve layerNo++; } - values[i] = layerNo; + if ( curveProperty == RiaDefines::CurveProperty::LAYERS ) + { + values[i] = layerNo; + } + else + { + CAF_ASSERT( curveProperty == RiaDefines::CurveProperty::FORMATIONS ); + values[i] = curveData.data[i]; + } + previousFormation = curveData.data[i]; previousFacies = faciesValues[i]; if ( useNetToGross )