Add reference well depth adjustment to geomech case (#9547)

- Fix bug in retrieving bottom TVD value from ref well
- Add result calculator for K-indices in geomech case
- Improve depth adjustment algorithm
This commit is contained in:
Jørgen Herje
2022-12-07 09:28:57 +01:00
committed by GitHub
parent 8c0719c75f
commit 2e5683aead
5 changed files with 228 additions and 52 deletions

View File

@@ -552,12 +552,6 @@ RimWellLogExtractionCurve::WellLogExtractionCurveData
// Reference well adjustment does not support simulated wells
if ( m_trajectoryType == WELL_PATH && wellExtractor.notNull() && refWellExtractor.notNull() )
{
// ************************************************
//
// Adjust measured dept values according to refWell
//
// ************************************************
RigEclipseResultAddress indexKResAdr( RiaDefines::ResultCatType::STATIC_NATIVE,
RiaResultNames::indexKResultName() );
eclipseCase->eclipseCaseData()->results( RiaDefines::PorosityModelType::MATRIX_MODEL )->ensureKnownResultLoaded( indexKResAdr );
@@ -601,8 +595,6 @@ RimWellLogExtractionCurve::WellLogExtractionCurveData
bool performDataSmoothing,
double smoothingThreshold )
{
// TODO: Add depth adjustements for reference well
WellLogExtractionCurveData curveData;
RimWellLogPlotCollection* wellLogCollection = RimMainPlotCollection::current()->wellLogPlotCollection();
cvf::ref<RigGeoMechWellLogExtractor> wellExtractor = wellLogCollection->findOrCreateExtractor( m_wellPath, geomCase );
@@ -641,23 +633,51 @@ RimWellLogExtractionCurve::WellLogExtractionCurveData
}
}
const std::string fieldName = m_geomResultDefinition->resultAddress().fieldName;
if ( fieldName == RiaResultNames::wbsAzimuthResult().toStdString() ||
fieldName == RiaResultNames::wbsInclinationResult().toStdString() )
{
// Do not adjust depth values of Azimuth and Inclination as they are
// dependent of the well geometry
return curveData;
}
if ( wellExtractor.notNull() && refWellExtractor.notNull() )
{
// Add reference well depth adjustments
// NOTE: Perform performCurveDataSmoothing() for refWell, as done for well?
// ************************************************
//
// Adjust measured dept values according to refWell
//
// ************************************************
RigFemResultAddress indexKResAdr( RigFemResultPosEnum::RIG_ELEMENT_NODAL, "INDEX", "INDEX_K" );
const size_t frameIdx = 0;
std::vector<double> refWellMeasuredDepthValues = refWellExtractor->cellIntersectionMDs();
std::vector<double> refWellTvDepthValues = refWellExtractor->cellIntersectionTVDs();
std::vector<double> wellIndexKValues;
std::vector<double> refWellIndexKValues;
if ( indexKResAdr.isValid() )
{
wellExtractor->curveData( indexKResAdr, frameIdx, &wellIndexKValues );
refWellExtractor->curveData( indexKResAdr, frameIdx, &refWellIndexKValues );
}
if ( !wellIndexKValues.empty() && !refWellIndexKValues.empty() )
{
adjustWellDepthValuesToReferenceWell( curveData.measuredDepthValues,
curveData.tvDepthValues,
wellIndexKValues,
refWellMeasuredDepthValues,
refWellTvDepthValues,
refWellIndexKValues );
}
}
return curveData;
}
//--------------------------------------------------------------------------------------------------
// Utility function to adjust well depth values according to reference well - match k-index
// enter/exit values and linearize between enter/exit of k-index
/// Utility function to adjust well depth values according to reference well - match
/// enter and exit values for k-layer and linearize for depth values between enter/exit of k-layer.
///
/// Performs depth adjustment from first common k-layer to last common k-layer - i.e common min and
/// max index-k, as long as the k-layers are asymptotically increasing.
//--------------------------------------------------------------------------------------------------
void RimWellLogExtractionCurve::adjustWellDepthValuesToReferenceWell( std::vector<double>& rMeasuredDepthValues,
std::vector<double>& rTvDepthValues,
@@ -666,12 +686,6 @@ void RimWellLogExtractionCurve::adjustWellDepthValuesToReferenceWell( std::vecto
const std::vector<double>& refWellTvDepthValues,
const std::vector<double>& refWellIndexKValues )
{
// Description:
// - Adjust values up to largest common k-index value
// Assumptions:
// - Both wells have min k-index equal to 1.
// - k-index values are continously increasing values between top and bottom of well
CAF_ASSERT( rMeasuredDepthValues.size() == rTvDepthValues.size() &&
"Number of depth values must be equal for well!" );
CAF_ASSERT( rMeasuredDepthValues.size() == indexKValues.size() &&
@@ -682,13 +696,15 @@ void RimWellLogExtractionCurve::adjustWellDepthValuesToReferenceWell( std::vecto
"Number of index K values must be number of depth values for reference well!" );
CAF_ASSERT( *std::min( indexKValues.cbegin(), indexKValues.cend() ) ==
*std::min( refWellIndexKValues.cbegin(), refWellIndexKValues.cend() ) &&
"Both index-K value vectors must have same start index-K layer" );
"Both index-K value vectors must containt common min index-K layer" );
// Find common min and max k-index value for range depth values adjustment
const double minLayerK = std::max( *std::min_element( refWellIndexKValues.cbegin(), refWellIndexKValues.cend() ),
*std::min_element( indexKValues.cbegin(), indexKValues.cend() ) );
const double maxLayerK = std::min( *std::max_element( refWellIndexKValues.cbegin(), refWellIndexKValues.cend() ),
*std::max_element( indexKValues.cbegin(), indexKValues.cend() ) );
// Find common min and max k-index value for range of depth values to adjust
const auto minLayerK =
static_cast<int>( std::max( *std::min_element( refWellIndexKValues.cbegin(), refWellIndexKValues.cend() ),
*std::min_element( indexKValues.cbegin(), indexKValues.cend() ) ) );
const auto maxLayerK =
static_cast<int>( std::min( *std::max_element( refWellIndexKValues.cbegin(), refWellIndexKValues.cend() ),
*std::max_element( indexKValues.cbegin(), indexKValues.cend() ) ) );
if ( minLayerK > maxLayerK )
{
RiaLogging::error(
@@ -696,32 +712,39 @@ void RimWellLogExtractionCurve::adjustWellDepthValuesToReferenceWell( std::vecto
return;
}
RigWellLogIndexDepthOffset refWellLogIndexDepthOffset;
for ( int kLayer = static_cast<int>( minLayerK ); kLayer <= static_cast<int>( maxLayerK ); kLayer++ )
// Only allow asymptotically increasing k-layers - break at first decreasing k-layer value
auto createKLayerAndIndexMap = []( const std::vector<double>& indexKValues, int minLayerK, int maxLayerK ) {
int prevKLayer = -1;
std::map<int, std::vector<size_t>> kLayerAndIndexesMap = {};
for ( size_t i = 0; i < indexKValues.size(); ++i )
{
const auto kLayer = static_cast<int>( indexKValues[i] );
if ( kLayer < minLayerK ) continue;
if ( kLayer < prevKLayer || kLayer > maxLayerK ) break;
kLayerAndIndexesMap[kLayer].push_back( i );
prevKLayer = kLayer;
}
return kLayerAndIndexesMap;
};
RigWellLogIndexDepthOffset refWellLogIndexDepthOffset;
std::map<int, std::vector<size_t>> refWellKLayerAndIndexesMap =
createKLayerAndIndexMap( refWellIndexKValues, minLayerK, maxLayerK );
for ( const auto& [kLayer, indexes] : refWellKLayerAndIndexesMap )
{
const auto kLayerTopIter =
std::find( refWellIndexKValues.cbegin(), refWellIndexKValues.cend(), static_cast<double>( kLayer ) );
const auto kLayerBottomRIter =
std::find( refWellIndexKValues.crbegin(), refWellIndexKValues.crend(), static_cast<double>( kLayer ) );
const auto indexTop = std::distance( refWellIndexKValues.cbegin(), kLayerTopIter );
const auto indexBottom = refWellIndexKValues.size() - 1 -
std::distance( refWellIndexKValues.crbegin(), kLayerBottomRIter );
const auto topMd = refWellMeasuredDepthValues[indexTop];
const auto bottomMd = refWellMeasuredDepthValues[indexBottom];
const auto topTvd = refWellTvDepthValues[indexTop];
const auto bottomTvd = refWellTvDepthValues[indexBottom];
refWellLogIndexDepthOffset.setIndexOffsetDepth( kLayer, topMd, bottomMd, topTvd, bottomTvd );
}
std::map<int, std::vector<size_t>> wellKLayerAndIndexesMap = {};
for ( size_t i = 0; i < indexKValues.size(); i++ )
{
const int kLayer = static_cast<int>( indexKValues[i] );
wellKLayerAndIndexesMap[kLayer].push_back( i );
if ( indexes.empty() ) continue;
const auto indexTop = indexes.front();
const auto indexBottom = indexes.back();
refWellLogIndexDepthOffset.setIndexOffsetDepth( kLayer,
refWellMeasuredDepthValues[indexTop],
refWellMeasuredDepthValues[indexBottom],
refWellTvDepthValues[indexTop],
refWellTvDepthValues[indexBottom] );
}
std::map<int, std::vector<size_t>> wellKLayerAndIndexesMap =
createKLayerAndIndexMap( indexKValues, minLayerK, maxLayerK );
for ( const auto& [kLayer, indexes] : wellKLayerAndIndexesMap )
{
const auto firstIdx = indexes.front();
@@ -731,7 +754,7 @@ void RimWellLogExtractionCurve::adjustWellDepthValuesToReferenceWell( std::vecto
rMeasuredDepthValues[firstIdx] = refWellLogIndexDepthOffset.getTopMd( kLayer );
rMeasuredDepthValues[lastIdx] = refWellLogIndexDepthOffset.getBottomMd( kLayer );
rTvDepthValues[firstIdx] = refWellLogIndexDepthOffset.getTopTvd( kLayer );
rTvDepthValues[lastIdx] = refWellLogIndexDepthOffset.getBottomMd( kLayer );
rTvDepthValues[lastIdx] = refWellLogIndexDepthOffset.getBottomTvd( kLayer );
}
else if ( indexes.size() > 2 && refWellLogIndexDepthOffset.hasIndex( kLayer ) )
{