Rename ApplicationCode to ApplicationLibCode

This commit is contained in:
Gaute Lindkvist
2021-01-06 14:55:29 +01:00
parent 751df1a421
commit 81699db187
3242 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,34 @@
set (SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RiaPolyArcLineSampler.h
${CMAKE_CURRENT_LIST_DIR}/RiaWellPlanCalculator.h
${CMAKE_CURRENT_LIST_DIR}/RiaSCurveCalculator.h
${CMAKE_CURRENT_LIST_DIR}/RiaArcCurveCalculator.h
${CMAKE_CURRENT_LIST_DIR}/RiaJCurveCalculator.h
${CMAKE_CURRENT_LIST_DIR}/RiaLineArcWellPathCalculator.h
)
set (SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RiaPolyArcLineSampler.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaWellPlanCalculator.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaSCurveCalculator.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaArcCurveCalculator.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaJCurveCalculator.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaLineArcWellPathCalculator.cpp
)
list(APPEND CODE_HEADER_FILES
${SOURCE_GROUP_HEADER_FILES}
)
list(APPEND CODE_SOURCE_FILES
${SOURCE_GROUP_SOURCE_FILES}
)
set (QT_MOC_HEADERS
${QT_MOC_HEADERS}
)
source_group( "Application\\Tools\\WellPathTools" FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} ${CMAKE_CURRENT_LIST_DIR}/CMakeLists_files.cmake )

View File

@@ -0,0 +1,102 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2018- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RiaArcCurveCalculator.h"
#include "RiaOffshoreSphericalCoords.h"
#include "cvfGeometryTools.h"
//--------------------------------------------------------------------------------------------------
/// + p1
/// t1 **
/// * + C
/// *
/// + p2
//--------------------------------------------------------------------------------------------------
RiaArcCurveCalculator::RiaArcCurveCalculator( cvf::Vec3d p1, cvf::Vec3d t1, cvf::Vec3d p2 )
: m_radius( std::numeric_limits<double>::infinity() )
, m_arcCS( cvf::Mat4d::ZERO )
, m_endAzi( 0 )
, m_endInc( 0 )
, m_curveStatus( OK )
{
bool isOk = t1.normalize();
if ( !isOk )
{
// No tangent. Bail out
m_curveStatus = FAILED_INPUT_OVERLAP;
return;
}
cvf::Vec3d p1p2 = p2 - p1;
cvf::Vec3d t12 = p1p2.getNormalized( &isOk );
if ( !isOk )
{
// p1 and p2 in the same place.
m_curveStatus = FAILED_INPUT_OVERLAP;
return;
}
cvf::Vec3d N = ( t1 ^ t12 ).getNormalized( &isOk );
if ( !isOk )
{
// P2 is on the p1 + k*t1 line. We have a straight line
m_curveStatus = OK_STRAIGHT_LINE;
RiaOffshoreSphericalCoords endTangent( t1 );
m_endTangent = t1;
m_endAzi = endTangent.azi();
m_endInc = endTangent.inc();
m_radius = std::numeric_limits<double>::infinity();
m_arcAngle = 0;
m_arcLength = p1p2.length();
return;
}
cvf::Vec3d tr1 = ( N ^ t1 ).getNormalized();
m_radius = 0.5 * p1p2.length() / ( tr1.dot( t12 ) );
cvf::Vec3d C = p1 + m_radius * tr1;
cvf::Vec3d nTr1 = -tr1;
m_arcCS = cvf::Mat4d::fromCoordSystemAxes( &nTr1, &t1, &N );
m_arcCS.setTranslation( C );
m_arcAngle = cvf::GeometryTools::getAngle( N, p1 - C, p2 - C );
m_arcLength = m_radius * m_arcAngle;
m_endTangent = N ^ ( p2 - C ).getNormalized();
RiaOffshoreSphericalCoords endTangent( m_endTangent );
m_endAzi = endTangent.azi();
m_endInc = endTangent.inc();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaArcCurveCalculator::RiaArcCurveCalculator( cvf::Vec3d p1, double azi1, double inc1, cvf::Vec3d p2 )
{
cvf::Vec3d t1( RiaOffshoreSphericalCoords::unitVectorFromAziInc( azi1, inc1 ) );
( *this ) = RiaArcCurveCalculator( p1, t1, p2 );
}

View File

@@ -0,0 +1,68 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2018- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cvfMatrix4.h"
#include "cvfVector3.h"
//--------------------------------------------------------------------------------------------------
/// + p1
/// t1 **
/// * + C
/// *
/// + p2
//--------------------------------------------------------------------------------------------------
class RiaArcCurveCalculator
{
public:
RiaArcCurveCalculator( cvf::Vec3d p1, cvf::Vec3d t1, cvf::Vec3d p2 );
RiaArcCurveCalculator( cvf::Vec3d p1, double azi1, double inc1, cvf::Vec3d p2 );
enum CurveStatus
{
OK,
OK_STRAIGHT_LINE,
FAILED_INPUT_OVERLAP
};
CurveStatus curveStatus() const { return m_curveStatus; }
cvf::Mat4d arcCS() const { return m_arcCS; }
double radius() const { return m_radius; }
double arcAngle() const { return m_arcAngle; }
double arcLength() const { return m_arcLength; }
cvf::Vec3d center() const { return m_arcCS.translation(); }
cvf::Vec3d normal() const { return cvf::Vec3d( m_arcCS.col( 2 ) ); }
double endAzimuth() const { return m_endAzi; }
double endInclination() const { return m_endInc; }
cvf::Vec3d endTangent() const { return m_endTangent; }
private:
CurveStatus m_curveStatus;
double m_radius;
double m_arcLength;
double m_arcAngle;
cvf::Mat4d m_arcCS;
double m_endAzi;
double m_endInc;
cvf::Vec3d m_endTangent;
};

View File

@@ -0,0 +1,95 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2018- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RiaJCurveCalculator.h"
#include "RiaArcCurveCalculator.h"
#include "RiaOffshoreSphericalCoords.h"
#include "cvfMatrix3.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaJCurveCalculator::RiaJCurveCalculator( cvf::Vec3d p1, double azi1, double inc1, double r1, cvf::Vec3d p2 )
: m_c1( cvf::Vec3d::UNDEFINED )
, m_n1( cvf::Vec3d::UNDEFINED )
, m_radius( std::numeric_limits<double>::infinity() )
, m_curveStatus( OK )
{
cvf::Vec3d t1( RiaOffshoreSphericalCoords::unitVectorFromAziInc( azi1, inc1 ) );
cvf::Vec3d p1p2 = p2 - p1;
cvf::Vec3d tr1 = p1p2 - ( p1p2.dot( t1 ) ) * t1;
double tr1Length = tr1.length();
if ( tr1Length < 1e-9 )
{
// p2 is on the p1 + t12 line. Degenerates to a line.
m_curveStatus = OK_STRAIGHT_LINE;
m_firstArcEndpoint = p2;
m_endAzi = azi1;
m_endInc = inc1;
return;
}
tr1 /= tr1Length;
cvf::Vec3d c1 = p1 + r1 * tr1;
cvf::Vec3d p2c1 = c1 - p2;
double p2c1Length = p2c1.length();
if ( p2c1Length < r1 || r1 == std::numeric_limits<double>::infinity() )
{
// Radius is too big. We can not get to point 2 using the requested radius.
m_curveStatus = FAILED_RADIUS_TOO_LARGE;
RiaArcCurveCalculator arc( p1, t1, p2 );
if ( arc.curveStatus() == RiaArcCurveCalculator::OK || arc.curveStatus() == RiaArcCurveCalculator::OK_STRAIGHT_LINE )
{
m_c1 = arc.center();
m_n1 = arc.normal();
m_firstArcEndpoint = p2;
m_endAzi = arc.endAzimuth();
m_endInc = arc.endInclination();
m_radius = arc.radius();
}
else
{
m_firstArcEndpoint = p2;
m_endAzi = azi1;
m_endInc = inc1;
}
return;
}
double d = sqrt( p2c1Length * p2c1Length - r1 * r1 );
double betha = asin( r1 / p2c1Length );
cvf::Vec3d tp2c1 = p2c1 / p2c1Length;
cvf::Vec3d nc1 = t1 ^ tr1;
cvf::Vec3d tp11p2 = -tp2c1.getTransformedVector( cvf::Mat3d::fromRotation( nc1, betha ) );
m_firstArcEndpoint = p2 - d * tp11p2;
m_c1 = c1;
m_n1 = nc1;
RiaOffshoreSphericalCoords endTangent( tp11p2 );
m_endAzi = endTangent.azi();
m_endInc = endTangent.inc();
}

View File

@@ -0,0 +1,67 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2018- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cvfVector3.h"
//--------------------------------------------------------------------------------------------------
/// + p1
/// t1 **
/// * r1 + C
/// *
/// + firstArcEndpoint
/// *
/// *
/// + p2
//--------------------------------------------------------------------------------------------------
class RiaJCurveCalculator
{
public:
RiaJCurveCalculator( cvf::Vec3d p1, double azi1, double inc1, double r1, cvf::Vec3d p2 );
enum CurveStatus
{
OK,
OK_STRAIGHT_LINE,
FAILED_INPUT_OVERLAP,
FAILED_RADIUS_TOO_LARGE
};
CurveStatus curveStatus() const { return m_curveStatus; }
cvf::Vec3d firstArcEndpoint() const { return m_firstArcEndpoint; }
double radius() const { return m_radius; }
cvf::Vec3d firstCenter() const { return m_c1; }
cvf::Vec3d firstNormal() const { return m_n1; }
double endAzimuth() const { return m_endAzi; }
double endInclination() const { return m_endInc; }
private:
CurveStatus m_curveStatus;
cvf::Vec3d m_firstArcEndpoint;
double m_radius;
cvf::Vec3d m_c1;
cvf::Vec3d m_n1;
double m_endAzi;
double m_endInc;
};

View File

@@ -0,0 +1,297 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2018- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RiaLineArcWellPathCalculator.h"
#include "RiaJCurveCalculator.h"
#include "RiaOffshoreSphericalCoords.h"
#include "RiaSCurveCalculator.h"
#include "cvfAssert.h"
#define M_PI 3.14159265358979323846 // pi
cvf::Vec3d smootheningTargetTangent( const cvf::Vec3d& p1, const cvf::Vec3d& p2, const cvf::Vec3d& p3 );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaLineArcWellPathCalculator::RiaLineArcWellPathCalculator( const cvf::Vec3d& referencePointXyz,
const std::vector<WellTarget>& activeWellPathTargets )
{
// Handle incomplete input
if ( activeWellPathTargets.size() < 2 )
{
m_startTangent = cvf::Vec3d::ZERO;
if ( activeWellPathTargets.size() == 1 )
{
m_lineArcEndpoints.push_back( activeWellPathTargets[0].targetPointXYZ + referencePointXyz );
m_targetStatuses.resize( activeWellPathTargets.size(),
{ !activeWellPathTargets[0].isTangentConstrained,
0.0,
0.0,
false,
true,
std::numeric_limits<double>::infinity(),
false,
true,
std::numeric_limits<double>::infinity() } );
}
return;
}
m_targetStatuses.resize( activeWellPathTargets.size(),
{ false,
0.0,
0.0,
false,
false,
std::numeric_limits<double>::infinity(),
false,
false,
std::numeric_limits<double>::infinity() } );
std::vector<WellTarget> adjustedWellPathTargets = activeWellPathTargets;
// Calculate sensible tangents for targets without a fixed one
if ( activeWellPathTargets.size() > 2 )
{
for ( size_t tIdx = 0; tIdx < activeWellPathTargets.size() - 2; ++tIdx )
{
if ( !activeWellPathTargets[tIdx + 1].isTangentConstrained )
{
cvf::Vec3d tangent = smootheningTargetTangent( activeWellPathTargets[tIdx].targetPointXYZ,
activeWellPathTargets[tIdx + 1].targetPointXYZ,
activeWellPathTargets[tIdx + 2].targetPointXYZ );
RiaOffshoreSphericalCoords tangentSphCS( tangent );
adjustedWellPathTargets[tIdx + 1].azimuth = tangentSphCS.azi();
adjustedWellPathTargets[tIdx + 1].inclination = tangentSphCS.inc();
adjustedWellPathTargets[tIdx + 1].isTangentConstrained = true;
m_targetStatuses[tIdx + 1].hasDerivedTangent = true;
m_targetStatuses[tIdx + 1].resultAzimuth = tangentSphCS.azi();
m_targetStatuses[tIdx + 1].resultInclination = tangentSphCS.inc();
}
}
}
m_lineArcEndpoints.push_back( activeWellPathTargets[0].targetPointXYZ + referencePointXyz );
// Handle first segment if it is not an S-Curve
size_t startSSegmentIdx = 0;
size_t endSSegementIdx = activeWellPathTargets.size() - 1;
if ( !adjustedWellPathTargets[0].isTangentConstrained )
{
startSSegmentIdx = 1;
const WellTarget& target1 = adjustedWellPathTargets[0];
const WellTarget& target2 = adjustedWellPathTargets[1];
WellTargetStatus& target1Status = m_targetStatuses[0];
WellTargetStatus& target2Status = m_targetStatuses[1];
if ( adjustedWellPathTargets[1].isTangentConstrained )
{
// Create an upside down J curve from target 2 back to 1
RiaJCurveCalculator jCurve( target2.targetPointXYZ,
target2.azimuth + M_PI,
M_PI - target2.inclination,
target2.radius1,
target1.targetPointXYZ );
if ( jCurve.curveStatus() == RiaJCurveCalculator::OK )
{
m_lineArcEndpoints.push_back( jCurve.firstArcEndpoint() + referencePointXyz );
}
else if ( jCurve.curveStatus() == RiaJCurveCalculator::FAILED_RADIUS_TOO_LARGE )
{
target2Status.hasOverriddenRadius1 = true;
target2Status.resultRadius1 = jCurve.radius();
}
m_lineArcEndpoints.push_back( target2.targetPointXYZ + referencePointXyz );
target1Status.hasDerivedTangent = true;
target1Status.resultAzimuth = jCurve.endAzimuth() + M_PI;
target1Status.resultInclination = M_PI - jCurve.endInclination();
target2Status.isRadius1Editable = true;
}
else // The complete wellpath is a straight line from target 1 to 2
{
m_lineArcEndpoints.push_back( target2.targetPointXYZ + referencePointXyz );
cvf::Vec3d t12 = target2.targetPointXYZ - target1.targetPointXYZ;
RiaOffshoreSphericalCoords t12Sph( t12 );
target1Status.hasDerivedTangent = true;
target1Status.resultAzimuth = t12Sph.azi();
target1Status.resultInclination = t12Sph.inc();
target2Status.hasDerivedTangent = true;
target2Status.resultAzimuth = t12Sph.azi();
target2Status.resultInclination = t12Sph.inc();
}
m_startTangent = RiaOffshoreSphericalCoords::unitVectorFromAziInc( target1Status.resultAzimuth,
target1Status.resultInclination );
}
else
{
m_startTangent = RiaOffshoreSphericalCoords::unitVectorFromAziInc( activeWellPathTargets[0].azimuth,
activeWellPathTargets[0].inclination );
}
if ( !adjustedWellPathTargets.back().isTangentConstrained )
{
endSSegementIdx -= 1;
}
// Calculate S-curves
if ( activeWellPathTargets.size() > 1 )
{
for ( size_t tIdx = startSSegmentIdx; tIdx < endSSegementIdx; ++tIdx )
{
const WellTarget& target1 = adjustedWellPathTargets[tIdx];
const WellTarget& target2 = adjustedWellPathTargets[tIdx + 1];
WellTargetStatus& target1Status = m_targetStatuses[tIdx];
WellTargetStatus& target2Status = m_targetStatuses[tIdx + 1];
// Ignore targets in the same place
if ( ( target1.targetPointXYZ - target2.targetPointXYZ ).length() < 1e-6 ) continue;
if ( target1.isTangentConstrained && target2.isTangentConstrained )
{
RiaSCurveCalculator sCurveCalc( target1.targetPointXYZ,
target1.azimuth,
target1.inclination,
target1.radius2,
target2.targetPointXYZ,
target2.azimuth,
target2.inclination,
target2.radius1 );
if ( sCurveCalc.solveStatus() != RiaSCurveCalculator::CONVERGED )
{
double p1p2Length = ( target2.targetPointXYZ - target1.targetPointXYZ ).length();
sCurveCalc = RiaSCurveCalculator::fromTangentsAndLength( target1.targetPointXYZ,
target1.azimuth,
target1.inclination,
0.2 * p1p2Length,
target2.targetPointXYZ,
target2.azimuth,
target2.inclination,
0.2 * p1p2Length );
// RiaLogging::warning("Using fall-back calculation of well path geometry between active target
// number: " + QString::number(tIdx+1) + " and " + QString::number(tIdx+2));
target1Status.hasOverriddenRadius2 = true;
target1Status.resultRadius2 = sCurveCalc.firstRadius();
target2Status.hasOverriddenRadius1 = true;
target2Status.resultRadius1 = sCurveCalc.secondRadius();
}
m_lineArcEndpoints.push_back( sCurveCalc.firstArcEndpoint() + referencePointXyz );
m_lineArcEndpoints.push_back( sCurveCalc.secondArcStartpoint() + referencePointXyz );
m_lineArcEndpoints.push_back( target2.targetPointXYZ + referencePointXyz );
target1Status.isRadius2Editable = true;
target2Status.isRadius1Editable = true;
}
}
}
// Handle last segment if (its not the same as the first) and it has not been handled as an S-Curve
if ( adjustedWellPathTargets.size() > 2 && endSSegementIdx < ( adjustedWellPathTargets.size() - 1 ) )
{
size_t targetCount = adjustedWellPathTargets.size();
const WellTarget& target1 = adjustedWellPathTargets[targetCount - 2];
const WellTarget& target2 = adjustedWellPathTargets[targetCount - 1];
WellTargetStatus& target1Status = m_targetStatuses[targetCount - 2];
WellTargetStatus& target2Status = m_targetStatuses[targetCount - 1];
// Create an ordinary J curve
RiaJCurveCalculator jCurve( target1.targetPointXYZ,
target1.azimuth,
target1.inclination,
target1.radius2,
target2.targetPointXYZ );
if ( jCurve.curveStatus() == RiaJCurveCalculator::OK )
{
m_lineArcEndpoints.push_back( jCurve.firstArcEndpoint() + referencePointXyz );
}
else if ( jCurve.curveStatus() == RiaJCurveCalculator::FAILED_RADIUS_TOO_LARGE )
{
target1Status.hasOverriddenRadius2 = true;
target1Status.resultRadius2 = jCurve.radius();
}
m_lineArcEndpoints.push_back( target2.targetPointXYZ + referencePointXyz );
target1Status.isRadius2Editable = true;
target2Status.hasDerivedTangent = true;
target2Status.resultAzimuth = jCurve.endAzimuth();
target2Status.resultInclination = jCurve.endInclination();
}
}
cvf::Vec3d smootheningTargetTangent( const cvf::Vec3d& p1, const cvf::Vec3d& p2, const cvf::Vec3d& p3 )
{
cvf::Vec3d t12 = p2 - p1;
cvf::Vec3d t23 = p3 - p2;
double length12 = t12.length();
double length23 = t23.length();
t12 /= length12; // Normalize
t23 /= length23; // Normalize
cvf::Vec3d t1t2Hor( t12 );
t1t2Hor.z() = 0.0;
double t12HorLength = t1t2Hor.length();
cvf::Vec3d t23Hor( t23 );
t23Hor.z() = 0.0;
double t23HorLength = t23Hor.length();
// Calculate weights as combo of inverse distance and horizontal component
double w12 = t12HorLength * 1.0 / length12;
double w23 = t23HorLength * 1.0 / length23;
// Weight the tangents
t12 *= w12; // Weight
t23 *= w23; // Weight
// Sum and normalization of weights
cvf::Vec3d averageTangent = 1.0 / ( w12 + w23 ) * ( t12 + t23 );
return averageTangent;
}

View File

@@ -0,0 +1,65 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2018- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cvfVector3.h"
#include <vector>
class RiaLineArcWellPathCalculator
{
public:
struct WellTarget
{
cvf::Vec3d targetPointXYZ;
bool isTangentConstrained;
double azimuth;
double inclination;
double radius1;
double radius2;
};
RiaLineArcWellPathCalculator( const cvf::Vec3d& referencePointXyz,
const std::vector<RiaLineArcWellPathCalculator::WellTarget>& targets );
struct WellTargetStatus
{
bool hasDerivedTangent;
double resultAzimuth;
double resultInclination;
bool isRadius1Editable;
bool hasOverriddenRadius1;
double resultRadius1;
bool isRadius2Editable;
bool hasOverriddenRadius2;
double resultRadius2;
};
cvf::Vec3d startTangent() const { return m_startTangent; }
const std::vector<cvf::Vec3d>& lineArcEndpoints() const { return m_lineArcEndpoints; }
const std::vector<WellTargetStatus>& targetStatuses() const { return m_targetStatuses; }
private:
cvf::Vec3d m_startTangent;
std::vector<cvf::Vec3d> m_lineArcEndpoints;
std::vector<WellTargetStatus> m_targetStatuses;
};

View File

@@ -0,0 +1,188 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2018- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RiaPolyArcLineSampler.h"
#include "RiaArcCurveCalculator.h"
#include "cvfGeometryTools.h"
#include "cvfMatrix4.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaPolyArcLineSampler::RiaPolyArcLineSampler( const cvf::Vec3d& startTangent,
const std::vector<cvf::Vec3d>& lineArcEndPoints )
: m_startTangent( startTangent )
, m_lineArcEndPoints( lineArcEndPoints )
, m_maxSamplingsInterval( 0.15 )
, m_isResamplingLines( true )
, m_totalMD( 0.0 )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::pair<std::vector<cvf::Vec3d>, std::vector<double>>
RiaPolyArcLineSampler::sampledPointsAndMDs( double sampleInterval, bool isResamplingLines )
{
CVF_ASSERT( sampleInterval > 0.0 );
m_maxSamplingsInterval = sampleInterval;
m_isResamplingLines = isResamplingLines;
m_points.clear();
m_meshDs.clear();
double startMD = 0.0;
std::vector<cvf::Vec3d> pointsNoDuplicates = RiaPolyArcLineSampler::pointsWithoutDuplicates( m_lineArcEndPoints );
if ( pointsNoDuplicates.size() < 2 ) return std::make_pair( m_points, m_meshDs );
m_totalMD = startMD;
cvf::Vec3d p1 = pointsNoDuplicates[0];
m_points.push_back( p1 );
m_meshDs.push_back( m_totalMD );
cvf::Vec3d t2 = m_startTangent;
for ( size_t pIdx = 0; pIdx < pointsNoDuplicates.size() - 1; ++pIdx )
{
sampleSegment( t2, pointsNoDuplicates[pIdx], pointsNoDuplicates[pIdx + 1], &t2 );
}
return std::make_pair( m_points, m_meshDs );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaPolyArcLineSampler::sampleSegment( cvf::Vec3d t1, cvf::Vec3d p1, cvf::Vec3d p2, cvf::Vec3d* endTangent )
{
cvf::Vec3d p1p2 = p2 - p1;
CVF_ASSERT( p1p2.lengthSquared() > 1e-20 );
if ( cvf::GeometryTools::getAngle( t1, p1p2 ) < 1e-5 )
{
sampleLine( p1, p2, endTangent );
}
else // resample arc
{
sampleArc( t1, p1, p2, endTangent );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<cvf::Vec3d> RiaPolyArcLineSampler::pointsWithoutDuplicates( const std::vector<cvf::Vec3d>& points )
{
std::vector<cvf::Vec3d> outputPoints;
cvf::Vec3d previousPoint = cvf::Vec3d::UNDEFINED;
const double threshold = 1e-6;
for ( const auto& p : points )
{
if ( previousPoint.isUndefined() || ( ( previousPoint - p ).lengthSquared() ) > threshold )
{
outputPoints.push_back( p );
previousPoint = p;
}
}
return outputPoints;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaPolyArcLineSampler::sampleLine( cvf::Vec3d p1, cvf::Vec3d p2, cvf::Vec3d* endTangent )
{
cvf::Vec3d p1p2 = p2 - p1;
double p1p2Length = p1p2.length();
if ( m_isResamplingLines && p1p2Length > m_maxSamplingsInterval )
{
cvf::Vec3d tp1p2 = p1p2 / p1p2Length;
double mdInc = m_maxSamplingsInterval;
while ( mdInc < p1p2Length )
{
cvf::Vec3d ps = p1 + mdInc * tp1p2;
m_points.push_back( ps );
m_meshDs.push_back( m_totalMD + mdInc );
mdInc += m_maxSamplingsInterval;
}
}
m_totalMD += p1p2Length;
m_points.push_back( p2 );
m_meshDs.push_back( m_totalMD );
( *endTangent ) = p1p2.getNormalized();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaPolyArcLineSampler::sampleArc( cvf::Vec3d t1, cvf::Vec3d p1, cvf::Vec3d p2, cvf::Vec3d* endTangent )
{
// Find arc CS
RiaArcCurveCalculator CS_rad( p1, t1, p2 );
double radius = CS_rad.radius();
cvf::Mat4d arcCS = CS_rad.arcCS();
double angleInc = m_maxSamplingsInterval / radius;
angleInc = angleInc < m_maxSamplingArcAngle ? angleInc : m_maxSamplingArcAngle; // Angle from 6 deg dogleg on 10 m
cvf::Vec3d C = CS_rad.center();
cvf::Vec3d N = CS_rad.normal();
// Sample arc by
// Rotate vector an increment, and transform to arc CS
double arcAngle = cvf::GeometryTools::getAngle( N, p1 - C, p2 - C );
if ( arcAngle / angleInc > 5000 )
{
angleInc = arcAngle / 5000;
}
for ( double angle = angleInc; angle < arcAngle; angle += angleInc )
{
cvf::Vec3d C_to_incP = cvf::Vec3d::X_AXIS;
C_to_incP *= radius;
C_to_incP.transformVector( cvf::Mat3d::fromRotation( cvf::Vec3d::Z_AXIS, angle ) );
C_to_incP.transformPoint( arcCS );
m_points.push_back( C_to_incP );
m_meshDs.push_back( m_totalMD + angle * radius );
}
m_totalMD += arcAngle * radius;
m_points.push_back( p2 );
m_meshDs.push_back( m_totalMD );
( *endTangent ) = CS_rad.endTangent();
}

View File

@@ -0,0 +1,50 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2018- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cvfVector3.h"
#include <vector>
class RiaPolyArcLineSampler
{
public:
RiaPolyArcLineSampler( const cvf::Vec3d& startTangent, const std::vector<cvf::Vec3d>& lineArcEndPoints );
std::pair<std::vector<cvf::Vec3d>, std::vector<double>> sampledPointsAndMDs( double maxSampleInterval,
bool isResamplingLines );
static std::vector<cvf::Vec3d> pointsWithoutDuplicates( const std::vector<cvf::Vec3d>& points );
private:
void sampleLine( cvf::Vec3d p1, cvf::Vec3d p2, cvf::Vec3d* endTangent );
void sampleArc( cvf::Vec3d t1, cvf::Vec3d p1, cvf::Vec3d p2, cvf::Vec3d* endTangent );
void sampleSegment( cvf::Vec3d t1, cvf::Vec3d p1, cvf::Vec3d p2, cvf::Vec3d* endTangent );
std::vector<cvf::Vec3d> m_points;
std::vector<double> m_meshDs;
double m_maxSamplingsInterval;
const double m_maxSamplingArcAngle = 0.07310818; // Angle from 6 deg dogleg on 10 m
bool m_isResamplingLines;
double m_totalMD;
cvf::Vec3d m_startTangent;
std::vector<cvf::Vec3d> m_lineArcEndPoints;
};

View File

@@ -0,0 +1,478 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2018- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RiaSCurveCalculator.h"
#include "RiaOffshoreSphericalCoords.h"
#include "cvfMatrix4.h"
#include <cmath>
#include <iostream>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaSCurveCalculator::RiaSCurveCalculator( cvf::Vec3d p1,
double azi1,
double inc1,
double rad1,
cvf::Vec3d p2,
double azi2,
double inc2,
double rad2 )
: m_isCalculationOK( false )
, m_p1( p1 )
, m_p2( p2 )
, m_firstArcEndpoint( p1 + 0.3 * ( p2 - p1 ) )
, m_secondArcStartpoint( p1 + 0.6 * ( p2 - p1 ) )
, m_r1( rad1 )
, m_r2( rad2 )
, m_ctrlPpointCurveStatus( NOT_SET )
, m_solveStatus( NOT_SOLVED )
{
initializeByFinding_q1q2( p1, azi1, inc1, rad1, p2, azi2, inc2, rad2 );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaSCurveCalculator::RiaSCurveCalculator( cvf::Vec3d p1, cvf::Vec3d q1, cvf::Vec3d p2, cvf::Vec3d q2 )
: m_isCalculationOK( true )
, m_p1( p1 )
, m_p2( p2 )
, m_ctrlPpointCurveStatus( NOT_SET )
, m_solveStatus( NOT_SOLVED )
{
using Vec3d = cvf::Vec3d;
bool isOk = true;
m_isCalculationOK = true;
Vec3d tq1q2 = ( q2 - q1 ).getNormalized( &isOk ); // !ok means the control points are in the same place. Could
// fallback to use only one circle segment + one line.
m_isCalculationOK = m_isCalculationOK && isOk;
Vec3d t1 = ( q1 - p1 ).getNormalized( &isOk ); // !ok means no tangent specified. Could fallback to use only one
// circle segment + one line.
m_isCalculationOK = m_isCalculationOK && isOk;
Vec3d t2 = ( p2 - q2 ).getNormalized( &isOk ); // !ok means no tangent specified. Could fallback to use only one
// circle segment + one line or only one straight line if both
// tangents are missing
m_isCalculationOK = m_isCalculationOK && isOk;
if ( !m_isCalculationOK )
{
m_ctrlPpointCurveStatus = FAILED_INPUT_OVERLAP;
}
{
Vec3d td1 = ( tq1q2 - t1 );
double td1Length = td1.length();
if ( td1Length > 1e-10 )
{
td1 /= td1Length;
m_c1 = q1 + ( ( q1 - p1 ).length() / ( td1 * ( -t1 ) ) ) * td1;
m_r1 = ( m_c1 - p1 ).length();
}
else // both control points are along t1. First curve has infinite radius
{
m_c1 = cvf::Vec3d::UNDEFINED;
m_r1 = std::numeric_limits<double>::infinity();
if ( m_ctrlPpointCurveStatus == NOT_SET )
{
m_ctrlPpointCurveStatus = OK_INFINITE_RADIUS1;
}
}
}
{
Vec3d td2 = ( -tq1q2 + t2 );
double td2Length = td2.length();
if ( td2Length > 1e-10 )
{
td2 /= td2Length;
m_c2 = q2 + ( ( q2 - p2 ).length() / ( td2 * ( t2 ) ) ) * td2;
m_r2 = ( m_c2 - p2 ).length();
}
else // both control points are along t2. Second curve has infinite radius
{
m_c2 = cvf::Vec3d::UNDEFINED;
m_r2 = std::numeric_limits<double>::infinity();
if ( m_ctrlPpointCurveStatus == NOT_SET )
{
m_ctrlPpointCurveStatus = OK_INFINITE_RADIUS2;
}
else if ( m_ctrlPpointCurveStatus == OK_INFINITE_RADIUS1 )
{
m_ctrlPpointCurveStatus = OK_INFINITE_RADIUS12;
}
}
}
m_firstArcEndpoint = q1 + ( q1 - p1 ).length() * tq1q2;
m_secondArcStartpoint = q2 - ( q2 - p2 ).length() * tq1q2;
if ( ( ( q1 - p1 ).length() + ( q2 - p2 ).length() ) > ( q2 - q1 ).length() ) // first arc end and second arc start
// is overlapping
{
m_ctrlPpointCurveStatus = FAILED_ARC_OVERLAP;
m_isCalculationOK = false;
}
if ( m_ctrlPpointCurveStatus == NOT_SET )
{
m_ctrlPpointCurveStatus = OK;
}
// The Circle normals. Will be set to cvf::Vec3d::ZERO if undefined.
m_n1 = ( t1 ^ tq1q2 ).getNormalized();
m_n2 = ( tq1q2 ^ t2 ).getNormalized();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaSCurveCalculator RiaSCurveCalculator::fromTangentsAndLength( cvf::Vec3d p1,
double azi1,
double inc1,
double lengthToQ1,
cvf::Vec3d p2,
double azi2,
double inc2,
double lengthToQ2 )
{
cvf::Vec3d t1( RiaOffshoreSphericalCoords::unitVectorFromAziInc( azi1, inc1 ) );
cvf::Vec3d t2( RiaOffshoreSphericalCoords::unitVectorFromAziInc( azi2, inc2 ) );
cvf::Vec3d Q1 = p1 + lengthToQ1 * t1;
cvf::Vec3d Q2 = p2 - lengthToQ2 * t2;
RiaSCurveCalculator curveFromControlPoints( p1, Q1, p2, Q2 );
return curveFromControlPoints;
}
//--------------------------------------------------------------------------------------------------
///
/// Needs to calculate J^-1 * [R1_error, R2_error]
/// | dR1_dq1 dR1_dq2 | 1 | dR2_dq2 -dR1_dq2 |
/// J = | | J^-1 = ---------------------------------- | |
/// | dR2_dq1 dR2_dq2 | dR1_dq1*dR2_dq2 - dR1_dq2*dR2_dq1 | -dR2_dq1 dR1_dq1 |
///
/// | q1_step | | R1_Error |
/// | | = - J^-1 | |
/// | q2_step | | R2_Error |
///
//--------------------------------------------------------------------------------------------------
void calculateNewStepsFromJacobi( double dR1_dq1,
double dR1_dq2,
double dR2_dq1,
double dR2_dq2,
double R1_error,
double R2_error,
double* newStepq1,
double* newStepq2 )
{
double invJacobiScale = 1.0 / ( dR1_dq1 * dR2_dq2 - dR2_dq1 * dR1_dq2 );
double invJacobi_R1q1 = invJacobiScale * dR2_dq2;
double invJacobi_R1q2 = invJacobiScale * -dR1_dq2;
double invJacobi_R2q1 = invJacobiScale * -dR2_dq1;
double invJacobi_R2q2 = invJacobiScale * dR1_dq1;
( *newStepq1 ) = -( invJacobi_R1q1 * R1_error + invJacobi_R1q2 * R2_error );
( *newStepq2 ) = -( invJacobi_R2q1 * R1_error + invJacobi_R2q2 * R2_error );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool isZeroCrossing( double newError, double oldError, double maxError )
{
if ( ( newError < -maxError && maxError < oldError ) || ( newError > maxError && -maxError > oldError ) )
{
return true;
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
/// Iterating with changing q1, q2 (lengths along tangent) to find solution with R1 = r1 and R2 = r2
/// R1(q1, q2), R2(q1, q2)
///
//--------------------------------------------------------------------------------------------------
void RiaSCurveCalculator::initializeByFinding_q1q2( cvf::Vec3d p1,
double azi1,
double inc1,
double r1,
cvf::Vec3d p2,
double azi2,
double inc2,
double r2 )
{
// Algorithm options
const int maxIterations = 40;
const double maxError = 0.01;
const double maxStepSize = 1.0e9;
const double maxLengthToQ = 1.0e10;
bool enableBackstepping = false;
//#define USE_JACOBI_UPDATE
//#define DEBUG_OUTPUT_ON
// Needs the initial partial derivatives to see the direction of change
// dR1/dq1, dR1/dq2, dR2/dq1, dR2/dq2
// Selects a sensible point in the domain for the evaluation
double p1p2Length = ( p2 - p1 ).length();
double delta = 0.01 * p1p2Length;
double initialq1q2 = 0.2 * p1p2Length;
double deltaPos = initialq1q2 + delta;
RiaSCurveCalculator ev_0 =
RiaSCurveCalculator::fromTangentsAndLength( p1, azi1, inc1, initialq1q2, p2, azi2, inc2, initialq1q2 );
if ( ev_0.curveStatus() == RiaSCurveCalculator::OK_INFINITE_RADIUS12 )
{
*this = ev_0;
this->m_solveStatus = CONVERGED;
return;
} // Todo: Handle infinite radius in one place
RiaSCurveCalculator ev_dq1 =
RiaSCurveCalculator::fromTangentsAndLength( p1, azi1, inc1, deltaPos, p2, azi2, inc2, initialq1q2 );
RiaSCurveCalculator ev_dq2 =
RiaSCurveCalculator::fromTangentsAndLength( p1, azi1, inc1, initialq1q2, p2, azi2, inc2, deltaPos );
// Initial Jacobi
double dR1_dq1 = ( ( r1 - ev_dq1.firstRadius() ) - ( r1 - ev_0.firstRadius() ) ) / delta;
double dR2_dq2 = ( ( r2 - ev_dq2.secondRadius() ) - ( r2 - ev_0.secondRadius() ) ) / delta;
// Initial function value (error)
double R1_error = r1 - ev_0.firstRadius();
double R2_error = r2 - ev_0.secondRadius();
// First steps
double q1Step = -R1_error / dR1_dq1;
double q2Step = -R2_error / dR2_dq2;
#ifdef USE_JACOBI_UPDATE
double dR1_dq2 = ( ( r1 - ev_dq2.firstRadius() ) - ( r1 - ev_0.firstRadius() ) ) / delta;
double dR2_dq1 = ( ( r2 - ev_dq1.secondRadius() ) - ( r2 - ev_0.secondRadius() ) ) / delta;
calculateNewStepsFromJacobi( dR1_dq1, dR1_dq2, dR2_dq1, dR2_dq2, R1_error, R2_error, &q1Step, &q2Step );
#endif
double q1 = initialq1q2;
double q2 = initialq1q2;
#ifdef DEBUG_OUTPUT_ON
std::cout << std::endl;
std::cout << "Targets: R1, R2: " << r1 << " , " << r2 << std::endl;
std::cout << 0 << ": " << q1Step << " , " << q2Step << " : " << q1 << " , " << q2 << " | " << ev_0.isOk() << " : "
<< ev_0.firstRadius() << " , " << ev_0.secondRadius() << " : " << R1_error << " , " << R2_error
<< std::endl;
#endif
SolveStatus solveResultStatus = NOT_SOLVED;
int backstepLevel = 0;
int iteration = 1;
for ( iteration = 1; iteration < maxIterations; ++iteration )
{
if ( fabs( q1Step ) > maxStepSize || fabs( q2Step ) > maxStepSize )
{
solveResultStatus = FAILED_MAX_TANGENT_STEP_REACHED;
break;
}
std::string q1R1StepCorrMarker;
std::string q2R2StepCorrMarker;
if ( q1 + q1Step < 0 )
{
q1Step = -0.9 * q1;
q1R1StepCorrMarker = "*";
}
if ( q2 + q2Step < 0 )
{
q2Step = -0.9 * q2;
q2R2StepCorrMarker = "*";
}
q1 += q1Step;
q2 += q2Step;
if ( fabs( q1 ) > maxLengthToQ || fabs( q2 ) > maxLengthToQ )
{
/// Max length along tangent reached
solveResultStatus = FAILED_MAX_LENGTH_ALONG_TANGENT_REACHED;
break;
}
RiaSCurveCalculator ev_1 = RiaSCurveCalculator::fromTangentsAndLength( p1, azi1, inc1, q1, p2, azi2, inc2, q2 );
double R1_error_new = r1 - ev_1.firstRadius();
double R2_error_new = r2 - ev_1.secondRadius();
#ifdef DEBUG_OUTPUT_ON
std::cout << iteration << ": " << q1Step << q1R1StepCorrMarker << " , " << q2Step << q2R2StepCorrMarker << " : "
<< q1 << " , " << q2 << " | " << ev_1.isOk() << " : " << ev_1.firstRadius() << " , "
<< ev_1.secondRadius() << " : " << R1_error_new << " , " << R2_error_new;
#endif
if ( ( fabs( R1_error_new ) < maxError || ev_1.curveStatus() == OK_INFINITE_RADIUS1 ) &&
( fabs( R2_error_new ) < maxError || ev_1.curveStatus() == OK_INFINITE_RADIUS2 ) )
{
ev_0 = ev_1;
// Result ok !
solveResultStatus = CONVERGED;
#ifdef DEBUG_OUTPUT_ON
std::cout << std::endl;
#endif
break;
}
if ( enableBackstepping ) // Experimental back-stepping
{
bool isZeroCrossingR1 = isZeroCrossing( R1_error_new, R1_error, maxError );
bool isZeroCrossingR2 = isZeroCrossing( R2_error_new, R2_error, maxError );
if ( isZeroCrossingR2 || isZeroCrossingR1 )
{
q1 -= q1Step;
q2 -= q2Step;
// if (isZeroCrossingR1)
q1Step = 0.9 * q1Step * fabs( R1_error ) / ( fabs( R1_error_new ) + fabs( R1_error ) );
// if (isZeroCrossingR2)
q2Step = 0.9 * q2Step * fabs( R2_error ) / ( fabs( R2_error_new ) + fabs( R2_error ) );
++backstepLevel;
#ifdef DEBUG_OUTPUT_ON
std::cout << " Backstep needed. " << std::endl;
#endif
continue;
}
else
{
backstepLevel = 0;
}
}
#ifdef DEBUG_OUTPUT_ON
std::cout << std::endl;
#endif
#ifdef USE_JACOBI_UPDATE
/// Update Jacobi using Broyden
// (R_error_n-Rerror_n-1) - Jn-1*dq
// J_n = Jn-1 + --------------------------------- (dq)T
// | dqn |^2
//
double dR1_error = R1_error_new - R1_error;
double dR2_error = R2_error_new - R2_error;
R1_error = R1_error_new;
R2_error = R2_error_new;
double stepNormScale = 1.0 / ( q1Step * q1Step + q2Step * q2Step );
dR1_dq1 = dR1_dq1 + stepNormScale * ( q1Step * ( dR1_error - q1Step * dR1_dq1 + q2Step * dR1_dq2 ) );
dR1_dq2 = dR1_dq2 + stepNormScale * ( q2Step * ( dR1_error - q1Step * dR1_dq1 + q2Step * dR1_dq2 ) );
dR2_dq1 = dR2_dq1 + stepNormScale * ( q1Step * ( dR2_error - q1Step * dR2_dq1 + q2Step * dR2_dq2 ) );
dR2_dq2 = dR2_dq2 + stepNormScale * ( q2Step * ( dR2_error - q1Step * dR2_dq1 + q2Step * dR2_dq2 ) );
calculateNewStepsFromJacobi( dR1_dq1, dR1_dq2, dR2_dq1, dR2_dq2, R1_error, R2_error, &q1Step, &q2Step );
#else
dR1_dq1 = ( ( r1 - ev_1.firstRadius() ) - ( r1 - ev_0.firstRadius() ) ) / q1Step;
dR2_dq2 = ( ( r2 - ev_1.secondRadius() ) - ( r2 - ev_0.secondRadius() ) ) / q2Step;
R1_error = R1_error_new;
R2_error = R2_error_new;
q1Step = -R1_error / dR1_dq1;
q2Step = -R2_error / dR2_dq2;
#endif
ev_0 = ev_1;
}
*this = ev_0;
if ( iteration >= maxIterations )
{
m_solveStatus = FAILED_MAX_ITERATIONS_REACHED;
// Max iterations reached
}
else
{
m_solveStatus = solveResultStatus;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaSCurveCalculator::dump() const
{
cvf::Vec3d v_C1 = firstCenter();
cvf::Vec3d v_C2 = secondCenter();
cvf::Vec3d v_N1 = firstNormal();
cvf::Vec3d v_N2 = secondNormal();
cvf::Vec3d v_P11 = firstArcEndpoint();
cvf::Vec3d v_P22 = secondArcStartpoint();
std::cout << " P1: "
<< "[ " << m_p1[0] << " " << m_p1[1] << " " << m_p1[2] << " " << std::endl;
std::cout << " P11: "
<< "[ " << v_P11[0] << " " << v_P11[1] << " " << v_P11[2] << " " << std::endl;
std::cout << " P22: "
<< "[ " << v_P22[0] << " " << v_P22[1] << " " << v_P22[2] << " " << std::endl;
std::cout << " P2: "
<< "[ " << m_p2[0] << " " << m_p2[1] << " " << m_p2[2] << " " << std::endl;
std::cout << " C1: "
<< "[ " << v_C1[0] << " " << v_C1[1] << " " << v_C1[2] << " " << std::endl;
std::cout << " C2: "
<< "[ " << v_C2[0] << " " << v_C2[1] << " " << v_C2[2] << " " << std::endl;
std::cout << " N1: "
<< "[ " << v_N1[0] << " " << v_N1[1] << " " << v_N1[2] << " " << std::endl;
std::cout << " N2: "
<< "[ " << v_N2[0] << " " << v_N2[1] << " " << v_N2[2] << " " << std::endl;
std::cout << " R1: "
<< "[ " << firstRadius() << " ]" << std::endl;
std::cout << " R2: "
<< "[ " << secondRadius() << " ]" << std::endl;
std::cout << " CtrPointStatus: " << m_ctrlPpointCurveStatus << " SolveStatus: " << m_solveStatus << std::endl;
}

View File

@@ -0,0 +1,98 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2018- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cvfVector3.h"
class RiaSCurveCalculator
{
public:
RiaSCurveCalculator( cvf::Vec3d p1, double azi1, double inc1, double r1, cvf::Vec3d p2, double azi2, double inc2, double r2 );
RiaSCurveCalculator( cvf::Vec3d p1, cvf::Vec3d q1, cvf::Vec3d p2, cvf::Vec3d q2 );
enum CurveStatus
{
NOT_SET,
OK,
OK_INFINITE_RADIUS1,
OK_INFINITE_RADIUS2,
OK_INFINITE_RADIUS12,
FAILED_INPUT_OVERLAP,
FAILED_ARC_OVERLAP
};
enum SolveStatus
{
NOT_SOLVED,
CONVERGED,
FAILED_MAX_LENGTH_ALONG_TANGENT_REACHED,
FAILED_MAX_TANGENT_STEP_REACHED,
FAILED_MAX_ITERATIONS_REACHED
};
bool isOk() const { return m_isCalculationOK; }
CurveStatus curveStatus() const { return m_ctrlPpointCurveStatus; }
SolveStatus solveStatus() const { return m_solveStatus; }
cvf::Vec3d firstArcEndpoint() const { return m_firstArcEndpoint; }
cvf::Vec3d secondArcStartpoint() const { return m_secondArcStartpoint; }
cvf::Vec3d firstCenter() const { return m_c1; }
cvf::Vec3d secondCenter() const { return m_c2; }
cvf::Vec3d firstNormal() const { return m_n1; }
cvf::Vec3d secondNormal() const { return m_n2; }
double firstRadius() const { return m_r1; }
double secondRadius() const { return m_r2; }
void dump() const;
static RiaSCurveCalculator fromTangentsAndLength( cvf::Vec3d p1,
double azi1,
double inc1,
double lengthToQ1,
cvf::Vec3d p2,
double azi2,
double inc2,
double lengthToQ2 );
private:
void initializeByFinding_q1q2( cvf::Vec3d p1,
double azi1,
double inc1,
double r1,
cvf::Vec3d p2,
double azi2,
double inc2,
double r2 );
bool m_isCalculationOK;
CurveStatus m_ctrlPpointCurveStatus;
SolveStatus m_solveStatus;
cvf::Vec3d m_p1;
cvf::Vec3d m_p2;
cvf::Vec3d m_firstArcEndpoint;
cvf::Vec3d m_secondArcStartpoint;
cvf::Vec3d m_c1;
cvf::Vec3d m_c2;
cvf::Vec3d m_n1;
cvf::Vec3d m_n2;
double m_r1;
double m_r2;
};

View File

@@ -0,0 +1,134 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2018- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RiaWellPlanCalculator.h"
#include "RiaArcCurveCalculator.h"
#include "RiaOffshoreSphericalCoords.h"
#include "cvfGeometryTools.h"
#include "cvfMatrix4.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaWellPlanCalculator::RiaWellPlanCalculator( const cvf::Vec3d& startTangent,
const std::vector<cvf::Vec3d>& lineArcEndPoints )
: m_startTangent( startTangent )
, m_lineArcEndPoints( lineArcEndPoints )
{
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 };
RiaOffshoreSphericalCoords startAziIncRad( m_startTangent );
segment.inc = cvf::Math::toDegrees( startAziIncRad.inc() );
segment.azi = cvf::Math::toDegrees( startAziIncRad.azi() );
segment.TVD = -lineArcEndPoints[0].z();
segment.NS = lineArcEndPoints[0].y();
segment.EW = lineArcEndPoints[0].x();
m_wpResult.push_back( segment );
cvf::Vec3d t2 = m_startTangent;
for ( size_t pIdx = 0; pIdx < m_lineArcEndPoints.size() - 1; ++pIdx )
{
addSegment( t2, m_lineArcEndPoints[pIdx], m_lineArcEndPoints[pIdx + 1], &t2 );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaWellPlanCalculator::addSegment( cvf::Vec3d t1, cvf::Vec3d p1, cvf::Vec3d p2, cvf::Vec3d* endTangent )
{
cvf::Vec3d p1p2 = p2 - p1;
double xyLength = std::sqrt( p1p2.x() * p1p2.x() + p1p2.y() * p1p2.y() );
double zLength = std::abs( p1p2.z() );
// 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 )
{
addLineSegment( p1, p2, endTangent );
}
else // resample arc
{
addArcSegment( t1, p1, p2, 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 };
cvf::Vec3d p1p2 = p2 - p1;
double length = p1p2.length();
segment.CL = length;
segment.MD = m_wpResult.back().MD + length;
cvf::Vec3d tangent = p1p2 / length;
RiaOffshoreSphericalCoords aziIncRad( p1p2 );
segment.inc = cvf::Math::toDegrees( aziIncRad.inc() );
segment.azi = cvf::Math::toDegrees( aziIncRad.azi() );
segment.TVD = -p2.z();
segment.NS = p2.y();
segment.EW = p2.x();
segment.dogleg = 0.0;
segment.build = 0.0;
segment.turn = 0.0;
m_wpResult.push_back( segment );
*endTangent = tangent;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
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 };
RiaArcCurveCalculator arcCalc( p1, t1, p2 );
segment.CL = arcCalc.arcLength();
segment.MD = m_wpResult.back().MD + segment.CL;
segment.inc = cvf::Math::toDegrees( arcCalc.endInclination() );
segment.azi = cvf::Math::toDegrees( arcCalc.endAzimuth() );
segment.TVD = -p2.z();
segment.NS = p2.y();
segment.EW = p2.x();
segment.dogleg = cvf::Math::toDegrees( 30.0 / arcCalc.radius() );
RiaOffshoreSphericalCoords startAziIncRad( t1 );
double buildInRadsPrLength = ( arcCalc.endInclination() - startAziIncRad.inc() ) / arcCalc.arcLength();
double turnInRadsPrLength = ( arcCalc.endAzimuth() - startAziIncRad.azi() ) / arcCalc.arcLength();
segment.build = 30 * cvf::Math::toDegrees( buildInRadsPrLength );
segment.turn = 30 * cvf::Math::toDegrees( turnInRadsPrLength );
m_wpResult.push_back( segment );
( *endTangent ) = arcCalc.endTangent();
}

View File

@@ -0,0 +1,55 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2018- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cvfVector3.h"
#include <vector>
class RiaWellPlanCalculator
{
public:
RiaWellPlanCalculator( const cvf::Vec3d& startTangent, const std::vector<cvf::Vec3d>& lineArcEndPoints );
struct WellPlanSegment
{
double MD;
double CL;
double inc;
double azi;
double TVD;
double NS;
double EW;
double dogleg;
double build;
double turn;
};
const std::vector<WellPlanSegment>& wellPlan() const { return m_wpResult; }
private:
void addSegment( cvf::Vec3d t1, cvf::Vec3d p1, cvf::Vec3d p2, cvf::Vec3d* endTangent );
void addLineSegment( cvf::Vec3d p1, cvf::Vec3d p2, cvf::Vec3d* endTangent );
void addArcSegment( cvf::Vec3d t1, cvf::Vec3d p1, cvf::Vec3d p2, cvf::Vec3d* endTangent );
cvf::Vec3d m_startTangent;
std::vector<cvf::Vec3d> m_lineArcEndPoints;
std::vector<WellPlanSegment> m_wpResult;
};