diff --git a/ApplicationCode/Commands/CMakeLists_files.cmake b/ApplicationCode/Commands/CMakeLists_files.cmake index a528229374..12c6a76858 100644 --- a/ApplicationCode/Commands/CMakeLists_files.cmake +++ b/ApplicationCode/Commands/CMakeLists_files.cmake @@ -92,6 +92,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RicDeleteTemporaryLgrsFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicExportContourMapToTextFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicExportContourMapToTextUi.h ${CMAKE_CURRENT_LIST_DIR}/RicNewMultiPlotFeature.h +${CMAKE_CURRENT_LIST_DIR}/RicExportFractureModelPlotToFileFeature.h ) @@ -182,6 +183,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RicDeleteTemporaryLgrsFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicExportContourMapToTextFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicExportContourMapToTextUi.cpp ${CMAKE_CURRENT_LIST_DIR}/RicNewMultiPlotFeature.cpp +${CMAKE_CURRENT_LIST_DIR}/RicExportFractureModelPlotToFileFeature.cpp ) diff --git a/ApplicationCode/Commands/RicExportFractureModelPlotToFileFeature.cpp b/ApplicationCode/Commands/RicExportFractureModelPlotToFileFeature.cpp new file mode 100644 index 0000000000..ee84bdd591 --- /dev/null +++ b/ApplicationCode/Commands/RicExportFractureModelPlotToFileFeature.cpp @@ -0,0 +1,77 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// 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 "RicExportFractureModelPlotToFileFeature.h" + +#include "RiaApplication.h" + +#include "RimFractureModelPlot.h" + +#include "RifFractureModelPlotExporter.h" + +#include "cafSelectionManager.h" +#include "cafUtils.h" + +#include +#include + +CAF_CMD_SOURCE_INIT( RicExportFractureModelPlotToFileFeature, "RicExportFractureModelPlotToFileFeature" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicExportFractureModelPlotToFileFeature::isCommandEnabled() +{ + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicExportFractureModelPlotToFileFeature::onActionTriggered( bool isChecked ) +{ + RimFractureModelPlot* fractureModelPlot = + caf::SelectionManager::instance()->selectedItemOfType(); + if ( !fractureModelPlot ) return; + + RiaApplication* app = RiaApplication::instance(); + QString defaultDir = app->lastUsedDialogDirectory( "FRACTURE_MODEL_PLOT" ); + + QString fileNameCandidate = "Geological"; + QString defaultFileName = defaultDir + "/" + caf::Utils::makeValidFileBasename( fileNameCandidate ) + ".frk"; + QString fileName = QFileDialog::getSaveFileName( nullptr, + "Select File for Fracture Model Plot Export", + defaultFileName, + "Geologic Model File(*.frk);;All files(*.*)" ); + + if ( fileName.isEmpty() ) return; + + RifFractureModelPlotExporter::writeToFile( fractureModelPlot, fileName ); + + // Remember the path to next time + app->setLastUsedDialogDirectory( "FRACTURE_MODEL_PLOT", QFileInfo( fileName ).absolutePath() ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicExportFractureModelPlotToFileFeature::setupActionLook( QAction* actionToSetup ) +{ + actionToSetup->setText( "Export Fracture Model Plot to File" ); + actionToSetup->setIcon( QIcon( ":/Save.png" ) ); +} diff --git a/ApplicationCode/Commands/RicExportFractureModelPlotToFileFeature.h b/ApplicationCode/Commands/RicExportFractureModelPlotToFileFeature.h new file mode 100644 index 0000000000..75a5de7852 --- /dev/null +++ b/ApplicationCode/Commands/RicExportFractureModelPlotToFileFeature.h @@ -0,0 +1,35 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// 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 "cafCmdFeature.h" + +//================================================================================================== +/// +//================================================================================================== +class RicExportFractureModelPlotToFileFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +protected: + // Overrides + bool isCommandEnabled() override; + void onActionTriggered( bool isChecked ) override; + void setupActionLook( QAction* actionToSetup ) override; +}; diff --git a/ApplicationCode/FileInterface/CMakeLists_files.cmake b/ApplicationCode/FileInterface/CMakeLists_files.cmake index 8c20fccf24..ea116b653d 100644 --- a/ApplicationCode/FileInterface/CMakeLists_files.cmake +++ b/ApplicationCode/FileInterface/CMakeLists_files.cmake @@ -54,6 +54,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RifSurfaceReader.h ${CMAKE_CURRENT_LIST_DIR}/RifRoffReader.h ${CMAKE_CURRENT_LIST_DIR}/RifColorLegendData.h ${CMAKE_CURRENT_LIST_DIR}/RifElasticPropertiesReader.h +${CMAKE_CURRENT_LIST_DIR}/RifFractureModelPlotExporter.h # HDF5 file reader is directly included in ResInsight main CmakeList.txt #${CMAKE_CURRENT_LIST_DIR}/RifHdf5Reader.h @@ -112,6 +113,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RifSurfaceReader.cpp ${CMAKE_CURRENT_LIST_DIR}/RifRoffReader.cpp ${CMAKE_CURRENT_LIST_DIR}/RifColorLegendData.cpp ${CMAKE_CURRENT_LIST_DIR}/RifElasticPropertiesReader.cpp +${CMAKE_CURRENT_LIST_DIR}/RifFractureModelPlotExporter.cpp # HDF5 file reader is directly included in ResInsight main CmakeList.txt #${CMAKE_CURRENT_LIST_DIR}/RifHdf5Reader.cpp diff --git a/ApplicationCode/FileInterface/RifFractureModelPlotExporter.cpp b/ApplicationCode/FileInterface/RifFractureModelPlotExporter.cpp new file mode 100644 index 0000000000..1a44a6c7aa --- /dev/null +++ b/ApplicationCode/FileInterface/RifFractureModelPlotExporter.cpp @@ -0,0 +1,123 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// 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 "RifFractureModelPlotExporter.h" + +#include "RimFractureModelPlot.h" + +#include +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RifFractureModelPlotExporter::writeToFile( RimFractureModelPlot* plot, const QString& filepath ) +{ + std::vector labels; + // TVD depth of top of zone (ft) + labels.push_back( "dpthlyr" ); + + // Stress at top of zone (psi) + labels.push_back( "strs" ); + + // Stress gradient (psi/ft) + labels.push_back( "strsg" ); + + // Young's modulus (MMpsi) + labels.push_back( "elyr" ); + + // Poisson's Ratio + labels.push_back( "poissonnr" ); + + // K-Ic (psi*sqrt(in) + labels.push_back( "tuflyr" ); + + // Fluid Loss Coefficient + labels.push_back( "clyrc" ); + + // Spurt loss (gal/100f^2) + labels.push_back( "clyrs" ); + + // Proppand Embedmeent (lb/ft^2) + labels.push_back( "pembed" ); + + // B2 Detailed Loss + // Reservoir Pressur (psi) + labels.push_back( "zoneResPres" ); + + // Porosity (fraction) + labels.push_back( "zonePorosity" ); + + // Horizontal Perm (md) + labels.push_back( "zoneHorizPerm" ); + + // Vertical Perm (md) + labels.push_back( "zoneVertPerm" ); + + std::map> values; + values["dpthlyr"] = plot->calculateTrueVerticalDepth(); + values["strs"] = plot->calculateStress(); + values["strsg"] = plot->calculateStressGradient(); + values["elyr"] = plot->calculateYoungsModulus(); + values["poissonnr"] = plot->calculatePoissonsRatio(); + values["tuflyr"] = plot->calculateKIc(); + values["clyrc"] = plot->calculateFluidLossCoefficient(); + values["clyrs"] = plot->calculateSpurtLoss(); + values["pembed"] = plot->calculateProppandEmbedment(); + values["zoneResPres"] = plot->calculateReservoirPressure(); + values["zonePorosity"] = plot->calculatePorosity(); + values["zoneHorizPerm"] = plot->calculateHorizontalPermeability(); + values["zoneVertPerm"] = plot->calculateVerticalPermeability(); + + QFile data( filepath ); + if ( !data.open( QFile::WriteOnly | QFile::Truncate ) ) + { + return false; + } + + QTextStream stream( &data ); + + for ( QString label : labels ) + { + appendToStream( stream, label, values[label] ); + } + + return true; +} + +void RifFractureModelPlotExporter::appendToStream( QTextStream& stream, const QString& label, const std::vector& values ) +{ + stream << "" + << "\n" + << label << "\n" + << "" + << "\n" + << 1 << "\n" + << "" + << "\n" + << values.size() << "\n" + << "" + << "\n"; + for ( auto val : values ) + { + stream << val << "\n"; + } + + stream << "" + << "\n"; +} diff --git a/ApplicationCode/FileInterface/RifFractureModelPlotExporter.h b/ApplicationCode/FileInterface/RifFractureModelPlotExporter.h new file mode 100644 index 0000000000..3e01805381 --- /dev/null +++ b/ApplicationCode/FileInterface/RifFractureModelPlotExporter.h @@ -0,0 +1,37 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// 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 + +class RimFractureModelPlot; +class QString; +class QTextStream; + +//================================================================================================== +// +//================================================================================================== +class RifFractureModelPlotExporter +{ +public: + static bool writeToFile( RimFractureModelPlot* plot, const QString& filepath ); + +private: + static void appendToStream( QTextStream& stream, const QString& label, const std::vector& values ); +}; diff --git a/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.cpp b/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.cpp index a2b2d0b12b..faa47ad135 100644 --- a/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.cpp +++ b/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.cpp @@ -71,6 +71,7 @@ #include "RimFormationNames.h" #include "RimFormationNamesCollection.h" #include "RimFractureModel.h" +#include "RimFractureModelPlot.h" #include "RimFractureTemplate.h" #include "RimFractureTemplateCollection.h" #include "RimGeoMechCase.h" @@ -433,6 +434,10 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection() menuBuilder << "RicImportFaciesFeature"; menuBuilder << "RicImportElasticPropertiesFeature"; } + else if ( dynamic_cast( firstUiItem ) ) + { + menuBuilder << "RicExportFractureModelPlotToFileFeature"; + } else if ( dynamic_cast( firstUiItem ) || dynamic_cast( firstUiItem ) || dynamic_cast( firstUiItem ) || diff --git a/ApplicationCode/ProjectDataModel/RimFractureModelPlot.cpp b/ApplicationCode/ProjectDataModel/RimFractureModelPlot.cpp index 1cf98c5565..05d445517a 100644 --- a/ApplicationCode/ProjectDataModel/RimFractureModelPlot.cpp +++ b/ApplicationCode/ProjectDataModel/RimFractureModelPlot.cpp @@ -23,6 +23,7 @@ #include "RimEclipseCase.h" #include "RimFractureModel.h" #include "RimFractureModelCurve.h" +#include "RimLayerCurve.h" #include "RigWellLogCurveData.h" @@ -90,3 +91,218 @@ void RimFractureModelPlot::getPorosityValues( std::vector& values ) cons } } } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimFractureModelPlot::calculateLayers( std::vector>& layerBoundaryDepths, + std::vector>& layerBoundaryIndexes ) const +{ + std::vector curves; + descendantsIncludingThisOfType( curves ); + + if ( curves.empty() ) + { + return; + } + + // Expect to have only one of these + RimLayerCurve* layerCurve = curves[0]; + + const RigWellLogCurveData* curveData = layerCurve->curveData(); + + // Find + std::vector depths = curveData->depths( RiaDefines::DepthTypeEnum::TRUE_VERTICAL_DEPTH ); + std::vector layerValues = curveData->xValues(); + + size_t startIndex = 0; + for ( size_t i = 0; i < depths.size(); i++ ) + { + if ( startIndex != i && ( layerValues[startIndex] != layerValues[i] || i == depths.size() - 1 ) ) + { + layerBoundaryDepths.push_back( std::make_pair( depths[startIndex], depths[i] ) ); + layerBoundaryIndexes.push_back( std::make_pair( startIndex, i ) ); + startIndex = i + 1; + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimFractureModelPlot::computeAverageByLayer( const std::vector>& layerBoundaryIndexes, + const std::vector& inputVector, + std::vector& result ) +{ + for ( auto boundaryIndex : layerBoundaryIndexes ) + { + double sum = 0.0; + int nValues = 0; + for ( size_t i = boundaryIndex.first; i < boundaryIndex.second; i++ ) + { + sum += inputVector[i]; + nValues++; + } + result.push_back( sum / nValues ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimWellLogExtractionCurve* RimFractureModelPlot::findCurveByName( const QString& curveName ) const +{ + std::vector curves; + descendantsIncludingThisOfType( curves ); + + for ( auto curve : curves ) + { + // TODO: This will not work if the user has changed the name of the curve: do something smarter. + if ( curve->curveName() == curveName ) + { + return curve; + } + } + + return nullptr; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimFractureModelPlot::calculateTrueVerticalDepth() const +{ + std::vector> layerBoundaryDepths; + std::vector> layerBoundaryIndexes; + + calculateLayers( layerBoundaryDepths, layerBoundaryIndexes ); + + std::vector tvdTopZone; + for ( auto p : layerBoundaryDepths ) + { + std::cout << "Layer boundaries: " << p.first << " - " << p.second << std::endl; + tvdTopZone.push_back( p.first ); + } + + // TODO: convert to feet!!!! + return tvdTopZone; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimFractureModelPlot::findCurveAndComputeLayeredAverage( const QString& curveName ) const +{ + RimWellLogExtractionCurve* curve = findCurveByName( curveName ); + if ( !curve ) + { + std::cerr << "NO " << curveName.toStdString() << " FOUND!!!" << std::endl; + return std::vector(); + } + + std::vector> layerBoundaryDepths; + std::vector> layerBoundaryIndexes; + calculateLayers( layerBoundaryDepths, layerBoundaryIndexes ); + + const RigWellLogCurveData* curveData = curve->curveData(); + std::vector values = curveData->xValues(); + std::vector result; + computeAverageByLayer( layerBoundaryIndexes, values, result ); + return result; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimFractureModelPlot::calculatePorosity() const +{ + return findCurveAndComputeLayeredAverage( "PORO" ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimFractureModelPlot::calculateReservoirPressure() const +{ + return findCurveAndComputeLayeredAverage( "PRESSURE" ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimFractureModelPlot::calculateHorizontalPermeability() const +{ + return findCurveAndComputeLayeredAverage( "PERMX" ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimFractureModelPlot::calculateVerticalPermeability() const +{ + return findCurveAndComputeLayeredAverage( "PERMZ" ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimFractureModelPlot::calculateStress() const +{ + return std::vector(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimFractureModelPlot::calculateStressGradient() const +{ + return std::vector(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimFractureModelPlot::calculateYoungsModulus() const +{ + return findCurveAndComputeLayeredAverage( "Young's Modulus" ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimFractureModelPlot::calculatePoissonsRatio() const +{ + return findCurveAndComputeLayeredAverage( "Poisson's Ratio" ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimFractureModelPlot::calculateKIc() const +{ + return findCurveAndComputeLayeredAverage( "K-Ic" ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimFractureModelPlot::calculateFluidLossCoefficient() const +{ + return std::vector(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimFractureModelPlot::calculateSpurtLoss() const +{ + return std::vector(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimFractureModelPlot::calculateProppandEmbedment() const +{ + return findCurveAndComputeLayeredAverage( "Proppant Embedment" ); +} diff --git a/ApplicationCode/ProjectDataModel/RimFractureModelPlot.h b/ApplicationCode/ProjectDataModel/RimFractureModelPlot.h index ef883e89d7..5dfe50d453 100644 --- a/ApplicationCode/ProjectDataModel/RimFractureModelPlot.h +++ b/ApplicationCode/ProjectDataModel/RimFractureModelPlot.h @@ -22,6 +22,10 @@ #include "cafPdmField.h" #include "cafPdmPtrField.h" +#include + +class RimWellLogExtractionCurve; + class RimFractureModelPlot : public RimDepthTrackPlot { CAF_PDM_HEADER_INIT; @@ -31,7 +35,29 @@ public: void getPorosityValues( std::vector& values ) const; + std::vector calculateTrueVerticalDepth() const; + std::vector calculatePorosity() const; + std::vector calculateVerticalPermeability() const; + std::vector calculateHorizontalPermeability() const; + std::vector calculateReservoirPressure() const; + std::vector calculateStress() const; + std::vector calculateStressGradient() const; + std::vector calculateYoungsModulus() const; + std::vector calculatePoissonsRatio() const; + std::vector calculateKIc() const; + std::vector calculateFluidLossCoefficient() const; + std::vector calculateSpurtLoss() const; + std::vector calculateProppandEmbedment() const; + protected: + std::vector findCurveAndComputeLayeredAverage( const QString& curveName ) const; + void calculateLayers( std::vector>& layerBoundaryDepths, + std::vector>& layerBoundaryIndexes ) const; + RimWellLogExtractionCurve* findCurveByName( const QString& curveName ) const; + static void computeAverageByLayer( const std::vector>& layerBoundaryIndexes, + const std::vector& inputVector, + std::vector& result ); + void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override; void onLoadDataAndUpdate() override;