Support different units when importing and exporting WBS LAS.

This commit is contained in:
Gaute Lindkvist 2020-01-29 12:52:07 +01:00
parent 3c05ae04e6
commit c9f5b47a90
40 changed files with 976 additions and 444 deletions

View File

@ -40,6 +40,8 @@ ${CMAKE_CURRENT_LIST_DIR}/RiaGitDiff.h
${CMAKE_CURRENT_LIST_DIR}/RiaCellDividingTools.h
${CMAKE_CURRENT_LIST_DIR}/RiaFieldHandleTools.h
${CMAKE_CURRENT_LIST_DIR}/RiaBoundingBoxTools.h
${CMAKE_CURRENT_LIST_DIR}/RiaWellLogUnitTools.h
)
set (SOURCE_GROUP_SOURCE_FILES
@ -79,6 +81,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RiaGitDiff.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaCellDividingTools.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaFieldHandleTools.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaBoundingBoxTools.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaWellLogUnitTools.cpp
)
list(APPEND CODE_HEADER_FILES

View File

@ -0,0 +1,331 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2020- Equinor AS
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RiaWellLogUnitTools.h"
#include "RiaEclipseUnitTools.h"
#include "RigWellPath.h"
#include "cafAssert.h"
#include <limits>
const double RiaWellLogUnitTools::GRAVITY_ACCEL = 9.81;
const double RiaWellLogUnitTools::UNIT_WEIGHT_OF_WATER = RiaWellLogUnitTools::GRAVITY_ACCEL * 1000.0; // N / m^3
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RiaWellLogUnitTools::noUnitString()
{
return "NO_UNIT";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RiaWellLogUnitTools::barUnitString()
{
return "Bar";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RiaWellLogUnitTools::barX100UnitString()
{
return "Bar x100";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RiaWellLogUnitTools::MPaUnitString()
{
return "MPa";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RiaWellLogUnitTools::gPerCm3UnitString()
{
return "g/cm3";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RiaWellLogUnitTools::convertDepths( const std::vector<double>& depthsIn,
RiaDefines::DepthUnitType unitsIn,
RiaDefines::DepthUnitType unitsOut )
{
if ( unitsOut == RiaDefines::UNIT_METER && unitsIn == RiaDefines::UNIT_FEET )
{
return multiply( depthsIn, RiaEclipseUnitTools::feetPerMeter() );
}
else if ( unitsOut == RiaDefines::UNIT_FEET && unitsIn == RiaDefines::UNIT_METER )
{
return multiply( depthsIn, RiaEclipseUnitTools::meterPerFeet() );
}
return depthsIn;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RiaWellLogUnitTools::convertValues( const std::vector<double>& tvdRKBs,
const std::vector<double>& valuesIn,
std::vector<double>* valuesOut,
const QString& unitsIn,
const QString& unitsOut )
{
CAF_ASSERT( valuesOut );
if ( unitsIn == unitsOut )
{
*valuesOut = valuesIn;
return true;
}
if ( unitsIn == gPerCm3UnitString() && unitsOut == barUnitString() )
{
*valuesOut = convertGpcm3ToBar( tvdRKBs, valuesIn );
return true;
}
else if ( unitsIn == barUnitString() && unitsOut == gPerCm3UnitString() )
{
*valuesOut = convertBarToGpcm3( tvdRKBs, valuesIn );
return true;
}
else if ( unitsIn == RiaWellLogUnitTools::noUnitString() && unitsOut == gPerCm3UnitString() )
{
*valuesOut = convertNormalizedByPPToBar( tvdRKBs, valuesIn );
*valuesOut = convertBarToGpcm3( tvdRKBs, *valuesOut );
}
else if ( unitsIn == gPerCm3UnitString() && unitsOut == RiaWellLogUnitTools::noUnitString() )
{
*valuesOut = convertGpcm3ToBar( tvdRKBs, valuesIn );
*valuesOut = convertBarToNormalizedByPP( tvdRKBs, *valuesOut );
}
else if ( unitsIn == MPaUnitString() && unitsOut == barUnitString() )
{
*valuesOut = multiply( valuesIn, 1.0 / MPaPerBar() );
return true;
}
else if ( unitsIn == barX100UnitString() && unitsOut == MPaUnitString() )
{
*valuesOut = multiply( valuesIn, 100.0 );
*valuesOut = multiply( *valuesOut, MPaPerBar() );
return true;
}
else if ( unitsIn == barX100UnitString() && unitsOut == barUnitString() )
{
*valuesOut = multiply( valuesIn, 100 );
return true;
}
else if ( unitsIn == barUnitString() && unitsOut == MPaUnitString() )
{
*valuesOut = multiply( valuesIn, MPaPerBar() );
return true;
}
else if ( unitsIn == barUnitString() && unitsOut == barX100UnitString() )
{
*valuesOut = multiply( valuesIn, 1.0 / 100.0 );
return true;
}
else if ( unitsIn == RiaWellLogUnitTools::noUnitString() && unitsOut == barUnitString() )
{
*valuesOut = convertNormalizedByPPToBar( tvdRKBs, valuesIn );
return true;
}
else if ( unitsIn == barUnitString() && unitsOut == RiaWellLogUnitTools::noUnitString() )
{
*valuesOut = convertBarToNormalizedByPP( tvdRKBs, valuesIn );
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RiaWellLogUnitTools::convertValues( std::vector<std::pair<double, double>>* measuredDepthsAndValues,
const QString& unitsIn,
const QString& unitsOut,
const RigWellPath* wellPath )
{
CAF_ASSERT( measuredDepthsAndValues );
if ( unitsIn == unitsOut ) return true;
std::vector<double> tvdRKBs( measuredDepthsAndValues->size(), 0.0 );
std::vector<double> values( measuredDepthsAndValues->size(), 0.0 );
for ( size_t i = 0; i < measuredDepthsAndValues->size(); ++i )
{
auto depthValuePair = ( *measuredDepthsAndValues )[i];
cvf::Vec3d point = wellPath->interpolatedPointAlongWellPath( depthValuePair.first );
tvdRKBs[i] = -point.z() + wellPath->rkbDiff();
values[i] = depthValuePair.second;
}
std::vector<double> valuesOut;
if ( convertValues( tvdRKBs, values, &valuesOut, unitsIn, unitsOut ) )
{
CAF_ASSERT( measuredDepthsAndValues->size() == valuesOut.size() );
for ( size_t i = 0; i < measuredDepthsAndValues->size(); ++i )
{
( *measuredDepthsAndValues )[i].second = valuesOut[i];
}
return true;
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RiaWellLogUnitTools::tvdRKBs( const std::vector<double>& measuredDepths, const RigWellPath* wellPath )
{
std::vector<double> tvdRKBs( measuredDepths.size(), 0.0 );
for ( size_t i = 0; i < measuredDepths.size(); ++i )
{
cvf::Vec3d point = wellPath->interpolatedPointAlongWellPath( measuredDepths[i] );
tvdRKBs[i] = -point.z() + wellPath->rkbDiff();
}
return tvdRKBs;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RiaWellLogUnitTools::convertGpcm3ToBar( const std::vector<double>& tvdRKBs,
const std::vector<double>& valuesInGpcm3 )
{
CAF_ASSERT( tvdRKBs.size() == valuesInGpcm3.size() );
std::vector<double> valuesInBar( valuesInGpcm3.size(), 0.0 );
for ( size_t i = 0; i < tvdRKBs.size(); ++i )
{
// We need SI as input (kg / m^3), so multiply by 1000:
double mudWeightsSI = valuesInGpcm3[i] * 1000;
// To get specific mudWeight (N / m^3):
double specificMudWeight = mudWeightsSI * GRAVITY_ACCEL;
// Pore pressure in pascal
double valuePascal = specificMudWeight * tvdRKBs[i];
// Pore pressure in bar
valuesInBar[i] = 1.0 / pascalPerBar() * valuePascal;
}
return valuesInBar;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RiaWellLogUnitTools::convertBarToGpcm3( const std::vector<double>& tvdRKBs,
const std::vector<double>& valuesInBar )
{
CAF_ASSERT( tvdRKBs.size() == valuesInBar.size() );
std::vector<double> valuesInGpcm3( valuesInBar.size(), 0.0 );
for ( size_t i = 0; i < tvdRKBs.size(); ++i )
{
// Pore pressure in pascal (N / m^2)
double valuePascal = pascalPerBar() * valuesInBar[i];
// N / m^3:
double specificMudWeight = valuePascal / tvdRKBs[i];
// Mud weight in SI (kg / m^3):
double mudWeightsSI = specificMudWeight / GRAVITY_ACCEL;
// Mud weights g/cm^3:
valuesInGpcm3[i] = mudWeightsSI / 1000;
}
return valuesInGpcm3;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RiaWellLogUnitTools::convertNormalizedByPPToBar( const std::vector<double>& tvdRKBs,
const std::vector<double>& normalizedValues )
{
CAF_ASSERT( tvdRKBs.size() == normalizedValues.size() );
std::vector<double> valuesInBar( tvdRKBs.size(), 0.0 );
for ( size_t i = 0; i < tvdRKBs.size(); ++i )
{
valuesInBar[i] = normalizedValues[i] * hydrostaticPorePressureBar( tvdRKBs[i] );
}
return valuesInBar;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RiaWellLogUnitTools::convertBarToNormalizedByPP( const std::vector<double>& tvdRKBs,
const std::vector<double>& valuesInBar )
{
CAF_ASSERT( tvdRKBs.size() == valuesInBar.size() );
std::vector<double> normalizedValues( tvdRKBs.size(), 0.0 );
for ( size_t i = 0; i < tvdRKBs.size(); ++i )
{
normalizedValues[i] = valuesInBar[i] / hydrostaticPorePressureBar( tvdRKBs[i] );
}
return normalizedValues;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RiaWellLogUnitTools::multiply( const std::vector<double>& valuesIn, double factor )
{
std::vector<double> valuesOut( valuesIn.size(), std::numeric_limits<double>::infinity() );
for ( size_t i = 0; i < 100; ++i )
{
valuesOut[i] = valuesIn[i] * factor;
}
return valuesOut;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RiaWellLogUnitTools::pascalPerBar()
{
return 1.0e5;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RiaWellLogUnitTools::MPaPerBar()
{
return 1.0e-1;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RiaWellLogUnitTools::hydrostaticPorePressureBar( double depth )
{
return 1.0 / pascalPerBar() * depth * UNIT_WEIGHT_OF_WATER;
}

View File

@ -0,0 +1,70 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2020- Equinor AS
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RiaDefines.h"
#include <QString>
#include <vector>
class RigWellPath;
class RiaWellLogUnitTools
{
public:
static const double GRAVITY_ACCEL;
static const double UNIT_WEIGHT_OF_WATER;
static QString noUnitString();
static QString barUnitString();
static QString barX100UnitString();
static QString MPaUnitString();
static QString gPerCm3UnitString();
public:
static std::vector<double> convertDepths( const std::vector<double>& depthsIn,
RiaDefines::DepthUnitType unitsIn,
RiaDefines::DepthUnitType unitsOut );
static bool convertValues( const std::vector<double>& tvdRKBs,
const std::vector<double>& valuesIn,
std::vector<double>* valuesOut,
const QString& unitsIn,
const QString& unitsOut );
static bool convertValues( std::vector<std::pair<double, double>>* measuredDepthsAndValues,
const QString& unitsIn,
const QString& unitsOut,
const RigWellPath* wellPath );
static std::vector<double> tvdRKBs( const std::vector<double>& measuredDepths, const RigWellPath* wellPath );
// Supported conversions
static std::vector<double> convertGpcm3ToBar( const std::vector<double>& tvdRKBs,
const std::vector<double>& valuesInGpcm3 );
static std::vector<double> convertBarToGpcm3( const std::vector<double>& tvdRKBs,
const std::vector<double>& valuesInBar );
static std::vector<double> convertNormalizedByPPToBar( const std::vector<double>& tvdRKBs,
const std::vector<double>& valuesInBar );
static std::vector<double> convertBarToNormalizedByPP( const std::vector<double>& tvdRKBs,
const std::vector<double>& valuesInBar );
static std::vector<double> multiply( const std::vector<double>& values, double factor );
static double pascalPerBar();
static double MPaPerBar();
static double hydrostaticPorePressureBar( double tvdRKB );
};

View File

@ -66,6 +66,7 @@ RicfExportWellLogPlotData::RicfExportWellLogPlotData()
RICF_InitField( &m_exportTvdRkb, "exportTvdRkb", false, "", "", "", "" );
RICF_InitField( &m_capitalizeFileNames, "capitalizeFileNames", false, "", "", "", "" );
RICF_InitField( &m_resampleInterval, "resampleInterval", 0.0, "", "", "", "" );
RICF_InitField( &m_convertCurveUnits, "convertCurveUnits", false, "", "", "", "" );
}
//--------------------------------------------------------------------------------------------------
@ -108,7 +109,8 @@ RicfCommandResponse RicfExportWellLogPlotData::execute()
m_exportTvdRkb(),
m_capitalizeFileNames(),
true,
m_resampleInterval() );
m_resampleInterval(),
m_convertCurveUnits() );
if ( exportedFiles.empty() )
{
errorMessages << QString( "No files exported for '%1'" ).arg( plot->description() );

View File

@ -69,4 +69,5 @@ private:
caf::PdmField<bool> m_exportTvdRkb;
caf::PdmField<bool> m_capitalizeFileNames;
caf::PdmField<double> m_resampleInterval;
caf::PdmField<bool> m_convertCurveUnits;
};

View File

@ -49,7 +49,8 @@ std::vector<QString> RicExportToLasFileFeature::exportToLasFiles( const QString&
bool exportTvdRkb,
bool capitalizeFileNames,
bool alwaysOverwrite,
double resampleInterval )
double resampleInterval,
bool convertCurveUnits )
{
std::vector<RimWellLogCurve*> allCurves;
std::vector<RimPlot*> plots = plotWindow->visiblePlots();
@ -77,7 +78,8 @@ std::vector<QString> RicExportToLasFileFeature::exportToLasFiles( const QString&
rkbDiffs,
capitalizeFileNames,
alwaysOverwrite,
resampleInterval );
resampleInterval,
convertCurveUnits );
}
}
@ -91,7 +93,8 @@ std::vector<QString> RicExportToLasFileFeature::exportToLasFiles( const QString&
const std::vector<double>& rkbDiffs,
bool capitalizeFileNames,
bool alwaysOverwrite,
double resampleInterval )
double resampleInterval,
bool convertCurveUnits )
{
RigLasFileExporter lasExporter( curves );
@ -107,7 +110,8 @@ std::vector<QString> RicExportToLasFileFeature::exportToLasFiles( const QString&
lasExporter.setRkbDiffs( wellNames, rkbDiffs );
}
writtenFiles = lasExporter.writeToFolder( exportFolder, filePrefix, capitalizeFileNames, alwaysOverwrite );
writtenFiles =
lasExporter.writeToFolder( exportFolder, filePrefix, capitalizeFileNames, alwaysOverwrite, convertCurveUnits );
// Remember the path to next time
RiaApplication::instance()->setLastUsedDialogDirectory( "WELL_LOGS_DIR", exportFolder );
@ -148,6 +152,7 @@ void RicExportToLasFileFeature::onActionTriggered( bool isChecked )
{
featureUi.filePrefix = "WBS_";
featureUi.capitalizeFileName = true;
featureUi.setUnitConversionOptionEnabled( true );
}
{
@ -163,7 +168,7 @@ void RicExportToLasFileFeature::onActionTriggered( bool isChecked )
"",
QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
RicExportFeatureImpl::configureForExport( propertyDialog.dialogButtonBox() );
propertyDialog.resize( QSize( 400, 330 ) );
propertyDialog.resize( QSize( 400, 360 ) );
if ( propertyDialog.exec() == QDialog::Accepted && !featureUi.exportFolder().isEmpty() )
{
@ -190,7 +195,9 @@ void RicExportToLasFileFeature::onActionTriggered( bool isChecked )
rkbDiffs,
featureUi.capitalizeFileName,
false,
resampleInterval );
resampleInterval,
featureUi.curveUnitConversion() ==
RicExportToLasFileResampleUi::CurveUnitConversion::EXPORT_WITH_STANDARD_UNITS );
}
}

View File

@ -42,7 +42,8 @@ public:
bool exportTvdRkb,
bool capitalizeFileNames,
bool alwaysOverwrite,
double resampleInterval );
double resampleInterval,
bool convertCurveUnits );
static std::vector<QString> exportToLasFiles( const QString& exportFolder,
const QString& filePrefix,
@ -51,7 +52,8 @@ public:
const std::vector<double>& rkbDiffs,
bool capitalizeFileNames,
bool alwaysOverwrite,
double resampleInterval );
double resampleInterval,
bool convertCurveUnits );
protected:
// Overrides

View File

@ -24,6 +24,20 @@
#include <cmath>
namespace caf
{
template <>
void RicExportToLasFileResampleUi::CurveUnitConversionEnum::setUp()
{
addItem( RicExportToLasFileResampleUi::CurveUnitConversion::EXPORT_NORMALIZED, "NORMALIZED", "Current Plot Units" );
addItem( RicExportToLasFileResampleUi::CurveUnitConversion::EXPORT_WITH_STANDARD_UNITS,
"STANDARD_UNITS",
"Convert to Standard Import Units" );
setDefault( RicExportToLasFileResampleUi::CurveUnitConversion::EXPORT_WITH_STANDARD_UNITS );
}
} // End namespace caf
CAF_PDM_SOURCE_INIT( RicExportToLasFileObj, "RicExportToLasFileObj" );
//--------------------------------------------------------------------------------------------------
@ -42,6 +56,7 @@ CAF_PDM_SOURCE_INIT( RicExportToLasFileResampleUi, "RicExportToLasFileResampleUi
///
//--------------------------------------------------------------------------------------------------
RicExportToLasFileResampleUi::RicExportToLasFileResampleUi( void )
: m_enableCurveUnitConversion( false )
{
CAF_PDM_InitObject( "Resample LAS curves for export", "", "", "" );
@ -49,6 +64,7 @@ RicExportToLasFileResampleUi::RicExportToLasFileResampleUi( void )
exportFolder.uiCapability()->setUiEditorTypeName( caf::PdmUiFilePathEditor::uiEditorTypeName() );
CAF_PDM_InitField( &filePrefix, "FilePrefix", QString( "" ), "File Prefix", "", "", "" );
CAF_PDM_InitField( &capitalizeFileName, "CapitalizeFileName", false, "Capitalize File Name", "", "", "" );
CAF_PDM_InitFieldNoDefault( &curveUnitConversion, "CurveUnitConversion", "Curve Units", "", "", "" );
CAF_PDM_InitField( &activateResample, "ActivateResample", false, "Resample Curve Data", "", "", "" );
activateResample.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN );
@ -108,6 +124,14 @@ void RicExportToLasFileResampleUi::setRkbDiffs( const std::vector<QString>& well
updateFieldVisibility();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicExportToLasFileResampleUi::setUnitConversionOptionEnabled( bool enabled )
{
m_enableCurveUnitConversion = enabled;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -172,6 +196,12 @@ void RicExportToLasFileResampleUi::defineUiOrdering( QString uiConfigName, caf::
uiOrdering.add( &exportFolder );
uiOrdering.add( &filePrefix );
uiOrdering.add( &capitalizeFileName );
if ( m_enableCurveUnitConversion )
{
uiOrdering.add( &curveUnitConversion );
}
{
caf::PdmUiGroup* group = uiOrdering.addNewGroup( "Resampling" );
@ -188,4 +218,6 @@ void RicExportToLasFileResampleUi::defineUiOrdering( QString uiConfigName, caf::
{
group->add( &obj->tvdrkbOffset );
}
uiOrdering.skipRemainingFields( true );
}

View File

@ -18,6 +18,7 @@
#pragma once
#include "cafAppEnum.h"
#include "cafPdmChildArrayField.h"
#include "cafPdmField.h"
#include "cafPdmObject.h"
@ -42,6 +43,14 @@ class RicExportToLasFileResampleUi : public caf::PdmObject
{
CAF_PDM_HEADER_INIT;
public:
enum class CurveUnitConversion
{
EXPORT_NORMALIZED,
EXPORT_WITH_STANDARD_UNITS
};
using CurveUnitConversionEnum = caf::AppEnum<CurveUnitConversion>;
public:
RicExportToLasFileResampleUi( void );
~RicExportToLasFileResampleUi() override;
@ -53,10 +62,12 @@ public:
caf::PdmField<bool> activateResample;
caf::PdmField<double> resampleInterval;
caf::PdmField<bool> exportTvdrkb;
caf::PdmField<bool> exportTvdrkb;
caf::PdmField<CurveUnitConversionEnum> curveUnitConversion;
void tvdrkbDiffForWellPaths( std::vector<double>* rkbDiffs );
void setRkbDiffs( const std::vector<QString>& wellNames, const std::vector<double>& rkbDiffs );
void setUnitConversionOptionEnabled( bool enabled );
void fieldChangedByUi( const caf::PdmFieldHandle* changedField,
const QVariant& oldValue,
@ -73,4 +84,6 @@ private:
private:
caf::PdmChildArrayField<RicExportToLasFileObj*> m_tvdrkbOffsets;
bool m_enableCurveUnitConversion;
};

View File

@ -24,6 +24,7 @@
#include "RimWellAllocationPlot.h"
#include "RimWellBoreStabilityPlot.h"
#include "RimWellLogCurve.h"
#include "RimWellLogTrack.h"
#include "RimWellRftPlot.h"
#include "cafSelectionManager.h"
@ -57,27 +58,26 @@ std::vector<RimWellLogCurve*> RicWellLogPlotCurveFeatureImpl::selectedWellLogCur
caf::PdmObjectHandle* objHandle = dynamic_cast<caf::PdmObjectHandle*>( selectedItem );
if ( objHandle )
{
std::vector<RimWellLogCurve*> childCurves;
objHandle->descendantsIncludingThisOfType( childCurves );
for ( RimWellLogCurve* curve : childCurves )
std::vector<RimWellLogTrack*> childTracks;
objHandle->descendantsIncludingThisOfType( childTracks );
for ( auto track : childTracks )
{
if ( !uniqueCurves.count( curve ) )
if ( track->showWindow() )
{
uniqueCurves.insert( curve );
allCurves.push_back( curve );
for ( RimWellLogCurve* curve : track->visibleCurves() )
{
if ( !uniqueCurves.count( curve ) )
{
uniqueCurves.insert( curve );
allCurves.push_back( curve );
}
}
}
}
}
}
}
// Sort by curve name in a way that retains the original order of equivalent items
// This way we have a completely deterministic order
std::stable_sort( allCurves.begin(), allCurves.end(), []( const RimWellLogCurve* lhs, const RimWellLogCurve* rhs ) {
return lhs->curveName() < rhs->curveName();
} );
return allCurves;
}

View File

@ -321,6 +321,7 @@ message ExportWellLogPlotDataRequest
bool exportTvdRkb = 5;
bool capitalizeFileNames = 6;
double resampleInterval = 7;
bool convertCurveUnits = 8;
}
message ExportContourMapToTextRequest

View File

@ -21,7 +21,7 @@ class WellLogPlot(Plot):
return cls(pdm_object)
return None
def export_data_as_las(self, export_folder, file_prefix='', export_tvdrkb=False, capitalize_file_names=False, resample_interval=0.0):
def export_data_as_las(self, export_folder, file_prefix='', export_tvdrkb=False, capitalize_file_names=False, resample_interval=0.0, convert_to_standard_units=False):
""" Export LAS file(s) for the current plot
Arguments:
@ -40,7 +40,8 @@ class WellLogPlot(Plot):
filePrefix=file_prefix,
exportTvdRkb=export_tvdrkb,
capitalizeFileNames=capitalize_file_names,
resampleInterval=resample_interval))
resampleInterval=resample_interval,
convertCurveUnits=convert_to_standard_units)
return res.exportWellLogPlotDataResult.exportedFiles
def export_data_as_ascii(self, export_folder, file_prefix='', capitalize_file_names=False):

View File

@ -112,6 +112,14 @@ QString RimWellFlowRateCurve::wellLogChannelUiName() const
return "AccumulatedFlowRate";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimWellFlowRateCurve::wellLogChannelUnits() const
{
return RiaWellLogUnitTools::noUnitString();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -48,6 +48,7 @@ public:
int timeStep();
QString wellName() const override;
QString wellLogChannelUiName() const override;
QString wellLogChannelUnits() const override;
void setGroupId( int groupId );
int groupId() const;

View File

@ -650,13 +650,51 @@ QString RimGeoMechResultDefinition::resultVariableName() const
RigWbsParameter param;
if ( RigWbsParameter::findParameter( resultFieldName(), &param ) )
{
QString lasName = param.sourceLabel( RigWbsParameter::LAS_FILE );
QString lasName = param.addressString( RigWbsParameter::LAS_FILE );
if ( !lasName.isEmpty() ) return lasName;
}
}
return resultVariableUiName();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimGeoMechResultDefinition::currentResultUnits() const
{
if ( this->resultFieldName() == "SE" || this->resultFieldName() == "ST" || this->resultFieldName() == "POR-Bar" ||
this->resultFieldName() == "SM" || this->resultFieldName() == "SEM" || this->resultFieldName() == "Q" )
{
return "Bar";
}
else if ( this->resultFieldName() == "MODULUS" )
{
return "GPa";
}
return RiaWellLogUnitTools::noUnitString();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimGeoMechResultDefinition::defaultLasUnits() const
{
QString units;
if ( m_resultPositionType == RIG_WELLPATH_DERIVED )
{
RigWbsParameter param;
if ( RigWbsParameter::findParameter( resultFieldName(), &param ) )
{
units = param.units( RigWbsParameter::LAS_FILE );
}
}
if ( units.isEmpty() )
{
units = currentResultUnits();
}
return units;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -742,15 +780,10 @@ void RimGeoMechResultDefinition::updateLegendTextAndRanges( RimRegularLegendConf
legendTitle += ", " + this->resultComponentUiName();
}
if ( this->resultFieldName() == "SE" || this->resultFieldName() == "ST" || this->resultFieldName() == "POR-Bar" ||
this->resultFieldName() == "SM" || this->resultFieldName() == "SEM" || this->resultFieldName() == "Q" )
QString unitString = currentResultUnits();
if ( unitString != RiaWellLogUnitTools::noUnitString() )
{
legendTitle += " [Bar]";
}
if ( this->resultFieldName() == "MODULUS" )
{
legendTitle += " [GPa]";
legendTitle += QString( " [%1]" ).arg( unitString );
}
if ( !this->diffResultUiShortName().isEmpty() )

View File

@ -68,6 +68,8 @@ public:
QString resultComponentUiName() const;
QString resultVariableUiName() const;
QString resultVariableName() const;
QString currentResultUnits() const;
QString defaultLasUnits() const;
bool hasCategoryResult() const
{

View File

@ -387,7 +387,7 @@ bool RimWbsParameters::hasLasFileWithChannel( const QString& channel ) const
bool RimWbsParameters::hasElementPropertyEntry( const RigFemResultAddress& resAddr ) const
{
RigFemPartResultsCollection* femPartResults = nullptr;
if ( m_geoMechCase && m_timeStep > 0 )
if ( m_geoMechCase && m_geoMechCase->geoMechData() && m_timeStep > 0 )
{
femPartResults = m_geoMechCase->geoMechData()->femPartResults();
if ( femPartResults )

View File

@ -131,6 +131,7 @@ void RimWellBoreStabilityPlot::childFieldChangedByUi( const caf::PdmFieldHandle*
//--------------------------------------------------------------------------------------------------
void RimWellBoreStabilityPlot::initAfterRead()
{
updateCommonDataSource();
applyDataSource();
}

View File

@ -113,9 +113,11 @@ void RimWellLogCurve::setValuesAndDepths( const std::vector<double>& xValues,
RiaDefines::DepthTypeEnum depthType,
double rkbDiff,
RiaDefines::DepthUnitType depthUnit,
bool isExtractionCurve )
bool isExtractionCurve,
const QString& xUnits )
{
m_curveData->setValuesAndDepths( xValues, depths, depthType, rkbDiff, depthUnit, isExtractionCurve );
m_curveData->setXUnits( xUnits );
calculateCurveDataXRange();
}
@ -126,9 +128,11 @@ void RimWellLogCurve::setValuesAndDepths( const std::vector<double>&
const std::map<RiaDefines::DepthTypeEnum, std::vector<double>>& depths,
double rkbDiff,
RiaDefines::DepthUnitType depthUnit,
bool isExtractionCurve )
bool isExtractionCurve,
const QString& xUnits )
{
m_curveData->setValuesAndDepths( xValues, depths, rkbDiff, depthUnit, isExtractionCurve );
m_curveData->setXUnits( xUnits );
calculateCurveDataXRange();
}
@ -140,11 +144,12 @@ void RimWellLogCurve::setValuesWithMdAndTVD( const std::vector<double>& xValues,
const std::vector<double>& tvdMSL,
double rkbDiff,
RiaDefines::DepthUnitType depthUnit,
bool isExtractionCurve )
bool isExtractionCurve,
const QString& xUnits )
{
std::map<RiaDefines::DepthTypeEnum, std::vector<double>> depths = {{RiaDefines::MEASURED_DEPTH, measuredDepths},
{RiaDefines::TRUE_VERTICAL_DEPTH, tvdMSL}};
setValuesAndDepths( xValues, depths, rkbDiff, depthUnit, isExtractionCurve );
setValuesAndDepths( xValues, depths, rkbDiff, depthUnit, isExtractionCurve, xUnits );
}
//--------------------------------------------------------------------------------------------------

View File

@ -20,6 +20,7 @@
#pragma once
#include "RiaDefines.h"
#include "RiaWellLogUnitTools.h"
#include "RimPlotCurve.h"
#include "cvfObject.h"
@ -47,24 +48,28 @@ public:
RiaDefines::DepthTypeEnum depthType,
double rkbDiff,
RiaDefines::DepthUnitType depthUnit,
bool isExtractionCurve );
bool isExtractionCurve,
const QString& xUnits = RiaWellLogUnitTools::noUnitString() );
void setValuesWithMdAndTVD( const std::vector<double>& xValues,
const std::vector<double>& measuredDepths,
const std::vector<double>& tvDepths,
double rkbDiff,
RiaDefines::DepthUnitType depthUnit,
bool isExtractionCurve );
bool isExtractionCurve,
const QString& xUnits = RiaWellLogUnitTools::noUnitString() );
void setValuesAndDepths( const std::vector<double>& xValues,
const std::map<RiaDefines::DepthTypeEnum, std::vector<double>>& depths,
double rkbDiff,
RiaDefines::DepthUnitType depthUnit,
bool isExtractionCurve );
bool isExtractionCurve,
const QString& xUnits = RiaWellLogUnitTools::noUnitString() );
const RigWellLogCurveData* curveData() const;
virtual QString wellName() const = 0;
virtual QString wellLogChannelUiName() const = 0;
virtual QString wellLogChannelName() const;
virtual QString wellLogChannelUnits() const = 0;
virtual QString wellDate() const
{
return "";

View File

@ -20,8 +20,10 @@
#include "RimWellLogExtractionCurve.h"
#include "RiaApplication.h"
#include "RiaLogging.h"
#include "RiaSimWellBranchTools.h"
#include "RiaWellLogUnitTools.h"
#include "RigCaseCellResultsData.h"
#include "RigEclipseCaseData.h"
#include "RigEclipseWellLogExtractor.h"
@ -450,6 +452,7 @@ void RimWellLogExtractionCurve::extractData( bool* isUsingPseudoLength,
double rkbDiff = 0.0;
RiaDefines::DepthUnitType depthUnit = RiaDefines::UNIT_METER;
QString xUnits = RiaWellLogUnitTools::noUnitString();
if ( eclExtractor.notNull() && eclipseCase )
{
@ -498,7 +501,7 @@ void RimWellLogExtractionCurve::extractData( bool* isUsingPseudoLength,
}
m_geomResultDefinition->loadResult();
geomExtractor->curveData( m_geomResultDefinition->resultAddress(), m_timeStep, &values );
xUnits = geomExtractor->curveData( m_geomResultDefinition->resultAddress(), m_timeStep, &values );
if ( performDataSmoothing )
{
geomExtractor->performCurveDataSmoothing( m_timeStep,
@ -518,7 +521,8 @@ void RimWellLogExtractionCurve::extractData( bool* isUsingPseudoLength,
RiaDefines::MEASURED_DEPTH,
0.0,
depthUnit,
!performDataSmoothing );
!performDataSmoothing,
xUnits );
}
else
{
@ -527,7 +531,8 @@ void RimWellLogExtractionCurve::extractData( bool* isUsingPseudoLength,
tvDepthValues,
rkbDiff,
depthUnit,
!performDataSmoothing );
!performDataSmoothing,
xUnits );
}
}
}
@ -541,88 +546,27 @@ void RimWellLogExtractionCurve::findAndLoadWbsParametersFromLasFiles( const RimW
auto allParams = RigWbsParameter::allParameters();
for ( const RigWbsParameter& parameter : allParams )
{
if ( parameter == RigWbsParameter::PP_Reservoir() || parameter == RigWbsParameter::PP_NonReservoir() )
{
findAndLoadPorePressuresFromLasFiles( wellPath, parameter, geomExtractor );
}
else if ( parameter == RigWbsParameter::UCS() )
{
findAndLoadUcsFromLasFiles( wellPath, geomExtractor );
}
else
{
// Generic LAS
QString lasAddress = parameter.addressString( RigWbsParameter::LAS_FILE );
QString lasAddress = parameter.addressString( RigWbsParameter::LAS_FILE );
std::vector<std::pair<double, double>> lasFileValues =
RimWellLogFile::findMdAndChannelValuesForWellPath( wellPath, lasAddress );
if ( !lasFileValues.empty() )
QString lasUnits;
std::vector<std::pair<double, double>> lasFileValues =
RimWellLogFile::findMdAndChannelValuesForWellPath( wellPath, lasAddress, &lasUnits );
if ( !lasFileValues.empty() )
{
QString extractorUnits = geomExtractor->parameterInputUnits( parameter );
if ( RiaWellLogUnitTools::convertValues( &lasFileValues, lasUnits, extractorUnits, wellPath->wellPathGeometry() ) )
{
geomExtractor->setWbsLasValues( parameter, lasFileValues );
}
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimWellLogExtractionCurve::findAndLoadUcsFromLasFiles( const RimWellPath* wellPath,
RigGeoMechWellLogExtractor* geomExtractor )
{
{
QString lasAddress = RigWbsParameter::UCS().addressString( RigWbsParameter::LAS_FILE );
std::vector<std::pair<double, double>> logFileUcs = RimWellLogFile::findMdAndChannelValuesForWellPath( wellPath,
lasAddress );
if ( !logFileUcs.empty() )
{
// TODO: UCS is typically in MPa, but not necessarily.
// We need to at least give a warning if the units don't match
// ... and preferable do a conversion.
for ( auto& ucsValue : logFileUcs )
else
{
ucsValue.second *= 10.0; // MPa -> Bar
QString errMsg = QString( "Could not convert units of LAS-channel %1 from %2 to %3" )
.arg( lasAddress )
.arg( lasUnits )
.arg( extractorUnits );
RiaLogging::error( errMsg );
}
geomExtractor->setWbsLasValues( RigWbsParameter::UCS(), logFileUcs );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimWellLogExtractionCurve::findAndLoadPorePressuresFromLasFiles( const RimWellPath* wellPath,
const RigWbsParameter& parameter,
RigGeoMechWellLogExtractor* geomExtractor )
{
{
std::vector<std::pair<double, double>> logFileMudWeights =
RimWellLogFile::findMdAndChannelValuesForWellPath( wellPath,
parameter.addressString( RigWbsParameter::LAS_FILE ) );
if ( !logFileMudWeights.empty() )
{
std::vector<std::pair<double, double>> porePressuresBar;
porePressuresBar.reserve( logFileMudWeights.size() );
for ( auto& mudWeight : logFileMudWeights )
{
// Log file mud weights come in SG units (g / cm^3).
// We need SI as input (kg / m^3), so multiply by 1000:
double mudWeightsSI = mudWeight.second * 1000.0;
// To get specific mudWeight (N / m^3):
double specificMudWeight = mudWeightsSI * 9.81;
double md = mudWeight.first;
cvf::Vec3d point = wellPath->wellPathGeometry()->interpolatedPointAlongWellPath( md );
double depth = -point.z() + wellPath->wellPathGeometry()->rkbDiff();
// Pore pressure in pascal
double ppPascal = specificMudWeight * depth;
// Pore pressure in bar
porePressuresBar.emplace_back( mudWeight.first, ppPascal * 1.0e-5 );
}
geomExtractor->setWbsLasValues( parameter, porePressuresBar );
}
}
}
@ -963,6 +907,27 @@ QString RimWellLogExtractionCurve::wellLogChannelName() const
return name;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimWellLogExtractionCurve::wellLogChannelUnits() const
{
RimGeoMechCase* geoMechCase = dynamic_cast<RimGeoMechCase*>( m_case.value() );
RimEclipseCase* eclipseCase = dynamic_cast<RimEclipseCase*>( m_case.value() );
QString name;
if ( eclipseCase )
{
name = RiaWellLogUnitTools::noUnitString();
}
else if ( geoMechCase )
{
name = m_geomResultDefinition->defaultLasUnits();
}
return name;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -66,6 +66,7 @@ public:
QString wellName() const override;
QString wellLogChannelUiName() const override;
QString wellLogChannelName() const override;
QString wellLogChannelUnits() const override;
QString wellDate() const override;
int branchIndex() const;
bool branchDetection() const;
@ -87,12 +88,6 @@ public:
static void findAndLoadWbsParametersFromLasFiles( const RimWellPath* wellPath,
RigGeoMechWellLogExtractor* geomExtractor );
static void findAndLoadUcsFromLasFiles( const RimWellPath* wellPath, RigGeoMechWellLogExtractor* geomExtractor );
static void findAndLoadPorePressuresFromLasFiles( const RimWellPath* wellPath,
const RigWbsParameter& parameter,
RigGeoMechWellLogExtractor* geomExtractor );
void setAutoNameComponents( bool addCaseName, bool addProperty, bool addWellname, bool addTimeStep, bool addDate );
protected:

View File

@ -257,7 +257,8 @@ void RimWellLogFile::updateFilePathsFromProjectPath( const QString& newProjectPa
///
//--------------------------------------------------------------------------------------------------
std::vector<std::pair<double, double>> RimWellLogFile::findMdAndChannelValuesForWellPath( const RimWellPath* wellPath,
const QString& channelName )
const QString& channelName,
QString* unitString /*=nullptr*/ )
{
CVF_ASSERT( wellPath );
std::vector<RimWellLogFile*> wellLogFiles;
@ -268,6 +269,10 @@ std::vector<std::pair<double, double>> RimWellLogFile::findMdAndChannelValuesFor
std::vector<double> channelValues = fileData->values( channelName );
if ( !channelValues.empty() )
{
if ( unitString )
{
*unitString = fileData->wellLogChannelUnitString( channelName );
}
std::vector<double> depthValues = fileData->depthValues();
CVF_ASSERT( depthValues.size() == channelValues.size() );
std::vector<std::pair<double, double>> depthValuePairs;

View File

@ -85,7 +85,8 @@ public:
void updateFilePathsFromProjectPath( const QString& newProjectPath, const QString& oldProjectPath );
static std::vector<std::pair<double, double>> findMdAndChannelValuesForWellPath( const RimWellPath* wellPath,
const QString& channelName );
const QString& channelName,
QString* unitString = nullptr );
private:
void setupBeforeSave() override;

View File

@ -57,7 +57,7 @@ RimWellLogFileCurve::RimWellLogFileCurve()
CAF_PDM_InitFieldNoDefault( &m_wellPath, "CurveWellPath", "Well Path", "", "", "" );
m_wellPath.uiCapability()->setUiTreeChildrenHidden( true );
CAF_PDM_InitFieldNoDefault( &m_wellLogChannnelName, "CurveWellLogChannel", "Well Log Channel", "", "", "" );
CAF_PDM_InitFieldNoDefault( &m_wellLogChannelName, "CurveWellLogChannel", "Well Log Channel", "", "", "" );
CAF_PDM_InitFieldNoDefault( &m_wellLogFile, "WellLogFile", "Well Log File", "", "", "" );
@ -87,7 +87,7 @@ void RimWellLogFileCurve::onLoadDataAndUpdate( bool updateParentPlot )
RigWellLogFile* wellLogFile = m_wellLogFile->wellLogFileData();
if ( wellLogFile )
{
std::vector<double> values = wellLogFile->values( m_wellLogChannnelName );
std::vector<double> values = wellLogFile->values( m_wellLogChannelName );
std::vector<double> measuredDepthValues = wellLogFile->depthValues();
std::vector<double> tvdMslValues = wellLogFile->tvdMslValues();
std::vector<double> tvdRkbValues = wellLogFile->tvdRkbValues();
@ -201,7 +201,7 @@ RimWellPath* RimWellLogFileCurve::wellPath() const
//--------------------------------------------------------------------------------------------------
void RimWellLogFileCurve::setWellLogChannelName( const QString& name )
{
m_wellLogChannnelName = name;
m_wellLogChannelName = name;
}
//--------------------------------------------------------------------------------------------------
@ -225,7 +225,7 @@ void RimWellLogFileCurve::fieldChangedByUi( const caf::PdmFieldHandle* changedFi
{
this->loadDataAndUpdate( true );
}
else if ( changedField == &m_wellLogChannnelName )
else if ( changedField == &m_wellLogChannelName )
{
this->loadDataAndUpdate( true );
}
@ -246,7 +246,7 @@ void RimWellLogFileCurve::defineUiOrdering( QString uiConfigName, caf::PdmUiOrde
caf::PdmUiGroup* curveDataGroup = uiOrdering.addNewGroup( "Curve Data" );
curveDataGroup->add( &m_wellPath );
curveDataGroup->add( &m_wellLogFile );
curveDataGroup->add( &m_wellLogChannnelName );
curveDataGroup->add( &m_wellLogChannelName );
caf::PdmUiGroup* appearanceGroup = uiOrdering.addNewGroup( "Appearance" );
RimPlotCurve::appearanceUiOrdering( *appearanceGroup );
@ -298,7 +298,7 @@ QList<caf::PdmOptionItemInfo> RimWellLogFileCurve::calculateValueOptions( const
}
}
if ( fieldNeedingOptions == &m_wellLogChannnelName )
if ( fieldNeedingOptions == &m_wellLogChannelName )
{
if ( m_wellPath() )
{
@ -372,9 +372,9 @@ QString RimWellLogFileCurve::createCurveAutoName()
name.push_back( wellName() );
name.push_back( "LAS" );
if ( !m_wellLogChannnelName().isEmpty() )
if ( !m_wellLogChannelName().isEmpty() )
{
name.push_back( m_wellLogChannnelName );
name.push_back( m_wellLogChannelName );
channelNameAvailable = true;
}
@ -387,8 +387,7 @@ QString RimWellLogFileCurve::createCurveAutoName()
RimWellLogPlot* wellLogPlot;
firstAncestorOrThisOfType( wellLogPlot );
CVF_ASSERT( wellLogPlot );
QString unitName = wellLogFile->wellLogChannelUnitString( m_wellLogChannnelName,
wellLogPlot->depthUnit() );
QString unitName = wellLogFile->wellLogChannelUnitString( m_wellLogChannelName, wellLogPlot->depthUnit() );
if ( !unitName.isEmpty() )
{
@ -414,7 +413,19 @@ QString RimWellLogFileCurve::createCurveAutoName()
//--------------------------------------------------------------------------------------------------
QString RimWellLogFileCurve::wellLogChannelUiName() const
{
return m_wellLogChannnelName;
return m_wellLogChannelName;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimWellLogFileCurve::wellLogChannelUnits() const
{
if ( m_wellLogFile && m_wellLogFile->wellLogFileData() )
{
return m_wellLogFile->wellLogFileData()->wellLogChannelUnitString( m_wellLogChannelName );
}
return RiaWellLogUnitTools::noUnitString();
}
//--------------------------------------------------------------------------------------------------

View File

@ -50,6 +50,7 @@ public:
// Overrides from RimWellLogPlotCurve
QString wellName() const override;
QString wellLogChannelUiName() const override;
QString wellLogChannelUnits() const override;
RimWellLogFile* wellLogFile() const;
@ -73,6 +74,6 @@ protected:
protected:
caf::PdmPtrField<RimWellPath*> m_wellPath;
caf::PdmPtrField<RimWellLogFile*> m_wellLogFile;
caf::PdmField<QString> m_wellLogChannnelName;
caf::PdmField<QString> m_wellLogChannelName;
caf::PdmField<QString> m_wellLogChannnelUnit;
};

View File

@ -144,6 +144,14 @@ QString RimWellLogRftCurve::wellLogChannelUiName() const
return m_wellLogChannelName().text();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimWellLogRftCurve::wellLogChannelUnits() const
{
return RiaWellLogUnitTools::noUnitString();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -60,6 +60,7 @@ public:
QString wellName() const override;
QString wellLogChannelUiName() const override;
QString wellLogChannelUnits() const override;
void setEclipseResultCase( RimEclipseResultCase* eclipseResultCase );
RimEclipseResultCase* eclipseResultCase() const;

View File

@ -278,6 +278,14 @@ QString RimWellMeasurementCurve::wellLogChannelUiName() const
return QString( "" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimWellMeasurementCurve::wellLogChannelUnits() const
{
return RiaWellLogUnitTools::noUnitString();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -49,6 +49,7 @@ public:
// Overrides from RimWellLogPlotCurve
QString wellName() const override;
QString wellLogChannelUiName() const override;
QString wellLogChannelUnits() const override;
protected:
// Overrides from RimWellLogCurve

View File

@ -31,6 +31,7 @@
#include "RigGeoMechBoreHoleStressCalculator.h"
#include "RigGeoMechCaseData.h"
#include "RiaWellLogUnitTools.h"
#include "RigWellLogExtractionTools.h"
#include "RigWellPath.h"
#include "RigWellPathGeometryTools.h"
@ -109,17 +110,17 @@ void RigGeoMechWellLogExtractor::performCurveDataSmoothing( int
std::vector<std::vector<double>*> dependentValues = {tvds, &interfaceShValuesDbl, &interfacePorePressuresDbl};
std::vector<unsigned char> smoothOrFilterSegments = determineFilteringOrSmoothing( interfacePorePressuresDbl );
filterShortSegments( mds, values, &smoothOrFilterSegments, dependentValues );
filterColinearSegments( mds, values, &smoothOrFilterSegments, dependentValues );
smoothSegments( mds, tvds, values, interfaceShValuesDbl, smoothOrFilterSegments, smoothingTreshold );
}
}
//--------------------------------------------------------------------------------------------------
///
/// Get curve data for a given parameter. Returns the output units of the data.
//--------------------------------------------------------------------------------------------------
void RigGeoMechWellLogExtractor::curveData( const RigFemResultAddress& resAddr, int frameIndex, std::vector<double>* values )
QString RigGeoMechWellLogExtractor::curveData( const RigFemResultAddress& resAddr,
int frameIndex,
std::vector<double>* values )
{
CVF_TIGHT_ASSERT( values );
@ -159,25 +160,31 @@ void RigGeoMechWellLogExtractor::curveData( const RigFemResultAddress& resAddr,
RigWbsParameter param;
if ( RigWbsParameter::findParameter( QString::fromStdString( resAddr.fieldName ), &param ) )
{
if ( param == RigWbsParameter::OBG0() )
if ( param == RigWbsParameter::FG_Shale() )
{
frameIndex = 0;
wellBoreFGShale( frameIndex, values );
}
calculateWbsParameterForAllSegments( param, frameIndex, values );
if ( param == RigWbsParameter::UCS() ) // UCS is reported as UCS/100
else
{
for ( double& value : *values )
if ( param == RigWbsParameter::OBG0() )
{
if ( isValid( value ) ) value /= 100.0;
frameIndex = 0;
}
calculateWbsParameterForAllSegments( param, frameIndex, values );
if ( param == RigWbsParameter::UCS() ) // UCS is reported as UCS/100
{
for ( double& value : *values )
{
if ( isValid( value ) ) value /= 100.0;
}
return RiaWellLogUnitTools::barX100UnitString();
}
}
}
}
}
else
else if ( resAddr.isValid() )
{
if ( !resAddr.isValid() ) return;
RigFemResultAddress convResAddr = resAddr;
// When showing POR results, always use the element nodal result,
@ -189,18 +196,20 @@ void RigGeoMechWellLogExtractor::curveData( const RigFemResultAddress& resAddr,
const std::vector<float>& resultValues = m_caseData->femPartResults()->resultValues( convResAddr, 0, frameIndex );
if ( resultValues.empty() ) return;
if ( !resultValues.empty() )
{
std::vector<float> interfaceValues = interpolateInterfaceValues( convResAddr, frameIndex, resultValues );
std::vector<float> interfaceValues = interpolateInterfaceValues( convResAddr, frameIndex, resultValues );
values->resize( interfaceValues.size(), std::numeric_limits<double>::infinity() );
values->resize( interfaceValues.size(), std::numeric_limits<double>::infinity() );
#pragma omp parallel for
for ( int64_t intersectionIdx = 0; intersectionIdx < (int64_t)m_intersections.size(); ++intersectionIdx )
{
( *values )[intersectionIdx] = static_cast<double>( interfaceValues[intersectionIdx] );
for ( int64_t intersectionIdx = 0; intersectionIdx < (int64_t)m_intersections.size(); ++intersectionIdx )
{
( *values )[intersectionIdx] = static_cast<double>( interfaceValues[intersectionIdx] );
}
}
}
return RiaWellLogUnitTools::noUnitString();
}
//--------------------------------------------------------------------------------------------------
@ -216,8 +225,6 @@ std::vector<RigGeoMechWellLogExtractor::WbsParameterSource>
std::vector<WbsParameterSource> finalSourcesPerSegment( m_intersections.size(), RigWbsParameter::UNDEFINED );
outputValues->resize( m_intersections.size(), std::numeric_limits<double>::infinity() );
if ( primarySource == RigWbsParameter::UNDEFINED )
{
return finalSourcesPerSegment;
@ -257,6 +264,8 @@ std::vector<RigGeoMechWellLogExtractor::WbsParameterSource>
elementPropertyValues = &( resultCollection->resultValues( elementPropertyAddr, 0, frameIndex ) );
}
std::vector<double> unscaledValues( m_intersections.size(), std::numeric_limits<double>::infinity() );
#pragma omp parallel for
for ( int64_t intersectionIdx = 0; intersectionIdx < (int64_t)m_intersections.size(); ++intersectionIdx )
{
@ -268,7 +277,7 @@ std::vector<RigGeoMechWellLogExtractor::WbsParameterSource>
if ( intersectionIdx < (int64_t)gridValues.size() &&
gridValues[intersectionIdx] != std::numeric_limits<double>::infinity() )
{
( *outputValues )[intersectionIdx] = gridValues[intersectionIdx];
unscaledValues[intersectionIdx] = gridValues[intersectionIdx];
finalSourcesPerSegment[intersectionIdx] = RigWbsParameter::GRID;
break;
}
@ -277,10 +286,10 @@ std::vector<RigGeoMechWellLogExtractor::WbsParameterSource>
{
if ( !lasFileValues.empty() )
{
double lasValue = getWellLogSegmentValue( intersectionIdx, lasFileValues );
double lasValue = getWellLogIntersectionValue( intersectionIdx, lasFileValues );
if ( lasValue != std::numeric_limits<double>::infinity() )
{
( *outputValues )[intersectionIdx] = lasValue;
unscaledValues[intersectionIdx] = lasValue;
finalSourcesPerSegment[intersectionIdx] = RigWbsParameter::LAS_FILE;
break;
}
@ -292,28 +301,28 @@ std::vector<RigGeoMechWellLogExtractor::WbsParameterSource>
size_t elmIdx = m_intersectedCellsGlobIdx[intersectionIdx];
if ( elmIdx < elementPropertyValues->size() )
{
( *outputValues )[intersectionIdx] = ( *elementPropertyValues )[elmIdx];
unscaledValues[intersectionIdx] = ( *elementPropertyValues )[elmIdx];
finalSourcesPerSegment[intersectionIdx] = RigWbsParameter::ELEMENT_PROPERTY_TABLE;
break;
}
}
else if ( *it == RigWbsParameter::HYDROSTATIC && isPPresult )
{
( *outputValues )[intersectionIdx] = hydroStaticPorePressureForSegment( intersectionIdx );
unscaledValues[intersectionIdx] = hydroStaticPorePressureForIntersection( intersectionIdx );
finalSourcesPerSegment[intersectionIdx] = RigWbsParameter::HYDROSTATIC;
break;
}
else if ( *it == RigWbsParameter::USER_DEFINED && isPPresult )
{
( *outputValues )[intersectionIdx] = userDefinedValue *
hydroStaticPorePressureForSegment( intersectionIdx );
unscaledValues[intersectionIdx] = userDefinedValue *
hydroStaticPorePressureForIntersection( intersectionIdx );
finalSourcesPerSegment[intersectionIdx] = RigWbsParameter::USER_DEFINED;
break;
}
else if ( *it == RigWbsParameter::USER_DEFINED )
{
( *outputValues )[intersectionIdx] = userDefinedValue;
unscaledValues[intersectionIdx] = userDefinedValue;
finalSourcesPerSegment[intersectionIdx] = RigWbsParameter::USER_DEFINED;
break;
}
@ -322,13 +331,29 @@ std::vector<RigGeoMechWellLogExtractor::WbsParameterSource>
if ( parameter.normalizeByHydrostaticPP() )
{
outputValues->resize( unscaledValues.size(), std::numeric_limits<double>::infinity() );
#pragma omp parallel for
for ( int64_t intersectionIdx = 0; intersectionIdx < (int64_t)m_intersections.size(); ++intersectionIdx )
{
( *outputValues )[intersectionIdx] /= hydroStaticPorePressureForSegment( intersectionIdx );
RigWbsParameter::Source source = finalSourcesPerSegment[intersectionIdx];
if ( source == RigWbsParameter::ELEMENT_PROPERTY_TABLE || source == RigWbsParameter::GRID )
{
( *outputValues )[intersectionIdx] = unscaledValues[intersectionIdx] /
hydroStaticPorePressureForSegment( intersectionIdx );
}
else
{
( *outputValues )[intersectionIdx] = unscaledValues[intersectionIdx] /
hydroStaticPorePressureForIntersection( intersectionIdx );
}
}
}
else
{
outputValues->swap( unscaledValues );
}
return finalSourcesPerSegment;
}
@ -466,7 +491,7 @@ std::vector<RigGeoMechWellLogExtractor::WbsParameterSource>
}
else
{
( *values )[intersectionIdx] = hydroStaticPorePressureForSegment( intersectionIdx );
( *values )[intersectionIdx] = hydroStaticPorePressureForIntersection( intersectionIdx );
sources[intersectionIdx] = RigWbsParameter::HYDROSTATIC;
}
}
@ -595,6 +620,8 @@ void RigGeoMechWellLogExtractor::wellBoreWallCurveData( const RigFemResultAddres
//--------------------------------------------------------------------------------------------------
void RigGeoMechWellLogExtractor::wellBoreFGShale( int frameIndex, std::vector<double>* values )
{
if ( values->empty() ) values->resize( m_intersections.size(), std::numeric_limits<double>::infinity() );
WbsParameterSource source = m_parameterSources.at( RigWbsParameter::FG_Shale() );
if ( source == RigWbsParameter::DERIVED_FROM_K0FG )
{
@ -709,6 +736,19 @@ void RigGeoMechWellLogExtractor::setWbsUserDefinedValue( RigWbsParameter paramet
m_userDefinedValues[parameter] = userDefinedValue;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RigGeoMechWellLogExtractor::parameterInputUnits( const RigWbsParameter& parameter )
{
if ( parameter == RigWbsParameter::PP_NonReservoir() || parameter == RigWbsParameter::PP_Reservoir() ||
parameter == RigWbsParameter::UCS() )
{
return RiaWellLogUnitTools::barUnitString();
}
return RiaWellLogUnitTools::noUnitString();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -1038,42 +1078,37 @@ cvf::Vec3f RigGeoMechWellLogExtractor::cellCentroid( size_t intersectionIdx ) co
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RigGeoMechWellLogExtractor::getWellLogSegmentValue( size_t intersectionIdx,
const std::vector<std::pair<double, double>>& wellLogValues ) const
double RigGeoMechWellLogExtractor::getWellLogIntersectionValue(
size_t intersectionIdx,
const std::vector<std::pair<double, double>>& wellLogValues ) const
{
if ( !wellLogValues.empty() )
{
double startMD, endMD;
if ( intersectionIdx % 2 == 0 )
{
startMD = m_intersectionMeasuredDepths[intersectionIdx];
endMD = m_intersectionMeasuredDepths[intersectionIdx + 1];
}
else
{
startMD = m_intersectionMeasuredDepths[intersectionIdx - 1];
endMD = m_intersectionMeasuredDepths[intersectionIdx];
}
const double eps = 1.0e-4;
RiaWeightedMeanCalculator<double> averageCalc;
for ( auto& depthAndValue : wellLogValues )
double intersection_md = m_intersectionMeasuredDepths[intersectionIdx];
for ( size_t i = 0; i < wellLogValues.size() - 1; ++i )
{
double las_md_i = wellLogValues[i].first;
double las_md_ip1 = wellLogValues[i + 1].first;
if ( cvf::Math::valueInRange( intersection_md, las_md_i, las_md_ip1 ) )
{
if ( cvf::Math::valueInRange( depthAndValue.first, startMD, endMD ) )
double dist_i = std::abs( intersection_md - las_md_i );
double dist_ip1 = std::abs( intersection_md - las_md_ip1 );
if ( dist_i < eps )
{
cvf::Vec3d position = m_wellPath->interpolatedPointAlongWellPath( depthAndValue.first );
cvf::Vec3d centroid( cellCentroid( intersectionIdx ) );
double weight = 1.0;
double dist = ( position - centroid ).length();
if ( dist > 1.0 )
{
weight = 1.0 / dist;
}
averageCalc.addValueAndWeight( depthAndValue.second, weight );
return wellLogValues[i].second;
}
else if ( dist_ip1 < eps )
{
return wellLogValues[i + 1].second;
}
else
{
RiaWeightedMeanCalculator<double> averageCalc;
averageCalc.addValueAndWeight( wellLogValues[i].second, 1.0 / dist_i );
averageCalc.addValueAndWeight( wellLogValues[i + 1].second, 1.0 / dist_ip1 );
return averageCalc.weightedMean();
}
}
if ( averageCalc.validAggregatedWeight() )
{
return averageCalc.weightedMean();
}
}
return std::numeric_limits<double>::infinity();
@ -1130,123 +1165,6 @@ void RigGeoMechWellLogExtractor::initializeResultValues( std::vector<caf::Ten3d>
resultValues.resize( resultCount );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigGeoMechWellLogExtractor::filterShortSegments( std::vector<double>* xValues,
std::vector<double>* yValues,
std::vector<unsigned char>* filterSegments,
std::vector<std::vector<double>*>& vectorOfDependentValues )
{
const double lengthEpsilon = 1.0e-3;
std::vector<double> simplerXValues;
std::vector<double> simplerYValues;
std::vector<unsigned char> simplerFilterSegments;
std::vector<std::vector<double>> simplerDependentValues( vectorOfDependentValues.size() );
simplerXValues.push_back( xValues->front() );
simplerYValues.push_back( yValues->front() );
simplerFilterSegments.push_back( filterSegments->front() );
for ( size_t n = 0; n < vectorOfDependentValues.size(); ++n )
{
simplerDependentValues[n].push_back( vectorOfDependentValues[n]->front() );
}
for ( int64_t i = 1; i < int64_t( xValues->size() - 1 ); ++i )
{
cvf::Vec2d vecIn( ( ( *xValues )[i] - simplerXValues.back() ) / std::max( 1.0, simplerXValues.back() ),
( ( *yValues )[i] - simplerYValues.back() ) / std::max( 1.0, simplerYValues.back() ) );
if ( ( *filterSegments )[i] == 0u || vecIn.length() > lengthEpsilon )
{
simplerXValues.push_back( ( *xValues )[i] );
simplerYValues.push_back( ( *yValues )[i] );
simplerFilterSegments.push_back( ( *filterSegments )[i] );
for ( size_t n = 0; n < vectorOfDependentValues.size(); ++n )
{
simplerDependentValues[n].push_back( ( *vectorOfDependentValues[n] )[i] );
}
}
}
simplerXValues.push_back( xValues->back() );
simplerYValues.push_back( yValues->back() );
simplerFilterSegments.push_back( filterSegments->back() );
for ( size_t i = 0; i < vectorOfDependentValues.size(); ++i )
{
simplerDependentValues[i].push_back( vectorOfDependentValues[i]->back() );
}
xValues->swap( simplerXValues );
yValues->swap( simplerYValues );
filterSegments->swap( simplerFilterSegments );
for ( size_t n = 0; n < vectorOfDependentValues.size(); ++n )
{
vectorOfDependentValues[n]->swap( simplerDependentValues[n] );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigGeoMechWellLogExtractor::filterColinearSegments( std::vector<double>* xValues,
std::vector<double>* yValues,
std::vector<unsigned char>* filterSegments,
std::vector<std::vector<double>*>& vectorOfDependentValues )
{
std::vector<double> simplerXValues;
std::vector<double> simplerYValues;
std::vector<unsigned char> simpledFilterSegments;
std::vector<std::vector<double>> simplerDependentValues( vectorOfDependentValues.size() );
for ( size_t i = 0; i < 2; ++i )
{
simplerXValues.push_back( ( *xValues )[i] );
simplerYValues.push_back( ( *yValues )[i] );
simpledFilterSegments.push_back( ( *filterSegments )[i] );
for ( size_t n = 0; n < vectorOfDependentValues.size(); ++n )
{
simplerDependentValues[n].push_back( ( *vectorOfDependentValues[n] )[i] );
}
}
for ( int64_t i = 2; i < int64_t( xValues->size() - 1 ); ++i )
{
cvf::Vec2d vecIn( ( ( *xValues )[i] - simplerXValues.back() ) / std::max( 1.0, simplerXValues.back() ),
( ( *yValues )[i] - simplerYValues.back() ) / std::max( 1.0, simplerYValues.back() ) );
cvf::Vec2d vecOut( ( ( *xValues )[i + 1] - ( *xValues )[i] ) / std::max( 1.0, ( *xValues )[i] ),
( ( *yValues )[i + 1] - ( *yValues )[i] ) / std::max( 1.0, ( *yValues )[i] ) );
vecIn.normalize();
vecOut.normalize();
double dotProduct = std::abs( vecIn * vecOut );
if ( ( *filterSegments )[i] == 0u || std::fabs( 1.0 - dotProduct ) > 1.0e-3 )
{
simplerXValues.push_back( ( *xValues )[i] );
simplerYValues.push_back( ( *yValues )[i] );
simpledFilterSegments.push_back( ( *filterSegments )[i] );
for ( size_t n = 0; n < vectorOfDependentValues.size(); ++n )
{
simplerDependentValues[n].push_back( ( *vectorOfDependentValues[n] )[i] );
}
}
}
simplerXValues.push_back( xValues->back() );
simplerYValues.push_back( yValues->back() );
simpledFilterSegments.push_back( filterSegments->back() );
for ( size_t i = 0; i < vectorOfDependentValues.size(); ++i )
{
simplerDependentValues[i].push_back( vectorOfDependentValues[i]->back() );
}
xValues->swap( simplerXValues );
yValues->swap( simplerYValues );
filterSegments->swap( simpledFilterSegments );
for ( size_t n = 0; n < vectorOfDependentValues.size(); ++n )
{
vectorOfDependentValues[n]->swap( simplerDependentValues[n] );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -1338,6 +1256,18 @@ std::vector<unsigned char>
return smoothOrFilterSegments;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RigGeoMechWellLogExtractor::hydroStaticPorePressureForIntersection( size_t intersectionIdx ) const
{
double trueVerticalDepth = m_intersectionTVDs[intersectionIdx];
double effectiveDepthMeters = trueVerticalDepth + wellPathData()->rkbDiff();
double hydroStaticPorePressurePascal = effectiveDepthMeters * UNIT_WEIGHT_OF_WATER;
double hydroStaticPorePressureBar = pascalToBar( hydroStaticPorePressurePascal );
return hydroStaticPorePressureBar;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -65,13 +65,15 @@ public:
std::vector<double>* values,
const double smoothingTreshold );
void curveData( const RigFemResultAddress& resAddr, int frameIndex, std::vector<double>* values );
QString curveData( const RigFemResultAddress& resAddr, int frameIndex, std::vector<double>* values );
const RigGeoMechCaseData* caseData();
void setWbsLasValues( const RigWbsParameter& parameter, const std::vector<std::pair<double, double>>& values );
void setWbsParametersSource( RigWbsParameter parameter, WbsParameterSource source );
void setWbsUserDefinedValue( RigWbsParameter parameter, double userDefinedValue );
static QString parameterInputUnits( const RigWbsParameter& parameter );
std::vector<double> porePressureSourceRegions( int frameIndex );
std::vector<double> poissonSourceRegions( int frameIndex );
std::vector<double> ucsSourceRegions( int frameIndex );
@ -117,8 +119,8 @@ private:
const caf::Ten3d& wellPathTensor );
cvf::Vec3f cellCentroid( size_t intersectionIdx ) const;
double getWellLogSegmentValue( size_t intersectionIdx,
const std::vector<std::pair<double, double>>& wellLogValues ) const;
double getWellLogIntersectionValue( size_t intersectionIdx,
const std::vector<std::pair<double, double>>& wellLogValues ) const;
static double pascalToBar( double pascalValue );
@ -147,6 +149,7 @@ private:
std::vector<unsigned char> determineFilteringOrSmoothing( const std::vector<double>& porePressures );
double hydroStaticPorePressureForIntersection( size_t intersectionIdx ) const;
double hydroStaticPorePressureForSegment( size_t intersectionIdx ) const;
static bool isValid( double value );
@ -156,9 +159,9 @@ private:
cvf::ref<RigGeoMechCaseData> m_caseData;
std::map<RigWbsParameter, std::vector<std::pair<double, double>>> m_lasFileValues;
std::map<RigWbsParameter, WbsParameterSource> m_parameterSources;
std::map<RigWbsParameter, double> m_userDefinedValues;
std::map<RigWbsParameter, QString> m_lasFileInputUnits;
std::map<RigWbsParameter, WbsParameterSource> m_parameterSources;
std::map<RigWbsParameter, double> m_userDefinedValues;
static const double UNIT_WEIGHT_OF_WATER;
};

View File

@ -62,7 +62,7 @@ public:
if ( !m_curveData->xValues().empty() )
{
std::vector<double> wellLogValues = m_curveData->xValues();
std::vector<double> wellLogValues = m_curveData->xValues( QString::fromStdString( m_unit ) );
for ( size_t vIdx = 0; vIdx < wellLogValues.size(); vIdx++ )
{
double value = wellLogValues[vIdx];
@ -339,7 +339,7 @@ void RigLasFileExporter::setResamplingInterval( double interval )
//--------------------------------------------------------------------------------------------------
void RigLasFileExporter::wellPathsAndRkbDiff( std::vector<QString>* wellNames, std::vector<double>* rkbDiffs )
{
std::vector<SingleLasFileMetaData> lasFileDescriptions = createLasFileDescriptions( m_curves );
std::vector<SingleLasFileMetaData> lasFileDescriptions = createLasFileDescriptions( m_curves, false );
std::set<QString> uniqueWellNames;
@ -366,7 +366,7 @@ void RigLasFileExporter::setRkbDiffs( const std::vector<QString>& wellNames, con
{
assert( wellNames.size() == rkbDiffs.size() );
std::vector<SingleLasFileMetaData> lasFileDescriptions = createLasFileDescriptions( m_curves );
std::vector<SingleLasFileMetaData> lasFileDescriptions = createLasFileDescriptions( m_curves, false );
for ( size_t i = 0; i < wellNames.size(); i++ )
{
@ -386,11 +386,12 @@ void RigLasFileExporter::setRkbDiffs( const std::vector<QString>& wellNames, con
std::vector<QString> RigLasFileExporter::writeToFolder( const QString& exportFolder,
const QString& filePrefix /*= ""*/,
bool capitalizeFileName /*= false*/,
bool alwaysOverwrite /*= false*/ )
bool alwaysOverwrite /*= false*/,
bool convertCurveUnits /*= false*/ )
{
std::vector<QString> writtenFiles;
std::vector<SingleLasFileMetaData> lasFileDescriptions = createLasFileDescriptions( m_curves );
std::vector<SingleLasFileMetaData> lasFileDescriptions = createLasFileDescriptions( m_curves, convertCurveUnits );
applyUserDefinedRkbOffsets( &lasFileDescriptions );
@ -439,7 +440,7 @@ std::vector<QString> RigLasFileExporter::writeToFolder( const QString& exportFol
///
//--------------------------------------------------------------------------------------------------
std::vector<SingleLasFileMetaData>
RigLasFileExporter::createLasFileDescriptions( const std::vector<RimWellLogCurve*>& curves )
RigLasFileExporter::createLasFileDescriptions( const std::vector<RimWellLogCurve*>& curves, bool convertCurveUnits )
{
std::vector<RimWellLogCurve*> eclipseCurves;
std::vector<RimWellLogCurve*> geoMechCurves;
@ -469,9 +470,9 @@ std::vector<SingleLasFileMetaData>
std::vector<SingleLasFileMetaData> lasFileDescriptions;
appendLasFileDescriptions( externalLasCurves, &lasFileDescriptions );
appendLasFileDescriptions( eclipseCurves, &lasFileDescriptions );
appendLasFileDescriptions( geoMechCurves, &lasFileDescriptions );
appendLasFileDescriptions( externalLasCurves, &lasFileDescriptions, convertCurveUnits );
appendLasFileDescriptions( eclipseCurves, &lasFileDescriptions, convertCurveUnits );
appendLasFileDescriptions( geoMechCurves, &lasFileDescriptions, convertCurveUnits );
return lasFileDescriptions;
}
@ -480,7 +481,8 @@ std::vector<SingleLasFileMetaData>
///
//--------------------------------------------------------------------------------------------------
void RigLasFileExporter::appendLasFileDescriptions( const std::vector<RimWellLogCurve*>& curves,
std::vector<SingleLasFileMetaData>* lasFileDescriptions )
std::vector<SingleLasFileMetaData>* lasFileDescriptions,
bool convertCurveUnits )
{
CVF_ASSERT( lasFileDescriptions );
@ -555,7 +557,17 @@ void RigLasFileExporter::appendLasFileDescriptions( const std::vector<RimWellLog
{
curveData = curve->curveData();
}
singleLasFileMeta.addLogData( curve->wellLogChannelName().toStdString(), "NO_UNIT", "", curveData );
QString units = curve->curveData()->xUnits();
if ( convertCurveUnits || units == RiaWellLogUnitTools::barX100UnitString() )
{
units = curve->wellLogChannelUnits();
}
singleLasFileMeta.addLogData( curve->wellLogChannelName().toStdString(),
units.toStdString(),
"",
curveData );
}
}

View File

@ -41,12 +41,15 @@ public:
std::vector<QString> writeToFolder( const QString& exportFolder,
const QString& filePrefix = "",
bool capitalizeFileName = false,
bool alwaysOverwrite = false );
bool alwaysOverwrite = false,
bool convertCurveUnits = false );
private:
std::vector<SingleLasFileMetaData> createLasFileDescriptions( const std::vector<RimWellLogCurve*>& curves );
std::vector<SingleLasFileMetaData> createLasFileDescriptions( const std::vector<RimWellLogCurve*>& curves,
bool convertCurveUnits );
void appendLasFileDescriptions( const std::vector<RimWellLogCurve*>& curves,
std::vector<SingleLasFileMetaData>* lasFileDescriptions );
std::vector<SingleLasFileMetaData>* lasFileDescriptions,
bool convertCurveUnits );
QString caseNameFromCurve( RimWellLogCurve* curve );
double rkbDiff( RimWellLogCurve* curve );

View File

@ -17,6 +17,8 @@
/////////////////////////////////////////////////////////////////////////////////
#include "RigWbsParameter.h"
#include "RiaWellLogUnitTools.h"
#include "cafAssert.h"
namespace caf
@ -39,7 +41,10 @@ void RigWbsParameter::SourceEnum::setUp()
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RigWbsParameter::RigWbsParameter( const QString& name, bool normalizeByHydroStaticPP, const SourceVector& sources )
RigWbsParameter::RigWbsParameter( const QString& name,
bool normalizeByHydroStaticPP,
const SourceVector& sources,
bool exclusiveOption )
: m_name( name )
, m_sources( sources )
, m_normalizeByHydroStaticPP( normalizeByHydroStaticPP )
@ -47,6 +52,29 @@ RigWbsParameter::RigWbsParameter( const QString& name, bool normalizeByHydroStat
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RigWbsParameter::RigWbsParameter( const RigWbsParameter& rhs )
: m_name( rhs.m_name )
, m_sources( rhs.m_sources )
, m_normalizeByHydroStaticPP( rhs.m_normalizeByHydroStaticPP )
, m_exclusiveOptions( rhs.m_exclusiveOptions )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RigWbsParameter& RigWbsParameter::operator=( const RigWbsParameter& rhs )
{
m_name = rhs.m_name;
m_sources = rhs.m_sources;
m_normalizeByHydroStaticPP = rhs.m_normalizeByHydroStaticPP;
m_exclusiveOptions = rhs.m_exclusiveOptions;
return *this;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -73,7 +101,30 @@ std::vector<RigWbsParameter::Source> RigWbsParameter::sources() const
//--------------------------------------------------------------------------------------------------
QString RigWbsParameter::addressString( Source source ) const
{
return address( source ).primary;
SourceAddress sourceAddress;
if ( address( source, &sourceAddress ) )
{
return sourceAddress.primary;
}
return "";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RigWbsParameter::units( Source source ) const
{
SourceAddress sourceAddress;
if ( address( source, &sourceAddress ) )
{
return sourceAddress.units;
}
// Try the units of the first available source
if ( !m_sources.empty() )
{
return m_sources.front().second.units;
}
return RiaWellLogUnitTools::noUnitString();
}
//--------------------------------------------------------------------------------------------------
@ -87,8 +138,12 @@ RigFemResultAddress RigWbsParameter::femAddress( Source source ) const
else if ( source == ELEMENT_PROPERTY_TABLE )
posType = RIG_ELEMENT;
auto addr = address( source );
return RigFemResultAddress( posType, addr.primary.toStdString(), addr.secondary.toStdString() );
SourceAddress addr;
if ( address( source, &addr ) )
{
return RigFemResultAddress( posType, addr.primary.toStdString(), addr.secondary.toStdString() );
}
return RigFemResultAddress();
}
//--------------------------------------------------------------------------------------------------
@ -150,15 +205,6 @@ QString RigWbsParameter::sourceUiLabel( Source currentSource,
return sourceLabel;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RigWbsParameter::sourceLabel( Source source )
{
SourceAddress addr = address( source );
return addr.primary;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -180,10 +226,10 @@ bool RigWbsParameter::operator<( const RigWbsParameter& rhs ) const
//--------------------------------------------------------------------------------------------------
RigWbsParameter RigWbsParameter::PP_Reservoir()
{
SourceVector sources = {{GRID, SourceAddress( "POR-Bar" )},
{LAS_FILE, SourceAddress( "POR" )},
{ELEMENT_PROPERTY_TABLE, SourceAddress( "POR" )}};
return RigWbsParameter( "PP", true, sources );
SourceVector sources = {{GRID, SourceAddress( "POR-Bar", "", RiaWellLogUnitTools::barUnitString() )},
{LAS_FILE, SourceAddress( "POR_RES_INP", "", RiaWellLogUnitTools::gPerCm3UnitString() )},
{ELEMENT_PROPERTY_TABLE, SourceAddress( "POR", "", RiaWellLogUnitTools::barUnitString() )}};
return RigWbsParameter( "PP Reservoir", true, sources );
}
//--------------------------------------------------------------------------------------------------
@ -193,9 +239,9 @@ RigWbsParameter RigWbsParameter::PP_NonReservoir()
{
return RigWbsParameter( "PP Non-Reservoir",
true,
{{LAS_FILE, SourceAddress( "POR_NONRESERVOIR" )},
{HYDROSTATIC, SourceAddress( "Hydrostatic" )},
{USER_DEFINED, SourceAddress()}} );
{{LAS_FILE, SourceAddress( "POR_NONRES_INP", "", RiaWellLogUnitTools::gPerCm3UnitString() )},
{HYDROSTATIC, SourceAddress( "Hydrostatic", "", RiaWellLogUnitTools::barUnitString() )},
{USER_DEFINED, SourceAddress( "", "", RiaWellLogUnitTools::barUnitString() )}} );
}
//--------------------------------------------------------------------------------------------------
@ -205,7 +251,7 @@ RigWbsParameter RigWbsParameter::poissonRatio()
{
return RigWbsParameter( "Poisson Ratio",
false,
{{LAS_FILE, SourceAddress( "POISSON_RATIO" )},
{{LAS_FILE, SourceAddress( "POISSON_RATIO_INP" )},
{ELEMENT_PROPERTY_TABLE, SourceAddress( "RATIO" )},
{USER_DEFINED, SourceAddress()}} );
}
@ -217,9 +263,9 @@ RigWbsParameter RigWbsParameter::UCS()
{
return RigWbsParameter( "UCS",
false,
{{LAS_FILE, SourceAddress( "UCS" )},
{ELEMENT_PROPERTY_TABLE, SourceAddress( "UCS" )},
{USER_DEFINED, SourceAddress()}} );
{{LAS_FILE, SourceAddress( "UCS_INP", "", RiaWellLogUnitTools::MPaUnitString() )},
{ELEMENT_PROPERTY_TABLE, SourceAddress( "UCS", RiaWellLogUnitTools::barUnitString() )},
{USER_DEFINED, SourceAddress( "", "", RiaWellLogUnitTools::barUnitString() )}} );
}
//--------------------------------------------------------------------------------------------------
@ -227,8 +273,10 @@ RigWbsParameter RigWbsParameter::UCS()
//--------------------------------------------------------------------------------------------------
RigWbsParameter RigWbsParameter::OBG()
{
std::vector<std::pair<Source, SourceAddress>> sources = {{GRID, SourceAddress( "ST", "S33" )}};
return RigWbsParameter( "OBG", true, sources );
std::vector<std::pair<Source, SourceAddress>> sources =
{{GRID, SourceAddress( "ST", "S33", RiaWellLogUnitTools::barUnitString() )},
{LAS_FILE, SourceAddress( "OBG_INP", "", RiaWellLogUnitTools::barUnitString() )}};
return RigWbsParameter( "OBG Input", true, sources );
}
//--------------------------------------------------------------------------------------------------
@ -236,8 +284,9 @@ RigWbsParameter RigWbsParameter::OBG()
//--------------------------------------------------------------------------------------------------
RigWbsParameter RigWbsParameter::OBG0()
{
std::vector<std::pair<Source, SourceAddress>> sources = {{GRID, SourceAddress( "ST", "S33" )},
{LAS_FILE, SourceAddress( "OBG0" )}};
std::vector<std::pair<Source, SourceAddress>> sources =
{{GRID, SourceAddress( "ST", "S33", RiaWellLogUnitTools::barUnitString() )},
{LAS_FILE, SourceAddress( "OBG0_INP", "", RiaWellLogUnitTools::barUnitString() )}};
return RigWbsParameter( "OBG0", true, sources );
}
@ -246,8 +295,10 @@ RigWbsParameter RigWbsParameter::OBG0()
//--------------------------------------------------------------------------------------------------
RigWbsParameter RigWbsParameter::SH()
{
std::vector<std::pair<Source, SourceAddress>> sources = {{GRID, SourceAddress( "ST", "S3" )}};
return RigWbsParameter( "SH", true, sources );
std::vector<std::pair<Source, SourceAddress>> sources =
{{GRID, SourceAddress( "ST", "S3", RiaWellLogUnitTools::barUnitString() )},
{LAS_FILE, SourceAddress( "SH_INP", "", RiaWellLogUnitTools::barUnitString() )}};
return RigWbsParameter( "SH Input", true, sources );
}
//--------------------------------------------------------------------------------------------------
@ -257,7 +308,7 @@ RigWbsParameter RigWbsParameter::DF()
{
return RigWbsParameter( "DF",
false,
{{LAS_FILE, SourceAddress( "DF" )},
{{LAS_FILE, SourceAddress( "DF_INP" )},
{ELEMENT_PROPERTY_TABLE, SourceAddress( "DF" )},
{USER_DEFINED, SourceAddress()}} );
}
@ -267,7 +318,7 @@ RigWbsParameter RigWbsParameter::DF()
//--------------------------------------------------------------------------------------------------
RigWbsParameter RigWbsParameter::K0_FG()
{
return RigWbsParameter( "K0_FG", false, {{LAS_FILE, SourceAddress( "K0_FG" )}, {USER_DEFINED, SourceAddress()}} );
return RigWbsParameter( "K0_FG", false, {{LAS_FILE, SourceAddress( "K0_FG_INP" )}, {USER_DEFINED, SourceAddress()}} );
}
//--------------------------------------------------------------------------------------------------
@ -275,7 +326,7 @@ RigWbsParameter RigWbsParameter::K0_FG()
//--------------------------------------------------------------------------------------------------
RigWbsParameter RigWbsParameter::K0_SH()
{
return RigWbsParameter( "K0_SH", false, {{LAS_FILE, SourceAddress( "K0_SH" )}, {USER_DEFINED, SourceAddress()}} );
return RigWbsParameter( "K0_SH", false, {{LAS_FILE, SourceAddress( "K0_SH_INP" )}, {USER_DEFINED, SourceAddress()}} );
}
//--------------------------------------------------------------------------------------------------
@ -284,8 +335,12 @@ RigWbsParameter RigWbsParameter::K0_SH()
RigWbsParameter RigWbsParameter::FG_Shale()
{
RigWbsParameter param( "FG Shale",
true,
{{DERIVED_FROM_K0FG, SourceAddress()}, {PROPORTIONAL_TO_SH, SourceAddress()}} );
false,
{
{DERIVED_FROM_K0FG, SourceAddress()},
{PROPORTIONAL_TO_SH, SourceAddress()},
{LAS_FILE, SourceAddress( "FG_SHALE_INP" )},
} );
param.setOptionsExclusive( true );
return param;
}
@ -316,11 +371,15 @@ bool RigWbsParameter::findParameter( QString parameterName, RigWbsParameter* fou
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RigWbsParameter::SourceAddress RigWbsParameter::address( Source source ) const
bool RigWbsParameter::address( Source source, RigWbsParameter::SourceAddress* sourceAddress ) const
{
for ( auto sourceEntryPair : m_sources )
{
if ( sourceEntryPair.first == source ) return sourceEntryPair.second;
if ( sourceEntryPair.first == source )
{
*sourceAddress = sourceEntryPair.second;
return true;
}
}
return SourceAddress();
return false;
}

View File

@ -1,6 +1,6 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- Ceetron Solutions AS
// Copyright (C) 2019- Equinor AS
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@ -19,6 +19,7 @@
#include "cafAppEnum.h"
#include "RiaWellLogUnitTools.h"
#include "RigFemResultAddress.h"
#include <QString>
@ -47,11 +48,16 @@ public:
public:
RigWbsParameter( const QString& name = "",
bool normalizeByHydroStaticPP = false,
const SourceVector& validSources = {} );
const SourceVector& validSources = {},
bool exclusiveOptions = false );
RigWbsParameter( const RigWbsParameter& rhs );
RigWbsParameter& operator=( const RigWbsParameter& rhs );
const QString& name() const;
std::vector<Source> sources() const;
QString addressString( Source source ) const;
QString units( Source source ) const;
RigFemResultAddress femAddress( Source source ) const;
bool normalizeByHydrostaticPP() const;
bool exclusiveOptions() const;
@ -62,7 +68,6 @@ public:
QString sourceUiLabel( Source currentSource,
const QString& delimiter = " ",
double userDefinedValue = std::numeric_limits<double>::infinity() );
QString sourceLabel( Source currentSource );
bool operator==( const RigWbsParameter& rhs ) const;
bool operator<( const RigWbsParameter& rhs ) const;
@ -88,14 +93,16 @@ private:
RigFemResultPosEnum resType;
QString primary; // i.e. grid field name, las entry, etc.
QString secondary; // i.e. grid component name
SourceAddress( QString primary = "", QString secondary = "" )
QString units; // The unit string
SourceAddress( QString primary = "", QString secondary = "", QString units = RiaWellLogUnitTools::noUnitString() )
: primary( primary )
, secondary( secondary )
, units( units )
{
}
};
SourceAddress address( Source source ) const;
bool address( Source source, SourceAddress* sourceAddress ) const;
private:
QString m_name;

View File

@ -20,8 +20,8 @@
#include "RigWellLogCurveData.h"
#include "RiaCurveDataTools.h"
#include "RiaEclipseUnitTools.h"
#include "RiaWellLogUnitTools.h"
#include "cvfAssert.h"
#include "cvfMath.h"
@ -35,6 +35,7 @@ RigWellLogCurveData::RigWellLogCurveData()
{
m_isExtractionCurve = false;
m_depthUnit = RiaDefines::UNIT_METER;
m_xUnitString = RiaWellLogUnitTools::noUnitString();
}
//--------------------------------------------------------------------------------------------------
@ -95,11 +96,44 @@ void RigWellLogCurveData::setValuesAndDepths( const std::vector<double>&
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<double>& RigWellLogCurveData::xValues() const
void RigWellLogCurveData::setXUnits( const QString& xUnitString )
{
m_xUnitString = xUnitString;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RigWellLogCurveData::xValues() const
{
return m_xValues;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RigWellLogCurveData::xValues( const QString& units ) const
{
std::vector<double> convertedValues;
if ( units != m_xUnitString && RiaWellLogUnitTools::convertValues( depths( RiaDefines::TRUE_VERTICAL_DEPTH_RKB ),
m_xValues,
&convertedValues,
m_xUnitString,
units ) )
{
return convertedValues;
}
return m_xValues;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RigWellLogCurveData::xUnits() const
{
return m_xUnitString;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -192,7 +226,9 @@ std::vector<double> RigWellLogCurveData::depthPlotValues( RiaDefines::DepthTypeE
}
else
{
std::vector<double> convertedValues = convertDepthValues( destinationDepthUnit, depthValues );
std::vector<double> convertedValues = RiaWellLogUnitTools().convertDepths( depthValues,
m_depthUnit,
destinationDepthUnit );
RiaCurveDataTools::getValuesByIntervals( convertedValues, m_intervalsOfContinousValidValues, &filteredValues );
}
}
@ -415,52 +451,3 @@ RiaDefines::DepthUnitType RigWellLogCurveData::depthUnit() const
{
return m_depthUnit;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RigWellLogCurveData::convertFromMeterToFeet( const std::vector<double>& valuesInMeter )
{
std::vector<double> valuesInFeet( valuesInMeter.size() );
for ( size_t i = 0; i < valuesInMeter.size(); i++ )
{
valuesInFeet[i] = valuesInMeter[i] * RiaEclipseUnitTools::feetPerMeter();
}
return valuesInFeet;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RigWellLogCurveData::convertFromFeetToMeter( const std::vector<double>& valuesInFeet )
{
std::vector<double> valuesInMeter( valuesInFeet.size() );
for ( size_t i = 0; i < valuesInFeet.size(); i++ )
{
valuesInMeter[i] = valuesInFeet[i] / RiaEclipseUnitTools::feetPerMeter();
}
return valuesInMeter;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RigWellLogCurveData::convertDepthValues( RiaDefines::DepthUnitType destinationDepthUnit,
const std::vector<double>& values ) const
{
CVF_ASSERT( destinationDepthUnit != m_depthUnit );
if ( destinationDepthUnit == RiaDefines::UNIT_METER && m_depthUnit == RiaDefines::UNIT_FEET )
{
return convertFromFeetToMeter( values );
}
else if ( destinationDepthUnit == RiaDefines::UNIT_FEET && m_depthUnit == RiaDefines::UNIT_METER )
{
return convertFromMeterToFeet( values );
}
return values;
}

View File

@ -20,9 +20,12 @@
#pragma once
#include "RiaDefines.h"
#include "RiaWellLogUnitTools.h"
#include "cvfObject.h"
#include <QString>
#include <map>
#include <set>
#include <vector>
@ -49,8 +52,11 @@ public:
double rkbDiff,
RiaDefines::DepthUnitType depthUnit,
bool isExtractionCurve );
void setXUnits( const QString& xUnitString );
const std::vector<double>& xValues() const;
std::vector<double> xValues() const;
std::vector<double> xValues( const QString& units ) const;
QString xUnits() const;
std::vector<double> depths( RiaDefines::DepthTypeEnum depthType ) const;
@ -78,12 +84,6 @@ private:
size_t stopIdx,
std::vector<std::pair<size_t, size_t>>* intervals );
std::vector<double> convertDepthValues( RiaDefines::DepthUnitType destinationDepthUnit,
const std::vector<double>& originalValues ) const;
static std::vector<double> convertFromMeterToFeet( const std::vector<double>& valuesInMeter );
static std::vector<double> convertFromFeetToMeter( const std::vector<double>& valuesInFeet );
private:
std::vector<double> m_xValues;
std::map<RiaDefines::DepthTypeEnum, std::vector<double>> m_depths;
@ -93,4 +93,5 @@ private:
std::vector<std::pair<size_t, size_t>> m_intervalsOfContinousValidValues;
RiaDefines::DepthUnitType m_depthUnit;
QString m_xUnitString;
};

View File

@ -260,6 +260,21 @@ QString RigWellLogFile::wellLogChannelUnitString( const QString& well
return unit;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RigWellLogFile::wellLogChannelUnitString( const QString& wellLogChannelName ) const
{
QString unit;
NRLib::LasWell* lasWell = dynamic_cast<NRLib::LasWell*>( m_wellLogFile );
if ( lasWell )
{
return QString::fromStdString( lasWell->unitName( wellLogChannelName.toStdString() ) );
}
return "";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -56,6 +56,7 @@ public:
QString wellLogChannelUnitString( const QString& wellLogChannelName,
RiaDefines::DepthUnitType displayDepthUnit ) const;
QString wellLogChannelUnitString( const QString& wellLogChannelName ) const;
RiaDefines::DepthUnitType depthUnit() const;
bool hasTvdMslChannel() const;