Skip to content

Commit

Permalink
Catenary same as MD-C and minor doc changes
Browse files Browse the repository at this point in the history
  • Loading branch information
RyanDavies19 committed Aug 24, 2023
1 parent 4a3d87e commit 8b8cb60
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 56 deletions.
5 changes: 3 additions & 2 deletions docs/source/user/moordyn/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
MoorDyn Users Guide
====================

A standalone C++ version of MoorDyn is also available outside the OpenFAST
repository. The documentation for the C++ version covers the input file format
The documentation for MoorDyn is avaible `here <https://moordyn.readthedocs.io>`_. It features instructions
for the use of MoorDynF, the module in OpenFAST, and MoorDynC, the standalone C++ code. Input file formats
are described in the `inputs section <>`_.
(`MoorDyn usage <https://moordyn.readthedocs.io/en/latest/usage.html>`_, specifically the section for V2)
usage of MoorDyn at the FAST.Farm level
(`MoorDyn with FAST.Farm <https://moordyn.readthedocs.io/en/latest/usage.html#moordyn-with-fast-farm>`_),
Expand Down
8 changes: 3 additions & 5 deletions modules/moordyn/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,10 @@ The Fortran implementation of MoorDyn, which has been developed
following the FAST Modularization Framework, is included as a module in
OpenFAST.

For the C++ implementation of MoorDyn, see http://www.matt-hall.ca/moordyn.
"MoorDyn C" can be compiled as a dynamically-linked library and features
simpler functions for easy coupling with models or scripts coded in C/C++,
Fortran, Matlab/Simulink, etc. It has recently been integrated into WEC-Sim.
For the C++ implementation of MoorDyn, see https://github.com/FloatingArrayDesign/MoorDyn.
"MoorDynC" is more adaptable to unique use cases and couplings. It can be compiled as a dynamically-linked library or wrapped for use in Python (as a module), Fortran, and Matlab. It features simpler functions for easy coupling with models or scripts coded in C/C++, Fortran, Matlab/Simulink, etc. An example of this coupling is it’s integration into WEC-Sim.

Both forms of MoorDyn feature the same underlying mooring model, use similar
Both forms of MoorDyn feature the same underlying mooring model, use the same
input and output conventions, and are being updated and improved in parallel.
They follow the same version numbering, with a "C" or "F" suffix for
differentiation.
130 changes: 81 additions & 49 deletions modules/moordyn/src/MoorDyn_Line.f90
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ SUBROUTINE Line_Initialize (Line, LineProp, rhoW, ErrStat, ErrMsg)
CHARACTER(ErrMsgLen) :: ErrMsg2 ! Error message if ErrStat2 /= ErrID_None
REAL(DbKi) :: WetWeight
REAL(DbKi) :: SeabedCD = 0.0_DbKi
REAL(DbKi) :: TenTol = 0.0001_DbKi
REAL(DbKi) :: Tol = 0.0001_DbKi
REAL(DbKi), ALLOCATABLE :: LSNodes(:)
REAL(DbKi), ALLOCATABLE :: LNodesX(:)
REAL(DbKi), ALLOCATABLE :: LNodesZ(:)
Expand Down Expand Up @@ -335,41 +335,59 @@ SUBROUTINE Line_Initialize (Line, LineProp, rhoW, ErrStat, ErrMsg)
! are stored in a module and thus their values are saved from CALL to
! CALL).

IF (XF == 0.0) THEN

CALL Catenary ( XF , ZF , Line%UnstrLen, LineProp%EA , &
WetWeight , SeabedCD, TenTol, (N+1) , &
LSNodes, LNodesX, LNodesZ , ErrStat2, ErrMsg2)
DO J = 0,N ! Loop through all nodes per line where the line position and tension can be output
Line%r(1,J) = Line%r(1,0) + (Line%r(1,N) - Line%r(1,0))*REAL(J, DbKi)/REAL(N, DbKi)
Line%r(2,J) = Line%r(2,0) + (Line%r(2,N) - Line%r(2,0))*REAL(J, DbKi)/REAL(N, DbKi)
Line%r(3,J) = Line%r(3,0) + (Line%r(3,N) - Line%r(3,0))*REAL(J, DbKi)/REAL(N, DbKi)
END DO

CALL WrScr(" Vertical initial profile for Line "//trim(Num2LStr(Line%IdNum))//".")

ELSE ! If the line is not vertical, solve for the catenary profile

CALL Catenary ( XF , ZF , Line%UnstrLen, LineProp%EA , &
WetWeight , SeabedCD, Tol, (N+1) , &
LSNodes, LNodesX, LNodesZ , ErrStat2, ErrMsg2)

IF (ErrStat2 == ErrID_None) THEN ! if it worked, use it
! Transform the positions of each node on the current line from the local
! coordinate system of the current line to the inertial frame coordinate
! system:
IF ((abs(LNodesZ(N+1) - ZF) > Tol) .AND. (ErrStat2 == ErrID_None)) THEN
! Check fairlead node z position is same as z distance between fairlead and anchor
ErrStat2 = ErrID_Warn
ErrMsg2 = ' Wrong catenary initial profile for Line '//trim(Num2LStr(Line%IdNum))//'. Fairlead and anchor vertical seperation has changed.'
ENDIF

IF (ErrStat2 == ErrID_None) THEN ! if it worked, use it
! Transform the positions of each node on the current line from the local
! coordinate system of the current line to the inertial frame coordinate
! system:

DO J = 0,N ! Loop through all nodes per line where the line position and tension can be output
Line%r(1,J) = Line%r(1,0) + LNodesX(J+1)*COSPhi
Line%r(2,J) = Line%r(2,0) + LNodesX(J+1)*SINPhi
Line%r(3,J) = Line%r(3,0) + LNodesZ(J+1)
ENDDO ! J - All nodes per line where the line position and tension can be output
DO J = 0,N ! Loop through all nodes per line where the line position and tension can be output
Line%r(1,J) = Line%r(1,0) + LNodesX(J+1)*COSPhi
Line%r(2,J) = Line%r(2,0) + LNodesX(J+1)*SINPhi
Line%r(3,J) = Line%r(3,0) + LNodesZ(J+1)
ENDDO ! J - All nodes per line where the line position and tension can be output

ELSE ! if there is a problem with the catenary approach, just stretch the nodes linearly between fairlead and anchor

ELSE ! if there is a problem with the catenary approach, just stretch the nodes linearly between fairlead and anchor
CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'Line_Initialize')
CALL WrScr(" Catenary solve of Line "//trim(Num2LStr(Line%IdNum))//" unsuccessful. Initializing as linear.")

!CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'Line_Initialize')
call WrScr(" Catenary solve of Line "//trim(Num2LStr(Line%IdNum))//" unsuccessful. Initializing as linear.")
! print *, "Node positions: "

! print *, "Node positions: "
DO J = 0,N ! Loop through all nodes per line where the line position and tension can be output
Line%r(1,J) = Line%r(1,0) + (Line%r(1,N) - Line%r(1,0))*REAL(J, DbKi)/REAL(N, DbKi)
Line%r(2,J) = Line%r(2,0) + (Line%r(2,N) - Line%r(2,0))*REAL(J, DbKi)/REAL(N, DbKi)
Line%r(3,J) = Line%r(3,0) + (Line%r(3,N) - Line%r(3,0))*REAL(J, DbKi)/REAL(N, DbKi)

! print*, Line%r(:,J)
ENDDO

! print*,"FYI line end A and B node coords are"
! print*, Line%r(:,0)
! print*, Line%r(:,N)
ENDIF

DO J = 0,N ! Loop through all nodes per line where the line position and tension can be output
Line%r(1,J) = Line%r(1,0) + (Line%r(1,N) - Line%r(1,0))*REAL(J, DbKi)/REAL(N, DbKi)
Line%r(2,J) = Line%r(2,0) + (Line%r(2,N) - Line%r(2,0))*REAL(J, DbKi)/REAL(N, DbKi)
Line%r(3,J) = Line%r(3,0) + (Line%r(3,N) - Line%r(3,0))*REAL(J, DbKi)/REAL(N, DbKi)

! print*, Line%r(:,J)
ENDDO

! print*,"FYI line end A and B node coords are"
! print*, Line%r(:,0)
! print*, Line%r(:,N)
ENDIF


Expand Down Expand Up @@ -500,6 +518,7 @@ SUBROUTINE Catenary ( XF_In, ZF_In, L_In , EA_In, &
INTEGER(4) :: MaxIter ! Maximum number of Newton-Raphson iterations possible before giving up (-)

LOGICAL :: FirstIter ! Flag to determine whether or not this is the first time through the Newton-Raphson interation (flag)
LOGICAL :: reverseFlag ! Flag for when the anchor is above the fairlead


ErrStat = ERrId_None
Expand All @@ -518,9 +537,15 @@ SUBROUTINE Catenary ( XF_In, ZF_In, L_In , EA_In, &
W = REAL( W_In , DbKi )
XF = REAL( XF_In , DbKi )
ZF = REAL( ZF_In , DbKi )
IF ( ZF < 0.0 ) THEN ! .TRUE. if the fairlead has passed below its anchor
ZF = -ZF
reverseFlag = .TRUE.
CALL WrScr(' Warning from catenary: Anchor point is above the fairlead point for Line '//trim(Num2LStr(Line%IdNum))//', consider changing.')
ELSE
reverseFlag = .FALSE.
ENDIF



! HF and VF cannot be initialized to zero when a portion of the line rests on the seabed and the anchor tension is nonzero

! Generate the initial guess values for the horizontal and vertical tensions
Expand All @@ -531,9 +556,9 @@ SUBROUTINE Catenary ( XF_In, ZF_In, L_In , EA_In, &
XF2 = XF*XF
ZF2 = ZF*ZF

IF ( XF == 0.0_DbKi ) THEN ! .TRUE. if the current mooring line is exactly vertical
Lamda0 = 1.0D+06
ELSEIF ( L <= SQRT( XF2 + ZF2 ) ) THEN ! .TRUE. if the current mooring line is taut
! IF ( XF == 0.0_DbKi ) THEN ! .TRUE. if the current mooring line is exactly vertical
! Lamda0 = 1.0D+06
IF ( L <= SQRT( XF2 + ZF2 ) ) THEN ! .TRUE. if the current mooring line is taut
Lamda0 = 0.2_DbKi
ELSE ! The current mooring line must be slack and not vertical
Lamda0 = SQRT( 3.0_DbKi*( ( L**2 - ZF2 )/XF2 - 1.0_DbKi ) )
Expand All @@ -549,33 +574,27 @@ SUBROUTINE Catenary ( XF_In, ZF_In, L_In , EA_In, &
IF ( Tol <= EPSILON(TOL) ) THEN ! .TRUE. when the convergence tolerance is specified incorrectly
ErrStat = ErrID_Warn
ErrMsg = ' Convergence tolerance must be greater than zero in routine Catenary().'
return
RETURN
ELSEIF ( XF < 0.0_DbKi ) THEN ! .TRUE. only when the local coordinate system is not computed correctly
ErrStat = ErrID_Warn
ErrMsg = ' The horizontal distance between an anchor and its'// &
' fairlead must not be less than zero in routine Catenary().'
return

ELSEIF ( ZF < 0.0_DbKi ) THEN ! .TRUE. if the fairlead has passed below its anchor
ErrStat = ErrID_Warn
ErrMsg = " A line's fairlead is defined as below its anchor. You may need to swap a line's fairlead and anchor end nodes."
return

RETURN
ELSEIF ( L <= 0.0_DbKi ) THEN ! .TRUE. when the unstretched line length is specified incorrectly
ErrStat = ErrID_Warn
ErrMsg = ' Unstretched length of line must be greater than zero in routine Catenary().'
return
RETURN

ELSEIF ( EA <= 0.0_DbKi ) THEN ! .TRUE. when the unstretched line length is specified incorrectly
ErrStat = ErrID_Warn
ErrMsg = ' Extensional stiffness of line must be greater than zero in routine Catenary().'
return
RETURN

ELSEIF ( W == 0.0_DbKi ) THEN ! .TRUE. when the weight of the line in fluid is zero so that catenary solution is ill-conditioned
ErrStat = ErrID_Warn
ErrMsg = ' The weight of the line in fluid must not be zero. '// &
' Routine Catenary() cannot solve quasi-static mooring line solution.'
return
RETURN


ELSEIF ( W > 0.0_DbKi ) THEN ! .TRUE. when the line will sink in fluid
Expand All @@ -584,9 +603,9 @@ SUBROUTINE Catenary ( XF_In, ZF_In, L_In , EA_In, &

IF ( ( L >= LMax ) .AND. ( CB >= 0.0_DbKi ) ) then ! .TRUE. if the line is as long or longer than its maximum possible value with seabed interaction
ErrStat = ErrID_Warn
!ErrMsg = ' Unstretched mooring line length too large. '// &
! ' Routine Catenary() cannot solve quasi-static mooring line solution.'
return
ErrMsg = ' Unstretched mooring line length too large. '// &
' Routine Catenary() cannot solve quasi-static mooring line solution.'
RETURN
END IF

ENDIF
Expand Down Expand Up @@ -717,13 +736,13 @@ SUBROUTINE Catenary ( XF_In, ZF_In, L_In , EA_In, &

DET = dXFdHF*dZFdVF - dXFdVF*dZFdHF

if ( EqualRealNos( DET, 0.0_DbKi ) ) then
IF ( EqualRealNos( DET, 0.0_DbKi ) ) THEN
!bjj: there is a serious problem with the debugger here when DET = 0
ErrStat = ErrID_Warn
ErrMsg = ' Iteration not convergent (DET is 0). '// &
' Routine Catenary() cannot solve quasi-static mooring line solution.'
return
endif
RETURN
ENDIF


dHF = ( -dZFdVF*EXF + dXFdVF*EZF )/DET ! This is the incremental change in horizontal tension at the fairlead as predicted by Newton-Raphson
Expand Down Expand Up @@ -937,6 +956,19 @@ SUBROUTINE Catenary ( XF_In, ZF_In, L_In , EA_In, &
ENDIF


IF (reverseFlag) THEN
! Follows process of MoorPy catenary.py
s = s( size(s):1:-1 )
X = X( size(X):1:-1 )
Z = Z( size(Z):1:-1 )
Te = Te( size(Te):1:-1 )
DO I = 1,N
s(I) = L - s(I)
X(I) = XF - X(I)
Z(I) = Z(I) - ZF
ENDDO
ZF = -ZF ! Return to orginal value
ENDIF

! The Newton-Raphson iteration is only accurate in double precision, so
! convert the output arguments back into the default precision for real
Expand Down

0 comments on commit 8b8cb60

Please sign in to comment.