mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
#2029 Well Log Plot: Handle curves with different depth in 'Show Plot Data'
This commit is contained in:
parent
c150f3a6f9
commit
f8ab0b2197
@ -28,6 +28,7 @@ set(SOURCE_GROUP_HEADER_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaCurveMerger.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaCurveMerger.inl
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaCurveDataTools.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaWellLogCurveMerger.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaTimeHistoryCurveResampler.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaStatisticsTools.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaOffshoreSphericalCoords.h
|
||||
@ -77,6 +78,7 @@ set(SOURCE_GROUP_SOURCE_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaFilePathTools.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaCurveMerger.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaCurveDataTools.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaWellLogCurveMerger.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaTimeHistoryCurveResampler.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaStatisticsTools.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaWeightedGeometricMeanCalculator.cpp
|
||||
|
@ -57,6 +57,9 @@ public:
|
||||
// See ExpressionParserImpl::assignVector()
|
||||
std::vector<double>& interpolatedYValuesForAllXValues( size_t curveIdx );
|
||||
|
||||
static void removeValuesForPartialCurves( std::set<XValueType, XComparator>& unionOfXValues,
|
||||
const std::vector<std::pair<XValueType, XValueType>>& originalXBounds );
|
||||
|
||||
public:
|
||||
// Helper methods, available as public to be able to access from unit tests
|
||||
|
||||
|
@ -194,33 +194,40 @@ void RiaCurveMerger<XValueType>::computeUnionOfXValues( bool includeValuesForPar
|
||||
originalXBounds.push_back( std::make_pair( *( minmax_it.first ), *( minmax_it.second ) ) );
|
||||
}
|
||||
|
||||
if ( !includeValuesForPartialCurves )
|
||||
{
|
||||
for ( auto it = unionOfXValues.begin(); it != unionOfXValues.end(); )
|
||||
{
|
||||
bool outsideBounds = false;
|
||||
for ( const auto& curveXBounds : originalXBounds )
|
||||
{
|
||||
if ( *it < curveXBounds.first || *it > curveXBounds.second )
|
||||
{
|
||||
outsideBounds = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( outsideBounds )
|
||||
{
|
||||
it = unionOfXValues.erase( it );
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( !includeValuesForPartialCurves ) removeValuesForPartialCurves( unionOfXValues, originalXBounds );
|
||||
|
||||
m_allXValues = std::vector<XValueType>( unionOfXValues.begin(), unionOfXValues.end() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename XValueType>
|
||||
void RiaCurveMerger<XValueType>::removeValuesForPartialCurves( std::set<XValueType, XComparator>& unionOfXValues,
|
||||
const std::vector<std::pair<XValueType, XValueType>>& originalXBounds )
|
||||
{
|
||||
for ( auto it = unionOfXValues.begin(); it != unionOfXValues.end(); )
|
||||
{
|
||||
bool outsideBounds = false;
|
||||
for ( const auto& curveXBounds : originalXBounds )
|
||||
{
|
||||
if ( *it < curveXBounds.first || *it > curveXBounds.second )
|
||||
{
|
||||
outsideBounds = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( outsideBounds )
|
||||
{
|
||||
it = unionOfXValues.erase( it );
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
195
ApplicationLibCode/Application/Tools/RiaWellLogCurveMerger.cpp
Normal file
195
ApplicationLibCode/Application/Tools/RiaWellLogCurveMerger.cpp
Normal file
@ -0,0 +1,195 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2021 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 "RiaWellLogCurveMerger.h"
|
||||
|
||||
#include "RiaCurveMerger.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaWellLogCurveMerger::RiaWellLogCurveMerger()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaWellLogCurveMerger::addCurveData( const std::vector<double>& xValues, const std::vector<double>& yValues )
|
||||
{
|
||||
CVF_ASSERT( xValues.size() == yValues.size() );
|
||||
|
||||
if ( !xValues.empty() )
|
||||
{
|
||||
m_originalValues.push_back( std::make_pair( xValues, yValues ) );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
size_t RiaWellLogCurveMerger::curveCount() const
|
||||
{
|
||||
return m_lookupValuesForAllCurves.size();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaCurveDataTools::CurveIntervals RiaWellLogCurveMerger::validIntervalsForAllXValues() const
|
||||
{
|
||||
return m_validIntervalsForAllXValues;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const std::vector<double>& RiaWellLogCurveMerger::allXValues() const
|
||||
{
|
||||
return m_allXValues;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const std::vector<double>& RiaWellLogCurveMerger::lookupYValuesForAllXValues( size_t curveIdx ) const
|
||||
{
|
||||
CVF_ASSERT( curveIdx < m_lookupValuesForAllCurves.size() );
|
||||
|
||||
return m_lookupValuesForAllCurves[curveIdx];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaWellLogCurveMerger::computeLookupValues( bool includeValuesFromPartialCurves )
|
||||
{
|
||||
m_validIntervalsForAllXValues.clear();
|
||||
m_allXValues.clear();
|
||||
m_lookupValuesForAllCurves.clear();
|
||||
|
||||
computeUnionOfXValues( includeValuesFromPartialCurves );
|
||||
|
||||
const size_t curveCount = m_originalValues.size();
|
||||
if ( curveCount == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t dataValueCount = m_allXValues.size();
|
||||
if ( dataValueCount == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_lookupValuesForAllCurves.resize( curveCount );
|
||||
|
||||
std::vector<double> accumulatedValidValues( dataValueCount, 1.0 );
|
||||
|
||||
for ( size_t curveIdx = 0; curveIdx < curveCount; curveIdx++ )
|
||||
{
|
||||
std::vector<double>& curveValues = m_lookupValuesForAllCurves[curveIdx];
|
||||
curveValues.resize( dataValueCount );
|
||||
|
||||
for ( size_t valueIndex = 0; valueIndex < dataValueCount; valueIndex++ )
|
||||
{
|
||||
double interpolValue = lookupYValue( m_allXValues[valueIndex],
|
||||
m_originalValues[curveIdx].first,
|
||||
m_originalValues[curveIdx].second );
|
||||
if ( !RiaCurveDataTools::isValidValue( interpolValue, false ) )
|
||||
{
|
||||
accumulatedValidValues[valueIndex] = HUGE_VAL;
|
||||
}
|
||||
|
||||
curveValues[valueIndex] = interpolValue;
|
||||
}
|
||||
}
|
||||
|
||||
m_validIntervalsForAllXValues = RiaCurveDataTools::calculateIntervalsOfValidValues( accumulatedValidValues, false );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
void RiaWellLogCurveMerger::computeUnionOfXValues( bool includeValuesForPartialCurves )
|
||||
{
|
||||
m_allXValues.clear();
|
||||
|
||||
std::set<double, XValueComparator<double>> unionOfXValues;
|
||||
|
||||
std::vector<std::pair<double, double>> originalXBounds;
|
||||
for ( const auto& curveData : m_originalValues )
|
||||
{
|
||||
if ( curveData.first.empty() ) continue;
|
||||
|
||||
// Well log data has top and bottom depth for each zone
|
||||
// Find the mid point in the zone to
|
||||
const std::vector<double>& xValues = curveData.first;
|
||||
for ( size_t i = 0; i < xValues.size(); i += 2 )
|
||||
{
|
||||
if ( i + 1 < xValues.size() )
|
||||
{
|
||||
double top = xValues.at( i );
|
||||
double bottom = xValues.at( i + 1 );
|
||||
double mid = ( top + bottom ) / 2.0;
|
||||
unionOfXValues.insert( mid );
|
||||
}
|
||||
}
|
||||
auto minmax_it = std::minmax_element( curveData.first.begin(), curveData.first.end() );
|
||||
originalXBounds.push_back( std::make_pair( *( minmax_it.first ), *( minmax_it.second ) ) );
|
||||
}
|
||||
|
||||
if ( !includeValuesForPartialCurves )
|
||||
RiaCurveMerger<double>::removeValuesForPartialCurves( unionOfXValues, originalXBounds );
|
||||
|
||||
m_allXValues = std::vector<double>( unionOfXValues.begin(), unionOfXValues.end() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RiaWellLogCurveMerger::lookupYValue( const double& interpolationXValue,
|
||||
const std::vector<double>& xValues,
|
||||
const std::vector<double>& yValues )
|
||||
{
|
||||
if ( yValues.size() != xValues.size() ) return HUGE_VAL;
|
||||
|
||||
const bool removeInterpolatedValues = false;
|
||||
|
||||
if ( interpolationXValue < xValues[0] ) return HUGE_VAL;
|
||||
|
||||
for ( size_t firstI = 0; firstI < xValues.size(); firstI++ )
|
||||
{
|
||||
if ( xValues.at( firstI ) >= interpolationXValue )
|
||||
{
|
||||
double firstValue = yValues.at( firstI );
|
||||
if ( !RiaCurveDataTools::isValidValue( firstValue, removeInterpolatedValues ) )
|
||||
{
|
||||
return HUGE_VAL;
|
||||
}
|
||||
|
||||
return firstValue;
|
||||
}
|
||||
}
|
||||
|
||||
return HUGE_VAL;
|
||||
}
|
55
ApplicationLibCode/Application/Tools/RiaWellLogCurveMerger.h
Normal file
55
ApplicationLibCode/Application/Tools/RiaWellLogCurveMerger.h
Normal file
@ -0,0 +1,55 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2021 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 "RiaCurveDataTools.h"
|
||||
|
||||
#include <ctime>
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
class RiaWellLogCurveMerger
|
||||
{
|
||||
public:
|
||||
RiaWellLogCurveMerger();
|
||||
|
||||
void addCurveData( const std::vector<double>& xValues, const std::vector<double>& yValues );
|
||||
size_t curveCount() const;
|
||||
|
||||
void computeLookupValues( bool includeValuesFromPartialCurves = true );
|
||||
|
||||
RiaCurveDataTools::CurveIntervals validIntervalsForAllXValues() const;
|
||||
const std::vector<double>& allXValues() const;
|
||||
const std::vector<double>& lookupYValuesForAllXValues( size_t curveIdx ) const;
|
||||
|
||||
private:
|
||||
void computeUnionOfXValues( bool includeValuesFromPartialCurves );
|
||||
|
||||
static double lookupYValue( const double& xValue,
|
||||
const std::vector<double>& curveXValues,
|
||||
const std::vector<double>& curveYValues );
|
||||
|
||||
std::vector<std::pair<std::vector<double>, std::vector<double>>> m_originalValues;
|
||||
|
||||
RiaCurveDataTools::CurveIntervals m_validIntervalsForAllXValues;
|
||||
|
||||
std::vector<double> m_allXValues;
|
||||
std::vector<std::vector<double>> m_lookupValuesForAllCurves;
|
||||
};
|
@ -25,6 +25,7 @@
|
||||
#include "RiaLogging.h"
|
||||
#include "RiaPreferences.h"
|
||||
#include "RiaSimWellBranchTools.h"
|
||||
#include "RiaWellLogCurveMerger.h"
|
||||
|
||||
#include "RigEclipseCaseData.h"
|
||||
#include "RigEclipseResultAddress.h"
|
||||
@ -844,6 +845,9 @@ QString RimWellLogTrack::asciiDataForPlotExport() const
|
||||
}
|
||||
}
|
||||
|
||||
RiaWellLogCurveMerger curveMerger;
|
||||
bool foundNonMatchingDepths = false;
|
||||
|
||||
for ( RimWellLogCurve* curve : m_curves() )
|
||||
{
|
||||
if ( !curve->isCurveVisible() ) continue;
|
||||
@ -858,7 +862,7 @@ QString RimWellLogTrack::asciiDataForPlotExport() const
|
||||
}
|
||||
|
||||
std::vector<double> xPlotValues = curveData->xPlotValues();
|
||||
if ( curveDepths.size() != xPlotValues.size() || xPlotValues.empty() )
|
||||
if ( xPlotValues.empty() )
|
||||
{
|
||||
curveNames.pop_back();
|
||||
|
||||
@ -868,6 +872,15 @@ QString RimWellLogTrack::asciiDataForPlotExport() const
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( curveDepths.size() != xPlotValues.size() )
|
||||
{
|
||||
foundNonMatchingDepths = true;
|
||||
}
|
||||
|
||||
std::vector<double> depths = curveData->depthPlotValues( depthType, depthUnit );
|
||||
curveMerger.addCurveData( depths, xPlotValues );
|
||||
|
||||
curvesPlotXValues.push_back( xPlotValues );
|
||||
}
|
||||
|
||||
@ -900,6 +913,26 @@ QString RimWellLogTrack::asciiDataForPlotExport() const
|
||||
}
|
||||
out += "\n";
|
||||
|
||||
// Resample when curves have different depth
|
||||
if ( foundNonMatchingDepths )
|
||||
{
|
||||
curvesPlotXValues.clear();
|
||||
curveDepths.clear();
|
||||
|
||||
curveMerger.computeLookupValues();
|
||||
|
||||
const std::vector<double>& allDepths = curveMerger.allXValues();
|
||||
curveDepths = allDepths;
|
||||
for ( size_t depthIdx = 0; depthIdx < allDepths.size(); depthIdx++ )
|
||||
{
|
||||
for ( size_t curveIdx = 0; curveIdx < curveMerger.curveCount(); ++curveIdx )
|
||||
{
|
||||
const std::vector<double>& curveValues = curveMerger.lookupYValuesForAllXValues( curveIdx );
|
||||
curvesPlotXValues.push_back( curveValues );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for ( size_t dIdx = 0; dIdx < curveDepths.size(); ++dIdx )
|
||||
{
|
||||
size_t i = dIdx;
|
||||
|
Loading…
Reference in New Issue
Block a user