#5780 #5795 Improve handling of air gap in modelled well paths + fix result instability.

* Stop using the auto generated target at sea level to generate the well path
* This is because the well path is used to generate the target at sea level.
* The alternative would be to iterate until the target and well path is stable, assuming it converges.
This commit is contained in:
Gaute Lindkvist 2020-04-15 08:40:12 +02:00 committed by Magne Sjaastad
parent 7b445a7fb7
commit 7bbbac8277
6 changed files with 50 additions and 49 deletions

View File

@ -33,7 +33,7 @@ RiaWellPlanCalculator::RiaWellPlanCalculator( const cvf::Vec3d& sta
{ {
if ( m_lineArcEndPoints.size() < 2 ) return; if ( m_lineArcEndPoints.size() < 2 ) return;
WellPlanSegment segment = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; WellPlanSegment segment = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
RiaOffshoreSphericalCoords startAziIncRad( m_startTangent ); RiaOffshoreSphericalCoords startAziIncRad( m_startTangent );
segment.inc = cvf::Math::toDegrees( startAziIncRad.inc() ); segment.inc = cvf::Math::toDegrees( startAziIncRad.inc() );
@ -58,9 +58,12 @@ RiaWellPlanCalculator::RiaWellPlanCalculator( const cvf::Vec3d& sta
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
void RiaWellPlanCalculator::addSegment( cvf::Vec3d t1, cvf::Vec3d p1, cvf::Vec3d p2, cvf::Vec3d* endTangent ) void RiaWellPlanCalculator::addSegment( cvf::Vec3d t1, cvf::Vec3d p1, cvf::Vec3d p2, cvf::Vec3d* endTangent )
{ {
cvf::Vec3d p1p2 = p2 - p1; cvf::Vec3d p1p2 = p2 - p1;
double xyLength = std::sqrt( p1p2.x() * p1p2.x() + p1p2.y() * p1p2.y() );
double zLength = std::abs( p1p2.z() );
CVF_ASSERT( p1p2.lengthSquared() > 1e-20 ); // We only show two decimals in the well plan anyway.
if ( xyLength < 1.0e-2 && zLength < 1.0e-2 ) return;
if ( cvf::GeometryTools::getAngle( t1, p1p2 ) < 1e-5 ) if ( cvf::GeometryTools::getAngle( t1, p1p2 ) < 1e-5 )
{ {
@ -77,7 +80,7 @@ void RiaWellPlanCalculator::addSegment( cvf::Vec3d t1, cvf::Vec3d p1, cvf::Vec3d
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
void RiaWellPlanCalculator::addLineSegment( cvf::Vec3d p1, cvf::Vec3d p2, cvf::Vec3d* endTangent ) void RiaWellPlanCalculator::addLineSegment( cvf::Vec3d p1, cvf::Vec3d p2, cvf::Vec3d* endTangent )
{ {
WellPlanSegment segment = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; WellPlanSegment segment = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
cvf::Vec3d p1p2 = p2 - p1; cvf::Vec3d p1p2 = p2 - p1;
double length = p1p2.length(); double length = p1p2.length();
@ -107,7 +110,7 @@ void RiaWellPlanCalculator::addLineSegment( cvf::Vec3d p1, cvf::Vec3d p2, cvf::V
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
void RiaWellPlanCalculator::addArcSegment( cvf::Vec3d t1, cvf::Vec3d p1, cvf::Vec3d p2, cvf::Vec3d* endTangent ) void RiaWellPlanCalculator::addArcSegment( cvf::Vec3d t1, cvf::Vec3d p1, cvf::Vec3d p2, cvf::Vec3d* endTangent )
{ {
WellPlanSegment segment = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; WellPlanSegment segment = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
RiaArcCurveCalculator arcCalc( p1, t1, p2 ); RiaArcCurveCalculator arcCalc( p1, t1, p2 );

View File

@ -86,7 +86,7 @@ void RicExportSelectedWellPathsFeature::writeWellPathGeometryToStream( QTextStre
} }
else else
{ {
rkb = modeledWellPath->geometryDefinition()->mdrkbAtFirstTarget(); rkb = modeledWellPath->geometryDefinition()->mdAtFirstTarget();
} }
} }
} }
@ -124,10 +124,10 @@ void RicExportSelectedWellPathsFeature::writeWellPathGeometryToStream( QTextStre
stream << "WELLNAME: '" << caf::Utils::makeValidFileBasename( exportName ) << "'" << endl; stream << "WELLNAME: '" << caf::Utils::makeValidFileBasename( exportName ) << "'" << endl;
auto numberFormat = RifTextDataTableDoubleFormatting( RIF_FLOAT, 2 ); auto numberFormat = RifTextDataTableDoubleFormatting( RIF_FLOAT, 2 );
formatter.header( {{"X", numberFormat, RIGHT}, formatter.header( { { "X", numberFormat, RIGHT },
{"Y", numberFormat, RIGHT}, { "Y", numberFormat, RIGHT },
{"TVDMSL", numberFormat, RIGHT}, { "TVDMSL", numberFormat, RIGHT },
{useMdRkb ? "MDRKB" : "MDMSL", numberFormat, RIGHT}} ); { useMdRkb ? "MDRKB" : "MDMSL", numberFormat, RIGHT } } );
while ( currMd < endMd ) while ( currMd < endMd )
{ {

View File

@ -149,16 +149,16 @@ bool RicCreateWellTargetsPickEventHandler::handle3dPickEvent( const Ric3dPickEve
if ( wellPathSourceInfo ) if ( wellPathSourceInfo )
{ {
double mdrkbAtFirstTarget = double mdAtFirstTarget =
wellPathSourceInfo->measuredDepth( firstPickItem.faceIdx(), intersectionPointInDomain ); wellPathSourceInfo->measuredDepth( firstPickItem.faceIdx(), intersectionPointInDomain );
RimModeledWellPath* modeledWellPath = dynamic_cast<RimModeledWellPath*>( wellPathSourceInfo->wellPath() ); RimModeledWellPath* modeledWellPath = dynamic_cast<RimModeledWellPath*>( wellPathSourceInfo->wellPath() );
if ( modeledWellPath ) if ( modeledWellPath )
{ {
mdrkbAtFirstTarget += modeledWellPath->geometryDefinition()->mdrkbAtFirstTarget(); mdAtFirstTarget += modeledWellPath->geometryDefinition()->mdAtFirstTarget();
} }
m_geometryToAddTargetsTo->setMdrkbAtFirstTarget( mdrkbAtFirstTarget ); m_geometryToAddTargetsTo->setMdAtFirstTarget( mdAtFirstTarget );
} }
} }

View File

@ -132,19 +132,17 @@ QString RimModeledWellPath::wellPlanText()
formatter.setTableRowLineAppendText( "" ); formatter.setTableRowLineAppendText( "" );
std::vector<RifTextDataTableColumn> tableHeader; std::vector<RifTextDataTableColumn> tableHeader;
tableHeader.push_back( {"MDRKB"} ); std::vector<QString> columns = { "MDRKB", "CL", "Inc", "Azi", "TVDMSL", "NS", "EW", "Dogleg", "Build", "Turn" };
tableHeader.push_back( {"CL"} ); for ( QString column : columns )
tableHeader.push_back( {"Inc"} ); {
tableHeader.push_back( {"Azi"} ); tableHeader.push_back(
tableHeader.push_back( {"TVDMSL"} ); RifTextDataTableColumn( column,
tableHeader.push_back( {"NS"} ); RifTextDataTableDoubleFormatting( RifTextDataTableDoubleFormat::RIF_FLOAT, 2 ) ) );
tableHeader.push_back( {"EW"} ); }
tableHeader.push_back( {"Dogleg"} );
tableHeader.push_back( {"Build"} );
tableHeader.push_back( {"Turn"} );
formatter.header( tableHeader ); formatter.header( tableHeader );
double mdrkbAtFirstTarget = m_geometryDefinition->mdrkbAtFirstTarget(); double mdrkbAtFirstTarget = m_geometryDefinition->mdAtFirstTarget() + m_geometryDefinition->airGap();
if ( m_geometryDefinition ) if ( m_geometryDefinition )
{ {
std::vector<RiaWellPlanCalculator::WellPlanSegment> wellPlan = m_geometryDefinition->wellPlan(); std::vector<RiaWellPlanCalculator::WellPlanSegment> wellPlan = m_geometryDefinition->wellPlan();

View File

@ -128,7 +128,7 @@ void RimWellPathGeometryDef::setAirGap( double airGap )
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
double RimWellPathGeometryDef::mdrkbAtFirstTarget() const double RimWellPathGeometryDef::mdAtFirstTarget() const
{ {
return m_mdAtFirstTarget; return m_mdAtFirstTarget;
} }
@ -136,9 +136,9 @@ double RimWellPathGeometryDef::mdrkbAtFirstTarget() const
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
void RimWellPathGeometryDef::setMdrkbAtFirstTarget( double mdrkb ) void RimWellPathGeometryDef::setMdAtFirstTarget( double md )
{ {
m_mdAtFirstTarget = mdrkb; m_mdAtFirstTarget = md;
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -148,8 +148,6 @@ cvf::ref<RigWellPath> RimWellPathGeometryDef::createWellPathGeometry()
{ {
cvf::ref<RigWellPath> wellPathGeometry = new RigWellPath; cvf::ref<RigWellPath> wellPathGeometry = new RigWellPath;
updateTargetAtSeaLevel();
RiaLineArcWellPathCalculator wellPathCalculator = lineArcWellPathCalculator(); RiaLineArcWellPathCalculator wellPathCalculator = lineArcWellPathCalculator();
if ( wellPathCalculator.lineArcEndpoints().size() < 2 ) return wellPathGeometry; if ( wellPathCalculator.lineArcEndpoints().size() < 2 ) return wellPathGeometry;
@ -165,6 +163,7 @@ cvf::ref<RigWellPath> RimWellPathGeometryDef::createWellPathGeometry()
{ {
wellPathGeometry->setDatumElevation( m_airGap ); wellPathGeometry->setDatumElevation( m_airGap );
} }
updateTargetAtSeaLevel();
return wellPathGeometry; return wellPathGeometry;
} }
@ -212,7 +211,7 @@ std::pair<RimWellPathTarget*, RimWellPathTarget*>
if ( wt->isEnabled() && !foundTarget ) before = wt; if ( wt->isEnabled() && !foundTarget ) before = wt;
} }
return {before, after}; return { before, after };
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -364,7 +363,7 @@ std::vector<RimWellPathTarget*> RimWellPathGeometryDef::activeWellTargets() cons
{ {
std::vector<RimWellPathTarget*> active; std::vector<RimWellPathTarget*> active;
if ( m_useAutoGeneratedTargetAtSeaLevel() && !m_wellTargets.empty() ) if ( m_useAutoGeneratedTargetAtSeaLevel && !m_wellTargets.empty() && m_autoTargetAtSeaLevel )
{ {
active.push_back( m_autoTargetAtSeaLevel.get() ); active.push_back( m_autoTargetAtSeaLevel.get() );
} }
@ -385,42 +384,43 @@ std::vector<RimWellPathTarget*> RimWellPathGeometryDef::activeWellTargets() cons
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
RiaLineArcWellPathCalculator RimWellPathGeometryDef::lineArcWellPathCalculator() const RiaLineArcWellPathCalculator RimWellPathGeometryDef::lineArcWellPathCalculator() const
{ {
std::vector<RimWellPathTarget*> wellTargets = activeWellTargets();
std::vector<RiaLineArcWellPathCalculator::WellTarget> targetDatas; std::vector<RiaLineArcWellPathCalculator::WellTarget> targetDatas;
for ( auto wellTarget : wellTargets ) for ( auto wellTarget : m_wellTargets )
{ {
targetDatas.push_back( wellTarget->wellTargetData() ); if ( wellTarget->isEnabled() )
{
targetDatas.push_back( wellTarget->wellTargetData() );
}
} }
RiaLineArcWellPathCalculator wellPathCalculator( referencePointXyz(), targetDatas ); RiaLineArcWellPathCalculator wellPathCalculator( referencePointXyz(), targetDatas );
const std::vector<RiaLineArcWellPathCalculator::WellTargetStatus>& targetStatuses = const std::vector<RiaLineArcWellPathCalculator::WellTargetStatus>& targetStatuses =
wellPathCalculator.targetStatuses(); wellPathCalculator.targetStatuses();
for ( size_t tIdx = 0; tIdx < wellTargets.size(); ++tIdx ) for ( size_t tIdx = 0; tIdx < m_wellTargets.size(); ++tIdx )
{ {
wellTargets[tIdx]->flagRadius1AsIncorrect( targetStatuses[tIdx].isRadius1Editable, false, 0 ); m_wellTargets[tIdx]->flagRadius1AsIncorrect( targetStatuses[tIdx].isRadius1Editable, false, 0 );
wellTargets[tIdx]->flagRadius2AsIncorrect( targetStatuses[tIdx].isRadius2Editable, false, 0 ); m_wellTargets[tIdx]->flagRadius2AsIncorrect( targetStatuses[tIdx].isRadius2Editable, false, 0 );
if ( targetStatuses[tIdx].hasDerivedTangent ) if ( targetStatuses[tIdx].hasDerivedTangent )
{ {
wellTargets[tIdx]->setDerivedTangent( targetStatuses[tIdx].resultAzimuth, m_wellTargets[tIdx]->setDerivedTangent( targetStatuses[tIdx].resultAzimuth,
targetStatuses[tIdx].resultInclination ); targetStatuses[tIdx].resultInclination );
} }
if ( targetStatuses[tIdx].hasOverriddenRadius1 ) if ( targetStatuses[tIdx].hasOverriddenRadius1 )
{ {
wellTargets[tIdx]->flagRadius1AsIncorrect( targetStatuses[tIdx].isRadius1Editable, m_wellTargets[tIdx]->flagRadius1AsIncorrect( targetStatuses[tIdx].isRadius1Editable,
true, true,
targetStatuses[tIdx].resultRadius1 ); targetStatuses[tIdx].resultRadius1 );
} }
if ( targetStatuses[tIdx].hasOverriddenRadius2 ) if ( targetStatuses[tIdx].hasOverriddenRadius2 )
{ {
wellTargets[tIdx]->flagRadius2AsIncorrect( targetStatuses[tIdx].isRadius2Editable, m_wellTargets[tIdx]->flagRadius2AsIncorrect( targetStatuses[tIdx].isRadius2Editable,
true, true,
targetStatuses[tIdx].resultRadius2 ); targetStatuses[tIdx].resultRadius2 );
} }
} }
@ -452,7 +452,7 @@ void RimWellPathGeometryDef::updateTargetAtSeaLevel()
newPos = firstTarget->targetPointXYZ() - horizontalLengthFromTarget * tangentInHorizontalPlane; newPos = firstTarget->targetPointXYZ() - horizontalLengthFromTarget * tangentInHorizontalPlane;
newPos.z() = -referencePointXyz().z(); newPos.z() = -referencePointXyz().z();
m_autoTargetAtSeaLevel->setAsPointXYZAndTangentTarget( {newPos[0], newPos[1], newPos[2]}, 0, 0 ); m_autoTargetAtSeaLevel->setAsPointXYZAndTangentTarget( { newPos[0], newPos[1], newPos[2] }, 0, 0 );
} }
} }

View File

@ -48,8 +48,8 @@ public:
double airGap() const; double airGap() const;
void setAirGap( double airGap ); void setAirGap( double airGap );
double mdrkbAtFirstTarget() const; double mdAtFirstTarget() const;
void setMdrkbAtFirstTarget( double mdrkb ); void setMdAtFirstTarget( double mdrkb );
cvf::ref<RigWellPath> createWellPathGeometry(); cvf::ref<RigWellPath> createWellPathGeometry();