Skip to content

Commit 0e68b2e

Browse files
authored
Merge pull request #2977 from RyanDavies19/MDF_bugfixes
Minor MoorDyn improvements
2 parents c847dbc + 1310654 commit 0e68b2e

File tree

5 files changed

+69
-49
lines changed

5 files changed

+69
-49
lines changed

docs/source/user/moordyn/index.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ usage of MoorDyn at the FAST.Farm level
1212
and links to publications with the relevant theory.
1313

1414

15-
The user guide can be downloaded below.
15+
Examples of how to use MoorDynF and MoorDynC can be found here:
1616

17-
`Official User's Guide <http://www.matt-hall.ca/files/MoorDyn%20Users%20Guide%202017-08-16.pdf>`_
17+
`MoorDyn Example Uses <https://github.com/FloatingArrayDesign/MoorDyn/tree/dev/example>`_

modules/moordyn/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# MoorDyn Module
22
This is an externally developed module with further information
3-
available on the developer's documentation site:
4-
[Matt Hall](http://www.matt-hall.ca/moordyn.html).
3+
available on the documentation site:
4+
[MoorDyn Docs](https://moordyn.readthedocs.io/en/latest/).
55

66
## Overview
77
MoorDyn is a lumped-mass mooring line model for simulating the dynamics of

modules/moordyn/src/MoorDyn.f90

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er
157157
CHARACTER(*), PARAMETER :: RoutineName = 'MD_Init'
158158

159159

160-
160+
! Initialize Err stat
161161
ErrStat = ErrID_None
162162
ErrMsg = ""
163163
m%zeros6 = 0.0_DbKi
@@ -241,13 +241,9 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er
241241
! read input file and create cross-referenced mooring system objects
242242
!---------------------------------------------------------------------------------------------
243243

244-
245-
! Initialize ErrStat
246-
ErrStat = ErrID_None
247-
ErrMsg = ""
248244

249245

250-
CALL WrScr( ' Parsing MoorDyn input file: '//trim(InitInp%FileName) )
246+
CALL WrScr( ' Parsing MoorDyn input file: '//trim(InitInp%FileName) )
251247

252248

253249
! -----------------------------------------------------------------
@@ -291,6 +287,13 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er
291287

292288
do while ( i <= FileInfo_In%NumLines )
293289

290+
if (INDEX(Line, "ECHO") > 0) then
291+
! check for Echo flag and if so, throw message suggesting write log
292+
ErrStat2 = ErrID_Info
293+
ErrMsg2 = 'MoorDyn does not support ECHO. Instead, enable the log file by setting WriteLog > 0.'
294+
CALL CheckError( ErrStat2, ErrMsg2 )
295+
end if
296+
294297
if (INDEX(Line, "---") > 0) then ! look for a header line
295298

296299
if ( ( INDEX(Line, "LINE DICTIONARY") > 0) .or. ( INDEX(Line, "LINE TYPES") > 0) ) then ! if line dictionary header
@@ -438,10 +441,10 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er
438441
read (OptValue,*) p%writeLog
439442
if (p%writeLog > 0) then ! if not zero, open a log file for output
440443
CALL GetNewUnit( p%UnLog )
441-
CALL OpenFOutFile ( p%UnLog, TRIM(p%RootName)//'.log', ErrStat, ErrMsg )
442-
IF ( ErrStat > AbortErrLev ) THEN
443-
ErrMsg = ' Failed to open MoorDyn log file: '//TRIM(ErrMsg)
444-
RETURN
444+
CALL OpenFOutFile ( p%UnLog, TRIM(p%RootName)//'.log', ErrStat2, ErrMsg2 )
445+
IF ( ErrStat2 > AbortErrLev ) THEN
446+
ErrMsg2 = ' Failed to open MoorDyn log file: '//TRIM(ErrMsg2)
447+
CALL CheckError( ErrStat2, ErrMsg2 ); IF (ErrStat >= AbortErrLev) RETURN
445448
END IF
446449
write(p%UnLog,'(A)', IOSTAT=ErrStat2) "MoorDyn v2 log file with output level "//TRIM(Num2LStr(p%writeLog))
447450
write(p%UnLog,'(A)', IOSTAT=ErrStat2) "Note: options above the writeLog line in the input file will not be recorded."
@@ -490,7 +493,9 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er
490493
else if ( OptString == 'DISABLEOUTTIME') then
491494
read (OptValue,*) p%disableOutTime
492495
else
493-
CALL SetErrStat( ErrID_Warn, 'Unable to interpret input '//trim(OptString)//' in OPTIONS section.', ErrStat, ErrMsg, RoutineName )
496+
ErrStat2 = ErrID_Warn
497+
ErrMsg2 = 'Unable to interpret input '//trim(OptString)//' in OPTIONS section.'
498+
CALL CheckError( ErrStat2, ErrMsg2 )
494499
end if
495500

496501
nOpts = nOpts + 1
@@ -548,7 +553,8 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er
548553

549554

550555
! set up seabed bathymetry
551-
CALL setupBathymetry(DepthValue, InitInp%WtrDepth, m%BathymetryGrid, m%BathGrid_Xs, m%BathGrid_Ys, ErrStat2, ErrMsg2)
556+
CALL setupBathymetry(p, DepthValue, InitInp%WtrDepth, m%BathymetryGrid, m%BathGrid_Xs, m%BathGrid_Ys, ErrStat2, ErrMsg2)
557+
CALL CheckError( ErrStat2, ErrMsg2 ); IF (ErrStat >= AbortErrLev) RETURN
552558
CALL getDepthFromBathymetry(m%BathymetryGrid, m%BathGrid_Xs, m%BathGrid_Ys, 0.0_DbKi, 0.0_DbKi, p%WtrDpth, nvec) ! set depth at 0,0 as nominal for waves etc
553559

554560

@@ -1254,10 +1260,6 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er
12541260
IF (SUM(m%RodList(l)%OutFlagList) > 0) m%RodList(l)%OutFlagList(1) = 1 ! this first entry signals whether to create any output file at all
12551261
! the above letter-index combinations define which OutFlagList entry corresponds to which output type
12561262

1257-
1258-
! specify IdNum of line for error checking
1259-
m%RodList(l)%IdNum = l
1260-
12611263
if (p%writeLog > 1) then
12621264
write(p%UnLog, '(A)' ) " - Rod"//trim(num2lstr(m%RodList(l)%IdNum))//":"
12631265
write(p%UnLog, '(A15,I2)' ) " ID : ", m%RodList(l)%IdNum
@@ -1268,7 +1270,7 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er
12681270

12691271
! check for sequential IdNums
12701272
IF ( m%RodList(l)%IdNum .NE. l ) THEN
1271-
CALL SetErrStat( ErrID_Fatal, 'Line numbers must be sequential starting from 1.', ErrStat, ErrMsg, RoutineName )
1273+
CALL SetErrStat( ErrID_Fatal, 'Rod numbers must be sequential starting from 1.', ErrStat, ErrMsg, RoutineName )
12721274
CALL CleanUp()
12731275
RETURN
12741276
END IF
@@ -1644,9 +1646,6 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er
16441646
! the above letter-index combinations define which OutFlagList entry corresponds to which output type
16451647

16461648

1647-
! specify IdNum of line for error checking
1648-
m%LineList(l)%IdNum = l
1649-
16501649
if (p%writeLog > 1) then
16511650
write(p%UnLog, '(A)' ) " - Line"//trim(num2lstr(m%LineList(l)%IdNum))//":"
16521651
write(p%UnLog, '(A15,I2)' ) " ID : ", m%LineList(l)%IdNum
@@ -2934,7 +2933,7 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er
29342933
ENDIF
29352934
endif
29362935

2937-
CALL WrScr(' MoorDyn initialization completed.')
2936+
CALL WrScr(' MoorDyn initialization completed.')
29382937
if (p%writeLog > 0) then
29392938
write(p%UnLog, '(A)') NewLine//"MoorDyn initialization completed."//NewLine
29402939
if (ErrStat /= ErrID_None) then
@@ -2997,7 +2996,7 @@ SUBROUTINE CheckError(ErrID,Msg)
29972996

29982997
IF (ErrStat /= ErrID_None) ErrMsg = TRIM(ErrMsg)//NewLine ! if there's a pre-existing warning/error, retain the message and start a new line
29992998

3000-
ErrMsg = TRIM(ErrMsg)//' MD_Init:'//TRIM(Msg)
2999+
ErrMsg = TRIM(ErrMsg)//RoutineName//":"//TRIM(Msg)
30013000
ErrStat = MAX(ErrStat, ErrID)
30023001

30033002
Msg = "" ! Reset the error message now that it has been logged into ErrMsg

modules/moordyn/src/MoorDyn_IO.f90

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,10 @@ MODULE MoorDyn_IO
128128
CONTAINS
129129

130130

131-
SUBROUTINE setupBathymetry(inputString, defaultDepth, BathGrid, BathGrid_Xs, BathGrid_Ys, ErrStat3, ErrMsg3)
131+
SUBROUTINE setupBathymetry(p, inputString, defaultDepth, BathGrid, BathGrid_Xs, BathGrid_Ys, ErrStat3, ErrMsg3)
132132
! SUBROUTINE getBathymetry(inputString, BathGrid, BathGrid_Xs, BathGrid_Ys, BathGrid_npoints, ErrStat3, ErrMsg3)
133133

134+
TYPE(MD_ParameterType), INTENT(INOUT) :: p ! Parameters
134135
CHARACTER(40), INTENT(IN ) :: inputString ! string describing water depth or bathymetry filename
135136
REAL(ReKi), INTENT(IN ) :: defaultDepth ! depth to use if inputString is empty
136137
REAL(DbKi), ALLOCATABLE, INTENT(INOUT) :: BathGrid (:,:)
@@ -144,7 +145,8 @@ SUBROUTINE setupBathymetry(inputString, defaultDepth, BathGrid, BathGrid_Xs, Bat
144145

145146
INTEGER(IntKi) :: ErrStat4
146147
CHARACTER(120) :: ErrMsg4
147-
CHARACTER(4096) :: Line2
148+
CHARACTER(4096) :: Line2
149+
CHARACTER(1024) :: FileName
148150

149151
CHARACTER(20) :: nGridX_string ! string to temporarily hold the nGridX string from Line2
150152
CHARACTER(20) :: nGridY_string ! string to temporarily hold the nGridY string from Line3
@@ -177,41 +179,63 @@ SUBROUTINE setupBathymetry(inputString, defaultDepth, BathGrid, BathGrid_Xs, Bat
177179
ELSE ! otherwise interpret the input as a file name to load the bathymetry lookup data from
178180
CALL WrScr(" The depth input contains letters so will load a bathymetry file.")
179181

182+
IF ( PathIsRelative( inputString ) ) THEN ! properly handle relative path <<<
183+
FileName = TRIM(p%PriPath)//TRIM(inputString)
184+
ELSE
185+
FileName = trim(inputString)
186+
END IF
187+
180188
! load lookup table data from file
181189
CALL GetNewUnit( UnCoef ) ! unit number for coefficient input file
182-
CALL OpenFInpFile( UnCoef, TRIM(inputString), ErrStat4, ErrMsg4 )
183-
cALL SetErrStat(ErrStat4, ErrMsg4, ErrStat3, ErrMsg3, 'MDIO_getBathymetry')
190+
CALL OpenFInpFile( UnCoef, FileName, ErrStat4, ErrMsg4 )
191+
CALL SetErrStat(ErrStat4, ErrMsg4, ErrStat3, ErrMsg3, 'MDIO_getBathymetry')
184192

185193
READ(UnCoef,'(A)',IOSTAT=ErrStat4) Line2 ! skip the first title line
186194
READ(UnCoef,*,IOSTAT=ErrStat4) nGridX_string, nGridX ! read in the second line as the number of x values in the BathGrid
187195
READ(UnCoef,*,IOSTAT=ErrStat4) nGridY_string, nGridY ! read in the third line as the number of y values in the BathGrid
188196

197+
! error check that the number of x and y values were read in correctly
198+
IF (ErrStat4 /= 0) THEN
199+
CALL SetErrStat(ErrID_Fatal, "Error reading the number of x and y values from the bathymetry file "//TRIM(inputString), ErrStat3, ErrMsg3, 'MDIO_getBathymetry')
200+
CLOSE (UnCoef)
201+
RETURN
202+
ENDIF
203+
189204
! Allocate the bathymetry matrix and associated grid x and y values
190205
ALLOCATE(BathGrid(nGridY, nGridX), STAT=ErrStat4)
191206
ALLOCATE(BathGrid_Xs(nGridX), STAT=ErrStat4)
192207
ALLOCATE(BathGrid_Ys(nGridY), STAT=ErrStat4)
193208

209+
! Error check that allocation was successful
210+
IF (ErrStat4 /= 0) THEN
211+
CALL SetErrStat(ErrID_Fatal, "Error allocating memory for the bathymetry grid from file "//TRIM(inputString), ErrStat3, ErrMsg3, 'MDIO_getBathymetry')
212+
CLOSE (UnCoef)
213+
RETURN
214+
ENDIF
215+
194216
DO I = 1, nGridY+1 ! loop through each line in the rest of the bathymetry file
195217

196218
READ(UnCoef,'(A)',IOSTAT=ErrStat4) Line2 ! read into a line and call it Line2
197-
IF (ErrStat4 > 0) EXIT
198219

199220
IF (I==1) THEN ! if it's the first line in the Bathymetry Grid, then it's a list of all the x values
200221
READ(Line2, *,IOSTAT=ErrStat4) BathGrid_Xs
201222
ELSE ! if it's not the first line, then the first value is a y value and the rest are the depth values
202223
READ(Line2, *,IOSTAT=ErrStat4) BathGrid_Ys(I-1), BathGrid(I-1,:)
203224
ENDIF
225+
226+
IF (ErrStat4 /= 0) THEN
227+
CALL SetErrStat(ErrID_Fatal, "Error reading the bathymetry file "//TRIM(inputString)//" at table line "//trIM(Num2Lstr(I)), ErrStat3, ErrMsg3, 'MDIO_getBathymetry')
228+
CLOSE (UnCoef)
229+
RETURN
230+
ENDIF
204231

205232
END DO
206233

234+
CLOSE (UnCoef)
235+
207236
IF (I < 2) THEN
208-
ErrStat3 = ErrID_Fatal
209-
ErrMsg3 = "Less than the minimum of 2 data lines found in file "//TRIM(inputString)
210-
CLOSE (UnCoef)
237+
CALL SetErrStat(ErrID_Fatal, "Less than the minimum of 2 data lines found in file "//TRIM(inputString), ErrStat3, ErrMsg3, 'MDIO_getBathymetry')
211238
RETURN
212-
ELSE
213-
! BathGrid_npoints = nGridX*nGridY ! save the number of points in the grid
214-
CLOSE (UnCoef)
215239
END IF
216240

217241
END IF

modules/moordyn/src/MoorDyn_Line.f90

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ SUBROUTINE Line_Initialize (Line, LineProp, p, ErrStat, ErrMsg)
375375
Line%r(3,J) = Line%r(3,0) + (Line%r(3,N) - Line%r(3,0))*REAL(J, DbKi)/REAL(N, DbKi)
376376
END DO
377377

378-
CALL WrScr(' Vertical initial profile for Line '//trim(Num2LStr(Line%IdNum))//'.')
378+
CALL WrScr(' Vertical initial profile for Line '//trim(Num2LStr(Line%IdNum))//'.')
379379

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

@@ -396,9 +396,9 @@ SUBROUTINE Line_Initialize (Line, LineProp, p, ErrStat, ErrMsg)
396396

397397
ELSE ! if there is a problem with the catenary approach, just stretch the nodes linearly between fairlead and anchor
398398
! CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, ' Line_Initialize: Line '//trim(Num2LStr(Line%IdNum))//' ')
399-
CALL WrScr(' Catenary solve of Line '//trim(Num2LStr(Line%IdNum))//' unsuccessful. Initializing as linear.')
399+
CALL WrScr(' Catenary solve of Line '//trim(Num2LStr(Line%IdNum))//' unsuccessful. Initializing as linear.')
400400
IF (wordy == 1) THEN
401-
CALL WrScr(' Message from catenary solver: '//ErrMsg2)
401+
CALL WrScr(' Message from catenary solver: '//ErrMsg2)
402402
ENDIF
403403

404404
DO J = 0,N ! Loop through all nodes per line where the line position and tension can be output
@@ -579,7 +579,7 @@ SUBROUTINE Catenary ( XF_In, ZF_In, L_In , EA_In, &
579579
IF ( ZF < 0.0 ) THEN ! .TRUE. if the fairlead has passed below its anchor
580580
ZF = -ZF
581581
reverseFlag = .TRUE.
582-
CALL WrScr(' Warning from catenary: Anchor point is above the fairlead point for Line '//trim(Num2LStr(Line%IdNum))//', consider changing.')
582+
CALL WrScr(' Warning from catenary: Anchor point is above the fairlead point for Line '//trim(Num2LStr(Line%IdNum))//', consider changing.')
583583
ELSE
584584
reverseFlag = .FALSE.
585585
ENDIF
@@ -1349,8 +1349,8 @@ SUBROUTINE Line_GetStateDeriv(Line, Xd, m, p, ErrStat, ErrMsg) !, FairFtot, Fai
13491349

13501350

13511351
! >>>> could do similar as above for nonlinear damping or bending stiffness <<<<
1352-
if (Line%nBApoints > 0) print *, 'Nonlinear elastic damping not yet implemented'
1353-
if (Line%nEIpoints > 0) print *, 'Nonlinear bending stiffness not yet implemented'
1352+
if (Line%nBApoints > 0) CALL SetErrStat(ErrID_Warn,'Nonlinear elastic damping not yet implemented',ErrStat,ErrMsg,RoutineName)
1353+
if (Line%nEIpoints > 0) CALL SetErrStat(ErrID_Warn,'Nonlinear bending stiffness not yet implemented',ErrStat,ErrMsg,RoutineName)
13541354

13551355

13561356
! basic elasticity model
@@ -1375,8 +1375,7 @@ SUBROUTINE Line_GetStateDeriv(Line, Xd, m, p, ErrStat, ErrMsg) !, FairFtot, Fai
13751375

13761376
! Double check none of the assumptions were violated (this should never happen)
13771377
IF (Line%alphaMBL <= 0 .OR. Line%vbeta <= 0 .OR. Line%l(I) <= 0 .OR. Line%dl_1(I) <= 0 .OR. EA_D < Line%EA) THEN
1378-
ErrStat = ErrID_Warn
1379-
ErrMsg = "Viscoelastic model: Assumption for mean load dependent dynamic stiffness violated"
1378+
CALL SetErrStat(ErrID_Warn,"Viscoelastic model: Assumption for mean load dependent dynamic stiffness violated",ErrStat,ErrMsg,RoutineName)
13801379
if (wordy > 2) then
13811380
print *, "Line%alphaMBL", Line%alphaMBL
13821381
print *, "Line%vbeta", Line%vbeta
@@ -1397,12 +1396,10 @@ SUBROUTINE Line_GetStateDeriv(Line, Xd, m, p, ErrStat, ErrMsg) !, FairFtot, Fai
13971396
endif
13981397

13991398
if (EA_D == 0.0) then ! Make sure EA != EA_D or else nans, also make sure EA_D != 0 or else nans.
1400-
ErrStat = ErrID_Fatal
1401-
ErrMsg = "Viscoelastic model: Dynamic stiffness cannot equal zero"
1399+
CALL SetErrStat(ErrID_Fatal,"Viscoelastic model: Dynamic stiffness cannot equal zero",ErrStat,ErrMsg,RoutineName)
14021400
return
14031401
else if (EA_D == Line%EA) then
1404-
ErrStat = ErrID_Fatal
1405-
ErrMsg = "Viscoelastic model: Dynamic stiffness cannot equal static stiffness"
1402+
CALL SetErrStat(ErrID_Fatal,"Viscoelastic model: Dynamic stiffness cannot equal static stiffness",ErrStat,ErrMsg,RoutineName)
14061403
return
14071404
endif
14081405

0 commit comments

Comments
 (0)