From 50b1820b60b9f2911c3b373fa4a73bcf198fb118 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Herje?= <82032112+jorgenherje@users.noreply.github.com> Date: Mon, 23 Jan 2023 12:46:54 +0100 Subject: [PATCH] Create depth adjusted LAS files * Add support for creating depth adjustment LAS files * Add RiaDefine for LAS file depth property names * Remove incorrect check in K-index Calculator Co-authored-by: jorgenherje Co-authored-by: Magne Sjaastad --- .misspell-fixer.ignore | 3 +- .../Application/CMakeLists_files.cmake | 2 + .../Application/RiaLasDefines.cpp | 43 ++ .../Application/RiaLasDefines.h | 28 ++ .../ExportCommands/CMakeLists_files.cmake | 6 + .../RicCreateDepthAdjustedLasFilesFeature.cpp | 176 ++++++++ .../RicCreateDepthAdjustedLasFilesFeature.h | 54 +++ .../RicCreateDepthAdjustedLasFilesImpl.cpp | 411 ++++++++++++++++++ .../RicCreateDepthAdjustedLasFilesImpl.h | 99 +++++ .../RicCreateDepthAdjustedLasFilesUi.cpp | 239 ++++++++++ .../RicCreateDepthAdjustedLasFilesUi.h | 71 +++ .../RigFemPartResultCalculatorKIndices.cpp | 37 +- .../RimContextCommandBuilder.cpp | 1 + .../ReservoirDataModel/RigWellLogFile.cpp | 8 + .../ReservoirDataModel/RigWellLogFile.h | 2 + 15 files changed, 1158 insertions(+), 22 deletions(-) create mode 100644 ApplicationLibCode/Application/RiaLasDefines.cpp create mode 100644 ApplicationLibCode/Application/RiaLasDefines.h create mode 100644 ApplicationLibCode/Commands/ExportCommands/RicCreateDepthAdjustedLasFilesFeature.cpp create mode 100644 ApplicationLibCode/Commands/ExportCommands/RicCreateDepthAdjustedLasFilesFeature.h create mode 100644 ApplicationLibCode/Commands/ExportCommands/RicCreateDepthAdjustedLasFilesImpl.cpp create mode 100644 ApplicationLibCode/Commands/ExportCommands/RicCreateDepthAdjustedLasFilesImpl.h create mode 100644 ApplicationLibCode/Commands/ExportCommands/RicCreateDepthAdjustedLasFilesUi.cpp create mode 100644 ApplicationLibCode/Commands/ExportCommands/RicCreateDepthAdjustedLasFilesUi.h diff --git a/.misspell-fixer.ignore b/.misspell-fixer.ignore index eee5547880..c86a84bd03 100644 --- a/.misspell-fixer.ignore +++ b/.misspell-fixer.ignore @@ -4,4 +4,5 @@ ^ApplicationExeCode/Resources/NorthView.svg ^ApplicationExeCode/Resources/SouthView.svg ^ApplicationExeCode/Resources/WestView.svg -^ApplicationLibCode/ProjectDataModel/RimEclipseStatisticsCaseEvaluator.cpp \ No newline at end of file +^ApplicationLibCode/ProjectDataModel/RimEclipseStatisticsCaseEvaluator.cpp +^ApplicationLibCode/Commands/ExportCommands/RicCreateDepthAdjustedLasFilesImpl.cpp \ No newline at end of file diff --git a/ApplicationLibCode/Application/CMakeLists_files.cmake b/ApplicationLibCode/Application/CMakeLists_files.cmake index 4394a57630..b2a0e28b2a 100644 --- a/ApplicationLibCode/Application/CMakeLists_files.cmake +++ b/ApplicationLibCode/Application/CMakeLists_files.cmake @@ -31,6 +31,7 @@ set(SOURCE_GROUP_HEADER_FILES ${CMAKE_CURRENT_LIST_DIR}/RiaPlotCollectionScheduler.h ${CMAKE_CURRENT_LIST_DIR}/RiaScheduler.h ${CMAKE_CURRENT_LIST_DIR}/RiaSummaryDefines.h + ${CMAKE_CURRENT_LIST_DIR}/RiaLasDefines.h ) set(SOURCE_GROUP_SOURCE_FILES @@ -66,6 +67,7 @@ set(SOURCE_GROUP_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/RiaPlotCollectionScheduler.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaScheduler.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaSummaryDefines.cpp + ${CMAKE_CURRENT_LIST_DIR}/RiaLasDefines.cpp ) list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES}) diff --git a/ApplicationLibCode/Application/RiaLasDefines.cpp b/ApplicationLibCode/Application/RiaLasDefines.cpp new file mode 100644 index 0000000000..fda3f6f5d5 --- /dev/null +++ b/ApplicationLibCode/Application/RiaLasDefines.cpp @@ -0,0 +1,43 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023- Equinor ASA +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RiaLasDefines.h" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiaDefines::propertyNameMeasuredDepth() +{ + return "DEPTH"; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiaDefines::propertyNameTvdMslDepth() +{ + return "TVDMSL"; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiaDefines::propertyNameTvdRkbDepth() +{ + return "TVDRKB"; +} diff --git a/ApplicationLibCode/Application/RiaLasDefines.h b/ApplicationLibCode/Application/RiaLasDefines.h new file mode 100644 index 0000000000..7b9128bf5f --- /dev/null +++ b/ApplicationLibCode/Application/RiaLasDefines.h @@ -0,0 +1,28 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023- Equinor ASA +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include + +namespace RiaDefines +{ +QString propertyNameMeasuredDepth(); +QString propertyNameTvdMslDepth(); +QString propertyNameTvdRkbDepth(); +}; // namespace RiaDefines diff --git a/ApplicationLibCode/Commands/ExportCommands/CMakeLists_files.cmake b/ApplicationLibCode/Commands/ExportCommands/CMakeLists_files.cmake index 3c925601c8..a9985071fe 100644 --- a/ApplicationLibCode/Commands/ExportCommands/CMakeLists_files.cmake +++ b/ApplicationLibCode/Commands/ExportCommands/CMakeLists_files.cmake @@ -26,6 +26,9 @@ set(SOURCE_GROUP_HEADER_FILES ${CMAKE_CURRENT_LIST_DIR}/RicExportLgrUi.h ${CMAKE_CURRENT_LIST_DIR}/RicEclipseCellResultToFileImpl.h ${CMAKE_CURRENT_LIST_DIR}/RicLgrSplitType.h + ${CMAKE_CURRENT_LIST_DIR}/RicCreateDepthAdjustedLasFilesFeature.h + ${CMAKE_CURRENT_LIST_DIR}/RicCreateDepthAdjustedLasFilesUi.h + ${CMAKE_CURRENT_LIST_DIR}/RicCreateDepthAdjustedLasFilesImpl.h ) set(SOURCE_GROUP_SOURCE_FILES @@ -55,6 +58,9 @@ set(SOURCE_GROUP_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/RicExportLgrFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicExportLgrUi.cpp ${CMAKE_CURRENT_LIST_DIR}/RicEclipseCellResultToFileImpl.cpp + ${CMAKE_CURRENT_LIST_DIR}/RicCreateDepthAdjustedLasFilesFeature.cpp + ${CMAKE_CURRENT_LIST_DIR}/RicCreateDepthAdjustedLasFilesUi.cpp + ${CMAKE_CURRENT_LIST_DIR}/RicCreateDepthAdjustedLasFilesImpl.cpp ) list(APPEND COMMAND_CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES}) diff --git a/ApplicationLibCode/Commands/ExportCommands/RicCreateDepthAdjustedLasFilesFeature.cpp b/ApplicationLibCode/Commands/ExportCommands/RicCreateDepthAdjustedLasFilesFeature.cpp new file mode 100644 index 0000000000..ffef52d334 --- /dev/null +++ b/ApplicationLibCode/Commands/ExportCommands/RicCreateDepthAdjustedLasFilesFeature.cpp @@ -0,0 +1,176 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023- Equinor ASA +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicCreateDepthAdjustedLasFilesFeature.h" + +#include "RiaLogging.h" + +#include "RicCreateDepthAdjustedLasFilesImpl.h" +#include "RicCreateDepthAdjustedLasFilesUi.h" +#include "RicExportFeatureImpl.h" + +#include "RigEclipseWellLogExtractor.h" +#include "RigGeoMechWellLogExtractor.h" + +#include "RimEclipseCase.h" +#include "RimGeoMechCase.h" +#include "RimMainPlotCollection.h" +#include "RimOilField.h" +#include "RimProject.h" +#include "RimWellLogFile.h" +#include "RimWellLogPlotCollection.h" +#include "RimWellPath.h" +#include "RimWellPathCollection.h" + +#include "cafPdmUiPropertyViewDialog.h" + +#include + +CAF_CMD_SOURCE_INIT( RicCreateDepthAdjustedLasFilesFeature, "RicCreateDepthAdjustedLasFilesFeature" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicCreateDepthAdjustedLasFilesFeature::isCommandEnabled() +{ + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateDepthAdjustedLasFilesFeature::onActionTriggered( bool isChecked ) +{ + RicCreateDepthAdjustedLasFilesUi featureUi; + featureUi.setDefaultValues(); + + caf::PdmUiPropertyViewDialog propertyDialog( nullptr, &featureUi, "Create Depth Adjusted LAS file(s)", "" ); + RicExportFeatureImpl::configureForExport( propertyDialog.dialogButtonBox() ); + propertyDialog.setWindowFlag( Qt::WindowCloseButtonHint, true ); + propertyDialog.resize( QSize( 850, 500 ) ); + + if ( propertyDialog.exec() == QDialog::Accepted ) + { + if ( !featureUi.hasValidSelections() ) + { + RiaLogging::warning( featureUi.invalidSelectionsLogString() ); + } + else + { + RimCase* selectedCase = featureUi.selectedCase(); + RimWellPath* sourceWell = featureUi.sourceWell(); + RimWellLogFile* sourceWellLogFile = sourceWell->wellLogFiles()[0]; + std::vector destinationWells = featureUi.destinationWells().ptrReferencedObjects(); + std::vector selectedResultProperties = featureUi.selectedResultProperties(); + QString exportFolder = featureUi.exportFolder(); + + RimEclipseCase* eclipseCase = dynamic_cast( selectedCase ); + RimGeoMechCase* geomCase = dynamic_cast( selectedCase ); + + if ( eclipseCase == nullptr && geomCase == nullptr ) + { + RiaLogging::warning( QString( "The selected case is invalid" ) ); + return; + } + + if ( eclipseCase != nullptr ) + { + createDepthAdjustedWellLogFileFromEclipseCase( eclipseCase, + sourceWell, + destinationWells, + selectedResultProperties, + exportFolder ); + } + else if ( geomCase != nullptr ) + { + createDepthAdjustedWellLogFileFromGeoMechCase( geomCase, + sourceWell, + destinationWells, + selectedResultProperties, + exportFolder ); + } + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateDepthAdjustedLasFilesFeature::setupActionLook( QAction* actionToSetup ) +{ + actionToSetup->setText( "Create Depth Adjusted LAS Files..." ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateDepthAdjustedLasFilesFeature::createDepthAdjustedWellLogFileFromEclipseCase( + RimEclipseCase* eclipseCase, + RimWellPath* sourceWell, + const std::vector destinationWells, + const std::vector& selectedResultProperties, + const QString& exportFolder ) +{ + if ( sourceWell->wellLogFiles().empty() ) return; + + RimWellLogPlotCollection* wellLogCollection = RimMainPlotCollection::current()->wellLogPlotCollection(); + cvf::ref sourceWellExtractor = + wellLogCollection->findOrCreateExtractor( sourceWell, eclipseCase ); + if ( sourceWellExtractor.isNull() ) + { + RiaLogging::info( QString( "Could not create RigEclipseWellLogExtractor for %1" ).arg( sourceWell->name() ) ); + return; + } + const double rkbDiff = sourceWellExtractor->wellPathGeometry()->rkbDiff(); + RicCreateDepthAdjustedLasFilesImpl::createDestinationWellsLasFiles( eclipseCase, + sourceWell, + destinationWells, + selectedResultProperties, + exportFolder, + rkbDiff ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateDepthAdjustedLasFilesFeature::createDepthAdjustedWellLogFileFromGeoMechCase( + RimGeoMechCase* geoMechCase, + RimWellPath* sourceWell, + const std::vector destinationWells, + const std::vector& selectedResultProperties, + const QString& exportFolder ) +{ + if ( sourceWell->wellLogFiles().empty() ) return; + + auto* wellLogFileData = sourceWell->wellLogFiles()[0]->wellLogFileData(); + RimWellLogPlotCollection* wellLogCollection = RimMainPlotCollection::current()->wellLogPlotCollection(); + cvf::ref sourceWellExtractor = + wellLogCollection->findOrCreateExtractor( sourceWell, geoMechCase ); + if ( sourceWellExtractor.isNull() ) + { + RiaLogging::info( QString( "Could not create RigGeoMechWellLogExtractor for %1" ).arg( sourceWell->name() ) ); + return; + } + const double rkbDiff = sourceWellExtractor->wellPathGeometry()->rkbDiff(); + RicCreateDepthAdjustedLasFilesImpl::createDestinationWellsLasFiles( geoMechCase, + sourceWell, + destinationWells, + selectedResultProperties, + exportFolder, + rkbDiff ); +} diff --git a/ApplicationLibCode/Commands/ExportCommands/RicCreateDepthAdjustedLasFilesFeature.h b/ApplicationLibCode/Commands/ExportCommands/RicCreateDepthAdjustedLasFilesFeature.h new file mode 100644 index 0000000000..24b05a7e22 --- /dev/null +++ b/ApplicationLibCode/Commands/ExportCommands/RicCreateDepthAdjustedLasFilesFeature.h @@ -0,0 +1,54 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023- Equinor ASA +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafCmdFeature.h" + +class RimEclipseCase; +class RimGeoMechCase; +class RimWellPath; + +//================================================================================================== +/// +//================================================================================================== +class RicCreateDepthAdjustedLasFilesFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +public: + RicCreateDepthAdjustedLasFilesFeature() = default; + +protected: + bool isCommandEnabled() override; + void onActionTriggered( bool isChecked ) override; + void setupActionLook( QAction* actionToSetup ) override; + +private: + void createDepthAdjustedWellLogFileFromEclipseCase( RimEclipseCase* eclipseCase, + RimWellPath* sourceWell, + const std::vector destinationWells, + const std::vector& selectedResultProperties, + const QString& exportFolder ); + + void createDepthAdjustedWellLogFileFromGeoMechCase( RimGeoMechCase* geoMechCase, + RimWellPath* sourceWell, + const std::vector destinationWells, + const std::vector& selectedResultProperties, + const QString& exportFolder ); +}; diff --git a/ApplicationLibCode/Commands/ExportCommands/RicCreateDepthAdjustedLasFilesImpl.cpp b/ApplicationLibCode/Commands/ExportCommands/RicCreateDepthAdjustedLasFilesImpl.cpp new file mode 100644 index 0000000000..fdd4e80def --- /dev/null +++ b/ApplicationLibCode/Commands/ExportCommands/RicCreateDepthAdjustedLasFilesImpl.cpp @@ -0,0 +1,411 @@ +#include "RicCreateDepthAdjustedLasFilesFeature.h" +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023- Equinor ASA +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicCreateDepthAdjustedLasFilesImpl.h" + +#include "RiaLogging.h" + +#include "RicCreateDepthAdjustedLasFilesUi.h" + +#include "RigCaseCellResultsData.h" +#include "RigEclipseCaseData.h" +#include "RigEclipseResultAddress.h" +#include "RigEclipseWellLogExtractor.h" +#include "RigGeoMechWellLogExtractor.h" +#include "RigResultAccessorFactory.h" + +#include "RimEclipseCase.h" +#include "RimGeoMechCase.h" +#include "RimMainPlotCollection.h" +#include "RimWellLogFile.h" +#include "RimWellLogPlotCollection.h" +#include "RimWellPath.h" + +#include "NRLib/nrlib/well/laswell.hpp" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void LasDepthValueAndIndexPerKLayer::insertIndexAndValue( int kLayer, size_t index, double value ) +{ + m_kLayerIndexAndValuePairsMap[kLayer][index] = value; +} +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool LasDepthValueAndIndexPerKLayer::hasKLayer( int kLayer ) const +{ + return m_kLayerIndexAndValuePairsMap.find( kLayer ) != m_kLayerIndexAndValuePairsMap.end(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::map LasDepthValueAndIndexPerKLayer::indexAndValuePairs( int kLayer ) const +{ + if ( !hasKLayer( kLayer ) ) return std::map(); + + return m_kLayerIndexAndValuePairsMap.at( kLayer ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::ref RicCreateDepthAdjustedLasFilesImpl::createIndexKResultAccessor( RimEclipseCase* eclipseCase ) +{ + const int firstTimeStep = 0; + const int gridIndex = 0; + RigEclipseResultAddress indexKResAdr( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::indexKResultName() ); + eclipseCase->eclipseCaseData()->results( RiaDefines::PorosityModelType::MATRIX_MODEL )->ensureKnownResultLoaded( indexKResAdr ); + + return RigResultAccessorFactory::createFromResultAddress( eclipseCase->eclipseCaseData(), + gridIndex, + RiaDefines::PorosityModelType::MATRIX_MODEL, + firstTimeStep, + indexKResAdr ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +LasDepthValueAndIndexPerKLayer RicCreateDepthAdjustedLasFilesImpl::createLasDepthIndexAndPercValuePerKLayerFromMap( + const std::vector& lasWellDepths, + const std::map& indexKDepthDataMap ) +{ + // Create container of depth value (in percent) and its original index in a LAS file vector + // categorized by K-layer. Depth value as percentage value between MD top and MD bottom for K-layer. + auto lasWellDepthValueAndIndexPerKLayer = LasDepthValueAndIndexPerKLayer(); + for ( size_t i = 0; i < lasWellDepths.size(); ++i ) + { + const double depth = lasWellDepths[i]; + for ( const auto& [indexK, depthData] : indexKDepthDataMap ) + { + if ( depthData.mdTop <= depth && depth <= depthData.mdBottom ) + { + const double percentage = ( depth - depthData.mdTop ) / ( depthData.mdBottom - depthData.mdTop ); + lasWellDepthValueAndIndexPerKLayer.insertIndexAndValue( indexK, i, percentage ); + break; + } + } + } + return lasWellDepthValueAndIndexPerKLayer; +} + +//-------------------------------------------------------------------------------------------------- +/// NOTE: map createIndexKDepthDataMapFromCase is created using well extractor, while sourceWellLogData depth +/// values are from LAS file. Floating point rounding in LAS file can occur, thus depth values might be placed +/// outside of K-layer close to top/bottom due to inaccuracy. +//-------------------------------------------------------------------------------------------------- +void RicCreateDepthAdjustedLasFilesImpl::createDestinationWellsLasFiles( RimCase* selectedCase, + RimWellPath* sourceWell, + const std::vector destinationWells, + const std::vector& selectedResultProperties, + const QString& exportFolder, + double rkbDiff ) +{ + auto* sourceWellLogData = sourceWell->wellLogFiles()[0]->wellLogFileData(); + const auto defaultPropertyMap = createDefaultPropertyMap( selectedResultProperties, sourceWellLogData ); + + // NOTE: map createIndexKDepthDataMapFromCase is created using well extractor, while sourceWellLogData depth + // values are from LAS file. Floating point rounding in LAS file can occur, thus depth values might be placed + // outside of K-layer close to top/bottom due to inaccuracy. + const auto sourceWellDepthIndexAndPercValuePerKLayer = + createLasDepthIndexAndPercValuePerKLayerFromMap( sourceWellLogData->depthValues(), + createIndexKDepthDataMapFromCase( selectedCase, sourceWell ) ); + for ( RimWellPath* well : destinationWells ) + { + const std::map destinationWellIndexKDepthsMap = + createIndexKDepthDataMapFromCase( selectedCase, well ); + + if ( destinationWellIndexKDepthsMap.empty() ) continue; + + std::vector mdValues; + std::vector tvdMslValues; + std::vector tvdRkbValues; + std::map> propertyMap = defaultPropertyMap; + for ( const auto& [indexK, depthData] : destinationWellIndexKDepthsMap ) + { + if ( !sourceWellDepthIndexAndPercValuePerKLayer.hasKLayer( indexK ) ) continue; + + for ( const auto& [index, depthPerc] : sourceWellDepthIndexAndPercValuePerKLayer.indexAndValuePairs( indexK ) ) + { + if ( sourceWellLogData->hasTvdMslChannel() ) + { + const double tvdMslValue = depthPerc * ( depthData.tvdBottom - depthData.tvdTop ) + depthData.tvdTop; + tvdMslValues.push_back( tvdMslValue ); + } + if ( sourceWellLogData->hasTvdRkbChannel() ) + { + const double tvdRkbValue = depthPerc * ( depthData.tvdBottom - depthData.tvdTop ) + + depthData.tvdTop + rkbDiff; + tvdRkbValues.push_back( tvdRkbValue ); + } + + const double mdValue = depthPerc * ( depthData.mdBottom - depthData.mdTop ) + depthData.mdTop; + mdValues.push_back( mdValue ); + for ( auto& [propertyName, values] : propertyMap ) + { + double value = sourceWellLogData->values( propertyName )[index]; + value = value == HUGE_VAL ? sourceWellLogData->getMissingValue() : value; + values.push_back( value ); + } + } + } + createDestinationWellLasFile( well->name(), + selectedCase->caseUserDescription(), + mdValues, + tvdMslValues, + tvdRkbValues, + propertyMap, + sourceWellLogData, + exportFolder ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateDepthAdjustedLasFilesImpl::createDestinationWellLasFile( const QString& wellName, + const QString& caseDescription, + const std::vector& mdValues, + const std::vector& tvdMslValues, + const std::vector& tvdRkbValues, + const std::map>& propertyMap, + const RigWellLogFile* sourceWellLogData, + const QString& exportFolder ) +{ + const auto depthUnitText = createDepthUnitText( sourceWellLogData->depthUnit() ); + const auto depthUnitComment = createDepthUnitComment( sourceWellLogData->depthUnit() ); + + const auto deptUnit = sourceWellLogData->depthUnit(); + + // Build LAS file + NRLib::LasWell lasFile; + + lasFile.setVersionInfo( "2.0" ); + lasFile.setDepthUnit( depthUnitText ); + lasFile.SetMissing( sourceWellLogData->getMissingValue() ); + lasFile.setStartDepth( *std::min_element( mdValues.begin(), mdValues.end() ) ); + lasFile.setStopDepth( *std::max_element( mdValues.begin(), mdValues.end() ) ); + + lasFile.addWellInfo( "WELL", wellName.toStdString() ); + lasFile.addWellInfo( "DATE", sourceWellLogData->date().toStdString() ); + + // Add Measured depth + lasFile.AddLog( RiaDefines::propertyNameMeasuredDepth().toStdString(), depthUnitText, "Depth " + depthUnitComment, mdValues ); + + // Add tvd msl values if existing + if ( !tvdMslValues.empty() ) + { + const auto unitText = + sourceWellLogData->wellLogChannelUnitString( RiaDefines::propertyNameTvdMslDepth(), deptUnit ).toStdString(); + lasFile.AddLog( RiaDefines::propertyNameTvdMslDepth().toStdString(), + unitText, + "True vertical depth " + depthUnitComment, + tvdMslValues ); + } + + // Add tvd rkb values if existing + if ( !tvdRkbValues.empty() ) + { + const auto unitText = + sourceWellLogData->wellLogChannelUnitString( RiaDefines::propertyNameTvdRkbDepth(), deptUnit ).toStdString(); + lasFile.AddLog( RiaDefines::propertyNameTvdRkbDepth().toStdString(), + unitText, + "True vertical depth (Rotary Kelly Bushing)", + tvdRkbValues ); + } + + // Add property values + for ( auto& [name, values] : propertyMap ) + { + std::string unitText = sourceWellLogData->wellLogChannelUnitString( name ).toStdString(); + lasFile.AddLog( name.toUpper().toStdString(), unitText, "", values ); + } + + std::vector commentHeader; + QString fullPathName = exportFolder + "/" + wellName + "_" + caseDescription + "_" + sourceWellLogData->date() + ".las"; + lasFile.WriteToFile( fullPathName.toStdString(), commentHeader ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::string RicCreateDepthAdjustedLasFilesImpl::createDepthUnitText( RiaDefines::DepthUnitType depthUnitType ) +{ + return depthUnitType == RiaDefines::DepthUnitType::UNIT_METER + ? "M" + : depthUnitType == RiaDefines::DepthUnitType::UNIT_FEET ? "FT" : ""; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::string RicCreateDepthAdjustedLasFilesImpl::createDepthUnitComment( RiaDefines::DepthUnitType depthUnitType ) +{ + return depthUnitType == RiaDefines::DepthUnitType::UNIT_METER + ? "in meters" + : depthUnitType == RiaDefines::DepthUnitType::UNIT_FEET ? "in feet" : "in Connection number"; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::map + RicCreateDepthAdjustedLasFilesImpl::createIndexKDepthDataMapFromCase( RimCase* selectedCase, RimWellPath* wellPath ) +{ + RimEclipseCase* eclipseCase = dynamic_cast( selectedCase ); + RimGeoMechCase* geomCase = dynamic_cast( selectedCase ); + + RimWellLogPlotCollection* wellLogCollection = RimMainPlotCollection::current()->wellLogPlotCollection(); + if ( eclipseCase != nullptr ) + { + cvf::ref wellExtractor = + wellLogCollection->findOrCreateExtractor( wellPath, eclipseCase ); + if ( wellExtractor.isNull() ) + { + RiaLogging::info( QString( "Could not create RigEclipseWellLogExtractor for %1" ).arg( wellPath->name() ) ); + } + const auto result = createIndexKDepthDataMap( wellExtractor, createIndexKResultAccessor( eclipseCase ) ); + if ( result.empty() ) + { + RiaLogging::info( QString( "Not able to create Index-K depth map for %1" ).arg( wellPath->name() ) ); + } + return result; + } + else if ( geomCase != nullptr ) + { + cvf::ref wellExtractor = wellLogCollection->findOrCreateExtractor( wellPath, geomCase ); + if ( wellExtractor.isNull() ) + { + RiaLogging::info( QString( "Could not create RigGeoMechWellLogExtractor for %1" ).arg( wellPath->name() ) ); + } + const auto result = createIndexKDepthDataMap( wellExtractor ); + if ( result.empty() ) + { + RiaLogging::info( QString( "Not able to create Index-K depth map for %1" ).arg( wellPath->name() ) ); + } + return result; + } + + RiaLogging::info( QString( "Invalid case when creating Index-K depth map for %1" ).arg( wellPath->name() ) ); + return std::map(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::map + RicCreateDepthAdjustedLasFilesImpl::createIndexKDepthDataMap( cvf::ref wellExtractor, + cvf::ref indexKResAcc ) +{ + std::vector wellIndexKValues; + wellExtractor->curveData( indexKResAcc.p(), &wellIndexKValues ); + return createIndexKDepthDataMapFromVectors( wellExtractor->cellIntersectionMDs(), + wellExtractor->cellIntersectionTVDs(), + wellIndexKValues ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::map + RicCreateDepthAdjustedLasFilesImpl::createIndexKDepthDataMap( cvf::ref wellExtractor ) +{ + const int frameIdx = 0; + const int timeStepIdx = 0; + RigFemResultAddress indexKResAdr( RigFemResultPosEnum::RIG_ELEMENT_NODAL, "INDEX", "INDEX_K" ); + std::vector wellIndexKValues; + wellExtractor->curveData( indexKResAdr, timeStepIdx, frameIdx, &wellIndexKValues ); + return createIndexKDepthDataMapFromVectors( wellExtractor->cellIntersectionMDs(), + wellExtractor->cellIntersectionTVDs(), + wellIndexKValues ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::map + RicCreateDepthAdjustedLasFilesImpl::createIndexKDepthDataMapFromVectors( const std::vector& wellMdValues, + const std::vector& wellTvdValues, + const std::vector& wellIndexKValues ) +{ + std::map indexKDepthsMap; + + // Must have non-empty equal length vectors! + if ( wellIndexKValues.empty() ) + { + RiaLogging::info( QString( "Empty vector of index-K values" ) ); + return indexKDepthsMap; + } + if ( wellMdValues.size() != wellTvdValues.size() || wellMdValues.size() != wellIndexKValues.size() ) + { + return indexKDepthsMap; + } + + int prevKLayer = -1; + for ( size_t i = 0; i < wellIndexKValues.size(); ++i ) + { + // Asymptotically increasing k-indexes! + const auto kLayer = static_cast( wellIndexKValues[i] ); + if ( kLayer < prevKLayer ) break; + + if ( indexKDepthsMap.find( kLayer ) == indexKDepthsMap.end() ) + { + indexKDepthsMap[kLayer] = IndexKDepthData(); + indexKDepthsMap[kLayer].mdTop = wellMdValues[i]; + indexKDepthsMap[kLayer].mdBottom = wellMdValues[i]; + indexKDepthsMap[kLayer].tvdTop = wellTvdValues[i]; + indexKDepthsMap[kLayer].tvdBottom = wellTvdValues[i]; + } + else + { + indexKDepthsMap[kLayer].mdBottom = wellMdValues[i]; + indexKDepthsMap[kLayer].tvdBottom = wellTvdValues[i]; + } + } + + return indexKDepthsMap; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::map> + RicCreateDepthAdjustedLasFilesImpl::createDefaultPropertyMap( const std::vector& selectedProperties, + const RigWellLogFile* wellLogFile ) +{ + const QStringList lasDepthNames = QStringList( { RiaDefines::propertyNameMeasuredDepth(), + RiaDefines::propertyNameTvdMslDepth(), + RiaDefines::propertyNameTvdRkbDepth() } ); + std::vector validPropertyNames; + for ( const auto& propertyName : selectedProperties ) + { + if ( !lasDepthNames.contains( propertyName ) && wellLogFile->wellLogChannelNames().contains( propertyName ) ) + { + validPropertyNames.push_back( propertyName ); + } + } + std::map> defaultPropertyMap; + for ( const auto& name : validPropertyNames ) + { + defaultPropertyMap[name]; + } + return defaultPropertyMap; +} diff --git a/ApplicationLibCode/Commands/ExportCommands/RicCreateDepthAdjustedLasFilesImpl.h b/ApplicationLibCode/Commands/ExportCommands/RicCreateDepthAdjustedLasFilesImpl.h new file mode 100644 index 0000000000..3665a141bc --- /dev/null +++ b/ApplicationLibCode/Commands/ExportCommands/RicCreateDepthAdjustedLasFilesImpl.h @@ -0,0 +1,99 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023- Equinor ASA +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RiaDefines.h" + +#include "cvfObject.h" + +class RigEclipseWellLogExtractor; +class RigGeoMechWellLogExtractor; +class RigResultAccessor; +class RigWellLogFile; +class RimCase; +class RimEclipseCase; +class RimWellPath; + +//================================================================================================== +/// Object to hold Depth value and its original index in a LAS file vector categorized by K-layer. +//================================================================================================== +class LasDepthValueAndIndexPerKLayer +{ +public: + LasDepthValueAndIndexPerKLayer() = default; + + void insertIndexAndValue( int kLayer, size_t index, double value ); + std::map indexAndValuePairs( int kLayer ) const; + bool hasKLayer( int kLayer ) const; + +private: + // Map of K-layer and Index and Value pairs for LAS file depth vectors + std::map> m_kLayerIndexAndValuePairsMap; +}; + +//================================================================================================== +/// +//================================================================================================== +namespace RicCreateDepthAdjustedLasFilesImpl +{ +struct IndexKDepthData +{ + double mdTop = 0.0; + double mdBottom = 0.0; + double tvdTop = 0.0; + double tvdBottom = 0.0; +}; + +cvf::ref createIndexKResultAccessor( RimEclipseCase* selectedCase ); + +void createDestinationWellsLasFiles( RimCase* selectedCase, + RimWellPath* sourceWell, + const std::vector destinationWells, + const std::vector& selectedResultProperties, + const QString& exportFolder, + double rkbDiff ); + +void createDestinationWellLasFile( const QString& wellName, + const QString& caseDescription, + const std::vector& mdValues, + const std::vector& tvdMslValues, + const std::vector& tvdRkbValues, + const std::map>& propertyMap, + const RigWellLogFile* sourceWellLogData, + const QString& exportFolder ); + +std::string createDepthUnitText( RiaDefines::DepthUnitType depthUnitType ); +std::string createDepthUnitComment( RiaDefines::DepthUnitType depthUnitType ); + +LasDepthValueAndIndexPerKLayer + createLasDepthIndexAndPercValuePerKLayerFromMap( const std::vector& lasWellDepths, + const std::map& indexKDepthDataMap ); +std::map createIndexKDepthDataMapFromCase( RimCase* selectedCase, RimWellPath* wellPath ); +std::map createIndexKDepthDataMap( cvf::ref wellExtractor, + cvf::ref indexKResAcc ); +std::map createIndexKDepthDataMap( cvf::ref wellExtractor ); + +std::map createIndexKDepthDataMapFromVectors( const std::vector& wellMdValues, + const std::vector& wellTvdValues, + const std::vector& wellIndexKValues ); + +std::map> createDefaultPropertyMap( const std::vector& selectedProperties, + const RigWellLogFile* wellLogFile ); + +}; // namespace RicCreateDepthAdjustedLasFilesImpl diff --git a/ApplicationLibCode/Commands/ExportCommands/RicCreateDepthAdjustedLasFilesUi.cpp b/ApplicationLibCode/Commands/ExportCommands/RicCreateDepthAdjustedLasFilesUi.cpp new file mode 100644 index 0000000000..cd5acaa8a4 --- /dev/null +++ b/ApplicationLibCode/Commands/ExportCommands/RicCreateDepthAdjustedLasFilesUi.cpp @@ -0,0 +1,239 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023- Equinor ASA +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicCreateDepthAdjustedLasFilesUi.h" + +#include "RiaApplication.h" + +#include "RimCase.h" +#include "RimOilField.h" +#include "RimProject.h" +#include "RimTools.h" +#include "RimWellLogFile.h" +#include "RimWellLogFileChannel.h" +#include "RimWellPath.h" +#include "RimWellPathCollection.h" + +#include "cafPdmUiCheckBoxEditor.h" +#include "cafPdmUiFilePathEditor.h" +#include "cafPdmUiOrdering.h" +#include "cafPdmUiTreeSelectionEditor.h" + +CAF_PDM_SOURCE_INIT( RicCreateDepthAdjustedLasFilesUi, "RicCreateDepthAdjustedLasFilesUi" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicCreateDepthAdjustedLasFilesUi::RicCreateDepthAdjustedLasFilesUi() +{ + CAF_PDM_InitField( &exportFolder, "ExportFolder", QString(), "Export Folder" ); + exportFolder.uiCapability()->setUiEditorTypeName( caf::PdmUiFilePathEditor::uiEditorTypeName() ); + + CAF_PDM_InitFieldNoDefault( &selectedCase, "SelectedCase", "Select Case" ); + CAF_PDM_InitFieldNoDefault( &sourceWell, "SourceWell", "Source Well" ); + CAF_PDM_InitFieldNoDefault( &selectedResultProperties, "SelectedResultProperties", "Selected Result Properties" ); + selectedResultProperties.uiCapability()->setUiEditorTypeName( caf::PdmUiTreeSelectionEditor::uiEditorTypeName() ); + CAF_PDM_InitFieldNoDefault( &destinationWells, "DestinationWells", "Destination Wells" ); + destinationWells.uiCapability()->setUiEditorTypeName( caf::PdmUiTreeSelectionEditor::uiEditorTypeName() ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicCreateDepthAdjustedLasFilesUi::~RicCreateDepthAdjustedLasFilesUi() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QList + RicCreateDepthAdjustedLasFilesUi::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) +{ + QList options; + + if ( fieldNeedingOptions == &selectedCase ) + { + RimTools::caseOptionItems( &options ); + } + if ( fieldNeedingOptions == &sourceWell ) + { + RimProject* proj = RimProject::current(); + if ( proj ) + { + std::vector allWellPaths = proj->activeOilField()->wellPathCollection->allWellPaths(); + for ( auto* wellPath : allWellPaths ) + { + if ( !wellPath->wellLogFiles().empty() ) + { + options.push_back( caf::PdmOptionItemInfo( wellPath->name(), wellPath ) ); + } + } + } + } + if ( fieldNeedingOptions == &selectedResultProperties ) + { + if ( sourceWell && !sourceWell->wellLogFiles().empty() ) + { + auto* firstWellLogFile = sourceWell->wellLogFiles()[0]; + for ( auto* property : firstWellLogFile->wellLogChannels() ) + { + if ( !m_depthProperties.contains( property->name() ) ) + { + options.push_back( caf::PdmOptionItemInfo( property->name(), property->name() ) ); + } + } + } + } + if ( fieldNeedingOptions == &destinationWells ) + { + RimProject* proj = RimProject::current(); + if ( proj ) + { + std::vector allWellPaths = proj->activeOilField()->wellPathCollection->allWellPaths(); + for ( auto* wellPath : allWellPaths ) + { + if ( wellPath != sourceWell ) + { + options.push_back( caf::PdmOptionItemInfo( wellPath->name(), wellPath ) ); + } + } + } + } + + return options; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateDepthAdjustedLasFilesUi::fieldChangedByUi( const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue ) +{ + if ( changedField == &sourceWell ) + { + selectedResultProperties.v().clear(); + destinationWells.clearWithoutDelete(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateDepthAdjustedLasFilesUi::defineEditorAttribute( const caf::PdmFieldHandle* field, + QString uiConfigName, + caf::PdmUiEditorAttribute* attribute ) +{ + if ( field == &exportFolder ) + { + caf::PdmUiFilePathEditorAttribute* myAttr = dynamic_cast( attribute ); + if ( myAttr ) + { + myAttr->m_selectDirectory = true; + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateDepthAdjustedLasFilesUi::setDefaultValues() +{ + // Default folder directory + QString defaultDir = + RiaApplication::instance()->lastUsedDialogDirectoryWithFallbackToProjectFolder( "WELL_LOGS_DIR" ); + exportFolder = defaultDir; + + // Default selected case and source well + RimProject* proj = RimProject::current(); + if ( proj ) + { + std::vector allCases; + proj->allCases( allCases ); + if ( !allCases.empty() ) selectedCase = allCases[0]; + + std::vector allWellPaths = proj->activeOilField()->wellPathCollection->allWellPaths(); + for ( auto* wellPath : allWellPaths ) + { + if ( !wellPath->wellLogFiles().empty() ) + { + sourceWell = wellPath; + break; + } + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicCreateDepthAdjustedLasFilesUi::hasValidSelections() const +{ + return !exportFolder().isEmpty() && sourceWell() != nullptr && selectedCase() != nullptr && + !selectedResultProperties().empty() && !destinationWells.empty(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RicCreateDepthAdjustedLasFilesUi::invalidSelectionsLogString() const +{ + if ( hasValidSelections() ) + { + return QString(); + } + + QString logStr; + if ( exportFolder().isEmpty() ) + { + logStr += "Selected Export folder is empty!\n"; + } + if ( selectedCase() == nullptr ) + { + logStr += "Selected case is not defined!\n"; + } + if ( sourceWell() == nullptr ) + { + logStr += "Source well is not defined!\n"; + } + if ( selectedResultProperties().empty() ) + { + logStr += "No result properties are selected!\n"; + } + if ( destinationWells.empty() ) + { + logStr += "No destination wells are selected!\n"; + } + + return logStr; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateDepthAdjustedLasFilesUi::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) +{ + uiOrdering.add( &exportFolder ); + uiOrdering.add( &selectedCase ); + uiOrdering.add( &sourceWell ); + uiOrdering.add( &selectedResultProperties ); + uiOrdering.add( &destinationWells ); + + uiOrdering.skipRemainingFields( true ); +} diff --git a/ApplicationLibCode/Commands/ExportCommands/RicCreateDepthAdjustedLasFilesUi.h b/ApplicationLibCode/Commands/ExportCommands/RicCreateDepthAdjustedLasFilesUi.h new file mode 100644 index 0000000000..a566b620c1 --- /dev/null +++ b/ApplicationLibCode/Commands/ExportCommands/RicCreateDepthAdjustedLasFilesUi.h @@ -0,0 +1,71 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023- Equinor ASA +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RiaLasDefines.h" + +#include "cafPdmField.h" +#include "cafPdmObject.h" +#include "cafPdmPtrArrayField.h" +#include "cafPdmPtrField.h" +#include "cafPdmUiItem.h" + +#include +#include +#include + +class RimCase; +class RimWellPath; + +//================================================================================================== +/// +//================================================================================================== +class RicCreateDepthAdjustedLasFilesUi : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; + +public: + RicCreateDepthAdjustedLasFilesUi(); + ~RicCreateDepthAdjustedLasFilesUi() override; + + QList calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override; + void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override; + void defineEditorAttribute( const caf::PdmFieldHandle* field, + QString uiConfigName, + caf::PdmUiEditorAttribute* attribute ) override; + + void setDefaultValues(); + bool hasValidSelections() const; + QString invalidSelectionsLogString() const; + +public: + caf::PdmField exportFolder; + caf::PdmPtrField selectedCase; + caf::PdmPtrField sourceWell; + caf::PdmField> selectedResultProperties; + caf::PdmPtrArrayField destinationWells; + +protected: + void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override; + +private: + const QStringList m_depthProperties = QStringList( { RiaDefines::propertyNameMeasuredDepth(), + RiaDefines::propertyNameTvdMslDepth(), + RiaDefines::propertyNameTvdRkbDepth() } ); +}; diff --git a/ApplicationLibCode/GeoMech/GeoMechDataModel/RigFemPartResultCalculatorKIndices.cpp b/ApplicationLibCode/GeoMech/GeoMechDataModel/RigFemPartResultCalculatorKIndices.cpp index ec3ffd3289..bdc46901d7 100644 --- a/ApplicationLibCode/GeoMech/GeoMechDataModel/RigFemPartResultCalculatorKIndices.cpp +++ b/ApplicationLibCode/GeoMech/GeoMechDataModel/RigFemPartResultCalculatorKIndices.cpp @@ -72,35 +72,30 @@ RigFemScalarResultFrames* RigFemPartResultCalculatorKIndices::calculate( int const size_t valCount = femPart->elementNodeResultCount(); dstFrameData.resize( valCount, std::numeric_limits::infinity() ); - const RigFormationNames* activeFormNames = m_resultCollection->activeFormationNames(); - stepCountProgress.incrementProgress(); - if ( activeFormNames ) - { - // Has to be done before the parallel loop because the first call allocates. - const RigFemPartGrid* structGrid = femPart->getOrCreateStructGrid(); + // Has to be done before the parallel loop because the first call allocates. + const RigFemPartGrid* structGrid = femPart->getOrCreateStructGrid(); - const int elementCount = femPart->elementCount(); + const int elementCount = femPart->elementCount(); - // Using max() as std::numeric_limits::infinity() returns 0 - constexpr size_t maxValue = std::numeric_limits::max(); + // Using max() as std::numeric_limits::infinity() returns 0 + constexpr size_t maxValue = std::numeric_limits::max(); #pragma omp parallel for - for ( int elmIdx = 0; elmIdx < elementCount; ++elmIdx ) - { - RigElementType elmType = femPart->elementType( elmIdx ); - int elmNodeCount = RigFemTypes::elementNodeCount( elmType ); + for ( int elmIdx = 0; elmIdx < elementCount; ++elmIdx ) + { + RigElementType elmType = femPart->elementType( elmIdx ); + int elmNodeCount = RigFemTypes::elementNodeCount( elmType ); - size_t i, j, k = maxValue; - bool validIndex = structGrid->ijkFromCellIndex( elmIdx, &i, &j, &k ); - if ( validIndex ) + size_t i, j, k = maxValue; + bool validIndex = structGrid->ijkFromCellIndex( elmIdx, &i, &j, &k ); + if ( validIndex ) + { + for ( int elmNodIdx = 0; elmNodIdx < elmNodeCount; ++elmNodIdx ) { - for ( int elmNodIdx = 0; elmNodIdx < elmNodeCount; ++elmNodIdx ) - { - size_t elmNodResIdx = femPart->elementNodeResultIdx( elmIdx, elmNodIdx ); - dstFrameData[elmNodResIdx] = k != maxValue ? static_cast( k ) : HUGE_VALF; - } + size_t elmNodResIdx = femPart->elementNodeResultIdx( elmIdx, elmNodIdx ); + dstFrameData[elmNodResIdx] = k != maxValue ? static_cast( k ) : HUGE_VALF; } } } diff --git a/ApplicationLibCode/ProjectDataModel/RimContextCommandBuilder.cpp b/ApplicationLibCode/ProjectDataModel/RimContextCommandBuilder.cpp index 379a83432e..26e2a87736 100644 --- a/ApplicationLibCode/ProjectDataModel/RimContextCommandBuilder.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimContextCommandBuilder.cpp @@ -342,6 +342,7 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection() menuBuilder << "RicNewEditableWellPathFeature"; menuBuilder << "RicPasteModeledWellPathFeature"; menuBuilder << "RicCreateEnsembleWellLogFeature"; + menuBuilder << "RicCreateDepthAdjustedLasFilesFeature"; menuBuilder.addSeparator(); menuBuilder.subMenuStart( "Import" ); menuBuilder << "RicWellPathsImportFileFeature"; diff --git a/ApplicationLibCode/ReservoirDataModel/RigWellLogFile.cpp b/ApplicationLibCode/ReservoirDataModel/RigWellLogFile.cpp index 092ad44738..6c891ec355 100644 --- a/ApplicationLibCode/ReservoirDataModel/RigWellLogFile.cpp +++ b/ApplicationLibCode/ReservoirDataModel/RigWellLogFile.cpp @@ -291,6 +291,14 @@ bool RigWellLogFile::hasTvdRkbChannel() const return !m_tvdRkbLogName.isEmpty(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RigWellLogFile::getMissingValue() const +{ + return m_wellLogFile->GetContMissing(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/ReservoirDataModel/RigWellLogFile.h b/ApplicationLibCode/ReservoirDataModel/RigWellLogFile.h index 474b61c087..6c4f1cd91c 100644 --- a/ApplicationLibCode/ReservoirDataModel/RigWellLogFile.h +++ b/ApplicationLibCode/ReservoirDataModel/RigWellLogFile.h @@ -61,6 +61,8 @@ public: bool hasTvdMslChannel() const; bool hasTvdRkbChannel() const; + double getMissingValue() const; + private: void close(); QString depthUnitString() const;