mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
Rename RimWellLogDiffCurve to RimWellLogCalculatedCurve and additional improvements
* Rename from DiffCurve to CalculatedCurve and add operators selection * Add option to select depth source for resampling in CalculatedCurve - Select source for depth values for resampling - Depths from first curve, second curve or union of these - Added unit tests for function creating union depth values and calculate value with selected operator. * Guard divide by zero * Adjust algorithm for union of depths - Prevent duplicated depth values (no need for enter/exist of k-layer when resampling) - Add threshold for depth distance - Update unit tests
This commit is contained in:
parent
a3efc16615
commit
5975fe6765
@ -30,8 +30,8 @@
|
||||
#include "RimProject.h"
|
||||
#include "RimSimWellInView.h"
|
||||
#include "RimSummaryCase.h"
|
||||
#include "RimWellLogCalculatedCurve.h"
|
||||
#include "RimWellLogCurveCommonDataSource.h"
|
||||
#include "RimWellLogDiffCurve.h"
|
||||
#include "RimWellLogExtractionCurve.h"
|
||||
#include "RimWellLogFile.h"
|
||||
#include "RimWellLogFileChannel.h"
|
||||
@ -586,12 +586,12 @@ RimWellMeasurementCurve* RicWellLogTools::addWellMeasurementCurve( RimWellLogTra
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimWellLogDiffCurve* RicWellLogTools::addWellLogDiffCurve( RimWellLogTrack* plotTrack, bool showPlotWindow )
|
||||
RimWellLogCalculatedCurve* RicWellLogTools::addWellLogCalculatedCurve( RimWellLogTrack* plotTrack, bool showPlotWindow )
|
||||
{
|
||||
CVF_ASSERT( plotTrack );
|
||||
|
||||
RimWellLogDiffCurve* curve = new RimWellLogDiffCurve();
|
||||
const cvf::Color3f curveColor = RicWellLogPlotCurveFeatureImpl::curveColorFromTable( plotTrack->curveCount() );
|
||||
RimWellLogCalculatedCurve* curve = new RimWellLogCalculatedCurve();
|
||||
const cvf::Color3f curveColor = RicWellLogPlotCurveFeatureImpl::curveColorFromTable( plotTrack->curveCount() );
|
||||
curve->setColor( curveColor );
|
||||
|
||||
plotTrack->addCurve( curve );
|
||||
|
@ -38,7 +38,7 @@ class RimWellPath;
|
||||
class RimWellMeasurementCurve;
|
||||
class RimSummaryCase;
|
||||
class RimWellLogCurve;
|
||||
class RimWellLogDiffCurve;
|
||||
class RimWellLogCalculatedCurve;
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
@ -73,7 +73,7 @@ public:
|
||||
bool showPlotWindow = true );
|
||||
static RimWellMeasurementCurve*
|
||||
addWellMeasurementCurve( RimWellLogTrack* plotTrack, RimWellPath* wellPath, const QString& measurementName, bool showPlotWindow = true );
|
||||
static RimWellLogDiffCurve* addWellLogDiffCurve( RimWellLogTrack* plotTrack, bool showPlotWindow = true );
|
||||
static RimWellLogCalculatedCurve* addWellLogCalculatedCurve( RimWellLogTrack* plotTrack, bool showPlotWindow = true );
|
||||
|
||||
static RimWellLogCurve* addSummaryRftCurve( RimWellLogTrack* plotTrack, RimSummaryCase* rimCase );
|
||||
static RimWellLogRftCurve* addSummaryRftSegmentCurve( RimWellLogTrack* plotTrack,
|
||||
|
@ -30,7 +30,7 @@ set(SOURCE_GROUP_HEADER_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicNewRftWellLogPlotFeature.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicNewRftSegmentWellLogPlotFeature.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicNewMultiPhaseRftSegmentPlotFeature.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicNewWellLogDiffCurveFeature.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicNewWellLogCalculatedCurveFeature.h
|
||||
)
|
||||
|
||||
set(SOURCE_GROUP_SOURCE_FILES
|
||||
@ -65,7 +65,7 @@ set(SOURCE_GROUP_SOURCE_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicNewRftWellLogPlotFeature.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicNewRftSegmentWellLogPlotFeature.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicNewMultiPhaseRftSegmentPlotFeature.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicNewWellLogDiffCurveFeature.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicNewWellLogCalculatedCurveFeature.cpp
|
||||
)
|
||||
|
||||
list(APPEND COMMAND_CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})
|
||||
|
@ -16,12 +16,12 @@
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "RicNewWellLogDiffCurveFeature.h"
|
||||
#include "RicNewWellLogCalculatedCurveFeature.h"
|
||||
|
||||
#include "RicWellLogTools.h"
|
||||
|
||||
#include "RimWellLogCalculatedCurve.h"
|
||||
#include "RimWellLogCurve.h"
|
||||
#include "RimWellLogDiffCurve.h"
|
||||
#include "RimWellLogTrack.h"
|
||||
|
||||
#include "RiuPlotMainWindowTools.h"
|
||||
@ -33,12 +33,12 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
CAF_CMD_SOURCE_INIT( RicNewWellLogDiffCurveFeature, "RicNewWellLogDiffCurveFeature" );
|
||||
CAF_CMD_SOURCE_INIT( RicNewWellLogCalculatedCurveFeature, "RicNewWellLogCalculatedCurveFeature" );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RicNewWellLogDiffCurveFeature::isCommandEnabled()
|
||||
bool RicNewWellLogCalculatedCurveFeature::isCommandEnabled()
|
||||
{
|
||||
std::vector<RimWellLogCurve*> wellLogCurves;
|
||||
caf::SelectionManager::instance()->objectsByType( &wellLogCurves );
|
||||
@ -49,12 +49,12 @@ bool RicNewWellLogDiffCurveFeature::isCommandEnabled()
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicNewWellLogDiffCurveFeature::onActionTriggered( bool isChecked )
|
||||
void RicNewWellLogCalculatedCurveFeature::onActionTriggered( bool isChecked )
|
||||
{
|
||||
RimWellLogTrack* wellLogTrack = caf::SelectionManager::instance()->selectedItemOfType<RimWellLogTrack>();
|
||||
if ( wellLogTrack )
|
||||
{
|
||||
RicWellLogTools::addWellLogDiffCurve( wellLogTrack );
|
||||
RicWellLogTools::addWellLogCalculatedCurve( wellLogTrack );
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -65,7 +65,7 @@ void RicNewWellLogDiffCurveFeature::onActionTriggered( bool isChecked )
|
||||
RimWellLogTrack* wellLogTrack = wellLogCurves[0]->firstAncestorOrThisOfType<RimWellLogTrack>();
|
||||
if ( !wellLogTrack ) return;
|
||||
|
||||
RimWellLogDiffCurve* newCurve = RicWellLogTools::addWellLogDiffCurve( wellLogTrack );
|
||||
RimWellLogCalculatedCurve* newCurve = RicWellLogTools::addWellLogCalculatedCurve( wellLogTrack );
|
||||
newCurve->setWellLogCurves( wellLogCurves[0], wellLogCurves[1] );
|
||||
newCurve->updateConnectedEditors();
|
||||
}
|
||||
@ -75,8 +75,8 @@ void RicNewWellLogDiffCurveFeature::onActionTriggered( bool isChecked )
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicNewWellLogDiffCurveFeature::setupActionLook( QAction* actionToSetup )
|
||||
void RicNewWellLogCalculatedCurveFeature::setupActionLook( QAction* actionToSetup )
|
||||
{
|
||||
actionToSetup->setText( "New Well Log Diff Curve" );
|
||||
actionToSetup->setText( "New Well Log Calculated Curve" );
|
||||
actionToSetup->setIcon( QIcon( ":/WellLogCurve16x16.png" ) );
|
||||
}
|
@ -23,7 +23,7 @@
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
class RicNewWellLogDiffCurveFeature : public caf::CmdFeature
|
||||
class RicNewWellLogCalculatedCurveFeature : public caf::CmdFeature
|
||||
{
|
||||
CAF_CMD_HEADER_INIT;
|
||||
|
@ -35,7 +35,7 @@
|
||||
#include "RimIntersectionCollection.h"
|
||||
#include "RimMainPlotCollection.h"
|
||||
#include "RimModeledWellPath.h"
|
||||
#include "RimWellLogDiffCurve.h"
|
||||
#include "RimWellLogCalculatedCurve.h"
|
||||
#include "RimWellLogExtractionCurve.h"
|
||||
#include "RimWellLogPlotCollection.h"
|
||||
#include "RimWellLogPlotNameConfig.h"
|
||||
@ -286,8 +286,8 @@ void RimGeoMechFaultReactivationResult::createWellLogCurves()
|
||||
const bool doUpdateAfter = true;
|
||||
RimWellLogTrack* wellLogExtractionDisplacementTrack =
|
||||
RicNewWellLogPlotFeatureImpl::createWellLogPlotTrack( doUpdateAfter, QString( "Fault Reactivation Displacement Curves" ), newPlot );
|
||||
RimWellLogTrack* wellLogDiffTrack =
|
||||
RicNewWellLogPlotFeatureImpl::createWellLogPlotTrack( doUpdateAfter, QString( "Fault Reactivation Displacement Diff" ), newPlot );
|
||||
RimWellLogTrack* wellLogCalculatedTrack =
|
||||
RicNewWellLogPlotFeatureImpl::createWellLogPlotTrack( doUpdateAfter, QString( "Fault Reactivation Displacement Difference" ), newPlot );
|
||||
RimWellLogTrack* wellLogExtractionFaultmobTrack =
|
||||
RicNewWellLogPlotFeatureImpl::createWellLogPlotTrack( doUpdateAfter, QString( "Fault Reactivation Faultmob Curves" ), newPlot );
|
||||
|
||||
@ -308,11 +308,12 @@ void RimGeoMechFaultReactivationResult::createWellLogCurves()
|
||||
return;
|
||||
}
|
||||
|
||||
// Create well log diff curve for m_faceAWellPath and m_faceBWellPath
|
||||
RimWellLogDiffCurve* faceWellLogDiffCurve = RicWellLogTools::addWellLogDiffCurve( wellLogDiffTrack );
|
||||
faceWellLogDiffCurve->setWellLogCurves( faceADisplacementCurve, faceBDisplacementCurve );
|
||||
faceWellLogDiffCurve->loadDataAndUpdate( true );
|
||||
faceWellLogDiffCurve->updateConnectedEditors();
|
||||
// Create well log calculated curve for m_faceAWellPath and m_faceBWellPath
|
||||
RimWellLogCalculatedCurve* wellLogCalculatedCurve = RicWellLogTools::addWellLogCalculatedCurve( wellLogCalculatedTrack );
|
||||
wellLogCalculatedCurve->setOperator( RimWellLogCalculatedCurve::Operators::SUBTRACT );
|
||||
wellLogCalculatedCurve->setWellLogCurves( faceADisplacementCurve, faceBDisplacementCurve );
|
||||
wellLogCalculatedCurve->loadDataAndUpdate( true );
|
||||
wellLogCalculatedCurve->updateConnectedEditors();
|
||||
|
||||
// Well log extraction faultmob curves
|
||||
RigFemResultAddress wellLogExtractionFaultmobResult( RigFemResultPosEnum::RIG_ELEMENT_NODAL_FACE, "SE", "FAULTMOB" );
|
||||
|
@ -639,7 +639,7 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection()
|
||||
menuBuilder << "RicNewWellLogRftCurveFeature";
|
||||
menuBuilder << "RicNewWellLogFileCurveFeature";
|
||||
menuBuilder << "RicNewWellMeasurementCurveFeature";
|
||||
menuBuilder << "RicNewWellLogDiffCurveFeature";
|
||||
menuBuilder << "RicNewWellLogCalculatedCurveFeature";
|
||||
menuBuilder << "RicNewEnsembleWellLogCurveSetFeature";
|
||||
menuBuilder << "Separator";
|
||||
menuBuilder << "RicDeleteSubPlotFeature";
|
||||
@ -1245,7 +1245,7 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection()
|
||||
}
|
||||
else if ( dynamic_cast<RimWellLogCurve*>( firstUiItem ) || dynamic_cast<RimWellLogTrack*>( firstUiItem ) )
|
||||
{
|
||||
menuBuilder << "RicNewWellLogDiffCurveFeature";
|
||||
menuBuilder << "RicNewWellLogCalculatedCurveFeature";
|
||||
menuBuilder << "RicExportToLasFileFeature";
|
||||
menuBuilder << "RicChangeDataSourceFeature";
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ set(SOURCE_GROUP_HEADER_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimRftTools.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimRftTopologyCurve.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimWellLogCurveInfoTextProvider.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimWellLogDiffCurve.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimWellLogCalculatedCurve.h
|
||||
)
|
||||
|
||||
set(SOURCE_GROUP_SOURCE_FILES
|
||||
@ -57,7 +57,7 @@ set(SOURCE_GROUP_SOURCE_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimRftTools.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimRftTopologyCurve.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimWellLogCurveInfoTextProvider.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimWellLogDiffCurve.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimWellLogCalculatedCurve.cpp
|
||||
)
|
||||
|
||||
list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})
|
||||
|
@ -0,0 +1,479 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "RimWellLogCalculatedCurve.h"
|
||||
|
||||
#include "RiaDefines.h"
|
||||
#include "RiaLogging.h"
|
||||
|
||||
#include "RigWellLogCurveData.h"
|
||||
|
||||
#include "RimMainPlotCollection.h"
|
||||
#include "RimOilField.h"
|
||||
#include "RimPlot.h"
|
||||
#include "RimProject.h"
|
||||
#include "RimWellLogPlot.h"
|
||||
#include "RimWellLogPlotCollection.h"
|
||||
#include "RimWellLogTrack.h"
|
||||
#include "RimWellPathCollection.h"
|
||||
|
||||
#include "RiuPlotCurve.h"
|
||||
|
||||
#include "cafPdmUiComboBoxEditor.h"
|
||||
#include "cafPdmUiTreeOrdering.h"
|
||||
|
||||
CAF_PDM_SOURCE_INIT( RimWellLogCalculatedCurve, "WellLogCalculatedCurve" );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
namespace caf
|
||||
{
|
||||
template <>
|
||||
void AppEnum<RimWellLogCalculatedCurve::Operators>::setUp()
|
||||
{
|
||||
addItem( RimWellLogCalculatedCurve::Operators::ADD, "ADD", "+" );
|
||||
addItem( RimWellLogCalculatedCurve::Operators::SUBTRACT, "SUBTRACT", "-" );
|
||||
addItem( RimWellLogCalculatedCurve::Operators::MULTIPLY, "MULTIPLY", "*" );
|
||||
addItem( RimWellLogCalculatedCurve::Operators::DIVIDE, "DIVIDE", "/" );
|
||||
setDefault( RimWellLogCalculatedCurve::Operators::SUBTRACT );
|
||||
}
|
||||
|
||||
template <>
|
||||
void AppEnum<RimWellLogCalculatedCurve::DepthSource>::setUp()
|
||||
{
|
||||
addItem( RimWellLogCalculatedCurve::DepthSource::FIRST, "FIRST", "First Curve" );
|
||||
addItem( RimWellLogCalculatedCurve::DepthSource::SECOND, "SECOND", "Second Curve" );
|
||||
addItem( RimWellLogCalculatedCurve::DepthSource::UNION, "UNION", "Union" );
|
||||
setDefault( RimWellLogCalculatedCurve::DepthSource::FIRST );
|
||||
}
|
||||
} // namespace caf
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimWellLogCalculatedCurve::RimWellLogCalculatedCurve()
|
||||
{
|
||||
CAF_PDM_InitObject( "Well Log Calculated Curve", ":/WellLogCurve16x16.png" );
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_operator, "Operator", "Operator" );
|
||||
m_operator.uiCapability()->setUiEditorTypeName( caf::PdmUiComboBoxEditor::uiEditorTypeName() );
|
||||
CAF_PDM_InitFieldNoDefault( &m_depthSource, "DepthSource", "Depth Source" );
|
||||
m_depthSource.uiCapability()->setUiEditorTypeName( caf::PdmUiComboBoxEditor::uiEditorTypeName() );
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_firstWellLogCurve, "FirstWellLogCurve", "First Well Log Curve" );
|
||||
CAF_PDM_InitFieldNoDefault( &m_secondWellLogCurve, "SecondWellLogCurve", "Second Well Log Curve" );
|
||||
|
||||
setNamingMethod( RiaDefines::ObjectNamingMethod::AUTO );
|
||||
setDeletable( true );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimWellLogCalculatedCurve::~RimWellLogCalculatedCurve()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellLogCalculatedCurve::setOperator( Operators operatorValue )
|
||||
{
|
||||
m_operator = operatorValue;
|
||||
if ( m_namingMethod() == RiaDefines::ObjectNamingMethod::AUTO )
|
||||
{
|
||||
setAutomaticName();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellLogCalculatedCurve::setWellLogCurves( RimWellLogCurve* firstWellLogCurve, RimWellLogCurve* secondWellLogCurve )
|
||||
{
|
||||
disconnectWellLogCurveChangedFromSlots( m_firstWellLogCurve );
|
||||
disconnectWellLogCurveChangedFromSlots( m_secondWellLogCurve );
|
||||
if ( firstWellLogCurve )
|
||||
{
|
||||
m_firstWellLogCurve = firstWellLogCurve;
|
||||
connectWellLogCurveChangedToSlots( m_firstWellLogCurve );
|
||||
}
|
||||
if ( secondWellLogCurve )
|
||||
{
|
||||
m_secondWellLogCurve = secondWellLogCurve;
|
||||
connectWellLogCurveChangedToSlots( m_secondWellLogCurve );
|
||||
}
|
||||
|
||||
if ( m_namingMethod() == RiaDefines::ObjectNamingMethod::AUTO )
|
||||
{
|
||||
setAutomaticName();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RimWellLogCalculatedCurve::createCurveAutoName()
|
||||
{
|
||||
if ( !m_firstWellLogCurve() || !m_secondWellLogCurve() ) return QString( "Not able to find source curves for calculated curve" );
|
||||
|
||||
const auto& operatorStr = m_operator().uiText();
|
||||
return QString( "Calculated (%1 %2 %3)" ).arg( m_firstWellLogCurve->curveName() ).arg( operatorStr ).arg( m_secondWellLogCurve->curveName() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellLogCalculatedCurve::onLoadDataAndUpdate( bool updateParentPlot )
|
||||
{
|
||||
if ( !m_firstWellLogCurve() || !m_secondWellLogCurve() ) return;
|
||||
|
||||
if ( m_namingMethod() == RiaDefines::ObjectNamingMethod::AUTO )
|
||||
{
|
||||
setAutomaticName();
|
||||
}
|
||||
|
||||
// Use well A as reference for resampled curve data
|
||||
auto* firstCurveData = m_firstWellLogCurve()->curveData();
|
||||
auto* secondCurveData = m_secondWellLogCurve()->curveData();
|
||||
|
||||
if ( !firstCurveData || !secondCurveData ) return;
|
||||
if ( firstCurveData->depthUnit() != secondCurveData->depthUnit() )
|
||||
{
|
||||
RiaLogging::warning( "Well log curve depth units are not the same" );
|
||||
}
|
||||
if ( firstCurveData->propertyValueUnit() != secondCurveData->propertyValueUnit() )
|
||||
{
|
||||
RiaLogging::warning( "Well log curve property value units are not the same" );
|
||||
}
|
||||
|
||||
// Find the data for resampling
|
||||
const auto depthType = RiaDefines::DepthTypeEnum::MEASURED_DEPTH;
|
||||
const std::vector<double> depthValues = depthValuesFromSource( depthType );
|
||||
const auto depthUnit = firstCurveData->depthUnit();
|
||||
const auto propertyUnit = firstCurveData->propertyValueUnit();
|
||||
|
||||
auto firstCurveDepthValues = firstCurveData->depths( depthType );
|
||||
auto firstCurvePropertyValues = firstCurveData->propertyValues();
|
||||
auto secondCurveDepthValues = secondCurveData->depths( depthType );
|
||||
auto secondCurvePropertyValues = secondCurveData->propertyValues();
|
||||
|
||||
// Resample curve depth and property values if needed
|
||||
if ( m_depthSource() != DepthSource::FIRST )
|
||||
{
|
||||
cvf::ref<RigWellLogCurveData> firstCurveDataResampled = firstCurveData->calculateResampledCurveData( depthType, depthValues );
|
||||
firstCurveDepthValues = firstCurveDataResampled->depths( depthType );
|
||||
firstCurvePropertyValues = firstCurveDataResampled->propertyValues();
|
||||
}
|
||||
if ( m_depthSource() != DepthSource::SECOND )
|
||||
{
|
||||
cvf::ref<RigWellLogCurveData> secondCurveDataResampled = secondCurveData->calculateResampledCurveData( depthType, depthValues );
|
||||
secondCurveDepthValues = secondCurveDataResampled->depths( depthType );
|
||||
secondCurvePropertyValues = secondCurveDataResampled->propertyValues();
|
||||
}
|
||||
|
||||
// Verify equal sizes
|
||||
if ( firstCurveDepthValues.size() != depthValues.size() ) return;
|
||||
if ( firstCurveDepthValues.size() != firstCurvePropertyValues.size() ) return;
|
||||
if ( firstCurveDepthValues.size() != secondCurveDepthValues.size() ) return;
|
||||
if ( firstCurveDepthValues.size() != secondCurvePropertyValues.size() ) return;
|
||||
|
||||
// Calculate curve
|
||||
std::vector<double> calculatedDepthValues( depthValues.size() );
|
||||
std::vector<double> calculatedPropertyValues( depthValues.size() );
|
||||
for ( size_t i = 0; i < depthValues.size(); ++i )
|
||||
{
|
||||
calculatedPropertyValues[i] = calculateValue( firstCurvePropertyValues[i], secondCurvePropertyValues[i], m_operator() );
|
||||
calculatedDepthValues[i] = depthValues[i];
|
||||
}
|
||||
|
||||
const bool useLogarithmicScale = false;
|
||||
const bool isExtractionCurve = false;
|
||||
|
||||
// Set curve data
|
||||
auto depthsMap = std::map<RiaDefines::DepthTypeEnum, std::vector<double>>();
|
||||
depthsMap[depthType] = calculatedDepthValues;
|
||||
setPropertyValuesAndDepths( calculatedPropertyValues, depthsMap, 0.0, depthUnit, isExtractionCurve, useLogarithmicScale, propertyUnit );
|
||||
|
||||
// Set curve data to plot
|
||||
std::vector<double> xPlotValues = curveData()->propertyValuesByIntervals();
|
||||
std::vector<double> yPlotValues = curveData()->depthValuesByIntervals( depthType, depthUnit );
|
||||
m_plotCurve->setSamplesFromXValuesAndYValues( xPlotValues, yPlotValues, useLogarithmicScale );
|
||||
updateCurvePresentation( updateParentPlot );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellLogCalculatedCurve::setAutomaticName()
|
||||
{
|
||||
m_curveName = createCurveAutoName();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellLogCalculatedCurve::onWellLogCurveChanged( const SignalEmitter* emitter )
|
||||
{
|
||||
loadDataAndUpdate( true );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellLogCalculatedCurve::connectWellLogCurveChangedToSlots( RimWellLogCurve* wellLogCurve )
|
||||
{
|
||||
if ( !wellLogCurve ) return;
|
||||
|
||||
wellLogCurve->dataChanged.connect( this, &RimWellLogCalculatedCurve::onWellLogCurveChanged );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellLogCalculatedCurve::disconnectWellLogCurveChangedFromSlots( RimWellLogCurve* wellLogCurve )
|
||||
{
|
||||
if ( !wellLogCurve ) return;
|
||||
|
||||
wellLogCurve->dataChanged.disconnect( this );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RimWellLogCalculatedCurve::calculateValue( double firstValue, double secondValue, Operators operatorValue )
|
||||
{
|
||||
if ( operatorValue == Operators::ADD )
|
||||
{
|
||||
return firstValue + secondValue;
|
||||
}
|
||||
if ( operatorValue == Operators::SUBTRACT )
|
||||
{
|
||||
return firstValue - secondValue;
|
||||
}
|
||||
if ( operatorValue == Operators::MULTIPLY )
|
||||
{
|
||||
return firstValue * secondValue;
|
||||
}
|
||||
if ( operatorValue == Operators::DIVIDE )
|
||||
{
|
||||
return secondValue == 0.0 ? std::numeric_limits<double>::infinity() : firstValue / secondValue;
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<double> RimWellLogCalculatedCurve::depthValuesFromSource( RiaDefines::DepthTypeEnum depthType ) const
|
||||
{
|
||||
if ( !m_firstWellLogCurve || !m_firstWellLogCurve->curveData() || !m_secondWellLogCurve || !m_secondWellLogCurve->curveData() )
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
if ( m_depthSource() == DepthSource::FIRST )
|
||||
{
|
||||
return m_firstWellLogCurve->curveData()->depths( depthType );
|
||||
}
|
||||
else if ( m_depthSource() == DepthSource::SECOND )
|
||||
{
|
||||
return m_secondWellLogCurve->curveData()->depths( depthType );
|
||||
}
|
||||
else if ( m_depthSource() == DepthSource::UNION )
|
||||
{
|
||||
return unionDepthValuesFromCurves( depthType );
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// As this method creates an union of depths from two vectors, the duplicated depths are neglected.
|
||||
/// The duplicated depths in a depth vector represent enter and exist of a k-layer. When resampling
|
||||
/// the curves using the union of depths, one does not know if the new depth values are at enter
|
||||
/// or exit of a layer. Therefore, the duplicated depths are neglected.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<double> RimWellLogCalculatedCurve::unionDepthValuesFromVectors( const std::vector<double>& firstDepths,
|
||||
const std::vector<double>& secondDepths,
|
||||
double threshold )
|
||||
{
|
||||
auto isWithinThreshold = [&]( double value, const std::vector<double>& existingValues ) -> bool
|
||||
{
|
||||
auto calculateDistance = []( double value1, double value2 ) -> double { return std::abs( value1 - value2 ); };
|
||||
for ( const auto& existingValue : existingValues )
|
||||
{
|
||||
if ( calculateDistance( value, existingValue ) < threshold )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// Get union of depths
|
||||
std::vector<double> unionDepths;
|
||||
auto insertIntoUnionDepthsVector = [&]( const std::vector<double>& depths, std::vector<double>& unionDepthsVector )
|
||||
{
|
||||
for ( const auto& depth : depths )
|
||||
{
|
||||
if ( isWithinThreshold( depth, unionDepthsVector ) ) continue;
|
||||
unionDepthsVector.push_back( depth );
|
||||
}
|
||||
};
|
||||
insertIntoUnionDepthsVector( firstDepths, unionDepths );
|
||||
insertIntoUnionDepthsVector( secondDepths, unionDepths );
|
||||
|
||||
// Sort vector
|
||||
std::sort( unionDepths.begin(), unionDepths.end() );
|
||||
|
||||
return unionDepths;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// When creating an union depth vector, the duplicated depth values are neglected. These duplicates
|
||||
/// indicates enter and exit of k-layer. However, when curves are resampled, this info is not
|
||||
/// representative and duplicated depth values are not needed.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<double> RimWellLogCalculatedCurve::unionDepthValuesFromCurves( RiaDefines::DepthTypeEnum depthType ) const
|
||||
{
|
||||
if ( !m_firstWellLogCurve || !m_firstWellLogCurve->curveData() || !m_secondWellLogCurve || !m_secondWellLogCurve->curveData() )
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
constexpr double depthThreshold = 0.1;
|
||||
|
||||
// Get union of depths
|
||||
const auto firstDepths = m_firstWellLogCurve->curveData()->depths( depthType );
|
||||
const auto secondDepths = m_secondWellLogCurve->curveData()->depths( depthType );
|
||||
|
||||
return unionDepthValuesFromVectors( firstDepths, secondDepths, depthThreshold );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RimWellLogCalculatedCurve::wellName() const
|
||||
{
|
||||
return m_curveName;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RimWellLogCalculatedCurve::wellLogChannelUiName() const
|
||||
{
|
||||
return m_curveName;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RimWellLogCalculatedCurve::wellLogChannelUnits() const
|
||||
{
|
||||
if ( m_firstWellLogCurve->wellLogChannelUnits() != m_secondWellLogCurve->wellLogChannelUnits() )
|
||||
{
|
||||
const auto& operatorStr = m_operator().uiText();
|
||||
return QString( "%1 %2 %3" )
|
||||
.arg( m_firstWellLogCurve->wellLogChannelUnits() )
|
||||
.arg( operatorStr )
|
||||
.arg( m_secondWellLogCurve->wellLogChannelUnits() );
|
||||
}
|
||||
return m_firstWellLogCurve->wellLogChannelUnits();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellLogCalculatedCurve::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
|
||||
{
|
||||
RimPlotCurve::updateFieldUiState();
|
||||
|
||||
caf::PdmUiGroup* group = uiOrdering.addNewGroup( "Data Source" );
|
||||
group->add( &m_depthSource );
|
||||
group->add( &m_firstWellLogCurve );
|
||||
group->add( &m_secondWellLogCurve );
|
||||
group->add( &m_operator );
|
||||
|
||||
RimStackablePlotCurve::defaultUiOrdering( uiOrdering );
|
||||
|
||||
uiOrdering.skipRemainingFields( true );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellLogCalculatedCurve::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName )
|
||||
{
|
||||
uiTreeOrdering.skipRemainingChildren( true );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellLogCalculatedCurve::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
|
||||
{
|
||||
RimWellLogCurve::fieldChangedByUi( changedField, oldValue, newValue );
|
||||
|
||||
if ( changedField == &m_firstWellLogCurve || changedField == &m_secondWellLogCurve )
|
||||
{
|
||||
if ( !m_firstWellLogCurve() || !m_secondWellLogCurve() ) return;
|
||||
|
||||
PdmObjectHandle* prevValue = oldValue.value<caf::PdmPointer<PdmObjectHandle>>().rawPtr();
|
||||
auto* prevWellLogCurve = dynamic_cast<RimWellLogCurve*>( prevValue );
|
||||
disconnectWellLogCurveChangedFromSlots( prevWellLogCurve );
|
||||
|
||||
if ( changedField == &m_firstWellLogCurve ) connectWellLogCurveChangedToSlots( m_firstWellLogCurve );
|
||||
if ( changedField == &m_secondWellLogCurve ) connectWellLogCurveChangedToSlots( m_secondWellLogCurve );
|
||||
|
||||
loadDataAndUpdate( true );
|
||||
}
|
||||
if ( changedField == &m_operator || changedField == &m_depthSource )
|
||||
{
|
||||
loadDataAndUpdate( true );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QList<caf::PdmOptionItemInfo> RimWellLogCalculatedCurve::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions )
|
||||
{
|
||||
QList<caf::PdmOptionItemInfo> options;
|
||||
|
||||
options = RimWellLogCurve::calculateValueOptions( fieldNeedingOptions );
|
||||
if ( !options.empty() ) return options;
|
||||
|
||||
if ( fieldNeedingOptions == &m_firstWellLogCurve || fieldNeedingOptions == &m_secondWellLogCurve )
|
||||
{
|
||||
RimWellLogPlotCollection* wellLogPlotCollection = RimMainPlotCollection::current()->wellLogPlotCollection();
|
||||
|
||||
if ( !wellLogPlotCollection ) return {};
|
||||
|
||||
// Find each well log plot in collection
|
||||
std::vector<RimWellLogCurve*> wellLogCurves = wellLogPlotCollection->descendantsOfType<RimWellLogCurve>();
|
||||
for ( RimWellLogCurve* curve : wellLogCurves )
|
||||
{
|
||||
if ( !curve || curve == this ) continue;
|
||||
options.push_back( caf::PdmOptionItemInfo( curve->curveName(), curve ) );
|
||||
}
|
||||
}
|
||||
return options;
|
||||
}
|
@ -30,14 +30,30 @@ class RimWellPath;
|
||||
///
|
||||
///
|
||||
//==================================================================================================
|
||||
class RimWellLogDiffCurve : public RimWellLogCurve
|
||||
class RimWellLogCalculatedCurve : public RimWellLogCurve
|
||||
{
|
||||
CAF_PDM_HEADER_INIT;
|
||||
|
||||
public:
|
||||
RimWellLogDiffCurve();
|
||||
~RimWellLogDiffCurve() override;
|
||||
enum class Operators
|
||||
{
|
||||
ADD,
|
||||
SUBTRACT,
|
||||
DIVIDE,
|
||||
MULTIPLY
|
||||
};
|
||||
enum class DepthSource
|
||||
{
|
||||
FIRST,
|
||||
SECOND,
|
||||
UNION
|
||||
};
|
||||
|
||||
public:
|
||||
RimWellLogCalculatedCurve();
|
||||
~RimWellLogCalculatedCurve() override;
|
||||
|
||||
void setOperator( Operators operatorValue );
|
||||
void setWellLogCurves( RimWellLogCurve* firstWellLogCurve, RimWellLogCurve* secondWellLogCurve );
|
||||
|
||||
// Inherited via RimWellLogCurve
|
||||
@ -45,6 +61,10 @@ public:
|
||||
QString wellLogChannelUiName() const override;
|
||||
QString wellLogChannelUnits() const override;
|
||||
|
||||
static double calculateValue( double firstValue, double secondValue, Operators operatorValue );
|
||||
static std::vector<double>
|
||||
unionDepthValuesFromVectors( const std::vector<double>& firstDepths, const std::vector<double>& secondDepths, double threshold );
|
||||
|
||||
protected:
|
||||
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
|
||||
void defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "" ) override;
|
||||
@ -62,9 +82,15 @@ private:
|
||||
void connectWellLogCurveChangedToSlots( RimWellLogCurve* wellLogCurve );
|
||||
void disconnectWellLogCurveChangedFromSlots( RimWellLogCurve* wellLogCurve );
|
||||
|
||||
std::vector<double> depthValuesFromSource( RiaDefines::DepthTypeEnum depthType ) const;
|
||||
std::vector<double> unionDepthValuesFromCurves( RiaDefines::DepthTypeEnum depthType ) const;
|
||||
|
||||
private:
|
||||
caf::PdmPtrField<RimCase*> m_case;
|
||||
|
||||
caf::PdmField<caf::AppEnum<Operators>> m_operator;
|
||||
caf::PdmField<caf::AppEnum<DepthSource>> m_depthSource;
|
||||
|
||||
caf::PdmPtrField<RimWellLogCurve*> m_firstWellLogCurve;
|
||||
caf::PdmPtrField<RimWellLogCurve*> m_secondWellLogCurve;
|
||||
};
|
@ -1,300 +0,0 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "RimWellLogDiffCurve.h"
|
||||
|
||||
#include "RiaDefines.h"
|
||||
#include "RiaLogging.h"
|
||||
|
||||
#include "RigWellLogCurveData.h"
|
||||
|
||||
#include "RimMainPlotCollection.h"
|
||||
#include "RimOilField.h"
|
||||
#include "RimPlot.h"
|
||||
#include "RimProject.h"
|
||||
#include "RimWellLogPlot.h"
|
||||
#include "RimWellLogPlotCollection.h"
|
||||
#include "RimWellLogTrack.h"
|
||||
#include "RimWellPathCollection.h"
|
||||
|
||||
#include "RiuPlotCurve.h"
|
||||
|
||||
#include "cafPdmUiTreeOrdering.h"
|
||||
|
||||
CAF_PDM_SOURCE_INIT( RimWellLogDiffCurve, "WellLogDiffCurve" );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimWellLogDiffCurve::RimWellLogDiffCurve()
|
||||
{
|
||||
CAF_PDM_InitObject( "Well Log Diff Curve", ":/WellLogCurve16x16.png" );
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_firstWellLogCurve, "FirstWellLogCurve", "First Well Log Curve" );
|
||||
CAF_PDM_InitFieldNoDefault( &m_secondWellLogCurve, "SecondWellLogCurve", "Second Well Log Curve" );
|
||||
|
||||
setNamingMethod( RiaDefines::ObjectNamingMethod::AUTO );
|
||||
setDeletable( true );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimWellLogDiffCurve::~RimWellLogDiffCurve()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellLogDiffCurve::setWellLogCurves( RimWellLogCurve* firstWellLogCurve, RimWellLogCurve* secondWellLogCurve )
|
||||
{
|
||||
disconnectWellLogCurveChangedFromSlots( m_firstWellLogCurve );
|
||||
disconnectWellLogCurveChangedFromSlots( m_secondWellLogCurve );
|
||||
if ( firstWellLogCurve )
|
||||
{
|
||||
m_firstWellLogCurve = firstWellLogCurve;
|
||||
connectWellLogCurveChangedToSlots( m_firstWellLogCurve );
|
||||
}
|
||||
if ( secondWellLogCurve )
|
||||
{
|
||||
m_secondWellLogCurve = secondWellLogCurve;
|
||||
connectWellLogCurveChangedToSlots( m_secondWellLogCurve );
|
||||
}
|
||||
|
||||
if ( m_namingMethod() == RiaDefines::ObjectNamingMethod::AUTO )
|
||||
{
|
||||
setAutomaticName();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RimWellLogDiffCurve::createCurveAutoName()
|
||||
{
|
||||
if ( !m_firstWellLogCurve() || !m_secondWellLogCurve() ) return QString( "Not able to find source curves for difference curve" );
|
||||
return QString( "Diff (%1 - %2)" ).arg( m_firstWellLogCurve->curveName() ).arg( m_secondWellLogCurve->curveName() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellLogDiffCurve::onLoadDataAndUpdate( bool updateParentPlot )
|
||||
{
|
||||
if ( !m_firstWellLogCurve() || !m_secondWellLogCurve() ) return;
|
||||
|
||||
if ( m_namingMethod() == RiaDefines::ObjectNamingMethod::AUTO )
|
||||
{
|
||||
setAutomaticName();
|
||||
}
|
||||
|
||||
// Use well A as reference for resampled curve data
|
||||
auto* firstCurveData = m_firstWellLogCurve()->curveData();
|
||||
auto* secondCurveData = m_secondWellLogCurve()->curveData();
|
||||
|
||||
if ( !firstCurveData || !secondCurveData ) return;
|
||||
if ( firstCurveData->depthUnit() != secondCurveData->depthUnit() )
|
||||
{
|
||||
RiaLogging::warning( "Well log curve depth units are not the same" );
|
||||
}
|
||||
if ( firstCurveData->propertyValueUnit() != secondCurveData->propertyValueUnit() )
|
||||
{
|
||||
RiaLogging::warning( "Well log curve property value units are not the same" );
|
||||
}
|
||||
|
||||
const auto depthUnit = firstCurveData->depthUnit();
|
||||
const auto depthType = RiaDefines::DepthTypeEnum::MEASURED_DEPTH;
|
||||
const auto propertyUnit = firstCurveData->propertyValueUnit();
|
||||
|
||||
// Get curve A depths and property values
|
||||
const auto firstCurveDepthValues = firstCurveData->depths( depthType );
|
||||
const auto firstCurvePropertyValues = firstCurveData->propertyValues();
|
||||
|
||||
// Resample curve B to curve A
|
||||
cvf::ref<RigWellLogCurveData> secondCurveDataResampled = secondCurveData->calculateResampledCurveData( depthType, firstCurveDepthValues );
|
||||
auto secondCurveDepthValuesResampled = secondCurveDataResampled->depths( depthType );
|
||||
auto secondCurvePropertyValuesResampled = secondCurveDataResampled->propertyValues();
|
||||
|
||||
// Verify equal sizes
|
||||
if ( firstCurveDepthValues.size() != firstCurvePropertyValues.size() ) return;
|
||||
if ( firstCurveDepthValues.size() != secondCurveDepthValuesResampled.size() ) return;
|
||||
if ( firstCurveDepthValues.size() != secondCurvePropertyValuesResampled.size() ) return;
|
||||
|
||||
// Calculate diff curve
|
||||
std::vector<double> curveDiffDepthValues( firstCurveDepthValues.size() );
|
||||
std::vector<double> curveDiffPropertyValues( firstCurvePropertyValues.size() );
|
||||
for ( size_t i = 0; i < firstCurvePropertyValues.size(); ++i )
|
||||
{
|
||||
curveDiffPropertyValues[i] = firstCurvePropertyValues[i] - secondCurvePropertyValuesResampled[i];
|
||||
curveDiffDepthValues[i] = firstCurveDepthValues[i];
|
||||
}
|
||||
|
||||
const bool useLogarithmicScale = false;
|
||||
const bool isExtractionCurve = false;
|
||||
|
||||
// Set curve data
|
||||
auto depthsMap = std::map<RiaDefines::DepthTypeEnum, std::vector<double>>();
|
||||
depthsMap[depthType] = curveDiffDepthValues;
|
||||
setPropertyValuesAndDepths( curveDiffPropertyValues, depthsMap, 0.0, depthUnit, isExtractionCurve, useLogarithmicScale, propertyUnit );
|
||||
|
||||
// Set curve data to plot
|
||||
std::vector<double> xPlotValues = curveData()->propertyValuesByIntervals();
|
||||
std::vector<double> yPlotValues = curveData()->depthValuesByIntervals( depthType, depthUnit );
|
||||
m_plotCurve->setSamplesFromXValuesAndYValues( xPlotValues, yPlotValues, useLogarithmicScale );
|
||||
updateCurvePresentation( updateParentPlot );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellLogDiffCurve::setAutomaticName()
|
||||
{
|
||||
m_curveName = createCurveAutoName();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellLogDiffCurve::onWellLogCurveChanged( const SignalEmitter* emitter )
|
||||
{
|
||||
onLoadDataAndUpdate( true );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellLogDiffCurve::connectWellLogCurveChangedToSlots( RimWellLogCurve* wellLogCurve )
|
||||
{
|
||||
if ( !wellLogCurve ) return;
|
||||
|
||||
wellLogCurve->dataChanged.connect( this, &RimWellLogDiffCurve::onWellLogCurveChanged );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellLogDiffCurve::disconnectWellLogCurveChangedFromSlots( RimWellLogCurve* wellLogCurve )
|
||||
{
|
||||
if ( !wellLogCurve ) return;
|
||||
|
||||
wellLogCurve->dataChanged.disconnect( this );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RimWellLogDiffCurve::wellName() const
|
||||
{
|
||||
return m_curveName;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RimWellLogDiffCurve::wellLogChannelUiName() const
|
||||
{
|
||||
return m_curveName;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RimWellLogDiffCurve::wellLogChannelUnits() const
|
||||
{
|
||||
CAF_ASSERT( "TO BE IMPLEMETNED!" );
|
||||
|
||||
if ( m_firstWellLogCurve->wellLogChannelUnits() != m_secondWellLogCurve->wellLogChannelUnits() )
|
||||
{
|
||||
return QString( "%1 - %2" ).arg( m_firstWellLogCurve->wellLogChannelUnits() ).arg( m_secondWellLogCurve->wellLogChannelUnits() );
|
||||
}
|
||||
return m_firstWellLogCurve->wellLogChannelUnits();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellLogDiffCurve::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
|
||||
{
|
||||
RimPlotCurve::updateFieldUiState();
|
||||
|
||||
caf::PdmUiGroup* group = uiOrdering.addNewGroup( "Data Source" );
|
||||
group->add( &m_firstWellLogCurve );
|
||||
group->add( &m_secondWellLogCurve );
|
||||
|
||||
RimStackablePlotCurve::defaultUiOrdering( uiOrdering );
|
||||
|
||||
uiOrdering.skipRemainingFields( true );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellLogDiffCurve::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName )
|
||||
{
|
||||
uiTreeOrdering.skipRemainingChildren( true );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellLogDiffCurve::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
|
||||
{
|
||||
RimWellLogCurve::fieldChangedByUi( changedField, oldValue, newValue );
|
||||
|
||||
if ( changedField == &m_firstWellLogCurve || changedField == &m_secondWellLogCurve )
|
||||
{
|
||||
if ( !m_firstWellLogCurve() || !m_secondWellLogCurve() ) return;
|
||||
|
||||
PdmObjectHandle* prevValue = oldValue.value<caf::PdmPointer<PdmObjectHandle>>().rawPtr();
|
||||
auto* prevWellLogCurve = dynamic_cast<RimWellLogCurve*>( prevValue );
|
||||
disconnectWellLogCurveChangedFromSlots( prevWellLogCurve );
|
||||
|
||||
if ( changedField == &m_firstWellLogCurve ) connectWellLogCurveChangedToSlots( m_firstWellLogCurve );
|
||||
if ( changedField == &m_secondWellLogCurve ) connectWellLogCurveChangedToSlots( m_firstWellLogCurve );
|
||||
|
||||
onLoadDataAndUpdate( true );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QList<caf::PdmOptionItemInfo> RimWellLogDiffCurve::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions )
|
||||
{
|
||||
QList<caf::PdmOptionItemInfo> options;
|
||||
|
||||
options = RimWellLogCurve::calculateValueOptions( fieldNeedingOptions );
|
||||
if ( !options.empty() ) return options;
|
||||
|
||||
if ( fieldNeedingOptions == &m_firstWellLogCurve || fieldNeedingOptions == &m_secondWellLogCurve )
|
||||
{
|
||||
RimWellLogPlotCollection* wellLogPlotCollection = RimMainPlotCollection::current()->wellLogPlotCollection();
|
||||
|
||||
if ( !wellLogPlotCollection ) return {};
|
||||
|
||||
// Find each well log plot in collection
|
||||
std::vector<RimWellLogCurve*> wellLogCurves = wellLogPlotCollection->descendantsOfType<RimWellLogCurve>();
|
||||
for ( RimWellLogCurve* curve : wellLogCurves )
|
||||
{
|
||||
if ( !curve || curve == this ) continue;
|
||||
options.push_back( caf::PdmOptionItemInfo( curve->curveName(), curve ) );
|
||||
}
|
||||
}
|
||||
return options;
|
||||
}
|
@ -92,6 +92,7 @@ set(SOURCE_GROUP_SOURCE_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaEnsembleNameTools-Test.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RigDeclineCurveCalculator-Test.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RigWellLogCurveData-Test.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimWellLogCalculatedCurve-Test.cpp
|
||||
)
|
||||
|
||||
if(RESINSIGHT_ENABLE_GRPC)
|
||||
|
@ -0,0 +1,95 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "gtest/gtest.h"
|
||||
|
||||
#include "RimWellLogCalculatedCurve.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
TEST( RimWellLogCalculatedCurve, unionDepthValuesFromVectors_singleValuesInDepthVectors )
|
||||
{
|
||||
// Depth vectors without duplicates
|
||||
const std::vector<double> depthValues1 = { 1.0, 2.0, 3.0, 4.0 };
|
||||
const std::vector<double> depthValues2 = { 2.0, 3.0, 4.0, 5.0 };
|
||||
const double threshold = 0.1;
|
||||
|
||||
// Expected duplicate occurrence of common depth values
|
||||
const std::vector<double> expectedUnionDepthValues = { 1.0, 2.0, 3.0, 4.0, 5.0 };
|
||||
|
||||
// Call the function under test
|
||||
const std::vector<double> unionDepthValues =
|
||||
RimWellLogCalculatedCurve::unionDepthValuesFromVectors( depthValues1, depthValues2, threshold );
|
||||
|
||||
ASSERT_EQ( unionDepthValues, expectedUnionDepthValues );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
TEST( RimWellLogCalculatedCurve, unionDepthValuesFromVectors_duplicateValuesInDepthVectors )
|
||||
{
|
||||
// Depth vectors with duplicates
|
||||
const std::vector<double> depthValues1 = { 0.0, 0.5, 0.5, 1.0, 1.0, 1.5, 1.5 };
|
||||
const std::vector<double> depthValues2 = { 1.5, 1.5, 2.0, 2.0, 2.5, 2.5, 3.0 };
|
||||
const double threshold = 0.1;
|
||||
|
||||
// Expected no duplicate occurrences of depth values
|
||||
const std::vector<double> expectedUnionDepthValues = { 0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0 };
|
||||
|
||||
// Call the function under test
|
||||
const std::vector<double> unionDepthValues =
|
||||
RimWellLogCalculatedCurve::unionDepthValuesFromVectors( depthValues1, depthValues2, threshold );
|
||||
|
||||
ASSERT_EQ( unionDepthValues, expectedUnionDepthValues );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
TEST( RimWellLogCalculatedCurve, unionDepthValuesFromVectors_thresholdVerification )
|
||||
{
|
||||
// Depth vectors with duplicates
|
||||
const std::vector<double> depthValues1 = { 0.0, 0.5, 1.0, 1.5 };
|
||||
const std::vector<double> depthValues2 = { 2.0, 2.5, 3.0, 4.0 };
|
||||
const double threshold = 0.6;
|
||||
|
||||
// Expected every second value to be skipped due to threshold
|
||||
const std::vector<double> expectedUnionDepthValues = { 0.0, 1.0, 2.0, 3.0, 4.0 };
|
||||
|
||||
// Call the function under test
|
||||
const std::vector<double> unionDepthValues =
|
||||
RimWellLogCalculatedCurve::unionDepthValuesFromVectors( depthValues1, depthValues2, threshold );
|
||||
|
||||
ASSERT_EQ( unionDepthValues, expectedUnionDepthValues );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
TEST( RimWellLogCalculatedCurve, calculateValue )
|
||||
{
|
||||
ASSERT_DOUBLE_EQ( 7.0, RimWellLogCalculatedCurve::calculateValue( 5.0, 2.0, RimWellLogCalculatedCurve::Operators::ADD ) );
|
||||
ASSERT_DOUBLE_EQ( 3.0, RimWellLogCalculatedCurve::calculateValue( 5.0, 2.0, RimWellLogCalculatedCurve::Operators::SUBTRACT ) );
|
||||
ASSERT_DOUBLE_EQ( 2.5, RimWellLogCalculatedCurve::calculateValue( 5.0, 2.0, RimWellLogCalculatedCurve::Operators::DIVIDE ) );
|
||||
ASSERT_DOUBLE_EQ( 10.0, RimWellLogCalculatedCurve::calculateValue( 5.0, 2.0, RimWellLogCalculatedCurve::Operators::MULTIPLY ) );
|
||||
|
||||
// Divide by zero
|
||||
ASSERT_DOUBLE_EQ( std::numeric_limits<double>::infinity(),
|
||||
RimWellLogCalculatedCurve::calculateValue( 5.0, 0.0, RimWellLogCalculatedCurve::Operators::DIVIDE ) );
|
||||
}
|
Loading…
Reference in New Issue
Block a user