From c9f5b47a9074f7e65a02debea1c8ec4748015f39 Mon Sep 17 00:00:00 2001 From: Gaute Lindkvist Date: Wed, 29 Jan 2020 12:52:07 +0100 Subject: [PATCH] Support different units when importing and exporting WBS LAS. --- .../Application/Tools/CMakeLists_files.cmake | 3 + .../Application/Tools/RiaWellLogUnitTools.cpp | 331 ++++++++++++++++++ .../Application/Tools/RiaWellLogUnitTools.h | 70 ++++ .../RicfExportWellLogPlotData.cpp | 4 +- .../RicfExportWellLogPlotData.h | 1 + .../RicExportToLasFileFeature.cpp | 19 +- .../RicExportToLasFileFeature.h | 6 +- .../RicExportToLasFileResampleUi.cpp | 32 ++ .../RicExportToLasFileResampleUi.h | 15 +- .../RicWellLogPlotCurveFeatureImpl.cpp | 26 +- .../GrpcInterface/GrpcProtos/Commands.proto | 1 + .../Python/rips/well_log_plot.py | 5 +- .../Flow/RimWellFlowRateCurve.cpp | 8 + .../Flow/RimWellFlowRateCurve.h | 1 + .../RimGeoMechResultDefinition.cpp | 51 ++- .../RimGeoMechResultDefinition.h | 2 + .../ProjectDataModel/RimWbsParameters.cpp | 2 +- .../RimWellBoreStabilityPlot.cpp | 1 + .../ProjectDataModel/RimWellLogCurve.cpp | 13 +- .../ProjectDataModel/RimWellLogCurve.h | 11 +- .../RimWellLogExtractionCurve.cpp | 123 +++---- .../RimWellLogExtractionCurve.h | 7 +- .../ProjectDataModel/RimWellLogFile.cpp | 7 +- .../ProjectDataModel/RimWellLogFile.h | 3 +- .../ProjectDataModel/RimWellLogFileCurve.cpp | 33 +- .../ProjectDataModel/RimWellLogFileCurve.h | 3 +- .../ProjectDataModel/RimWellLogRftCurve.cpp | 8 + .../ProjectDataModel/RimWellLogRftCurve.h | 1 + .../RimWellMeasurementCurve.cpp | 8 + .../RimWellMeasurementCurve.h | 1 + .../RigGeoMechWellLogExtractor.cpp | 292 ++++++--------- .../RigGeoMechWellLogExtractor.h | 15 +- .../ReservoirDataModel/RigLasFileExporter.cpp | 34 +- .../ReservoirDataModel/RigLasFileExporter.h | 9 +- .../ReservoirDataModel/RigWbsParameter.cpp | 135 +++++-- .../ReservoirDataModel/RigWbsParameter.h | 17 +- .../RigWellLogCurveData.cpp | 91 +++-- .../ReservoirDataModel/RigWellLogCurveData.h | 15 +- .../ReservoirDataModel/RigWellLogFile.cpp | 15 + .../ReservoirDataModel/RigWellLogFile.h | 1 + 40 files changed, 976 insertions(+), 444 deletions(-) create mode 100644 ApplicationCode/Application/Tools/RiaWellLogUnitTools.cpp create mode 100644 ApplicationCode/Application/Tools/RiaWellLogUnitTools.h diff --git a/ApplicationCode/Application/Tools/CMakeLists_files.cmake b/ApplicationCode/Application/Tools/CMakeLists_files.cmake index 44b34c6c61..5543c3cd86 100644 --- a/ApplicationCode/Application/Tools/CMakeLists_files.cmake +++ b/ApplicationCode/Application/Tools/CMakeLists_files.cmake @@ -40,6 +40,8 @@ ${CMAKE_CURRENT_LIST_DIR}/RiaGitDiff.h ${CMAKE_CURRENT_LIST_DIR}/RiaCellDividingTools.h ${CMAKE_CURRENT_LIST_DIR}/RiaFieldHandleTools.h ${CMAKE_CURRENT_LIST_DIR}/RiaBoundingBoxTools.h +${CMAKE_CURRENT_LIST_DIR}/RiaWellLogUnitTools.h + ) set (SOURCE_GROUP_SOURCE_FILES @@ -79,6 +81,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RiaGitDiff.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaCellDividingTools.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaFieldHandleTools.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaBoundingBoxTools.cpp +${CMAKE_CURRENT_LIST_DIR}/RiaWellLogUnitTools.cpp ) list(APPEND CODE_HEADER_FILES diff --git a/ApplicationCode/Application/Tools/RiaWellLogUnitTools.cpp b/ApplicationCode/Application/Tools/RiaWellLogUnitTools.cpp new file mode 100644 index 0000000000..a994feddc9 --- /dev/null +++ b/ApplicationCode/Application/Tools/RiaWellLogUnitTools.cpp @@ -0,0 +1,331 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2020- Equinor AS +// +// 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 "RiaWellLogUnitTools.h" + +#include "RiaEclipseUnitTools.h" +#include "RigWellPath.h" + +#include "cafAssert.h" + +#include + +const double RiaWellLogUnitTools::GRAVITY_ACCEL = 9.81; +const double RiaWellLogUnitTools::UNIT_WEIGHT_OF_WATER = RiaWellLogUnitTools::GRAVITY_ACCEL * 1000.0; // N / m^3 + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiaWellLogUnitTools::noUnitString() +{ + return "NO_UNIT"; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiaWellLogUnitTools::barUnitString() +{ + return "Bar"; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiaWellLogUnitTools::barX100UnitString() +{ + return "Bar x100"; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiaWellLogUnitTools::MPaUnitString() +{ + return "MPa"; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiaWellLogUnitTools::gPerCm3UnitString() +{ + return "g/cm3"; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RiaWellLogUnitTools::convertDepths( const std::vector& depthsIn, + RiaDefines::DepthUnitType unitsIn, + RiaDefines::DepthUnitType unitsOut ) +{ + if ( unitsOut == RiaDefines::UNIT_METER && unitsIn == RiaDefines::UNIT_FEET ) + { + return multiply( depthsIn, RiaEclipseUnitTools::feetPerMeter() ); + } + else if ( unitsOut == RiaDefines::UNIT_FEET && unitsIn == RiaDefines::UNIT_METER ) + { + return multiply( depthsIn, RiaEclipseUnitTools::meterPerFeet() ); + } + return depthsIn; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RiaWellLogUnitTools::convertValues( const std::vector& tvdRKBs, + const std::vector& valuesIn, + std::vector* valuesOut, + const QString& unitsIn, + const QString& unitsOut ) +{ + CAF_ASSERT( valuesOut ); + + if ( unitsIn == unitsOut ) + { + *valuesOut = valuesIn; + return true; + } + + if ( unitsIn == gPerCm3UnitString() && unitsOut == barUnitString() ) + { + *valuesOut = convertGpcm3ToBar( tvdRKBs, valuesIn ); + return true; + } + else if ( unitsIn == barUnitString() && unitsOut == gPerCm3UnitString() ) + { + *valuesOut = convertBarToGpcm3( tvdRKBs, valuesIn ); + return true; + } + else if ( unitsIn == RiaWellLogUnitTools::noUnitString() && unitsOut == gPerCm3UnitString() ) + { + *valuesOut = convertNormalizedByPPToBar( tvdRKBs, valuesIn ); + *valuesOut = convertBarToGpcm3( tvdRKBs, *valuesOut ); + } + else if ( unitsIn == gPerCm3UnitString() && unitsOut == RiaWellLogUnitTools::noUnitString() ) + { + *valuesOut = convertGpcm3ToBar( tvdRKBs, valuesIn ); + *valuesOut = convertBarToNormalizedByPP( tvdRKBs, *valuesOut ); + } + else if ( unitsIn == MPaUnitString() && unitsOut == barUnitString() ) + + { + *valuesOut = multiply( valuesIn, 1.0 / MPaPerBar() ); + return true; + } + else if ( unitsIn == barX100UnitString() && unitsOut == MPaUnitString() ) + { + *valuesOut = multiply( valuesIn, 100.0 ); + *valuesOut = multiply( *valuesOut, MPaPerBar() ); + return true; + } + else if ( unitsIn == barX100UnitString() && unitsOut == barUnitString() ) + { + *valuesOut = multiply( valuesIn, 100 ); + return true; + } + else if ( unitsIn == barUnitString() && unitsOut == MPaUnitString() ) + { + *valuesOut = multiply( valuesIn, MPaPerBar() ); + return true; + } + else if ( unitsIn == barUnitString() && unitsOut == barX100UnitString() ) + { + *valuesOut = multiply( valuesIn, 1.0 / 100.0 ); + return true; + } + else if ( unitsIn == RiaWellLogUnitTools::noUnitString() && unitsOut == barUnitString() ) + { + *valuesOut = convertNormalizedByPPToBar( tvdRKBs, valuesIn ); + return true; + } + else if ( unitsIn == barUnitString() && unitsOut == RiaWellLogUnitTools::noUnitString() ) + { + *valuesOut = convertBarToNormalizedByPP( tvdRKBs, valuesIn ); + } + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RiaWellLogUnitTools::convertValues( std::vector>* measuredDepthsAndValues, + const QString& unitsIn, + const QString& unitsOut, + const RigWellPath* wellPath ) +{ + CAF_ASSERT( measuredDepthsAndValues ); + if ( unitsIn == unitsOut ) return true; + + std::vector tvdRKBs( measuredDepthsAndValues->size(), 0.0 ); + std::vector values( measuredDepthsAndValues->size(), 0.0 ); + for ( size_t i = 0; i < measuredDepthsAndValues->size(); ++i ) + { + auto depthValuePair = ( *measuredDepthsAndValues )[i]; + cvf::Vec3d point = wellPath->interpolatedPointAlongWellPath( depthValuePair.first ); + + tvdRKBs[i] = -point.z() + wellPath->rkbDiff(); + values[i] = depthValuePair.second; + } + std::vector valuesOut; + if ( convertValues( tvdRKBs, values, &valuesOut, unitsIn, unitsOut ) ) + { + CAF_ASSERT( measuredDepthsAndValues->size() == valuesOut.size() ); + for ( size_t i = 0; i < measuredDepthsAndValues->size(); ++i ) + { + ( *measuredDepthsAndValues )[i].second = valuesOut[i]; + } + return true; + } + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RiaWellLogUnitTools::tvdRKBs( const std::vector& measuredDepths, const RigWellPath* wellPath ) +{ + std::vector tvdRKBs( measuredDepths.size(), 0.0 ); + for ( size_t i = 0; i < measuredDepths.size(); ++i ) + { + cvf::Vec3d point = wellPath->interpolatedPointAlongWellPath( measuredDepths[i] ); + tvdRKBs[i] = -point.z() + wellPath->rkbDiff(); + } + return tvdRKBs; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RiaWellLogUnitTools::convertGpcm3ToBar( const std::vector& tvdRKBs, + const std::vector& valuesInGpcm3 ) +{ + CAF_ASSERT( tvdRKBs.size() == valuesInGpcm3.size() ); + + std::vector valuesInBar( valuesInGpcm3.size(), 0.0 ); + for ( size_t i = 0; i < tvdRKBs.size(); ++i ) + { + // We need SI as input (kg / m^3), so multiply by 1000: + double mudWeightsSI = valuesInGpcm3[i] * 1000; + + // To get specific mudWeight (N / m^3): + double specificMudWeight = mudWeightsSI * GRAVITY_ACCEL; + + // Pore pressure in pascal + double valuePascal = specificMudWeight * tvdRKBs[i]; + + // Pore pressure in bar + valuesInBar[i] = 1.0 / pascalPerBar() * valuePascal; + } + return valuesInBar; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RiaWellLogUnitTools::convertBarToGpcm3( const std::vector& tvdRKBs, + const std::vector& valuesInBar ) +{ + CAF_ASSERT( tvdRKBs.size() == valuesInBar.size() ); + + std::vector valuesInGpcm3( valuesInBar.size(), 0.0 ); + for ( size_t i = 0; i < tvdRKBs.size(); ++i ) + { + // Pore pressure in pascal (N / m^2) + double valuePascal = pascalPerBar() * valuesInBar[i]; + + // N / m^3: + double specificMudWeight = valuePascal / tvdRKBs[i]; + + // Mud weight in SI (kg / m^3): + double mudWeightsSI = specificMudWeight / GRAVITY_ACCEL; + + // Mud weights g/cm^3: + valuesInGpcm3[i] = mudWeightsSI / 1000; + } + return valuesInGpcm3; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RiaWellLogUnitTools::convertNormalizedByPPToBar( const std::vector& tvdRKBs, + const std::vector& normalizedValues ) +{ + CAF_ASSERT( tvdRKBs.size() == normalizedValues.size() ); + + std::vector valuesInBar( tvdRKBs.size(), 0.0 ); + for ( size_t i = 0; i < tvdRKBs.size(); ++i ) + { + valuesInBar[i] = normalizedValues[i] * hydrostaticPorePressureBar( tvdRKBs[i] ); + } + return valuesInBar; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RiaWellLogUnitTools::convertBarToNormalizedByPP( const std::vector& tvdRKBs, + const std::vector& valuesInBar ) +{ + CAF_ASSERT( tvdRKBs.size() == valuesInBar.size() ); + + std::vector normalizedValues( tvdRKBs.size(), 0.0 ); + for ( size_t i = 0; i < tvdRKBs.size(); ++i ) + { + normalizedValues[i] = valuesInBar[i] / hydrostaticPorePressureBar( tvdRKBs[i] ); + } + return normalizedValues; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RiaWellLogUnitTools::multiply( const std::vector& valuesIn, double factor ) +{ + std::vector valuesOut( valuesIn.size(), std::numeric_limits::infinity() ); + for ( size_t i = 0; i < 100; ++i ) + { + valuesOut[i] = valuesIn[i] * factor; + } + return valuesOut; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RiaWellLogUnitTools::pascalPerBar() +{ + return 1.0e5; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RiaWellLogUnitTools::MPaPerBar() +{ + return 1.0e-1; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RiaWellLogUnitTools::hydrostaticPorePressureBar( double depth ) +{ + return 1.0 / pascalPerBar() * depth * UNIT_WEIGHT_OF_WATER; +} diff --git a/ApplicationCode/Application/Tools/RiaWellLogUnitTools.h b/ApplicationCode/Application/Tools/RiaWellLogUnitTools.h new file mode 100644 index 0000000000..fddbed56b4 --- /dev/null +++ b/ApplicationCode/Application/Tools/RiaWellLogUnitTools.h @@ -0,0 +1,70 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2020- Equinor AS +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "RiaDefines.h" + +#include + +#include + +class RigWellPath; + +class RiaWellLogUnitTools +{ +public: + static const double GRAVITY_ACCEL; + static const double UNIT_WEIGHT_OF_WATER; + + static QString noUnitString(); + static QString barUnitString(); + static QString barX100UnitString(); + static QString MPaUnitString(); + static QString gPerCm3UnitString(); + +public: + static std::vector convertDepths( const std::vector& depthsIn, + RiaDefines::DepthUnitType unitsIn, + RiaDefines::DepthUnitType unitsOut ); + static bool convertValues( const std::vector& tvdRKBs, + const std::vector& valuesIn, + std::vector* valuesOut, + const QString& unitsIn, + const QString& unitsOut ); + static bool convertValues( std::vector>* measuredDepthsAndValues, + const QString& unitsIn, + const QString& unitsOut, + const RigWellPath* wellPath ); + + static std::vector tvdRKBs( const std::vector& measuredDepths, const RigWellPath* wellPath ); + + // Supported conversions + static std::vector convertGpcm3ToBar( const std::vector& tvdRKBs, + const std::vector& valuesInGpcm3 ); + static std::vector convertBarToGpcm3( const std::vector& tvdRKBs, + const std::vector& valuesInBar ); + + static std::vector convertNormalizedByPPToBar( const std::vector& tvdRKBs, + const std::vector& valuesInBar ); + static std::vector convertBarToNormalizedByPP( const std::vector& tvdRKBs, + const std::vector& valuesInBar ); + static std::vector multiply( const std::vector& values, double factor ); + static double pascalPerBar(); + static double MPaPerBar(); + static double hydrostaticPorePressureBar( double tvdRKB ); +}; diff --git a/ApplicationCode/CommandFileInterface/RicfExportWellLogPlotData.cpp b/ApplicationCode/CommandFileInterface/RicfExportWellLogPlotData.cpp index ce5b3708b6..5762c1836f 100644 --- a/ApplicationCode/CommandFileInterface/RicfExportWellLogPlotData.cpp +++ b/ApplicationCode/CommandFileInterface/RicfExportWellLogPlotData.cpp @@ -66,6 +66,7 @@ RicfExportWellLogPlotData::RicfExportWellLogPlotData() RICF_InitField( &m_exportTvdRkb, "exportTvdRkb", false, "", "", "", "" ); RICF_InitField( &m_capitalizeFileNames, "capitalizeFileNames", false, "", "", "", "" ); RICF_InitField( &m_resampleInterval, "resampleInterval", 0.0, "", "", "", "" ); + RICF_InitField( &m_convertCurveUnits, "convertCurveUnits", false, "", "", "", "" ); } //-------------------------------------------------------------------------------------------------- @@ -108,7 +109,8 @@ RicfCommandResponse RicfExportWellLogPlotData::execute() m_exportTvdRkb(), m_capitalizeFileNames(), true, - m_resampleInterval() ); + m_resampleInterval(), + m_convertCurveUnits() ); if ( exportedFiles.empty() ) { errorMessages << QString( "No files exported for '%1'" ).arg( plot->description() ); diff --git a/ApplicationCode/CommandFileInterface/RicfExportWellLogPlotData.h b/ApplicationCode/CommandFileInterface/RicfExportWellLogPlotData.h index 82aab5dc2e..4a9f28ea5a 100644 --- a/ApplicationCode/CommandFileInterface/RicfExportWellLogPlotData.h +++ b/ApplicationCode/CommandFileInterface/RicfExportWellLogPlotData.h @@ -69,4 +69,5 @@ private: caf::PdmField m_exportTvdRkb; caf::PdmField m_capitalizeFileNames; caf::PdmField m_resampleInterval; + caf::PdmField m_convertCurveUnits; }; diff --git a/ApplicationCode/Commands/ExportCommands/RicExportToLasFileFeature.cpp b/ApplicationCode/Commands/ExportCommands/RicExportToLasFileFeature.cpp index b0f486d434..fb0a69ad9f 100644 --- a/ApplicationCode/Commands/ExportCommands/RicExportToLasFileFeature.cpp +++ b/ApplicationCode/Commands/ExportCommands/RicExportToLasFileFeature.cpp @@ -49,7 +49,8 @@ std::vector RicExportToLasFileFeature::exportToLasFiles( const QString& bool exportTvdRkb, bool capitalizeFileNames, bool alwaysOverwrite, - double resampleInterval ) + double resampleInterval, + bool convertCurveUnits ) { std::vector allCurves; std::vector plots = plotWindow->visiblePlots(); @@ -77,7 +78,8 @@ std::vector RicExportToLasFileFeature::exportToLasFiles( const QString& rkbDiffs, capitalizeFileNames, alwaysOverwrite, - resampleInterval ); + resampleInterval, + convertCurveUnits ); } } @@ -91,7 +93,8 @@ std::vector RicExportToLasFileFeature::exportToLasFiles( const QString& const std::vector& rkbDiffs, bool capitalizeFileNames, bool alwaysOverwrite, - double resampleInterval ) + double resampleInterval, + bool convertCurveUnits ) { RigLasFileExporter lasExporter( curves ); @@ -107,7 +110,8 @@ std::vector RicExportToLasFileFeature::exportToLasFiles( const QString& lasExporter.setRkbDiffs( wellNames, rkbDiffs ); } - writtenFiles = lasExporter.writeToFolder( exportFolder, filePrefix, capitalizeFileNames, alwaysOverwrite ); + writtenFiles = + lasExporter.writeToFolder( exportFolder, filePrefix, capitalizeFileNames, alwaysOverwrite, convertCurveUnits ); // Remember the path to next time RiaApplication::instance()->setLastUsedDialogDirectory( "WELL_LOGS_DIR", exportFolder ); @@ -148,6 +152,7 @@ void RicExportToLasFileFeature::onActionTriggered( bool isChecked ) { featureUi.filePrefix = "WBS_"; featureUi.capitalizeFileName = true; + featureUi.setUnitConversionOptionEnabled( true ); } { @@ -163,7 +168,7 @@ void RicExportToLasFileFeature::onActionTriggered( bool isChecked ) "", QDialogButtonBox::Ok | QDialogButtonBox::Cancel ); RicExportFeatureImpl::configureForExport( propertyDialog.dialogButtonBox() ); - propertyDialog.resize( QSize( 400, 330 ) ); + propertyDialog.resize( QSize( 400, 360 ) ); if ( propertyDialog.exec() == QDialog::Accepted && !featureUi.exportFolder().isEmpty() ) { @@ -190,7 +195,9 @@ void RicExportToLasFileFeature::onActionTriggered( bool isChecked ) rkbDiffs, featureUi.capitalizeFileName, false, - resampleInterval ); + resampleInterval, + featureUi.curveUnitConversion() == + RicExportToLasFileResampleUi::CurveUnitConversion::EXPORT_WITH_STANDARD_UNITS ); } } diff --git a/ApplicationCode/Commands/ExportCommands/RicExportToLasFileFeature.h b/ApplicationCode/Commands/ExportCommands/RicExportToLasFileFeature.h index 66cf59b8ac..c14b304e0f 100644 --- a/ApplicationCode/Commands/ExportCommands/RicExportToLasFileFeature.h +++ b/ApplicationCode/Commands/ExportCommands/RicExportToLasFileFeature.h @@ -42,7 +42,8 @@ public: bool exportTvdRkb, bool capitalizeFileNames, bool alwaysOverwrite, - double resampleInterval ); + double resampleInterval, + bool convertCurveUnits ); static std::vector exportToLasFiles( const QString& exportFolder, const QString& filePrefix, @@ -51,7 +52,8 @@ public: const std::vector& rkbDiffs, bool capitalizeFileNames, bool alwaysOverwrite, - double resampleInterval ); + double resampleInterval, + bool convertCurveUnits ); protected: // Overrides diff --git a/ApplicationCode/Commands/ExportCommands/RicExportToLasFileResampleUi.cpp b/ApplicationCode/Commands/ExportCommands/RicExportToLasFileResampleUi.cpp index 2616bf95ab..97a264aa37 100644 --- a/ApplicationCode/Commands/ExportCommands/RicExportToLasFileResampleUi.cpp +++ b/ApplicationCode/Commands/ExportCommands/RicExportToLasFileResampleUi.cpp @@ -24,6 +24,20 @@ #include +namespace caf +{ +template <> +void RicExportToLasFileResampleUi::CurveUnitConversionEnum::setUp() +{ + addItem( RicExportToLasFileResampleUi::CurveUnitConversion::EXPORT_NORMALIZED, "NORMALIZED", "Current Plot Units" ); + addItem( RicExportToLasFileResampleUi::CurveUnitConversion::EXPORT_WITH_STANDARD_UNITS, + "STANDARD_UNITS", + "Convert to Standard Import Units" ); + setDefault( RicExportToLasFileResampleUi::CurveUnitConversion::EXPORT_WITH_STANDARD_UNITS ); +} + +} // End namespace caf + CAF_PDM_SOURCE_INIT( RicExportToLasFileObj, "RicExportToLasFileObj" ); //-------------------------------------------------------------------------------------------------- @@ -42,6 +56,7 @@ CAF_PDM_SOURCE_INIT( RicExportToLasFileResampleUi, "RicExportToLasFileResampleUi /// //-------------------------------------------------------------------------------------------------- RicExportToLasFileResampleUi::RicExportToLasFileResampleUi( void ) + : m_enableCurveUnitConversion( false ) { CAF_PDM_InitObject( "Resample LAS curves for export", "", "", "" ); @@ -49,6 +64,7 @@ RicExportToLasFileResampleUi::RicExportToLasFileResampleUi( void ) exportFolder.uiCapability()->setUiEditorTypeName( caf::PdmUiFilePathEditor::uiEditorTypeName() ); CAF_PDM_InitField( &filePrefix, "FilePrefix", QString( "" ), "File Prefix", "", "", "" ); CAF_PDM_InitField( &capitalizeFileName, "CapitalizeFileName", false, "Capitalize File Name", "", "", "" ); + CAF_PDM_InitFieldNoDefault( &curveUnitConversion, "CurveUnitConversion", "Curve Units", "", "", "" ); CAF_PDM_InitField( &activateResample, "ActivateResample", false, "Resample Curve Data", "", "", "" ); activateResample.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN ); @@ -108,6 +124,14 @@ void RicExportToLasFileResampleUi::setRkbDiffs( const std::vector& well updateFieldVisibility(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicExportToLasFileResampleUi::setUnitConversionOptionEnabled( bool enabled ) +{ + m_enableCurveUnitConversion = enabled; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -172,6 +196,12 @@ void RicExportToLasFileResampleUi::defineUiOrdering( QString uiConfigName, caf:: uiOrdering.add( &exportFolder ); uiOrdering.add( &filePrefix ); uiOrdering.add( &capitalizeFileName ); + + if ( m_enableCurveUnitConversion ) + { + uiOrdering.add( &curveUnitConversion ); + } + { caf::PdmUiGroup* group = uiOrdering.addNewGroup( "Resampling" ); @@ -188,4 +218,6 @@ void RicExportToLasFileResampleUi::defineUiOrdering( QString uiConfigName, caf:: { group->add( &obj->tvdrkbOffset ); } + + uiOrdering.skipRemainingFields( true ); } diff --git a/ApplicationCode/Commands/ExportCommands/RicExportToLasFileResampleUi.h b/ApplicationCode/Commands/ExportCommands/RicExportToLasFileResampleUi.h index b77b9bffea..5bb5c75481 100644 --- a/ApplicationCode/Commands/ExportCommands/RicExportToLasFileResampleUi.h +++ b/ApplicationCode/Commands/ExportCommands/RicExportToLasFileResampleUi.h @@ -18,6 +18,7 @@ #pragma once +#include "cafAppEnum.h" #include "cafPdmChildArrayField.h" #include "cafPdmField.h" #include "cafPdmObject.h" @@ -42,6 +43,14 @@ class RicExportToLasFileResampleUi : public caf::PdmObject { CAF_PDM_HEADER_INIT; +public: + enum class CurveUnitConversion + { + EXPORT_NORMALIZED, + EXPORT_WITH_STANDARD_UNITS + }; + using CurveUnitConversionEnum = caf::AppEnum; + public: RicExportToLasFileResampleUi( void ); ~RicExportToLasFileResampleUi() override; @@ -53,10 +62,12 @@ public: caf::PdmField activateResample; caf::PdmField resampleInterval; - caf::PdmField exportTvdrkb; + caf::PdmField exportTvdrkb; + caf::PdmField curveUnitConversion; void tvdrkbDiffForWellPaths( std::vector* rkbDiffs ); void setRkbDiffs( const std::vector& wellNames, const std::vector& rkbDiffs ); + void setUnitConversionOptionEnabled( bool enabled ); void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, @@ -73,4 +84,6 @@ private: private: caf::PdmChildArrayField m_tvdrkbOffsets; + + bool m_enableCurveUnitConversion; }; diff --git a/ApplicationCode/Commands/WellLogCommands/RicWellLogPlotCurveFeatureImpl.cpp b/ApplicationCode/Commands/WellLogCommands/RicWellLogPlotCurveFeatureImpl.cpp index b21dc25287..a105b3e042 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicWellLogPlotCurveFeatureImpl.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicWellLogPlotCurveFeatureImpl.cpp @@ -24,6 +24,7 @@ #include "RimWellAllocationPlot.h" #include "RimWellBoreStabilityPlot.h" #include "RimWellLogCurve.h" +#include "RimWellLogTrack.h" #include "RimWellRftPlot.h" #include "cafSelectionManager.h" @@ -57,27 +58,26 @@ std::vector RicWellLogPlotCurveFeatureImpl::selectedWellLogCur caf::PdmObjectHandle* objHandle = dynamic_cast( selectedItem ); if ( objHandle ) { - std::vector childCurves; - objHandle->descendantsIncludingThisOfType( childCurves ); - - for ( RimWellLogCurve* curve : childCurves ) + std::vector childTracks; + objHandle->descendantsIncludingThisOfType( childTracks ); + for ( auto track : childTracks ) { - if ( !uniqueCurves.count( curve ) ) + if ( track->showWindow() ) { - uniqueCurves.insert( curve ); - allCurves.push_back( curve ); + for ( RimWellLogCurve* curve : track->visibleCurves() ) + { + if ( !uniqueCurves.count( curve ) ) + { + uniqueCurves.insert( curve ); + allCurves.push_back( curve ); + } + } } } } } } - // Sort by curve name in a way that retains the original order of equivalent items - // This way we have a completely deterministic order - std::stable_sort( allCurves.begin(), allCurves.end(), []( const RimWellLogCurve* lhs, const RimWellLogCurve* rhs ) { - return lhs->curveName() < rhs->curveName(); - } ); - return allCurves; } diff --git a/ApplicationCode/GrpcInterface/GrpcProtos/Commands.proto b/ApplicationCode/GrpcInterface/GrpcProtos/Commands.proto index a550d07151..1171ad75bd 100644 --- a/ApplicationCode/GrpcInterface/GrpcProtos/Commands.proto +++ b/ApplicationCode/GrpcInterface/GrpcProtos/Commands.proto @@ -321,6 +321,7 @@ message ExportWellLogPlotDataRequest bool exportTvdRkb = 5; bool capitalizeFileNames = 6; double resampleInterval = 7; + bool convertCurveUnits = 8; } message ExportContourMapToTextRequest diff --git a/ApplicationCode/GrpcInterface/Python/rips/well_log_plot.py b/ApplicationCode/GrpcInterface/Python/rips/well_log_plot.py index b192fddc56..10b688d9e9 100644 --- a/ApplicationCode/GrpcInterface/Python/rips/well_log_plot.py +++ b/ApplicationCode/GrpcInterface/Python/rips/well_log_plot.py @@ -21,7 +21,7 @@ class WellLogPlot(Plot): return cls(pdm_object) return None - def export_data_as_las(self, export_folder, file_prefix='', export_tvdrkb=False, capitalize_file_names=False, resample_interval=0.0): + def export_data_as_las(self, export_folder, file_prefix='', export_tvdrkb=False, capitalize_file_names=False, resample_interval=0.0, convert_to_standard_units=False): """ Export LAS file(s) for the current plot Arguments: @@ -40,7 +40,8 @@ class WellLogPlot(Plot): filePrefix=file_prefix, exportTvdRkb=export_tvdrkb, capitalizeFileNames=capitalize_file_names, - resampleInterval=resample_interval)) + resampleInterval=resample_interval, + convertCurveUnits=convert_to_standard_units) return res.exportWellLogPlotDataResult.exportedFiles def export_data_as_ascii(self, export_folder, file_prefix='', capitalize_file_names=False): diff --git a/ApplicationCode/ProjectDataModel/Flow/RimWellFlowRateCurve.cpp b/ApplicationCode/ProjectDataModel/Flow/RimWellFlowRateCurve.cpp index 1e6798d22b..41fcc1ab1d 100644 --- a/ApplicationCode/ProjectDataModel/Flow/RimWellFlowRateCurve.cpp +++ b/ApplicationCode/ProjectDataModel/Flow/RimWellFlowRateCurve.cpp @@ -112,6 +112,14 @@ QString RimWellFlowRateCurve::wellLogChannelUiName() const return "AccumulatedFlowRate"; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimWellFlowRateCurve::wellLogChannelUnits() const +{ + return RiaWellLogUnitTools::noUnitString(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/Flow/RimWellFlowRateCurve.h b/ApplicationCode/ProjectDataModel/Flow/RimWellFlowRateCurve.h index c2fb92bade..d4fed7d0f6 100644 --- a/ApplicationCode/ProjectDataModel/Flow/RimWellFlowRateCurve.h +++ b/ApplicationCode/ProjectDataModel/Flow/RimWellFlowRateCurve.h @@ -48,6 +48,7 @@ public: int timeStep(); QString wellName() const override; QString wellLogChannelUiName() const override; + QString wellLogChannelUnits() const override; void setGroupId( int groupId ); int groupId() const; diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechResultDefinition.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechResultDefinition.cpp index e35301fd92..a0ebdb12bf 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechResultDefinition.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechResultDefinition.cpp @@ -650,13 +650,51 @@ QString RimGeoMechResultDefinition::resultVariableName() const RigWbsParameter param; if ( RigWbsParameter::findParameter( resultFieldName(), ¶m ) ) { - QString lasName = param.sourceLabel( RigWbsParameter::LAS_FILE ); + QString lasName = param.addressString( RigWbsParameter::LAS_FILE ); if ( !lasName.isEmpty() ) return lasName; } } return resultVariableUiName(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimGeoMechResultDefinition::currentResultUnits() const +{ + if ( this->resultFieldName() == "SE" || this->resultFieldName() == "ST" || this->resultFieldName() == "POR-Bar" || + this->resultFieldName() == "SM" || this->resultFieldName() == "SEM" || this->resultFieldName() == "Q" ) + { + return "Bar"; + } + else if ( this->resultFieldName() == "MODULUS" ) + { + return "GPa"; + } + return RiaWellLogUnitTools::noUnitString(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimGeoMechResultDefinition::defaultLasUnits() const +{ + QString units; + if ( m_resultPositionType == RIG_WELLPATH_DERIVED ) + { + RigWbsParameter param; + if ( RigWbsParameter::findParameter( resultFieldName(), ¶m ) ) + { + units = param.units( RigWbsParameter::LAS_FILE ); + } + } + if ( units.isEmpty() ) + { + units = currentResultUnits(); + } + return units; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -742,15 +780,10 @@ void RimGeoMechResultDefinition::updateLegendTextAndRanges( RimRegularLegendConf legendTitle += ", " + this->resultComponentUiName(); } - if ( this->resultFieldName() == "SE" || this->resultFieldName() == "ST" || this->resultFieldName() == "POR-Bar" || - this->resultFieldName() == "SM" || this->resultFieldName() == "SEM" || this->resultFieldName() == "Q" ) + QString unitString = currentResultUnits(); + if ( unitString != RiaWellLogUnitTools::noUnitString() ) { - legendTitle += " [Bar]"; - } - - if ( this->resultFieldName() == "MODULUS" ) - { - legendTitle += " [GPa]"; + legendTitle += QString( " [%1]" ).arg( unitString ); } if ( !this->diffResultUiShortName().isEmpty() ) diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechResultDefinition.h b/ApplicationCode/ProjectDataModel/RimGeoMechResultDefinition.h index edc7e6c20a..bd4c396db3 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechResultDefinition.h +++ b/ApplicationCode/ProjectDataModel/RimGeoMechResultDefinition.h @@ -68,6 +68,8 @@ public: QString resultComponentUiName() const; QString resultVariableUiName() const; QString resultVariableName() const; + QString currentResultUnits() const; + QString defaultLasUnits() const; bool hasCategoryResult() const { diff --git a/ApplicationCode/ProjectDataModel/RimWbsParameters.cpp b/ApplicationCode/ProjectDataModel/RimWbsParameters.cpp index ad89386bf0..c9da1dcd75 100644 --- a/ApplicationCode/ProjectDataModel/RimWbsParameters.cpp +++ b/ApplicationCode/ProjectDataModel/RimWbsParameters.cpp @@ -387,7 +387,7 @@ bool RimWbsParameters::hasLasFileWithChannel( const QString& channel ) const bool RimWbsParameters::hasElementPropertyEntry( const RigFemResultAddress& resAddr ) const { RigFemPartResultsCollection* femPartResults = nullptr; - if ( m_geoMechCase && m_timeStep > 0 ) + if ( m_geoMechCase && m_geoMechCase->geoMechData() && m_timeStep > 0 ) { femPartResults = m_geoMechCase->geoMechData()->femPartResults(); if ( femPartResults ) diff --git a/ApplicationCode/ProjectDataModel/RimWellBoreStabilityPlot.cpp b/ApplicationCode/ProjectDataModel/RimWellBoreStabilityPlot.cpp index a220c66f3c..52bea75bd9 100644 --- a/ApplicationCode/ProjectDataModel/RimWellBoreStabilityPlot.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellBoreStabilityPlot.cpp @@ -131,6 +131,7 @@ void RimWellBoreStabilityPlot::childFieldChangedByUi( const caf::PdmFieldHandle* //-------------------------------------------------------------------------------------------------- void RimWellBoreStabilityPlot::initAfterRead() { + updateCommonDataSource(); applyDataSource(); } diff --git a/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp index d480b9b1c0..e43151e197 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp @@ -113,9 +113,11 @@ void RimWellLogCurve::setValuesAndDepths( const std::vector& xValues, RiaDefines::DepthTypeEnum depthType, double rkbDiff, RiaDefines::DepthUnitType depthUnit, - bool isExtractionCurve ) + bool isExtractionCurve, + const QString& xUnits ) { m_curveData->setValuesAndDepths( xValues, depths, depthType, rkbDiff, depthUnit, isExtractionCurve ); + m_curveData->setXUnits( xUnits ); calculateCurveDataXRange(); } @@ -126,9 +128,11 @@ void RimWellLogCurve::setValuesAndDepths( const std::vector& const std::map>& depths, double rkbDiff, RiaDefines::DepthUnitType depthUnit, - bool isExtractionCurve ) + bool isExtractionCurve, + const QString& xUnits ) { m_curveData->setValuesAndDepths( xValues, depths, rkbDiff, depthUnit, isExtractionCurve ); + m_curveData->setXUnits( xUnits ); calculateCurveDataXRange(); } @@ -140,11 +144,12 @@ void RimWellLogCurve::setValuesWithMdAndTVD( const std::vector& xValues, const std::vector& tvdMSL, double rkbDiff, RiaDefines::DepthUnitType depthUnit, - bool isExtractionCurve ) + bool isExtractionCurve, + const QString& xUnits ) { std::map> depths = {{RiaDefines::MEASURED_DEPTH, measuredDepths}, {RiaDefines::TRUE_VERTICAL_DEPTH, tvdMSL}}; - setValuesAndDepths( xValues, depths, rkbDiff, depthUnit, isExtractionCurve ); + setValuesAndDepths( xValues, depths, rkbDiff, depthUnit, isExtractionCurve, xUnits ); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimWellLogCurve.h b/ApplicationCode/ProjectDataModel/RimWellLogCurve.h index c6fc1f6c13..74b666aa30 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogCurve.h +++ b/ApplicationCode/ProjectDataModel/RimWellLogCurve.h @@ -20,6 +20,7 @@ #pragma once #include "RiaDefines.h" +#include "RiaWellLogUnitTools.h" #include "RimPlotCurve.h" #include "cvfObject.h" @@ -47,24 +48,28 @@ public: RiaDefines::DepthTypeEnum depthType, double rkbDiff, RiaDefines::DepthUnitType depthUnit, - bool isExtractionCurve ); + bool isExtractionCurve, + const QString& xUnits = RiaWellLogUnitTools::noUnitString() ); void setValuesWithMdAndTVD( const std::vector& xValues, const std::vector& measuredDepths, const std::vector& tvDepths, double rkbDiff, RiaDefines::DepthUnitType depthUnit, - bool isExtractionCurve ); + bool isExtractionCurve, + const QString& xUnits = RiaWellLogUnitTools::noUnitString() ); void setValuesAndDepths( const std::vector& xValues, const std::map>& depths, double rkbDiff, RiaDefines::DepthUnitType depthUnit, - bool isExtractionCurve ); + bool isExtractionCurve, + const QString& xUnits = RiaWellLogUnitTools::noUnitString() ); const RigWellLogCurveData* curveData() const; virtual QString wellName() const = 0; virtual QString wellLogChannelUiName() const = 0; virtual QString wellLogChannelName() const; + virtual QString wellLogChannelUnits() const = 0; virtual QString wellDate() const { return ""; diff --git a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp index 06e7b3ae41..a04db39c99 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp @@ -20,8 +20,10 @@ #include "RimWellLogExtractionCurve.h" #include "RiaApplication.h" +#include "RiaLogging.h" #include "RiaSimWellBranchTools.h" +#include "RiaWellLogUnitTools.h" #include "RigCaseCellResultsData.h" #include "RigEclipseCaseData.h" #include "RigEclipseWellLogExtractor.h" @@ -450,6 +452,7 @@ void RimWellLogExtractionCurve::extractData( bool* isUsingPseudoLength, double rkbDiff = 0.0; RiaDefines::DepthUnitType depthUnit = RiaDefines::UNIT_METER; + QString xUnits = RiaWellLogUnitTools::noUnitString(); if ( eclExtractor.notNull() && eclipseCase ) { @@ -498,7 +501,7 @@ void RimWellLogExtractionCurve::extractData( bool* isUsingPseudoLength, } m_geomResultDefinition->loadResult(); - geomExtractor->curveData( m_geomResultDefinition->resultAddress(), m_timeStep, &values ); + xUnits = geomExtractor->curveData( m_geomResultDefinition->resultAddress(), m_timeStep, &values ); if ( performDataSmoothing ) { geomExtractor->performCurveDataSmoothing( m_timeStep, @@ -518,7 +521,8 @@ void RimWellLogExtractionCurve::extractData( bool* isUsingPseudoLength, RiaDefines::MEASURED_DEPTH, 0.0, depthUnit, - !performDataSmoothing ); + !performDataSmoothing, + xUnits ); } else { @@ -527,7 +531,8 @@ void RimWellLogExtractionCurve::extractData( bool* isUsingPseudoLength, tvDepthValues, rkbDiff, depthUnit, - !performDataSmoothing ); + !performDataSmoothing, + xUnits ); } } } @@ -541,88 +546,27 @@ void RimWellLogExtractionCurve::findAndLoadWbsParametersFromLasFiles( const RimW auto allParams = RigWbsParameter::allParameters(); for ( const RigWbsParameter& parameter : allParams ) { - if ( parameter == RigWbsParameter::PP_Reservoir() || parameter == RigWbsParameter::PP_NonReservoir() ) - { - findAndLoadPorePressuresFromLasFiles( wellPath, parameter, geomExtractor ); - } - else if ( parameter == RigWbsParameter::UCS() ) - { - findAndLoadUcsFromLasFiles( wellPath, geomExtractor ); - } - else - { - // Generic LAS - QString lasAddress = parameter.addressString( RigWbsParameter::LAS_FILE ); + QString lasAddress = parameter.addressString( RigWbsParameter::LAS_FILE ); - std::vector> lasFileValues = - RimWellLogFile::findMdAndChannelValuesForWellPath( wellPath, lasAddress ); - if ( !lasFileValues.empty() ) + QString lasUnits; + std::vector> lasFileValues = + RimWellLogFile::findMdAndChannelValuesForWellPath( wellPath, lasAddress, &lasUnits ); + if ( !lasFileValues.empty() ) + { + QString extractorUnits = geomExtractor->parameterInputUnits( parameter ); + + if ( RiaWellLogUnitTools::convertValues( &lasFileValues, lasUnits, extractorUnits, wellPath->wellPathGeometry() ) ) { geomExtractor->setWbsLasValues( parameter, lasFileValues ); } - } - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimWellLogExtractionCurve::findAndLoadUcsFromLasFiles( const RimWellPath* wellPath, - RigGeoMechWellLogExtractor* geomExtractor ) -{ - { - QString lasAddress = RigWbsParameter::UCS().addressString( RigWbsParameter::LAS_FILE ); - std::vector> logFileUcs = RimWellLogFile::findMdAndChannelValuesForWellPath( wellPath, - lasAddress ); - if ( !logFileUcs.empty() ) - { - // TODO: UCS is typically in MPa, but not necessarily. - // We need to at least give a warning if the units don't match - // ... and preferable do a conversion. - for ( auto& ucsValue : logFileUcs ) + else { - ucsValue.second *= 10.0; // MPa -> Bar + QString errMsg = QString( "Could not convert units of LAS-channel %1 from %2 to %3" ) + .arg( lasAddress ) + .arg( lasUnits ) + .arg( extractorUnits ); + RiaLogging::error( errMsg ); } - geomExtractor->setWbsLasValues( RigWbsParameter::UCS(), logFileUcs ); - } - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimWellLogExtractionCurve::findAndLoadPorePressuresFromLasFiles( const RimWellPath* wellPath, - const RigWbsParameter& parameter, - RigGeoMechWellLogExtractor* geomExtractor ) -{ - { - std::vector> logFileMudWeights = - RimWellLogFile::findMdAndChannelValuesForWellPath( wellPath, - parameter.addressString( RigWbsParameter::LAS_FILE ) ); - if ( !logFileMudWeights.empty() ) - { - std::vector> porePressuresBar; - porePressuresBar.reserve( logFileMudWeights.size() ); - - for ( auto& mudWeight : logFileMudWeights ) - { - // Log file mud weights come in SG units (g / cm^3). - // We need SI as input (kg / m^3), so multiply by 1000: - double mudWeightsSI = mudWeight.second * 1000.0; - // To get specific mudWeight (N / m^3): - double specificMudWeight = mudWeightsSI * 9.81; - - double md = mudWeight.first; - cvf::Vec3d point = wellPath->wellPathGeometry()->interpolatedPointAlongWellPath( md ); - double depth = -point.z() + wellPath->wellPathGeometry()->rkbDiff(); - - // Pore pressure in pascal - double ppPascal = specificMudWeight * depth; - - // Pore pressure in bar - porePressuresBar.emplace_back( mudWeight.first, ppPascal * 1.0e-5 ); - } - geomExtractor->setWbsLasValues( parameter, porePressuresBar ); } } } @@ -963,6 +907,27 @@ QString RimWellLogExtractionCurve::wellLogChannelName() const return name; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimWellLogExtractionCurve::wellLogChannelUnits() const +{ + RimGeoMechCase* geoMechCase = dynamic_cast( m_case.value() ); + RimEclipseCase* eclipseCase = dynamic_cast( m_case.value() ); + + QString name; + if ( eclipseCase ) + { + name = RiaWellLogUnitTools::noUnitString(); + } + else if ( geoMechCase ) + { + name = m_geomResultDefinition->defaultLasUnits(); + } + + return name; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.h b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.h index 210b8196b0..19dfe47d83 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.h +++ b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.h @@ -66,6 +66,7 @@ public: QString wellName() const override; QString wellLogChannelUiName() const override; QString wellLogChannelName() const override; + QString wellLogChannelUnits() const override; QString wellDate() const override; int branchIndex() const; bool branchDetection() const; @@ -87,12 +88,6 @@ public: static void findAndLoadWbsParametersFromLasFiles( const RimWellPath* wellPath, RigGeoMechWellLogExtractor* geomExtractor ); - static void findAndLoadUcsFromLasFiles( const RimWellPath* wellPath, RigGeoMechWellLogExtractor* geomExtractor ); - - static void findAndLoadPorePressuresFromLasFiles( const RimWellPath* wellPath, - const RigWbsParameter& parameter, - RigGeoMechWellLogExtractor* geomExtractor ); - void setAutoNameComponents( bool addCaseName, bool addProperty, bool addWellname, bool addTimeStep, bool addDate ); protected: diff --git a/ApplicationCode/ProjectDataModel/RimWellLogFile.cpp b/ApplicationCode/ProjectDataModel/RimWellLogFile.cpp index e9481ea864..0717f674df 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogFile.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogFile.cpp @@ -257,7 +257,8 @@ void RimWellLogFile::updateFilePathsFromProjectPath( const QString& newProjectPa /// //-------------------------------------------------------------------------------------------------- std::vector> RimWellLogFile::findMdAndChannelValuesForWellPath( const RimWellPath* wellPath, - const QString& channelName ) + const QString& channelName, + QString* unitString /*=nullptr*/ ) { CVF_ASSERT( wellPath ); std::vector wellLogFiles; @@ -268,6 +269,10 @@ std::vector> RimWellLogFile::findMdAndChannelValuesFor std::vector channelValues = fileData->values( channelName ); if ( !channelValues.empty() ) { + if ( unitString ) + { + *unitString = fileData->wellLogChannelUnitString( channelName ); + } std::vector depthValues = fileData->depthValues(); CVF_ASSERT( depthValues.size() == channelValues.size() ); std::vector> depthValuePairs; diff --git a/ApplicationCode/ProjectDataModel/RimWellLogFile.h b/ApplicationCode/ProjectDataModel/RimWellLogFile.h index 1b2273d44b..3a654c7d9b 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogFile.h +++ b/ApplicationCode/ProjectDataModel/RimWellLogFile.h @@ -85,7 +85,8 @@ public: void updateFilePathsFromProjectPath( const QString& newProjectPath, const QString& oldProjectPath ); static std::vector> findMdAndChannelValuesForWellPath( const RimWellPath* wellPath, - const QString& channelName ); + const QString& channelName, + QString* unitString = nullptr ); private: void setupBeforeSave() override; diff --git a/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp index e16ed0f957..6edd584014 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp @@ -57,7 +57,7 @@ RimWellLogFileCurve::RimWellLogFileCurve() CAF_PDM_InitFieldNoDefault( &m_wellPath, "CurveWellPath", "Well Path", "", "", "" ); m_wellPath.uiCapability()->setUiTreeChildrenHidden( true ); - CAF_PDM_InitFieldNoDefault( &m_wellLogChannnelName, "CurveWellLogChannel", "Well Log Channel", "", "", "" ); + CAF_PDM_InitFieldNoDefault( &m_wellLogChannelName, "CurveWellLogChannel", "Well Log Channel", "", "", "" ); CAF_PDM_InitFieldNoDefault( &m_wellLogFile, "WellLogFile", "Well Log File", "", "", "" ); @@ -87,7 +87,7 @@ void RimWellLogFileCurve::onLoadDataAndUpdate( bool updateParentPlot ) RigWellLogFile* wellLogFile = m_wellLogFile->wellLogFileData(); if ( wellLogFile ) { - std::vector values = wellLogFile->values( m_wellLogChannnelName ); + std::vector values = wellLogFile->values( m_wellLogChannelName ); std::vector measuredDepthValues = wellLogFile->depthValues(); std::vector tvdMslValues = wellLogFile->tvdMslValues(); std::vector tvdRkbValues = wellLogFile->tvdRkbValues(); @@ -201,7 +201,7 @@ RimWellPath* RimWellLogFileCurve::wellPath() const //-------------------------------------------------------------------------------------------------- void RimWellLogFileCurve::setWellLogChannelName( const QString& name ) { - m_wellLogChannnelName = name; + m_wellLogChannelName = name; } //-------------------------------------------------------------------------------------------------- @@ -225,7 +225,7 @@ void RimWellLogFileCurve::fieldChangedByUi( const caf::PdmFieldHandle* changedFi { this->loadDataAndUpdate( true ); } - else if ( changedField == &m_wellLogChannnelName ) + else if ( changedField == &m_wellLogChannelName ) { this->loadDataAndUpdate( true ); } @@ -246,7 +246,7 @@ void RimWellLogFileCurve::defineUiOrdering( QString uiConfigName, caf::PdmUiOrde caf::PdmUiGroup* curveDataGroup = uiOrdering.addNewGroup( "Curve Data" ); curveDataGroup->add( &m_wellPath ); curveDataGroup->add( &m_wellLogFile ); - curveDataGroup->add( &m_wellLogChannnelName ); + curveDataGroup->add( &m_wellLogChannelName ); caf::PdmUiGroup* appearanceGroup = uiOrdering.addNewGroup( "Appearance" ); RimPlotCurve::appearanceUiOrdering( *appearanceGroup ); @@ -298,7 +298,7 @@ QList RimWellLogFileCurve::calculateValueOptions( const } } - if ( fieldNeedingOptions == &m_wellLogChannnelName ) + if ( fieldNeedingOptions == &m_wellLogChannelName ) { if ( m_wellPath() ) { @@ -372,9 +372,9 @@ QString RimWellLogFileCurve::createCurveAutoName() name.push_back( wellName() ); name.push_back( "LAS" ); - if ( !m_wellLogChannnelName().isEmpty() ) + if ( !m_wellLogChannelName().isEmpty() ) { - name.push_back( m_wellLogChannnelName ); + name.push_back( m_wellLogChannelName ); channelNameAvailable = true; } @@ -387,8 +387,7 @@ QString RimWellLogFileCurve::createCurveAutoName() RimWellLogPlot* wellLogPlot; firstAncestorOrThisOfType( wellLogPlot ); CVF_ASSERT( wellLogPlot ); - QString unitName = wellLogFile->wellLogChannelUnitString( m_wellLogChannnelName, - wellLogPlot->depthUnit() ); + QString unitName = wellLogFile->wellLogChannelUnitString( m_wellLogChannelName, wellLogPlot->depthUnit() ); if ( !unitName.isEmpty() ) { @@ -414,7 +413,19 @@ QString RimWellLogFileCurve::createCurveAutoName() //-------------------------------------------------------------------------------------------------- QString RimWellLogFileCurve::wellLogChannelUiName() const { - return m_wellLogChannnelName; + return m_wellLogChannelName; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimWellLogFileCurve::wellLogChannelUnits() const +{ + if ( m_wellLogFile && m_wellLogFile->wellLogFileData() ) + { + return m_wellLogFile->wellLogFileData()->wellLogChannelUnitString( m_wellLogChannelName ); + } + return RiaWellLogUnitTools::noUnitString(); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.h b/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.h index 88642f0180..37fcec4f61 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.h +++ b/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.h @@ -50,6 +50,7 @@ public: // Overrides from RimWellLogPlotCurve QString wellName() const override; QString wellLogChannelUiName() const override; + QString wellLogChannelUnits() const override; RimWellLogFile* wellLogFile() const; @@ -73,6 +74,6 @@ protected: protected: caf::PdmPtrField m_wellPath; caf::PdmPtrField m_wellLogFile; - caf::PdmField m_wellLogChannnelName; + caf::PdmField m_wellLogChannelName; caf::PdmField m_wellLogChannnelUnit; }; diff --git a/ApplicationCode/ProjectDataModel/RimWellLogRftCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogRftCurve.cpp index e17ccc546a..ee2fca99a4 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogRftCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogRftCurve.cpp @@ -144,6 +144,14 @@ QString RimWellLogRftCurve::wellLogChannelUiName() const return m_wellLogChannelName().text(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimWellLogRftCurve::wellLogChannelUnits() const +{ + return RiaWellLogUnitTools::noUnitString(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimWellLogRftCurve.h b/ApplicationCode/ProjectDataModel/RimWellLogRftCurve.h index 1cf16da8dc..f9d040b7f3 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogRftCurve.h +++ b/ApplicationCode/ProjectDataModel/RimWellLogRftCurve.h @@ -60,6 +60,7 @@ public: QString wellName() const override; QString wellLogChannelUiName() const override; + QString wellLogChannelUnits() const override; void setEclipseResultCase( RimEclipseResultCase* eclipseResultCase ); RimEclipseResultCase* eclipseResultCase() const; diff --git a/ApplicationCode/ProjectDataModel/RimWellMeasurementCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellMeasurementCurve.cpp index 4d14775ced..5b24de37fd 100644 --- a/ApplicationCode/ProjectDataModel/RimWellMeasurementCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellMeasurementCurve.cpp @@ -278,6 +278,14 @@ QString RimWellMeasurementCurve::wellLogChannelUiName() const return QString( "" ); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimWellMeasurementCurve::wellLogChannelUnits() const +{ + return RiaWellLogUnitTools::noUnitString(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimWellMeasurementCurve.h b/ApplicationCode/ProjectDataModel/RimWellMeasurementCurve.h index 62b1d503ac..412783841a 100644 --- a/ApplicationCode/ProjectDataModel/RimWellMeasurementCurve.h +++ b/ApplicationCode/ProjectDataModel/RimWellMeasurementCurve.h @@ -49,6 +49,7 @@ public: // Overrides from RimWellLogPlotCurve QString wellName() const override; QString wellLogChannelUiName() const override; + QString wellLogChannelUnits() const override; protected: // Overrides from RimWellLogCurve diff --git a/ApplicationCode/ReservoirDataModel/RigGeoMechWellLogExtractor.cpp b/ApplicationCode/ReservoirDataModel/RigGeoMechWellLogExtractor.cpp index c11bab40dd..6cb94ab30f 100644 --- a/ApplicationCode/ReservoirDataModel/RigGeoMechWellLogExtractor.cpp +++ b/ApplicationCode/ReservoirDataModel/RigGeoMechWellLogExtractor.cpp @@ -31,6 +31,7 @@ #include "RigGeoMechBoreHoleStressCalculator.h" #include "RigGeoMechCaseData.h" +#include "RiaWellLogUnitTools.h" #include "RigWellLogExtractionTools.h" #include "RigWellPath.h" #include "RigWellPathGeometryTools.h" @@ -109,17 +110,17 @@ void RigGeoMechWellLogExtractor::performCurveDataSmoothing( int std::vector*> dependentValues = {tvds, &interfaceShValuesDbl, &interfacePorePressuresDbl}; std::vector smoothOrFilterSegments = determineFilteringOrSmoothing( interfacePorePressuresDbl ); - filterShortSegments( mds, values, &smoothOrFilterSegments, dependentValues ); - filterColinearSegments( mds, values, &smoothOrFilterSegments, dependentValues ); smoothSegments( mds, tvds, values, interfaceShValuesDbl, smoothOrFilterSegments, smoothingTreshold ); } } //-------------------------------------------------------------------------------------------------- -/// +/// Get curve data for a given parameter. Returns the output units of the data. //-------------------------------------------------------------------------------------------------- -void RigGeoMechWellLogExtractor::curveData( const RigFemResultAddress& resAddr, int frameIndex, std::vector* values ) +QString RigGeoMechWellLogExtractor::curveData( const RigFemResultAddress& resAddr, + int frameIndex, + std::vector* values ) { CVF_TIGHT_ASSERT( values ); @@ -159,25 +160,31 @@ void RigGeoMechWellLogExtractor::curveData( const RigFemResultAddress& resAddr, RigWbsParameter param; if ( RigWbsParameter::findParameter( QString::fromStdString( resAddr.fieldName ), ¶m ) ) { - if ( param == RigWbsParameter::OBG0() ) + if ( param == RigWbsParameter::FG_Shale() ) { - frameIndex = 0; + wellBoreFGShale( frameIndex, values ); } - calculateWbsParameterForAllSegments( param, frameIndex, values ); - if ( param == RigWbsParameter::UCS() ) // UCS is reported as UCS/100 + else { - for ( double& value : *values ) + if ( param == RigWbsParameter::OBG0() ) { - if ( isValid( value ) ) value /= 100.0; + frameIndex = 0; + } + calculateWbsParameterForAllSegments( param, frameIndex, values ); + if ( param == RigWbsParameter::UCS() ) // UCS is reported as UCS/100 + { + for ( double& value : *values ) + { + if ( isValid( value ) ) value /= 100.0; + } + return RiaWellLogUnitTools::barX100UnitString(); } } } } } - else + else if ( resAddr.isValid() ) { - if ( !resAddr.isValid() ) return; - RigFemResultAddress convResAddr = resAddr; // When showing POR results, always use the element nodal result, @@ -189,18 +196,20 @@ void RigGeoMechWellLogExtractor::curveData( const RigFemResultAddress& resAddr, const std::vector& resultValues = m_caseData->femPartResults()->resultValues( convResAddr, 0, frameIndex ); - if ( resultValues.empty() ) return; + if ( !resultValues.empty() ) + { + std::vector interfaceValues = interpolateInterfaceValues( convResAddr, frameIndex, resultValues ); - std::vector interfaceValues = interpolateInterfaceValues( convResAddr, frameIndex, resultValues ); - - values->resize( interfaceValues.size(), std::numeric_limits::infinity() ); + values->resize( interfaceValues.size(), std::numeric_limits::infinity() ); #pragma omp parallel for - for ( int64_t intersectionIdx = 0; intersectionIdx < (int64_t)m_intersections.size(); ++intersectionIdx ) - { - ( *values )[intersectionIdx] = static_cast( interfaceValues[intersectionIdx] ); + for ( int64_t intersectionIdx = 0; intersectionIdx < (int64_t)m_intersections.size(); ++intersectionIdx ) + { + ( *values )[intersectionIdx] = static_cast( interfaceValues[intersectionIdx] ); + } } } + return RiaWellLogUnitTools::noUnitString(); } //-------------------------------------------------------------------------------------------------- @@ -216,8 +225,6 @@ std::vector std::vector finalSourcesPerSegment( m_intersections.size(), RigWbsParameter::UNDEFINED ); - outputValues->resize( m_intersections.size(), std::numeric_limits::infinity() ); - if ( primarySource == RigWbsParameter::UNDEFINED ) { return finalSourcesPerSegment; @@ -257,6 +264,8 @@ std::vector elementPropertyValues = &( resultCollection->resultValues( elementPropertyAddr, 0, frameIndex ) ); } + std::vector unscaledValues( m_intersections.size(), std::numeric_limits::infinity() ); + #pragma omp parallel for for ( int64_t intersectionIdx = 0; intersectionIdx < (int64_t)m_intersections.size(); ++intersectionIdx ) { @@ -268,7 +277,7 @@ std::vector if ( intersectionIdx < (int64_t)gridValues.size() && gridValues[intersectionIdx] != std::numeric_limits::infinity() ) { - ( *outputValues )[intersectionIdx] = gridValues[intersectionIdx]; + unscaledValues[intersectionIdx] = gridValues[intersectionIdx]; finalSourcesPerSegment[intersectionIdx] = RigWbsParameter::GRID; break; } @@ -277,10 +286,10 @@ std::vector { if ( !lasFileValues.empty() ) { - double lasValue = getWellLogSegmentValue( intersectionIdx, lasFileValues ); + double lasValue = getWellLogIntersectionValue( intersectionIdx, lasFileValues ); if ( lasValue != std::numeric_limits::infinity() ) { - ( *outputValues )[intersectionIdx] = lasValue; + unscaledValues[intersectionIdx] = lasValue; finalSourcesPerSegment[intersectionIdx] = RigWbsParameter::LAS_FILE; break; } @@ -292,28 +301,28 @@ std::vector size_t elmIdx = m_intersectedCellsGlobIdx[intersectionIdx]; if ( elmIdx < elementPropertyValues->size() ) { - ( *outputValues )[intersectionIdx] = ( *elementPropertyValues )[elmIdx]; + unscaledValues[intersectionIdx] = ( *elementPropertyValues )[elmIdx]; finalSourcesPerSegment[intersectionIdx] = RigWbsParameter::ELEMENT_PROPERTY_TABLE; break; } } else if ( *it == RigWbsParameter::HYDROSTATIC && isPPresult ) { - ( *outputValues )[intersectionIdx] = hydroStaticPorePressureForSegment( intersectionIdx ); + unscaledValues[intersectionIdx] = hydroStaticPorePressureForIntersection( intersectionIdx ); finalSourcesPerSegment[intersectionIdx] = RigWbsParameter::HYDROSTATIC; break; } else if ( *it == RigWbsParameter::USER_DEFINED && isPPresult ) { - ( *outputValues )[intersectionIdx] = userDefinedValue * - hydroStaticPorePressureForSegment( intersectionIdx ); + unscaledValues[intersectionIdx] = userDefinedValue * + hydroStaticPorePressureForIntersection( intersectionIdx ); finalSourcesPerSegment[intersectionIdx] = RigWbsParameter::USER_DEFINED; break; } else if ( *it == RigWbsParameter::USER_DEFINED ) { - ( *outputValues )[intersectionIdx] = userDefinedValue; + unscaledValues[intersectionIdx] = userDefinedValue; finalSourcesPerSegment[intersectionIdx] = RigWbsParameter::USER_DEFINED; break; } @@ -322,13 +331,29 @@ std::vector if ( parameter.normalizeByHydrostaticPP() ) { + outputValues->resize( unscaledValues.size(), std::numeric_limits::infinity() ); + #pragma omp parallel for for ( int64_t intersectionIdx = 0; intersectionIdx < (int64_t)m_intersections.size(); ++intersectionIdx ) { - ( *outputValues )[intersectionIdx] /= hydroStaticPorePressureForSegment( intersectionIdx ); + RigWbsParameter::Source source = finalSourcesPerSegment[intersectionIdx]; + + if ( source == RigWbsParameter::ELEMENT_PROPERTY_TABLE || source == RigWbsParameter::GRID ) + { + ( *outputValues )[intersectionIdx] = unscaledValues[intersectionIdx] / + hydroStaticPorePressureForSegment( intersectionIdx ); + } + else + { + ( *outputValues )[intersectionIdx] = unscaledValues[intersectionIdx] / + hydroStaticPorePressureForIntersection( intersectionIdx ); + } } } - + else + { + outputValues->swap( unscaledValues ); + } return finalSourcesPerSegment; } @@ -466,7 +491,7 @@ std::vector } else { - ( *values )[intersectionIdx] = hydroStaticPorePressureForSegment( intersectionIdx ); + ( *values )[intersectionIdx] = hydroStaticPorePressureForIntersection( intersectionIdx ); sources[intersectionIdx] = RigWbsParameter::HYDROSTATIC; } } @@ -595,6 +620,8 @@ void RigGeoMechWellLogExtractor::wellBoreWallCurveData( const RigFemResultAddres //-------------------------------------------------------------------------------------------------- void RigGeoMechWellLogExtractor::wellBoreFGShale( int frameIndex, std::vector* values ) { + if ( values->empty() ) values->resize( m_intersections.size(), std::numeric_limits::infinity() ); + WbsParameterSource source = m_parameterSources.at( RigWbsParameter::FG_Shale() ); if ( source == RigWbsParameter::DERIVED_FROM_K0FG ) { @@ -709,6 +736,19 @@ void RigGeoMechWellLogExtractor::setWbsUserDefinedValue( RigWbsParameter paramet m_userDefinedValues[parameter] = userDefinedValue; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RigGeoMechWellLogExtractor::parameterInputUnits( const RigWbsParameter& parameter ) +{ + if ( parameter == RigWbsParameter::PP_NonReservoir() || parameter == RigWbsParameter::PP_Reservoir() || + parameter == RigWbsParameter::UCS() ) + { + return RiaWellLogUnitTools::barUnitString(); + } + return RiaWellLogUnitTools::noUnitString(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -1038,42 +1078,37 @@ cvf::Vec3f RigGeoMechWellLogExtractor::cellCentroid( size_t intersectionIdx ) co //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -double RigGeoMechWellLogExtractor::getWellLogSegmentValue( size_t intersectionIdx, - const std::vector>& wellLogValues ) const +double RigGeoMechWellLogExtractor::getWellLogIntersectionValue( + size_t intersectionIdx, + const std::vector>& wellLogValues ) const { - if ( !wellLogValues.empty() ) - { - double startMD, endMD; - if ( intersectionIdx % 2 == 0 ) - { - startMD = m_intersectionMeasuredDepths[intersectionIdx]; - endMD = m_intersectionMeasuredDepths[intersectionIdx + 1]; - } - else - { - startMD = m_intersectionMeasuredDepths[intersectionIdx - 1]; - endMD = m_intersectionMeasuredDepths[intersectionIdx]; - } + const double eps = 1.0e-4; - RiaWeightedMeanCalculator averageCalc; - for ( auto& depthAndValue : wellLogValues ) + double intersection_md = m_intersectionMeasuredDepths[intersectionIdx]; + for ( size_t i = 0; i < wellLogValues.size() - 1; ++i ) + { + double las_md_i = wellLogValues[i].first; + double las_md_ip1 = wellLogValues[i + 1].first; + if ( cvf::Math::valueInRange( intersection_md, las_md_i, las_md_ip1 ) ) { - if ( cvf::Math::valueInRange( depthAndValue.first, startMD, endMD ) ) + double dist_i = std::abs( intersection_md - las_md_i ); + double dist_ip1 = std::abs( intersection_md - las_md_ip1 ); + + if ( dist_i < eps ) { - cvf::Vec3d position = m_wellPath->interpolatedPointAlongWellPath( depthAndValue.first ); - cvf::Vec3d centroid( cellCentroid( intersectionIdx ) ); - double weight = 1.0; - double dist = ( position - centroid ).length(); - if ( dist > 1.0 ) - { - weight = 1.0 / dist; - } - averageCalc.addValueAndWeight( depthAndValue.second, weight ); + return wellLogValues[i].second; + } + else if ( dist_ip1 < eps ) + { + return wellLogValues[i + 1].second; + } + else + { + RiaWeightedMeanCalculator averageCalc; + averageCalc.addValueAndWeight( wellLogValues[i].second, 1.0 / dist_i ); + averageCalc.addValueAndWeight( wellLogValues[i + 1].second, 1.0 / dist_ip1 ); + return averageCalc.weightedMean(); } - } - if ( averageCalc.validAggregatedWeight() ) - { - return averageCalc.weightedMean(); } } return std::numeric_limits::infinity(); @@ -1130,123 +1165,6 @@ void RigGeoMechWellLogExtractor::initializeResultValues( std::vector resultValues.resize( resultCount ); } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RigGeoMechWellLogExtractor::filterShortSegments( std::vector* xValues, - std::vector* yValues, - std::vector* filterSegments, - std::vector*>& vectorOfDependentValues ) -{ - const double lengthEpsilon = 1.0e-3; - - std::vector simplerXValues; - std::vector simplerYValues; - std::vector simplerFilterSegments; - std::vector> simplerDependentValues( vectorOfDependentValues.size() ); - - simplerXValues.push_back( xValues->front() ); - simplerYValues.push_back( yValues->front() ); - simplerFilterSegments.push_back( filterSegments->front() ); - for ( size_t n = 0; n < vectorOfDependentValues.size(); ++n ) - { - simplerDependentValues[n].push_back( vectorOfDependentValues[n]->front() ); - } - for ( int64_t i = 1; i < int64_t( xValues->size() - 1 ); ++i ) - { - cvf::Vec2d vecIn( ( ( *xValues )[i] - simplerXValues.back() ) / std::max( 1.0, simplerXValues.back() ), - ( ( *yValues )[i] - simplerYValues.back() ) / std::max( 1.0, simplerYValues.back() ) ); - if ( ( *filterSegments )[i] == 0u || vecIn.length() > lengthEpsilon ) - { - simplerXValues.push_back( ( *xValues )[i] ); - simplerYValues.push_back( ( *yValues )[i] ); - simplerFilterSegments.push_back( ( *filterSegments )[i] ); - for ( size_t n = 0; n < vectorOfDependentValues.size(); ++n ) - { - simplerDependentValues[n].push_back( ( *vectorOfDependentValues[n] )[i] ); - } - } - } - simplerXValues.push_back( xValues->back() ); - simplerYValues.push_back( yValues->back() ); - simplerFilterSegments.push_back( filterSegments->back() ); - for ( size_t i = 0; i < vectorOfDependentValues.size(); ++i ) - { - simplerDependentValues[i].push_back( vectorOfDependentValues[i]->back() ); - } - - xValues->swap( simplerXValues ); - yValues->swap( simplerYValues ); - filterSegments->swap( simplerFilterSegments ); - for ( size_t n = 0; n < vectorOfDependentValues.size(); ++n ) - { - vectorOfDependentValues[n]->swap( simplerDependentValues[n] ); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RigGeoMechWellLogExtractor::filterColinearSegments( std::vector* xValues, - std::vector* yValues, - std::vector* filterSegments, - std::vector*>& vectorOfDependentValues ) -{ - std::vector simplerXValues; - std::vector simplerYValues; - std::vector simpledFilterSegments; - std::vector> simplerDependentValues( vectorOfDependentValues.size() ); - - for ( size_t i = 0; i < 2; ++i ) - { - simplerXValues.push_back( ( *xValues )[i] ); - simplerYValues.push_back( ( *yValues )[i] ); - simpledFilterSegments.push_back( ( *filterSegments )[i] ); - - for ( size_t n = 0; n < vectorOfDependentValues.size(); ++n ) - { - simplerDependentValues[n].push_back( ( *vectorOfDependentValues[n] )[i] ); - } - } - for ( int64_t i = 2; i < int64_t( xValues->size() - 1 ); ++i ) - { - cvf::Vec2d vecIn( ( ( *xValues )[i] - simplerXValues.back() ) / std::max( 1.0, simplerXValues.back() ), - ( ( *yValues )[i] - simplerYValues.back() ) / std::max( 1.0, simplerYValues.back() ) ); - cvf::Vec2d vecOut( ( ( *xValues )[i + 1] - ( *xValues )[i] ) / std::max( 1.0, ( *xValues )[i] ), - ( ( *yValues )[i + 1] - ( *yValues )[i] ) / std::max( 1.0, ( *yValues )[i] ) ); - vecIn.normalize(); - vecOut.normalize(); - double dotProduct = std::abs( vecIn * vecOut ); - - if ( ( *filterSegments )[i] == 0u || std::fabs( 1.0 - dotProduct ) > 1.0e-3 ) - { - simplerXValues.push_back( ( *xValues )[i] ); - simplerYValues.push_back( ( *yValues )[i] ); - simpledFilterSegments.push_back( ( *filterSegments )[i] ); - for ( size_t n = 0; n < vectorOfDependentValues.size(); ++n ) - { - simplerDependentValues[n].push_back( ( *vectorOfDependentValues[n] )[i] ); - } - } - } - simplerXValues.push_back( xValues->back() ); - simplerYValues.push_back( yValues->back() ); - simpledFilterSegments.push_back( filterSegments->back() ); - - for ( size_t i = 0; i < vectorOfDependentValues.size(); ++i ) - { - simplerDependentValues[i].push_back( vectorOfDependentValues[i]->back() ); - } - - xValues->swap( simplerXValues ); - yValues->swap( simplerYValues ); - filterSegments->swap( simpledFilterSegments ); - for ( size_t n = 0; n < vectorOfDependentValues.size(); ++n ) - { - vectorOfDependentValues[n]->swap( simplerDependentValues[n] ); - } -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -1338,6 +1256,18 @@ std::vector return smoothOrFilterSegments; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RigGeoMechWellLogExtractor::hydroStaticPorePressureForIntersection( size_t intersectionIdx ) const +{ + double trueVerticalDepth = m_intersectionTVDs[intersectionIdx]; + double effectiveDepthMeters = trueVerticalDepth + wellPathData()->rkbDiff(); + double hydroStaticPorePressurePascal = effectiveDepthMeters * UNIT_WEIGHT_OF_WATER; + double hydroStaticPorePressureBar = pascalToBar( hydroStaticPorePressurePascal ); + return hydroStaticPorePressureBar; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ReservoirDataModel/RigGeoMechWellLogExtractor.h b/ApplicationCode/ReservoirDataModel/RigGeoMechWellLogExtractor.h index dd9a112c92..ba7ce772df 100644 --- a/ApplicationCode/ReservoirDataModel/RigGeoMechWellLogExtractor.h +++ b/ApplicationCode/ReservoirDataModel/RigGeoMechWellLogExtractor.h @@ -65,13 +65,15 @@ public: std::vector* values, const double smoothingTreshold ); - void curveData( const RigFemResultAddress& resAddr, int frameIndex, std::vector* values ); + QString curveData( const RigFemResultAddress& resAddr, int frameIndex, std::vector* values ); const RigGeoMechCaseData* caseData(); void setWbsLasValues( const RigWbsParameter& parameter, const std::vector>& values ); void setWbsParametersSource( RigWbsParameter parameter, WbsParameterSource source ); void setWbsUserDefinedValue( RigWbsParameter parameter, double userDefinedValue ); + static QString parameterInputUnits( const RigWbsParameter& parameter ); + std::vector porePressureSourceRegions( int frameIndex ); std::vector poissonSourceRegions( int frameIndex ); std::vector ucsSourceRegions( int frameIndex ); @@ -117,8 +119,8 @@ private: const caf::Ten3d& wellPathTensor ); cvf::Vec3f cellCentroid( size_t intersectionIdx ) const; - double getWellLogSegmentValue( size_t intersectionIdx, - const std::vector>& wellLogValues ) const; + double getWellLogIntersectionValue( size_t intersectionIdx, + const std::vector>& wellLogValues ) const; static double pascalToBar( double pascalValue ); @@ -147,6 +149,7 @@ private: std::vector determineFilteringOrSmoothing( const std::vector& porePressures ); + double hydroStaticPorePressureForIntersection( size_t intersectionIdx ) const; double hydroStaticPorePressureForSegment( size_t intersectionIdx ) const; static bool isValid( double value ); @@ -156,9 +159,9 @@ private: cvf::ref m_caseData; std::map>> m_lasFileValues; - - std::map m_parameterSources; - std::map m_userDefinedValues; + std::map m_lasFileInputUnits; + std::map m_parameterSources; + std::map m_userDefinedValues; static const double UNIT_WEIGHT_OF_WATER; }; diff --git a/ApplicationCode/ReservoirDataModel/RigLasFileExporter.cpp b/ApplicationCode/ReservoirDataModel/RigLasFileExporter.cpp index 11a9c3a0b0..cd57d5f596 100644 --- a/ApplicationCode/ReservoirDataModel/RigLasFileExporter.cpp +++ b/ApplicationCode/ReservoirDataModel/RigLasFileExporter.cpp @@ -62,7 +62,7 @@ public: if ( !m_curveData->xValues().empty() ) { - std::vector wellLogValues = m_curveData->xValues(); + std::vector wellLogValues = m_curveData->xValues( QString::fromStdString( m_unit ) ); for ( size_t vIdx = 0; vIdx < wellLogValues.size(); vIdx++ ) { double value = wellLogValues[vIdx]; @@ -339,7 +339,7 @@ void RigLasFileExporter::setResamplingInterval( double interval ) //-------------------------------------------------------------------------------------------------- void RigLasFileExporter::wellPathsAndRkbDiff( std::vector* wellNames, std::vector* rkbDiffs ) { - std::vector lasFileDescriptions = createLasFileDescriptions( m_curves ); + std::vector lasFileDescriptions = createLasFileDescriptions( m_curves, false ); std::set uniqueWellNames; @@ -366,7 +366,7 @@ void RigLasFileExporter::setRkbDiffs( const std::vector& wellNames, con { assert( wellNames.size() == rkbDiffs.size() ); - std::vector lasFileDescriptions = createLasFileDescriptions( m_curves ); + std::vector lasFileDescriptions = createLasFileDescriptions( m_curves, false ); for ( size_t i = 0; i < wellNames.size(); i++ ) { @@ -386,11 +386,12 @@ void RigLasFileExporter::setRkbDiffs( const std::vector& wellNames, con std::vector RigLasFileExporter::writeToFolder( const QString& exportFolder, const QString& filePrefix /*= ""*/, bool capitalizeFileName /*= false*/, - bool alwaysOverwrite /*= false*/ ) + bool alwaysOverwrite /*= false*/, + bool convertCurveUnits /*= false*/ ) { std::vector writtenFiles; - std::vector lasFileDescriptions = createLasFileDescriptions( m_curves ); + std::vector lasFileDescriptions = createLasFileDescriptions( m_curves, convertCurveUnits ); applyUserDefinedRkbOffsets( &lasFileDescriptions ); @@ -439,7 +440,7 @@ std::vector RigLasFileExporter::writeToFolder( const QString& exportFol /// //-------------------------------------------------------------------------------------------------- std::vector - RigLasFileExporter::createLasFileDescriptions( const std::vector& curves ) + RigLasFileExporter::createLasFileDescriptions( const std::vector& curves, bool convertCurveUnits ) { std::vector eclipseCurves; std::vector geoMechCurves; @@ -469,9 +470,9 @@ std::vector std::vector lasFileDescriptions; - appendLasFileDescriptions( externalLasCurves, &lasFileDescriptions ); - appendLasFileDescriptions( eclipseCurves, &lasFileDescriptions ); - appendLasFileDescriptions( geoMechCurves, &lasFileDescriptions ); + appendLasFileDescriptions( externalLasCurves, &lasFileDescriptions, convertCurveUnits ); + appendLasFileDescriptions( eclipseCurves, &lasFileDescriptions, convertCurveUnits ); + appendLasFileDescriptions( geoMechCurves, &lasFileDescriptions, convertCurveUnits ); return lasFileDescriptions; } @@ -480,7 +481,8 @@ std::vector /// //-------------------------------------------------------------------------------------------------- void RigLasFileExporter::appendLasFileDescriptions( const std::vector& curves, - std::vector* lasFileDescriptions ) + std::vector* lasFileDescriptions, + bool convertCurveUnits ) { CVF_ASSERT( lasFileDescriptions ); @@ -555,7 +557,17 @@ void RigLasFileExporter::appendLasFileDescriptions( const std::vectorcurveData(); } - singleLasFileMeta.addLogData( curve->wellLogChannelName().toStdString(), "NO_UNIT", "", curveData ); + QString units = curve->curveData()->xUnits(); + + if ( convertCurveUnits || units == RiaWellLogUnitTools::barX100UnitString() ) + { + units = curve->wellLogChannelUnits(); + } + + singleLasFileMeta.addLogData( curve->wellLogChannelName().toStdString(), + units.toStdString(), + "", + curveData ); } } diff --git a/ApplicationCode/ReservoirDataModel/RigLasFileExporter.h b/ApplicationCode/ReservoirDataModel/RigLasFileExporter.h index 31b45666c4..fd4793ce61 100644 --- a/ApplicationCode/ReservoirDataModel/RigLasFileExporter.h +++ b/ApplicationCode/ReservoirDataModel/RigLasFileExporter.h @@ -41,12 +41,15 @@ public: std::vector writeToFolder( const QString& exportFolder, const QString& filePrefix = "", bool capitalizeFileName = false, - bool alwaysOverwrite = false ); + bool alwaysOverwrite = false, + bool convertCurveUnits = false ); private: - std::vector createLasFileDescriptions( const std::vector& curves ); + std::vector createLasFileDescriptions( const std::vector& curves, + bool convertCurveUnits ); void appendLasFileDescriptions( const std::vector& curves, - std::vector* lasFileDescriptions ); + std::vector* lasFileDescriptions, + bool convertCurveUnits ); QString caseNameFromCurve( RimWellLogCurve* curve ); double rkbDiff( RimWellLogCurve* curve ); diff --git a/ApplicationCode/ReservoirDataModel/RigWbsParameter.cpp b/ApplicationCode/ReservoirDataModel/RigWbsParameter.cpp index 3835a6b75f..32a0e03a84 100644 --- a/ApplicationCode/ReservoirDataModel/RigWbsParameter.cpp +++ b/ApplicationCode/ReservoirDataModel/RigWbsParameter.cpp @@ -17,6 +17,8 @@ ///////////////////////////////////////////////////////////////////////////////// #include "RigWbsParameter.h" +#include "RiaWellLogUnitTools.h" + #include "cafAssert.h" namespace caf @@ -39,7 +41,10 @@ void RigWbsParameter::SourceEnum::setUp() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RigWbsParameter::RigWbsParameter( const QString& name, bool normalizeByHydroStaticPP, const SourceVector& sources ) +RigWbsParameter::RigWbsParameter( const QString& name, + bool normalizeByHydroStaticPP, + const SourceVector& sources, + bool exclusiveOption ) : m_name( name ) , m_sources( sources ) , m_normalizeByHydroStaticPP( normalizeByHydroStaticPP ) @@ -47,6 +52,29 @@ RigWbsParameter::RigWbsParameter( const QString& name, bool normalizeByHydroStat { } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigWbsParameter::RigWbsParameter( const RigWbsParameter& rhs ) + : m_name( rhs.m_name ) + , m_sources( rhs.m_sources ) + , m_normalizeByHydroStaticPP( rhs.m_normalizeByHydroStaticPP ) + , m_exclusiveOptions( rhs.m_exclusiveOptions ) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigWbsParameter& RigWbsParameter::operator=( const RigWbsParameter& rhs ) +{ + m_name = rhs.m_name; + m_sources = rhs.m_sources; + m_normalizeByHydroStaticPP = rhs.m_normalizeByHydroStaticPP; + m_exclusiveOptions = rhs.m_exclusiveOptions; + return *this; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -73,7 +101,30 @@ std::vector RigWbsParameter::sources() const //-------------------------------------------------------------------------------------------------- QString RigWbsParameter::addressString( Source source ) const { - return address( source ).primary; + SourceAddress sourceAddress; + if ( address( source, &sourceAddress ) ) + { + return sourceAddress.primary; + } + return ""; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RigWbsParameter::units( Source source ) const +{ + SourceAddress sourceAddress; + if ( address( source, &sourceAddress ) ) + { + return sourceAddress.units; + } + // Try the units of the first available source + if ( !m_sources.empty() ) + { + return m_sources.front().second.units; + } + return RiaWellLogUnitTools::noUnitString(); } //-------------------------------------------------------------------------------------------------- @@ -87,8 +138,12 @@ RigFemResultAddress RigWbsParameter::femAddress( Source source ) const else if ( source == ELEMENT_PROPERTY_TABLE ) posType = RIG_ELEMENT; - auto addr = address( source ); - return RigFemResultAddress( posType, addr.primary.toStdString(), addr.secondary.toStdString() ); + SourceAddress addr; + if ( address( source, &addr ) ) + { + return RigFemResultAddress( posType, addr.primary.toStdString(), addr.secondary.toStdString() ); + } + return RigFemResultAddress(); } //-------------------------------------------------------------------------------------------------- @@ -150,15 +205,6 @@ QString RigWbsParameter::sourceUiLabel( Source currentSource, return sourceLabel; } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QString RigWbsParameter::sourceLabel( Source source ) -{ - SourceAddress addr = address( source ); - return addr.primary; -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -180,10 +226,10 @@ bool RigWbsParameter::operator<( const RigWbsParameter& rhs ) const //-------------------------------------------------------------------------------------------------- RigWbsParameter RigWbsParameter::PP_Reservoir() { - SourceVector sources = {{GRID, SourceAddress( "POR-Bar" )}, - {LAS_FILE, SourceAddress( "POR" )}, - {ELEMENT_PROPERTY_TABLE, SourceAddress( "POR" )}}; - return RigWbsParameter( "PP", true, sources ); + SourceVector sources = {{GRID, SourceAddress( "POR-Bar", "", RiaWellLogUnitTools::barUnitString() )}, + {LAS_FILE, SourceAddress( "POR_RES_INP", "", RiaWellLogUnitTools::gPerCm3UnitString() )}, + {ELEMENT_PROPERTY_TABLE, SourceAddress( "POR", "", RiaWellLogUnitTools::barUnitString() )}}; + return RigWbsParameter( "PP Reservoir", true, sources ); } //-------------------------------------------------------------------------------------------------- @@ -193,9 +239,9 @@ RigWbsParameter RigWbsParameter::PP_NonReservoir() { return RigWbsParameter( "PP Non-Reservoir", true, - {{LAS_FILE, SourceAddress( "POR_NONRESERVOIR" )}, - {HYDROSTATIC, SourceAddress( "Hydrostatic" )}, - {USER_DEFINED, SourceAddress()}} ); + {{LAS_FILE, SourceAddress( "POR_NONRES_INP", "", RiaWellLogUnitTools::gPerCm3UnitString() )}, + {HYDROSTATIC, SourceAddress( "Hydrostatic", "", RiaWellLogUnitTools::barUnitString() )}, + {USER_DEFINED, SourceAddress( "", "", RiaWellLogUnitTools::barUnitString() )}} ); } //-------------------------------------------------------------------------------------------------- @@ -205,7 +251,7 @@ RigWbsParameter RigWbsParameter::poissonRatio() { return RigWbsParameter( "Poisson Ratio", false, - {{LAS_FILE, SourceAddress( "POISSON_RATIO" )}, + {{LAS_FILE, SourceAddress( "POISSON_RATIO_INP" )}, {ELEMENT_PROPERTY_TABLE, SourceAddress( "RATIO" )}, {USER_DEFINED, SourceAddress()}} ); } @@ -217,9 +263,9 @@ RigWbsParameter RigWbsParameter::UCS() { return RigWbsParameter( "UCS", false, - {{LAS_FILE, SourceAddress( "UCS" )}, - {ELEMENT_PROPERTY_TABLE, SourceAddress( "UCS" )}, - {USER_DEFINED, SourceAddress()}} ); + {{LAS_FILE, SourceAddress( "UCS_INP", "", RiaWellLogUnitTools::MPaUnitString() )}, + {ELEMENT_PROPERTY_TABLE, SourceAddress( "UCS", RiaWellLogUnitTools::barUnitString() )}, + {USER_DEFINED, SourceAddress( "", "", RiaWellLogUnitTools::barUnitString() )}} ); } //-------------------------------------------------------------------------------------------------- @@ -227,8 +273,10 @@ RigWbsParameter RigWbsParameter::UCS() //-------------------------------------------------------------------------------------------------- RigWbsParameter RigWbsParameter::OBG() { - std::vector> sources = {{GRID, SourceAddress( "ST", "S33" )}}; - return RigWbsParameter( "OBG", true, sources ); + std::vector> sources = + {{GRID, SourceAddress( "ST", "S33", RiaWellLogUnitTools::barUnitString() )}, + {LAS_FILE, SourceAddress( "OBG_INP", "", RiaWellLogUnitTools::barUnitString() )}}; + return RigWbsParameter( "OBG Input", true, sources ); } //-------------------------------------------------------------------------------------------------- @@ -236,8 +284,9 @@ RigWbsParameter RigWbsParameter::OBG() //-------------------------------------------------------------------------------------------------- RigWbsParameter RigWbsParameter::OBG0() { - std::vector> sources = {{GRID, SourceAddress( "ST", "S33" )}, - {LAS_FILE, SourceAddress( "OBG0" )}}; + std::vector> sources = + {{GRID, SourceAddress( "ST", "S33", RiaWellLogUnitTools::barUnitString() )}, + {LAS_FILE, SourceAddress( "OBG0_INP", "", RiaWellLogUnitTools::barUnitString() )}}; return RigWbsParameter( "OBG0", true, sources ); } @@ -246,8 +295,10 @@ RigWbsParameter RigWbsParameter::OBG0() //-------------------------------------------------------------------------------------------------- RigWbsParameter RigWbsParameter::SH() { - std::vector> sources = {{GRID, SourceAddress( "ST", "S3" )}}; - return RigWbsParameter( "SH", true, sources ); + std::vector> sources = + {{GRID, SourceAddress( "ST", "S3", RiaWellLogUnitTools::barUnitString() )}, + {LAS_FILE, SourceAddress( "SH_INP", "", RiaWellLogUnitTools::barUnitString() )}}; + return RigWbsParameter( "SH Input", true, sources ); } //-------------------------------------------------------------------------------------------------- @@ -257,7 +308,7 @@ RigWbsParameter RigWbsParameter::DF() { return RigWbsParameter( "DF", false, - {{LAS_FILE, SourceAddress( "DF" )}, + {{LAS_FILE, SourceAddress( "DF_INP" )}, {ELEMENT_PROPERTY_TABLE, SourceAddress( "DF" )}, {USER_DEFINED, SourceAddress()}} ); } @@ -267,7 +318,7 @@ RigWbsParameter RigWbsParameter::DF() //-------------------------------------------------------------------------------------------------- RigWbsParameter RigWbsParameter::K0_FG() { - return RigWbsParameter( "K0_FG", false, {{LAS_FILE, SourceAddress( "K0_FG" )}, {USER_DEFINED, SourceAddress()}} ); + return RigWbsParameter( "K0_FG", false, {{LAS_FILE, SourceAddress( "K0_FG_INP" )}, {USER_DEFINED, SourceAddress()}} ); } //-------------------------------------------------------------------------------------------------- @@ -275,7 +326,7 @@ RigWbsParameter RigWbsParameter::K0_FG() //-------------------------------------------------------------------------------------------------- RigWbsParameter RigWbsParameter::K0_SH() { - return RigWbsParameter( "K0_SH", false, {{LAS_FILE, SourceAddress( "K0_SH" )}, {USER_DEFINED, SourceAddress()}} ); + return RigWbsParameter( "K0_SH", false, {{LAS_FILE, SourceAddress( "K0_SH_INP" )}, {USER_DEFINED, SourceAddress()}} ); } //-------------------------------------------------------------------------------------------------- @@ -284,8 +335,12 @@ RigWbsParameter RigWbsParameter::K0_SH() RigWbsParameter RigWbsParameter::FG_Shale() { RigWbsParameter param( "FG Shale", - true, - {{DERIVED_FROM_K0FG, SourceAddress()}, {PROPORTIONAL_TO_SH, SourceAddress()}} ); + false, + { + {DERIVED_FROM_K0FG, SourceAddress()}, + {PROPORTIONAL_TO_SH, SourceAddress()}, + {LAS_FILE, SourceAddress( "FG_SHALE_INP" )}, + } ); param.setOptionsExclusive( true ); return param; } @@ -316,11 +371,15 @@ bool RigWbsParameter::findParameter( QString parameterName, RigWbsParameter* fou //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RigWbsParameter::SourceAddress RigWbsParameter::address( Source source ) const +bool RigWbsParameter::address( Source source, RigWbsParameter::SourceAddress* sourceAddress ) const { for ( auto sourceEntryPair : m_sources ) { - if ( sourceEntryPair.first == source ) return sourceEntryPair.second; + if ( sourceEntryPair.first == source ) + { + *sourceAddress = sourceEntryPair.second; + return true; + } } - return SourceAddress(); + return false; } diff --git a/ApplicationCode/ReservoirDataModel/RigWbsParameter.h b/ApplicationCode/ReservoirDataModel/RigWbsParameter.h index 54d6538381..ef91e0f9d5 100644 --- a/ApplicationCode/ReservoirDataModel/RigWbsParameter.h +++ b/ApplicationCode/ReservoirDataModel/RigWbsParameter.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2019- Ceetron Solutions AS +// Copyright (C) 2019- Equinor AS // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ #include "cafAppEnum.h" +#include "RiaWellLogUnitTools.h" #include "RigFemResultAddress.h" #include @@ -47,11 +48,16 @@ public: public: RigWbsParameter( const QString& name = "", bool normalizeByHydroStaticPP = false, - const SourceVector& validSources = {} ); + const SourceVector& validSources = {}, + bool exclusiveOptions = false ); + RigWbsParameter( const RigWbsParameter& rhs ); + + RigWbsParameter& operator=( const RigWbsParameter& rhs ); const QString& name() const; std::vector sources() const; QString addressString( Source source ) const; + QString units( Source source ) const; RigFemResultAddress femAddress( Source source ) const; bool normalizeByHydrostaticPP() const; bool exclusiveOptions() const; @@ -62,7 +68,6 @@ public: QString sourceUiLabel( Source currentSource, const QString& delimiter = " ", double userDefinedValue = std::numeric_limits::infinity() ); - QString sourceLabel( Source currentSource ); bool operator==( const RigWbsParameter& rhs ) const; bool operator<( const RigWbsParameter& rhs ) const; @@ -88,14 +93,16 @@ private: RigFemResultPosEnum resType; QString primary; // i.e. grid field name, las entry, etc. QString secondary; // i.e. grid component name - SourceAddress( QString primary = "", QString secondary = "" ) + QString units; // The unit string + SourceAddress( QString primary = "", QString secondary = "", QString units = RiaWellLogUnitTools::noUnitString() ) : primary( primary ) , secondary( secondary ) + , units( units ) { } }; - SourceAddress address( Source source ) const; + bool address( Source source, SourceAddress* sourceAddress ) const; private: QString m_name; diff --git a/ApplicationCode/ReservoirDataModel/RigWellLogCurveData.cpp b/ApplicationCode/ReservoirDataModel/RigWellLogCurveData.cpp index c462c4be02..51741b8504 100644 --- a/ApplicationCode/ReservoirDataModel/RigWellLogCurveData.cpp +++ b/ApplicationCode/ReservoirDataModel/RigWellLogCurveData.cpp @@ -20,8 +20,8 @@ #include "RigWellLogCurveData.h" #include "RiaCurveDataTools.h" - #include "RiaEclipseUnitTools.h" +#include "RiaWellLogUnitTools.h" #include "cvfAssert.h" #include "cvfMath.h" @@ -35,6 +35,7 @@ RigWellLogCurveData::RigWellLogCurveData() { m_isExtractionCurve = false; m_depthUnit = RiaDefines::UNIT_METER; + m_xUnitString = RiaWellLogUnitTools::noUnitString(); } //-------------------------------------------------------------------------------------------------- @@ -95,11 +96,44 @@ void RigWellLogCurveData::setValuesAndDepths( const std::vector& //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -const std::vector& RigWellLogCurveData::xValues() const +void RigWellLogCurveData::setXUnits( const QString& xUnitString ) +{ + m_xUnitString = xUnitString; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RigWellLogCurveData::xValues() const { return m_xValues; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RigWellLogCurveData::xValues( const QString& units ) const +{ + std::vector convertedValues; + if ( units != m_xUnitString && RiaWellLogUnitTools::convertValues( depths( RiaDefines::TRUE_VERTICAL_DEPTH_RKB ), + m_xValues, + &convertedValues, + m_xUnitString, + units ) ) + { + return convertedValues; + } + return m_xValues; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RigWellLogCurveData::xUnits() const +{ + return m_xUnitString; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -192,7 +226,9 @@ std::vector RigWellLogCurveData::depthPlotValues( RiaDefines::DepthTypeE } else { - std::vector convertedValues = convertDepthValues( destinationDepthUnit, depthValues ); + std::vector convertedValues = RiaWellLogUnitTools().convertDepths( depthValues, + m_depthUnit, + destinationDepthUnit ); RiaCurveDataTools::getValuesByIntervals( convertedValues, m_intervalsOfContinousValidValues, &filteredValues ); } } @@ -415,52 +451,3 @@ RiaDefines::DepthUnitType RigWellLogCurveData::depthUnit() const { return m_depthUnit; } - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::vector RigWellLogCurveData::convertFromMeterToFeet( const std::vector& valuesInMeter ) -{ - std::vector valuesInFeet( valuesInMeter.size() ); - - for ( size_t i = 0; i < valuesInMeter.size(); i++ ) - { - valuesInFeet[i] = valuesInMeter[i] * RiaEclipseUnitTools::feetPerMeter(); - } - - return valuesInFeet; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::vector RigWellLogCurveData::convertFromFeetToMeter( const std::vector& valuesInFeet ) -{ - std::vector valuesInMeter( valuesInFeet.size() ); - - for ( size_t i = 0; i < valuesInFeet.size(); i++ ) - { - valuesInMeter[i] = valuesInFeet[i] / RiaEclipseUnitTools::feetPerMeter(); - } - - return valuesInMeter; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::vector RigWellLogCurveData::convertDepthValues( RiaDefines::DepthUnitType destinationDepthUnit, - const std::vector& values ) const -{ - CVF_ASSERT( destinationDepthUnit != m_depthUnit ); - - if ( destinationDepthUnit == RiaDefines::UNIT_METER && m_depthUnit == RiaDefines::UNIT_FEET ) - { - return convertFromFeetToMeter( values ); - } - else if ( destinationDepthUnit == RiaDefines::UNIT_FEET && m_depthUnit == RiaDefines::UNIT_METER ) - { - return convertFromMeterToFeet( values ); - } - return values; -} diff --git a/ApplicationCode/ReservoirDataModel/RigWellLogCurveData.h b/ApplicationCode/ReservoirDataModel/RigWellLogCurveData.h index aad33506ec..ce46b08b36 100644 --- a/ApplicationCode/ReservoirDataModel/RigWellLogCurveData.h +++ b/ApplicationCode/ReservoirDataModel/RigWellLogCurveData.h @@ -20,9 +20,12 @@ #pragma once #include "RiaDefines.h" +#include "RiaWellLogUnitTools.h" #include "cvfObject.h" +#include + #include #include #include @@ -49,8 +52,11 @@ public: double rkbDiff, RiaDefines::DepthUnitType depthUnit, bool isExtractionCurve ); + void setXUnits( const QString& xUnitString ); - const std::vector& xValues() const; + std::vector xValues() const; + std::vector xValues( const QString& units ) const; + QString xUnits() const; std::vector depths( RiaDefines::DepthTypeEnum depthType ) const; @@ -78,12 +84,6 @@ private: size_t stopIdx, std::vector>* intervals ); - std::vector convertDepthValues( RiaDefines::DepthUnitType destinationDepthUnit, - const std::vector& originalValues ) const; - - static std::vector convertFromMeterToFeet( const std::vector& valuesInMeter ); - static std::vector convertFromFeetToMeter( const std::vector& valuesInFeet ); - private: std::vector m_xValues; std::map> m_depths; @@ -93,4 +93,5 @@ private: std::vector> m_intervalsOfContinousValidValues; RiaDefines::DepthUnitType m_depthUnit; + QString m_xUnitString; }; diff --git a/ApplicationCode/ReservoirDataModel/RigWellLogFile.cpp b/ApplicationCode/ReservoirDataModel/RigWellLogFile.cpp index 5952bc8f1a..35894b5414 100644 --- a/ApplicationCode/ReservoirDataModel/RigWellLogFile.cpp +++ b/ApplicationCode/ReservoirDataModel/RigWellLogFile.cpp @@ -260,6 +260,21 @@ QString RigWellLogFile::wellLogChannelUnitString( const QString& well return unit; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RigWellLogFile::wellLogChannelUnitString( const QString& wellLogChannelName ) const +{ + QString unit; + + NRLib::LasWell* lasWell = dynamic_cast( m_wellLogFile ); + if ( lasWell ) + { + return QString::fromStdString( lasWell->unitName( wellLogChannelName.toStdString() ) ); + } + return ""; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ReservoirDataModel/RigWellLogFile.h b/ApplicationCode/ReservoirDataModel/RigWellLogFile.h index 1f231b802f..bce0a25aa3 100644 --- a/ApplicationCode/ReservoirDataModel/RigWellLogFile.h +++ b/ApplicationCode/ReservoirDataModel/RigWellLogFile.h @@ -56,6 +56,7 @@ public: QString wellLogChannelUnitString( const QString& wellLogChannelName, RiaDefines::DepthUnitType displayDepthUnit ) const; + QString wellLogChannelUnitString( const QString& wellLogChannelName ) const; RiaDefines::DepthUnitType depthUnit() const; bool hasTvdMslChannel() const;