#9439 Fix unstable location of generated well target at sea level

NB! This fix will update the location of well target at sea level, and can potentially change the MD from sea level to first user defined well target. This will affect completions defined for the modelled well, as they are defined by MD.

* #9439 Make MD more predictable when toggling sea level target.
* #9439 Avoid updating well path tangents when toggling sea level target
* Disable IO of well target at sea level


Co-authored-by: Magne Sjaastad <magne.sjaastad@ceetronsolutions.com>
This commit is contained in:
Kristian Bendiksen 2022-12-19 13:24:04 +01:00 committed by GitHub
parent befab37588
commit 254c74be13
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 78 additions and 36 deletions

View File

@ -99,6 +99,10 @@ RimWellPathGeometryDef::RimWellPathGeometryDef()
m_autoTargetAtSeaLevel = new RimWellPathTarget;
m_autoTargetAtSeaLevel->setEnabled( false );
// Disable IO was introduced to avoid errors related to unstable location of well target at sea level.
// https://github.com/OPM/ResInsight/issues/9439
m_autoTargetAtSeaLevel.xmlCapability()->disableIO();
CAF_PDM_InitScriptableField( &m_isAttachedToParentWell, "AttachedToParentWell", false, "Attached to Parent Well" );
CAF_PDM_InitFieldNoDefault( &m_fixedWellPathPoints, "FixedWellPathPoints", "" );
CAF_PDM_InitFieldNoDefault( &m_fixedMeasuredDepths, "FixedMeasuredDepths", "" );
@ -257,17 +261,28 @@ std::vector<RimWellPathTarget*> RimWellPathGeometryDef::createTargets( const std
//--------------------------------------------------------------------------------------------------
cvf::ref<RigWellPath> RimWellPathGeometryDef::createWellPathGeometry()
{
cvf::ref<RigWellPath> wellPathGeometry = new RigWellPath;
// User defined well targets can be updated from 3D view or from table. Always update location for well target at
// sea level.
updateTargetAtSeaLevel();
if ( m_useAutoGeneratedTargetAtSeaLevel )
{
updateTargetAtSeaLevel();
}
double offsetMd = m_useAutoGeneratedTargetAtSeaLevel ? 0.0 : m_mdAtFirstTarget;
return createWellPathGeometry( m_useAutoGeneratedTargetAtSeaLevel, offsetMd, true );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::ref<RigWellPath> RimWellPathGeometryDef::createWellPathGeometry( bool useAutoGeneratedTargetAtSeaLevel,
double offsetMd,
bool updateTargets ) const
{
cvf::ref<RigWellPath> wellPathGeometry = new RigWellPath;
std::vector<cvf::Vec3d> wellPathPoints = m_fixedWellPathPoints;
std::vector<double> measuredDepths = m_fixedMeasuredDepths;
RiaLineArcWellPathCalculator wellPathCalculator = lineArcWellPathCalculator();
RiaLineArcWellPathCalculator wellPathCalculator =
lineArcWellPathCalculator( useAutoGeneratedTargetAtSeaLevel, updateTargets );
if ( wellPathCalculator.lineArcEndpoints().size() >= 2 )
{
@ -275,15 +290,11 @@ cvf::ref<RigWellPath> RimWellPathGeometryDef::createWellPathGeometry()
auto [sampledWellPathPoints, sampledMeasuredDepths] = arcLineSampler.sampledPointsAndMDs( 30, false );
wellPathPoints.insert( wellPathPoints.end(), sampledWellPathPoints.begin(), sampledWellPathPoints.end() );
double startMD = 0.0;
double startMD = offsetMd;
if ( !measuredDepths.empty() )
{
startMD = measuredDepths.back();
}
else if ( !m_useAutoGeneratedTargetAtSeaLevel )
{
startMD = m_mdAtFirstTarget;
}
for ( auto md : sampledMeasuredDepths )
{
@ -306,7 +317,8 @@ cvf::ref<RigWellPath> RimWellPathGeometryDef::createWellPathGeometry()
//--------------------------------------------------------------------------------------------------
std::vector<RiaWellPlanCalculator::WellPlanSegment> RimWellPathGeometryDef::wellPlan() const
{
RiaLineArcWellPathCalculator wellPathCalculator = lineArcWellPathCalculator();
RiaLineArcWellPathCalculator wellPathCalculator =
lineArcWellPathCalculator( m_useAutoGeneratedTargetAtSeaLevel, false );
RiaWellPlanCalculator wpCalc( wellPathCalculator.startTangent(), wellPathCalculator.lineArcEndpoints() );
@ -517,21 +529,28 @@ void RimWellPathGeometryDef::fieldChangedByUi( const caf::PdmFieldHandle* change
RimWellPathGeometryDefTools::updateLinkedGeometryDefinitions( linkedDefs, delta );
}
}
else if ( changedField == &m_useAutoGeneratedTargetAtSeaLevel && !m_useAutoGeneratedTargetAtSeaLevel )
else if ( changedField == &m_useAutoGeneratedTargetAtSeaLevel )
{
auto firstTarget = firstActiveTarget();
if ( firstTarget != nullptr )
updateTargetAtSeaLevel();
if ( !m_useAutoGeneratedTargetAtSeaLevel() )
{
auto firstLocationXYZ = firstTarget->targetPointXYZ() + anchorPointXyz();
auto firstTarget = firstActiveTarget();
if ( firstTarget != nullptr )
{
auto firstLocationXYZ = firstTarget->targetPointXYZ() + anchorPointXyz();
// Temporarily enable target at sea level to be able to create a complete geometry to find MD of first
// target of the complete geometry
m_useAutoGeneratedTargetAtSeaLevel = true;
auto wellPathGeo = createWellPathGeometry();
m_useAutoGeneratedTargetAtSeaLevel = false;
// Temporarily enable target at sea level to be able to create a complete geometry to find MD of first
// target of the complete geometry
auto wellPathGeo = createWellPathGeometry( true, 0.0, false );
double mdAtFirstTarget = wellPathGeo->closestMeasuredDepth( firstLocationXYZ );
m_mdAtFirstTarget = mdAtFirstTarget;
double mdAtFirstTarget = wellPathGeo->closestMeasuredDepth( firstLocationXYZ );
m_mdAtFirstTarget = mdAtFirstTarget;
}
}
else
{
m_mdAtFirstTarget = 0.0;
}
}
@ -584,10 +603,18 @@ void RimWellPathGeometryDef::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTre
///
//--------------------------------------------------------------------------------------------------
std::vector<RimWellPathTarget*> RimWellPathGeometryDef::activeWellTargets() const
{
return activeWellTargets( m_useAutoGeneratedTargetAtSeaLevel );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimWellPathTarget*> RimWellPathGeometryDef::activeWellTargets( bool useAutoGeneratedTargetAtSeaLevel ) const
{
std::vector<RimWellPathTarget*> active;
if ( m_useAutoGeneratedTargetAtSeaLevel && !m_wellTargets.empty() && m_autoTargetAtSeaLevel )
if ( useAutoGeneratedTargetAtSeaLevel && !m_wellTargets.empty() && m_autoTargetAtSeaLevel )
{
active.push_back( m_autoTargetAtSeaLevel );
}
@ -606,11 +633,12 @@ std::vector<RimWellPathTarget*> RimWellPathGeometryDef::activeWellTargets() cons
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaLineArcWellPathCalculator RimWellPathGeometryDef::lineArcWellPathCalculator() const
RiaLineArcWellPathCalculator RimWellPathGeometryDef::lineArcWellPathCalculator( bool useAutoGeneratedTargetAtSeaLevel,
bool updateTargets ) const
{
std::vector<RimWellPathTarget*> activeTargets;
auto candidates = activeWellTargets();
auto candidates = activeWellTargets( useAutoGeneratedTargetAtSeaLevel );
if ( !candidates.empty() )
{
activeTargets.push_back( candidates.front() );
@ -637,18 +665,21 @@ RiaLineArcWellPathCalculator RimWellPathGeometryDef::lineArcWellPathCalculator()
const std::vector<RiaLineArcWellPathCalculator::WellTargetStatus>& targetStatuses =
wellPathCalculator.targetStatuses();
for ( size_t tIdx = 0; tIdx < activeTargets.size(); ++tIdx )
if ( updateTargets )
{
activeTargets[tIdx]->setDerivedTangent( targetStatuses[tIdx].resultAzimuthRadians,
targetStatuses[tIdx].resultInclinationRadians );
for ( size_t tIdx = 0; tIdx < activeTargets.size(); ++tIdx )
{
activeTargets[tIdx]->setDerivedTangent( targetStatuses[tIdx].resultAzimuthRadians,
targetStatuses[tIdx].resultInclinationRadians );
activeTargets[tIdx]->setRadius1Data( targetStatuses[tIdx].isRadius1Editable,
targetStatuses[tIdx].hasOverriddenRadius1,
targetStatuses[tIdx].resultRadius1 );
activeTargets[tIdx]->setRadius1Data( targetStatuses[tIdx].isRadius1Editable,
targetStatuses[tIdx].hasOverriddenRadius1,
targetStatuses[tIdx].resultRadius1 );
activeTargets[tIdx]->setRadius2Data( targetStatuses[tIdx].isRadius2Editable,
targetStatuses[tIdx].hasOverriddenRadius2,
targetStatuses[tIdx].resultRadius2 );
activeTargets[tIdx]->setRadius2Data( targetStatuses[tIdx].isRadius2Editable,
targetStatuses[tIdx].hasOverriddenRadius2,
targetStatuses[tIdx].resultRadius2 );
}
}
return wellPathCalculator;
@ -661,6 +692,12 @@ void RimWellPathGeometryDef::updateTargetAtSeaLevel()
{
if ( m_useAutoGeneratedTargetAtSeaLevel && !m_wellTargets.empty() )
{
// Update tangents for existing well targets without the target at sea level.
bool useAutoGeneratedTargetAtSeaLevel = false;
double offsetMd = 0.0;
bool updateTargets = true;
createWellPathGeometry( useAutoGeneratedTargetAtSeaLevel, offsetMd, updateTargets );
cvf::Vec3d newPos = cvf::Vec3d::ZERO;
auto firstTarget = m_wellTargets[0];

View File

@ -95,6 +95,10 @@ public:
bool showAbsoluteCoordinates() const;
protected:
std::vector<RimWellPathTarget*> activeWellTargets( bool useAutoGeneratedTargetAtSeaLevel ) const;
cvf::ref<RigWellPath>
createWellPathGeometry( bool useAutoGeneratedTargetAtSeaLevel, double offsetMd, bool updateTargets ) const;
void defineCustomContextMenu( const caf::PdmFieldHandle* fieldNeedingMenu, QMenu* menu, QWidget* fieldEditorWidget ) override;
void defineEditorAttribute( const caf::PdmFieldHandle* field,
@ -113,7 +117,8 @@ private:
void initAfterRead() override;
QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override;
RiaLineArcWellPathCalculator lineArcWellPathCalculator() const;
RiaLineArcWellPathCalculator lineArcWellPathCalculator( bool useAutoGeneratedTargetAtSeaLevel,
bool updateTargets = true ) const;
void updateTargetAtSeaLevel();