mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
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 <jorgenherje@users.noreply.github.com> Co-authored-by: Magne Sjaastad <magne.sjaastad@ceetronsolutions.com>
This commit is contained in:
@@ -5,3 +5,4 @@
|
||||
^ApplicationExeCode/Resources/SouthView.svg
|
||||
^ApplicationExeCode/Resources/WestView.svg
|
||||
^ApplicationLibCode/ProjectDataModel/RimEclipseStatisticsCaseEvaluator.cpp
|
||||
^ApplicationLibCode/Commands/ExportCommands/RicCreateDepthAdjustedLasFilesImpl.cpp
|
@@ -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})
|
||||
|
43
ApplicationLibCode/Application/RiaLasDefines.cpp
Normal file
43
ApplicationLibCode/Application/RiaLasDefines.cpp
Normal file
@@ -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 <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "RiaLasDefines.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaDefines::propertyNameMeasuredDepth()
|
||||
{
|
||||
return "DEPTH";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaDefines::propertyNameTvdMslDepth()
|
||||
{
|
||||
return "TVDMSL";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaDefines::propertyNameTvdRkbDepth()
|
||||
{
|
||||
return "TVDRKB";
|
||||
}
|
28
ApplicationLibCode/Application/RiaLasDefines.h
Normal file
28
ApplicationLibCode/Application/RiaLasDefines.h
Normal file
@@ -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 <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
|
||||
namespace RiaDefines
|
||||
{
|
||||
QString propertyNameMeasuredDepth();
|
||||
QString propertyNameTvdMslDepth();
|
||||
QString propertyNameTvdRkbDepth();
|
||||
}; // namespace RiaDefines
|
@@ -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})
|
||||
|
@@ -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 <http://www.gnu.org/licenses/gpl.html>
|
||||
// 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 <QAction>
|
||||
|
||||
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<RimWellPath*> destinationWells = featureUi.destinationWells().ptrReferencedObjects();
|
||||
std::vector<QString> selectedResultProperties = featureUi.selectedResultProperties();
|
||||
QString exportFolder = featureUi.exportFolder();
|
||||
|
||||
RimEclipseCase* eclipseCase = dynamic_cast<RimEclipseCase*>( selectedCase );
|
||||
RimGeoMechCase* geomCase = dynamic_cast<RimGeoMechCase*>( 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<RimWellPath*> destinationWells,
|
||||
const std::vector<QString>& selectedResultProperties,
|
||||
const QString& exportFolder )
|
||||
{
|
||||
if ( sourceWell->wellLogFiles().empty() ) return;
|
||||
|
||||
RimWellLogPlotCollection* wellLogCollection = RimMainPlotCollection::current()->wellLogPlotCollection();
|
||||
cvf::ref<RigEclipseWellLogExtractor> 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<RimWellPath*> destinationWells,
|
||||
const std::vector<QString>& selectedResultProperties,
|
||||
const QString& exportFolder )
|
||||
{
|
||||
if ( sourceWell->wellLogFiles().empty() ) return;
|
||||
|
||||
auto* wellLogFileData = sourceWell->wellLogFiles()[0]->wellLogFileData();
|
||||
RimWellLogPlotCollection* wellLogCollection = RimMainPlotCollection::current()->wellLogPlotCollection();
|
||||
cvf::ref<RigGeoMechWellLogExtractor> 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 );
|
||||
}
|
@@ -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 <http://www.gnu.org/licenses/gpl.html>
|
||||
// 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<RimWellPath*> destinationWells,
|
||||
const std::vector<QString>& selectedResultProperties,
|
||||
const QString& exportFolder );
|
||||
|
||||
void createDepthAdjustedWellLogFileFromGeoMechCase( RimGeoMechCase* geoMechCase,
|
||||
RimWellPath* sourceWell,
|
||||
const std::vector<RimWellPath*> destinationWells,
|
||||
const std::vector<QString>& selectedResultProperties,
|
||||
const QString& exportFolder );
|
||||
};
|
@@ -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 <http://www.gnu.org/licenses/gpl.html>
|
||||
// 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<size_t, double> LasDepthValueAndIndexPerKLayer::indexAndValuePairs( int kLayer ) const
|
||||
{
|
||||
if ( !hasKLayer( kLayer ) ) return std::map<size_t, double>();
|
||||
|
||||
return m_kLayerIndexAndValuePairsMap.at( kLayer );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cvf::ref<RigResultAccessor> 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<double>& lasWellDepths,
|
||||
const std::map<int, IndexKDepthData>& 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<RimWellPath*> destinationWells,
|
||||
const std::vector<QString>& 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<int, IndexKDepthData> destinationWellIndexKDepthsMap =
|
||||
createIndexKDepthDataMapFromCase( selectedCase, well );
|
||||
|
||||
if ( destinationWellIndexKDepthsMap.empty() ) continue;
|
||||
|
||||
std::vector<double> mdValues;
|
||||
std::vector<double> tvdMslValues;
|
||||
std::vector<double> tvdRkbValues;
|
||||
std::map<QString, std::vector<double>> 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<double>& mdValues,
|
||||
const std::vector<double>& tvdMslValues,
|
||||
const std::vector<double>& tvdRkbValues,
|
||||
const std::map<QString, std::vector<double>>& 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<std::string> 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<int, RicCreateDepthAdjustedLasFilesImpl::IndexKDepthData>
|
||||
RicCreateDepthAdjustedLasFilesImpl::createIndexKDepthDataMapFromCase( RimCase* selectedCase, RimWellPath* wellPath )
|
||||
{
|
||||
RimEclipseCase* eclipseCase = dynamic_cast<RimEclipseCase*>( selectedCase );
|
||||
RimGeoMechCase* geomCase = dynamic_cast<RimGeoMechCase*>( selectedCase );
|
||||
|
||||
RimWellLogPlotCollection* wellLogCollection = RimMainPlotCollection::current()->wellLogPlotCollection();
|
||||
if ( eclipseCase != nullptr )
|
||||
{
|
||||
cvf::ref<RigEclipseWellLogExtractor> 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<RigGeoMechWellLogExtractor> 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<int, RicCreateDepthAdjustedLasFilesImpl::IndexKDepthData>();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::map<int, RicCreateDepthAdjustedLasFilesImpl::IndexKDepthData>
|
||||
RicCreateDepthAdjustedLasFilesImpl::createIndexKDepthDataMap( cvf::ref<RigEclipseWellLogExtractor> wellExtractor,
|
||||
cvf::ref<RigResultAccessor> indexKResAcc )
|
||||
{
|
||||
std::vector<double> wellIndexKValues;
|
||||
wellExtractor->curveData( indexKResAcc.p(), &wellIndexKValues );
|
||||
return createIndexKDepthDataMapFromVectors( wellExtractor->cellIntersectionMDs(),
|
||||
wellExtractor->cellIntersectionTVDs(),
|
||||
wellIndexKValues );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::map<int, RicCreateDepthAdjustedLasFilesImpl::IndexKDepthData>
|
||||
RicCreateDepthAdjustedLasFilesImpl::createIndexKDepthDataMap( cvf::ref<RigGeoMechWellLogExtractor> wellExtractor )
|
||||
{
|
||||
const int frameIdx = 0;
|
||||
const int timeStepIdx = 0;
|
||||
RigFemResultAddress indexKResAdr( RigFemResultPosEnum::RIG_ELEMENT_NODAL, "INDEX", "INDEX_K" );
|
||||
std::vector<double> wellIndexKValues;
|
||||
wellExtractor->curveData( indexKResAdr, timeStepIdx, frameIdx, &wellIndexKValues );
|
||||
return createIndexKDepthDataMapFromVectors( wellExtractor->cellIntersectionMDs(),
|
||||
wellExtractor->cellIntersectionTVDs(),
|
||||
wellIndexKValues );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::map<int, RicCreateDepthAdjustedLasFilesImpl::IndexKDepthData>
|
||||
RicCreateDepthAdjustedLasFilesImpl::createIndexKDepthDataMapFromVectors( const std::vector<double>& wellMdValues,
|
||||
const std::vector<double>& wellTvdValues,
|
||||
const std::vector<double>& wellIndexKValues )
|
||||
{
|
||||
std::map<int, IndexKDepthData> 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<int>( 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<QString, std::vector<double>>
|
||||
RicCreateDepthAdjustedLasFilesImpl::createDefaultPropertyMap( const std::vector<QString>& selectedProperties,
|
||||
const RigWellLogFile* wellLogFile )
|
||||
{
|
||||
const QStringList lasDepthNames = QStringList( { RiaDefines::propertyNameMeasuredDepth(),
|
||||
RiaDefines::propertyNameTvdMslDepth(),
|
||||
RiaDefines::propertyNameTvdRkbDepth() } );
|
||||
std::vector<QString> validPropertyNames;
|
||||
for ( const auto& propertyName : selectedProperties )
|
||||
{
|
||||
if ( !lasDepthNames.contains( propertyName ) && wellLogFile->wellLogChannelNames().contains( propertyName ) )
|
||||
{
|
||||
validPropertyNames.push_back( propertyName );
|
||||
}
|
||||
}
|
||||
std::map<QString, std::vector<double>> defaultPropertyMap;
|
||||
for ( const auto& name : validPropertyNames )
|
||||
{
|
||||
defaultPropertyMap[name];
|
||||
}
|
||||
return defaultPropertyMap;
|
||||
}
|
@@ -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 <http://www.gnu.org/licenses/gpl.html>
|
||||
// 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<size_t, double> 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<int, std::map<size_t, double>> m_kLayerIndexAndValuePairsMap;
|
||||
};
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
namespace RicCreateDepthAdjustedLasFilesImpl
|
||||
{
|
||||
struct IndexKDepthData
|
||||
{
|
||||
double mdTop = 0.0;
|
||||
double mdBottom = 0.0;
|
||||
double tvdTop = 0.0;
|
||||
double tvdBottom = 0.0;
|
||||
};
|
||||
|
||||
cvf::ref<RigResultAccessor> createIndexKResultAccessor( RimEclipseCase* selectedCase );
|
||||
|
||||
void createDestinationWellsLasFiles( RimCase* selectedCase,
|
||||
RimWellPath* sourceWell,
|
||||
const std::vector<RimWellPath*> destinationWells,
|
||||
const std::vector<QString>& selectedResultProperties,
|
||||
const QString& exportFolder,
|
||||
double rkbDiff );
|
||||
|
||||
void createDestinationWellLasFile( const QString& wellName,
|
||||
const QString& caseDescription,
|
||||
const std::vector<double>& mdValues,
|
||||
const std::vector<double>& tvdMslValues,
|
||||
const std::vector<double>& tvdRkbValues,
|
||||
const std::map<QString, std::vector<double>>& propertyMap,
|
||||
const RigWellLogFile* sourceWellLogData,
|
||||
const QString& exportFolder );
|
||||
|
||||
std::string createDepthUnitText( RiaDefines::DepthUnitType depthUnitType );
|
||||
std::string createDepthUnitComment( RiaDefines::DepthUnitType depthUnitType );
|
||||
|
||||
LasDepthValueAndIndexPerKLayer
|
||||
createLasDepthIndexAndPercValuePerKLayerFromMap( const std::vector<double>& lasWellDepths,
|
||||
const std::map<int, IndexKDepthData>& indexKDepthDataMap );
|
||||
std::map<int, IndexKDepthData> createIndexKDepthDataMapFromCase( RimCase* selectedCase, RimWellPath* wellPath );
|
||||
std::map<int, IndexKDepthData> createIndexKDepthDataMap( cvf::ref<RigEclipseWellLogExtractor> wellExtractor,
|
||||
cvf::ref<RigResultAccessor> indexKResAcc );
|
||||
std::map<int, IndexKDepthData> createIndexKDepthDataMap( cvf::ref<RigGeoMechWellLogExtractor> wellExtractor );
|
||||
|
||||
std::map<int, IndexKDepthData> createIndexKDepthDataMapFromVectors( const std::vector<double>& wellMdValues,
|
||||
const std::vector<double>& wellTvdValues,
|
||||
const std::vector<double>& wellIndexKValues );
|
||||
|
||||
std::map<QString, std::vector<double>> createDefaultPropertyMap( const std::vector<QString>& selectedProperties,
|
||||
const RigWellLogFile* wellLogFile );
|
||||
|
||||
}; // namespace RicCreateDepthAdjustedLasFilesImpl
|
@@ -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 <http://www.gnu.org/licenses/gpl.html>
|
||||
// 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<caf::PdmOptionItemInfo>
|
||||
RicCreateDepthAdjustedLasFilesUi::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions )
|
||||
{
|
||||
QList<caf::PdmOptionItemInfo> options;
|
||||
|
||||
if ( fieldNeedingOptions == &selectedCase )
|
||||
{
|
||||
RimTools::caseOptionItems( &options );
|
||||
}
|
||||
if ( fieldNeedingOptions == &sourceWell )
|
||||
{
|
||||
RimProject* proj = RimProject::current();
|
||||
if ( proj )
|
||||
{
|
||||
std::vector<RimWellPath*> 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<RimWellPath*> 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<caf::PdmUiFilePathEditorAttribute*>( 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<RimCase*> allCases;
|
||||
proj->allCases( allCases );
|
||||
if ( !allCases.empty() ) selectedCase = allCases[0];
|
||||
|
||||
std::vector<RimWellPath*> 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 );
|
||||
}
|
@@ -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 <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "RiaLasDefines.h"
|
||||
|
||||
#include "cafPdmField.h"
|
||||
#include "cafPdmObject.h"
|
||||
#include "cafPdmPtrArrayField.h"
|
||||
#include "cafPdmPtrField.h"
|
||||
#include "cafPdmUiItem.h"
|
||||
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
class RimCase;
|
||||
class RimWellPath;
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
class RicCreateDepthAdjustedLasFilesUi : public caf::PdmObject
|
||||
{
|
||||
CAF_PDM_HEADER_INIT;
|
||||
|
||||
public:
|
||||
RicCreateDepthAdjustedLasFilesUi();
|
||||
~RicCreateDepthAdjustedLasFilesUi() override;
|
||||
|
||||
QList<caf::PdmOptionItemInfo> 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<QString> exportFolder;
|
||||
caf::PdmPtrField<RimCase*> selectedCase;
|
||||
caf::PdmPtrField<RimWellPath*> sourceWell;
|
||||
caf::PdmField<std::vector<QString>> selectedResultProperties;
|
||||
caf::PdmPtrArrayField<RimWellPath*> destinationWells;
|
||||
|
||||
protected:
|
||||
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
|
||||
|
||||
private:
|
||||
const QStringList m_depthProperties = QStringList( { RiaDefines::propertyNameMeasuredDepth(),
|
||||
RiaDefines::propertyNameTvdMslDepth(),
|
||||
RiaDefines::propertyNameTvdRkbDepth() } );
|
||||
};
|
@@ -72,35 +72,30 @@ RigFemScalarResultFrames* RigFemPartResultCalculatorKIndices::calculate( int
|
||||
const size_t valCount = femPart->elementNodeResultCount();
|
||||
dstFrameData.resize( valCount, std::numeric_limits<float>::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<size_t>::infinity() returns 0
|
||||
constexpr size_t maxValue = std::numeric_limits<size_t>::max();
|
||||
// Using max() as std::numeric_limits<size_t>::infinity() returns 0
|
||||
constexpr size_t maxValue = std::numeric_limits<size_t>::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<float>( k ) : HUGE_VALF;
|
||||
}
|
||||
size_t elmNodResIdx = femPart->elementNodeResultIdx( elmIdx, elmNodIdx );
|
||||
dstFrameData[elmNodResIdx] = k != maxValue ? static_cast<float>( k ) : HUGE_VALF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -342,6 +342,7 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection()
|
||||
menuBuilder << "RicNewEditableWellPathFeature";
|
||||
menuBuilder << "RicPasteModeledWellPathFeature";
|
||||
menuBuilder << "RicCreateEnsembleWellLogFeature";
|
||||
menuBuilder << "RicCreateDepthAdjustedLasFilesFeature";
|
||||
menuBuilder.addSeparator();
|
||||
menuBuilder.subMenuStart( "Import" );
|
||||
menuBuilder << "RicWellPathsImportFileFeature";
|
||||
|
@@ -291,6 +291,14 @@ bool RigWellLogFile::hasTvdRkbChannel() const
|
||||
return !m_tvdRkbLogName.isEmpty();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RigWellLogFile::getMissingValue() const
|
||||
{
|
||||
return m_wellLogFile->GetContMissing();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
@@ -61,6 +61,8 @@ public:
|
||||
bool hasTvdMslChannel() const;
|
||||
bool hasTvdRkbChannel() const;
|
||||
|
||||
double getMissingValue() const;
|
||||
|
||||
private:
|
||||
void close();
|
||||
QString depthUnitString() const;
|
||||
|
Reference in New Issue
Block a user