From 8d9ad2b5aecf83dd06d2bdc601b7e9de8f56641a Mon Sep 17 00:00:00 2001 From: RyanDavies19 Date: Thu, 2 Nov 2023 13:57:50 -0600 Subject: [PATCH 01/18] Adds standalone mode (Farmsize = -1) and fixes pinned rod inertial forces --- modules/moordyn/src/MoorDyn.f90 | 61 ++++++++++++++++-------- modules/moordyn/src/MoorDyn_Driver.f90 | 41 +++++++++++++--- modules/moordyn/src/MoorDyn_Registry.txt | 5 +- modules/moordyn/src/MoorDyn_Rod.f90 | 7 ++- modules/moordyn/src/MoorDyn_Types.f90 | 2 + 5 files changed, 83 insertions(+), 33 deletions(-) diff --git a/modules/moordyn/src/MoorDyn.f90 b/modules/moordyn/src/MoorDyn.f90 index 2bc70eedc2..c342cc189e 100644 --- a/modules/moordyn/src/MoorDyn.f90 +++ b/modules/moordyn/src/MoorDyn.f90 @@ -201,6 +201,8 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er m%PtfmInit = InitInp%PtfmInit(:,1) ! is this copying necssary in case this is an individual instance in FAST.Farm? + p%Standalone = InitInp%Standalone + ! Check if this MoorDyn instance is being run from FAST.Farm (indicated by FarmSize > 0) @@ -208,7 +210,10 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er CALL WrScr(' >>> MoorDyn is running in array mode <<< ') ! could make sure the size of this is right: SIZE(InitInp%FarmCoupledKinematics) p%nTurbines = InitInp%FarmSize - else ! FarmSize==0 indicates normal, FAST module mode + else if (InitInp%FarmSize < 0) then ! Farmsize==-1 indicates standlone, run MoorDyn as a standalone code with no openfast coupling + p%Standalone = 1 + p%nTurbines = 1 + else ! FarmSize==0 indicates normal, FAST module mode p%nTurbines = 1 ! if a regular FAST module mode, we treat it like a nTurbine=1 farm case END IF @@ -1009,7 +1014,7 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er else if ((let1 == "CONNECT") .or. (let1 == "CON") .or. (let1 == "FREE")) then m%RodList(l)%typeNum = 0 - p%nFreeRods=p%nFreeRods+1 ! add this pinned rod to the free list because it is half free + p%nFreeRods=p%nFreeRods+1 m%RodStateIs1(p%nFreeRods) = Nx+1 m%RodStateIsN(p%nFreeRods) = Nx+12 @@ -1769,14 +1774,18 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er CALL MeshPositionNode(u%CoupledKinematics(iTurb), J, rRef(1:3), ErrStat2, ErrMsg2) ! defaults to identity orientation matrix !TODO: >>> should also maybe set reference orientation (which might make part of a couple lines down redundant) <<< - ! calculate initial point relative position, adjusted due to initial platform translations - u%CoupledKinematics(iTurb)%TranslationDisp(:,J) = InitInp%PtfmInit(1:3,iTurb) - rRef(1:3) OrMat2 = MATMUL(OrMat, TRANSPOSE( EulerConstruct( rRef(4:6)))) ! combine the Body's relative orientation with the turbine's initial orientation u%CoupledKinematics(iTurb)%Orientation(:,:,J) = OrMat2 ! set the result as the current orientation of the body <<< ! set absolute initial positions in MoorDyn - m%BodyList(m%CpldBodyIs(l,iTurb))%r6(1:3) = u%CoupledKinematics(iTurb)%Position(:,J) + u%CoupledKinematics(iTurb)%TranslationDisp(:,J) + p%TurbineRefPos(:,iTurb) + IF (p%Standalone == 1) THEN + m%BodyList(m%CpldBodyIs(l,iTurb))%r6(1:3) = u%CoupledKinematics(iTurb)%Position(:,J) + ELSE + ! calculate initial point relative position, adjusted due to initial platform translations + u%CoupledKinematics(iTurb)%TranslationDisp(:,J) = InitInp%PtfmInit(1:3,iTurb) - rRef(1:3) + m%BodyList(m%CpldBodyIs(l,iTurb))%r6(1:3) = u%CoupledKinematics(iTurb)%Position(:,J) + u%CoupledKinematics(iTurb)%TranslationDisp(:,J) + p%TurbineRefPos(:,iTurb) + ENDIF m%BodyList(m%CpldBodyIs(l,iTurb))%r6(4:6) = EulerExtract(MATMUL(OrMat, TRANSPOSE( EulerConstruct( rRef(4:6))))) ! apply rotation from PtfmInit onto input file's body orientation to get its true initial orientation CALL MeshConstructElement(u%CoupledKinematics(iTurb), ELEMENT_POINT, ErrStat2, ErrMsg2, J) ! set node as point element @@ -1793,18 +1802,24 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er OrMatRef = TRANSPOSE( m%RodList(m%CpldRodIs(l,iTurb))%OrMat ) ! for now set reference orientation as per input file <<< CALL MeshPositionNode(u%CoupledKinematics(iTurb), J, rRef(1:3), ErrStat2, ErrMsg2, OrMatRef) ! assign the reference position and orientation - ! calculate initial point relative position, adjusted due to initial platform rotations and translations <<< could convert to array math - u%CoupledKinematics(iTurb)%TranslationDisp(1,J) = InitInp%PtfmInit(1,iTurb) + OrMat(1,1)*rRef(1) + OrMat(2,1)*rRef(2) + OrMat(3,1)*rRef(3) - rRef(1) - u%CoupledKinematics(iTurb)%TranslationDisp(2,J) = InitInp%PtfmInit(2,iTurb) + OrMat(1,2)*rRef(1) + OrMat(2,2)*rRef(2) + OrMat(3,2)*rRef(3) - rRef(2) - u%CoupledKinematics(iTurb)%TranslationDisp(3,J) = InitInp%PtfmInit(3,iTurb) + OrMat(1,3)*rRef(1) + OrMat(2,3)*rRef(2) + OrMat(3,3)*rRef(3) - rRef(3) - OrMat2 = MATMUL(OrMat, TRANSPOSE( EulerConstruct( rRef(4:6)))) ! combine the Rod's relative orientation with the turbine's initial orientation u%CoupledKinematics(iTurb)%Orientation(:,:,J) = OrMat2 ! set the result as the current orientation of the rod <<< ! set absolute initial positions in MoorDyn - m%RodList(m%CpldRodIs(l,iTurb))%r6(1:3) = u%CoupledKinematics(iTurb)%Position(:,J) + u%CoupledKinematics(iTurb)%TranslationDisp(:,J) + p%TurbineRefPos(:,iTurb) + IF (p%Standalone == 1) THEN + m%RodList(m%CpldRodIs(l,iTurb))%r6(1:3) = u%CoupledKinematics(iTurb)%Position(:,J) + ELSE + ! calculate initial point relative position, adjusted due to initial platform rotations and translations <<< could convert to array math + u%CoupledKinematics(iTurb)%TranslationDisp(1,J) = InitInp%PtfmInit(1,iTurb) + OrMat(1,1)*rRef(1) + OrMat(2,1)*rRef(2) + OrMat(3,1)*rRef(3) - rRef(1) + u%CoupledKinematics(iTurb)%TranslationDisp(2,J) = InitInp%PtfmInit(2,iTurb) + OrMat(1,2)*rRef(1) + OrMat(2,2)*rRef(2) + OrMat(3,2)*rRef(3) - rRef(2) + u%CoupledKinematics(iTurb)%TranslationDisp(3,J) = InitInp%PtfmInit(3,iTurb) + OrMat(1,3)*rRef(1) + OrMat(2,3)*rRef(2) + OrMat(3,3)*rRef(3) - rRef(3) + m%RodList(m%CpldRodIs(l,iTurb))%r6(1:3) = u%CoupledKinematics(iTurb)%Position(:,J) + u%CoupledKinematics(iTurb)%TranslationDisp(:,J) + p%TurbineRefPos(:,iTurb) + ENDIF m%RodList(m%CpldRodIs(l,iTurb))%r6(4:6) = EulerExtract(MATMUL(OrMat, OrMatRef)) ! apply rotation from PtfmInit onto input file's rod orientation to get its true initial orientation + + m%RodList(m%CpldRodIs(l,iTurb))%r6 = [0,0,-5,0,0,-1] ! Hack for testing the pinned rods + ! >>> still need to set Rod initial orientations accounting for PtfmInit rotation <<< CALL MeshConstructElement(u%CoupledKinematics(iTurb), ELEMENT_POINT, ErrStat2, ErrMsg2, J) @@ -1819,15 +1834,17 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er ! set reference position as per input file <<< what about turbine positions in array? rRef(1:3) = m%PointList(m%CpldPointIs(l,iTurb))%r CALL MeshPositionNode(u%CoupledKinematics(iTurb), J, rRef(1:3), ErrStat2, ErrMsg2) - - ! calculate initial point relative position, adjusted due to initial platform rotations and translations <<< could convert to array math - u%CoupledKinematics(iTurb)%TranslationDisp(1,J) = InitInp%PtfmInit(1,iTurb) + OrMat(1,1)*rRef(1) + OrMat(2,1)*rRef(2) + OrMat(3,1)*rRef(3) - rRef(1) - u%CoupledKinematics(iTurb)%TranslationDisp(2,J) = InitInp%PtfmInit(2,iTurb) + OrMat(1,2)*rRef(1) + OrMat(2,2)*rRef(2) + OrMat(3,2)*rRef(3) - rRef(2) - u%CoupledKinematics(iTurb)%TranslationDisp(3,J) = InitInp%PtfmInit(3,iTurb) + OrMat(1,3)*rRef(1) + OrMat(2,3)*rRef(2) + OrMat(3,3)*rRef(3) - rRef(3) - + ! set absolute initial positions in MoorDyn - m%PointList(m%CpldPointIs(l,iTurb))%r = u%CoupledKinematics(iTurb)%Position(:,J) + u%CoupledKinematics(iTurb)%TranslationDisp(:,J) + p%TurbineRefPos(:,iTurb) - + IF (p%Standalone == 1) THEN + m%PointList(m%CpldPointIs(l,iTurb))%r = u%CoupledKinematics(iTurb)%Position(:,J) + ELSE + ! calculate initial point relative position, adjusted due to initial platform rotations and translations <<< could convert to array math + u%CoupledKinematics(iTurb)%TranslationDisp(1,J) = InitInp%PtfmInit(1,iTurb) + OrMat(1,1)*rRef(1) + OrMat(2,1)*rRef(2) + OrMat(3,1)*rRef(3) - rRef(1) + u%CoupledKinematics(iTurb)%TranslationDisp(2,J) = InitInp%PtfmInit(2,iTurb) + OrMat(1,2)*rRef(1) + OrMat(2,2)*rRef(2) + OrMat(3,2)*rRef(3) - rRef(2) + u%CoupledKinematics(iTurb)%TranslationDisp(3,J) = InitInp%PtfmInit(3,iTurb) + OrMat(1,3)*rRef(1) + OrMat(2,3)*rRef(2) + OrMat(3,3)*rRef(3) - rRef(3) + m%PointList(m%CpldPointIs(l,iTurb))%r = u%CoupledKinematics(iTurb)%Position(:,J) + u%CoupledKinematics(iTurb)%TranslationDisp(:,J) + p%TurbineRefPos(:,iTurb) + ENDIF CALL MeshConstructElement(u%CoupledKinematics(iTurb), ELEMENT_POINT, ErrStat2, ErrMsg2, J) ! lastly, do this to set the attached line endpoint positions: @@ -2973,8 +2990,10 @@ SUBROUTINE MD_CalcContStateDeriv( t, u, p, x, xd, z, other, m, dxdt, ErrStat, Er END DO DO l = 1,p%nCpldRods(iTurb) - CALL Rod_DoRHS(m%RodList(m%CpldRodIs(l,iTurb)), m, p) - ! NOTE: this won't compute net loads on Rod. Need Rod_GetNetForceAndMass for that. Change? <<<< + IF (m%RodList(m%CpldRodIs(l,iTurb))%typeNum /= -1) THEN ! For a coupled pinned rod, Rod_GetStateDeriv already calls doRHS + CALL Rod_DoRHS(m%RodList(m%CpldRodIs(l,iTurb)), m, p) + ! NOTE: this won't compute net loads on Rod. Need Rod_GetNetForceAndMass for that. Change? <<<< + ENDIF END DO DO l = 1,p%nCpldBodies(iTurb) diff --git a/modules/moordyn/src/MoorDyn_Driver.f90 b/modules/moordyn/src/MoorDyn_Driver.f90 index 83e2e5e65b..46ed87cd17 100644 --- a/modules/moordyn/src/MoorDyn_Driver.f90 +++ b/modules/moordyn/src/MoorDyn_Driver.f90 @@ -173,6 +173,11 @@ PROGRAM MoorDyn_Driver ! do OpenFAST vs FAST.Farm related setup MD_InitInp%FarmSize = drvrInitInp%FarmSize + IF (MD_InitInp%FarmSize < 0) THEN + MD_InitInp%Standalone = 1 + ELSE + MD_InitInp%Standalone = 0 + ENDIF if (drvrInitInp%FarmSize > 0) then ! Check if this MoorDyn instance is being run from FAST.Farm (indicated by FarmSize > 0) nTurbines = drvrInitInp%FarmSize @@ -493,7 +498,11 @@ PROGRAM MoorDyn_Driver J = 1 ! the starting index of the relevant DOFs in the input array ! any coupled bodies (type -1) DO l = 1,MD_p%nCpldBodies(iTurb) - MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) - MD_p%TurbineRefPos(:,iTurb) + IF (MD_InitInp%Standalone == 1) THEN + MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) + ELSE + MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) - MD_p%TurbineRefPos(:,iTurb) + ENDIF MD_u(1)%CoupledKinematics(iTurb)%Orientation( :,:,K) = EulerConstruct( r_in(i, J+3:J+5) ) ! full Euler angle approach MD_u(1)%CoupledKinematics(iTurb)%TranslationVel( :,K) = rd_in(i, J:J+2) MD_u(1)%CoupledKinematics(iTurb)%RotationVel( :,K) = rd_in(i, J+3:J+5) @@ -507,7 +516,11 @@ PROGRAM MoorDyn_Driver ! any coupled rods (type -1 or -2) >>> need to make rotations ignored if it's a pinned rod <<< DO l = 1,MD_p%nCpldRods(iTurb) - MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) - MD_p%TurbineRefPos(:,iTurb) + IF (MD_InitInp%Standalone == 1) THEN + MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) + ELSE + MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) - MD_p%TurbineRefPos(:,iTurb) + ENDIF MD_u(1)%CoupledKinematics(iTurb)%Orientation( :,:,K) = EulerConstruct( r_in(i, J+3:J+5) ) MD_u(1)%CoupledKinematics(iTurb)%TranslationVel( :,K) = rd_in(i, J:J+2) MD_u(1)%CoupledKinematics(iTurb)%RotationVel( :,K) = rd_in(i, J+3:J+5) @@ -521,7 +534,11 @@ PROGRAM MoorDyn_Driver ! any coupled points (type -1) DO l = 1, MD_p%nCpldPoints(iTurb) - MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) - MD_p%TurbineRefPos(:,iTurb) + IF (MD_InitInp%Standalone == 1) THEN + MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) + ELSE + MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) - MD_p%TurbineRefPos(:,iTurb) + ENDIF MD_u(1)%CoupledKinematics(iTurb)%TranslationVel( :,K) = rd_in(i, J:J+2) MD_u(1)%CoupledKinematics(iTurb)%TranslationAcc( :,K) = 0.0_DbKi !rdd_in(i, J:J+2) @@ -582,7 +599,11 @@ PROGRAM MoorDyn_Driver J = 1 ! the starting index of the relevant DOFs in the input array ! any coupled bodies (type -1) DO l = 1,MD_p%nCpldBodies(iTurb) - MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) - MD_p%TurbineRefPos(:,iTurb) + IF (MD_InitInp%Standalone == 1) THEN + MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) + ELSE + MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) - MD_p%TurbineRefPos(:,iTurb) + ENDIF MD_u(1)%CoupledKinematics(iTurb)%Orientation( :,:,K) = EulerConstruct( r_in(i, J+3:J+5) ) ! full Euler angle approach MD_u(1)%CoupledKinematics(iTurb)%TranslationVel( :,K) = rd_in(i, J:J+2) MD_u(1)%CoupledKinematics(iTurb)%RotationVel( :,K) = rd_in(i, J+3:J+5) @@ -596,7 +617,11 @@ PROGRAM MoorDyn_Driver ! any coupled rods (type -1 or -2) >>> need to make rotations ignored if it's a pinned rod <<< DO l = 1,MD_p%nCpldRods(iTurb) - MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) - MD_p%TurbineRefPos(:,iTurb) + IF (MD_InitInp%Standalone == 1) THEN + MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) + ELSE + MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) - MD_p%TurbineRefPos(:,iTurb) + ENDIF MD_u(1)%CoupledKinematics(iTurb)%Orientation( :,:,K) = EulerConstruct( r_in(i, J+3:J+5) ) MD_u(1)%CoupledKinematics(iTurb)%TranslationVel( :,K) = rd_in(i, J:J+2) MD_u(1)%CoupledKinematics(iTurb)%RotationVel( :,K) = rd_in(i, J+3:J+5) @@ -610,7 +635,11 @@ PROGRAM MoorDyn_Driver ! any coupled points (type -1) DO l = 1, MD_p%nCpldPoints(iTurb) - MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) - MD_p%TurbineRefPos(:,iTurb) + IF (MD_InitInp%Standalone == 1) THEN + MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) + ELSE + MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) - MD_p%TurbineRefPos(:,iTurb) + ENDIF MD_u(1)%CoupledKinematics(iTurb)%TranslationVel( :,K) = rd_in(i, J:J+2) MD_u(1)%CoupledKinematics(iTurb)%TranslationAcc( :,K) = 0.0_DbKi !rdd_in(i, J:J+2) diff --git a/modules/moordyn/src/MoorDyn_Registry.txt b/modules/moordyn/src/MoorDyn_Registry.txt index 7965106d56..48baad2dd0 100644 --- a/modules/moordyn/src/MoorDyn_Registry.txt +++ b/modules/moordyn/src/MoorDyn_Registry.txt @@ -24,7 +24,8 @@ typedef MoorDyn/MD InitInputType ReKi g - -99 typedef ^ ^ ReKi rhoW - -999.9 - "sea density" "[kg/m^3]" typedef ^ ^ ReKi WtrDepth - -999.9 - "depth of water" "[m]" typedef ^ ^ ReKi PtfmInit {:}{:} - - "initial position of platform(s) shape: 6, nTurbines" - -typedef ^ ^ IntKi FarmSize - 0 - "Indicates normal FAST module mode if 0, FAST.Farm coupled mode and =nTurbines if >0" - +typedef ^ ^ IntKi FarmSize - 0 - "Indicates normal FAST module mode if 0, FAST.Farm coupled mode and =nTurbines if >0, standalone mode if -1" - +typedef ^ ^ IntKi Standalone - 0 - "Indicates MoorDyn run as standalone code if 1, coupled if 0" - typedef ^ ^ ReKi TurbineRefPos {:}{:} - - "reference position of turbines in farm, shape: 3, nTurbines" - typedef ^ ^ ReKi Tmax - - - "simulation duration" "[s]" typedef ^ ^ CHARACTER(1024) FileName - "" - "MoorDyn input file" @@ -148,7 +149,7 @@ typedef ^ ^ DbKi M {3}{3} typedef ^ MD_Rod IntKi IdNum - - - "integer identifier of this Line" typedef ^ ^ CHARACTER(10) type - - - "type of Rod. should match one of RodProp names" typedef ^ ^ IntKi PropsIdNum - - - "the IdNum of the associated rod properties" - -typedef ^ ^ IntKi typeNum - - - "integer identifying the type. 0=fixed, 1=vessel, 2=point" +typedef ^ ^ IntKi typeNum - - - "integer identifying the type. 0=fixed, 1=vessel, 2=point, -1=coupledpinned" typedef ^ ^ IntKi AttachedA {10} - - "list of IdNums of lines attached to end A" typedef ^ ^ IntKi AttachedB {10} - - "list of IdNums of lines attached to end B" typedef ^ ^ IntKi TopA {10} - - "list of ints specifying whether each line is attached at 1 = top/fairlead(end B), 0 = bottom/anchor(end A)" diff --git a/modules/moordyn/src/MoorDyn_Rod.f90 b/modules/moordyn/src/MoorDyn_Rod.f90 index f7f25e4d93..feb5e6dc53 100644 --- a/modules/moordyn/src/MoorDyn_Rod.f90 +++ b/modules/moordyn/src/MoorDyn_Rod.f90 @@ -491,8 +491,7 @@ SUBROUTINE Rod_GetStateDeriv(Rod, Xd, m, p) ELSE ! pinned rod, 6 states (rotational only) ! account for moment in response to end A acceleration due to inertial coupling (off-diagonal sub-matrix terms) - !Fnet(4:6) = Fnet(4:6) - MATMUL(M_out(4:6,1:3), Rod%a6(1:3)) ! <<0 [-] + INTEGER(IntKi) :: Standalone = 0 !< Indicates MoorDyn run as standalone code if 1, coupled if 0, standalone mode if -1 [-] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: TurbineRefPos !< reference position of turbines in farm, shape: 3, nTurbines [-] REAL(ReKi) :: Tmax !< simulation duration [[s]] CHARACTER(1024) :: FileName !< MoorDyn input file [-] @@ -459,6 +460,7 @@ MODULE MoorDyn_Types INTEGER(IntKi) , DIMENSION(:), ALLOCATABLE :: dxIdx_map2_xStateIdx !< Mapping array from index of dX array to corresponding state index [-] LOGICAL :: VisMeshes !< Using visualization meshes as requested by glue code [-] TYPE(VisDiam) , DIMENSION(:), ALLOCATABLE :: VisRodsDiam !< Diameters for visualization of rods [-] + INTEGER(IntKi) :: Standalone !< Indicates MoorDyn run as standalone code if 1, coupled if 0 [-] END TYPE MD_ParameterType ! ======================= ! ========= MD_InputType ======= From 6d16c6e518c1441d38c7cb1bc5c611deaca3c396 Mon Sep 17 00:00:00 2001 From: RyanDavies19 Date: Thu, 2 Nov 2023 14:03:15 -0600 Subject: [PATCH 02/18] Additonaly standalone variable in registry --- modules/moordyn/src/MoorDyn_Registry.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/moordyn/src/MoorDyn_Registry.txt b/modules/moordyn/src/MoorDyn_Registry.txt index 48baad2dd0..440a83b940 100644 --- a/modules/moordyn/src/MoorDyn_Registry.txt +++ b/modules/moordyn/src/MoorDyn_Registry.txt @@ -428,6 +428,7 @@ typedef ^ ^ Integer Jac_nx - typedef ^ ^ Integer dxIdx_map2_xStateIdx {:} - - "Mapping array from index of dX array to corresponding state index" - typedef ^ ^ Logical VisMeshes - - - "Using visualization meshes as requested by glue code" - typedef ^ ^ VisDiam VisRodsDiam {:} - - "Diameters for visualization of rods" - +typedef ^ ^ IntKi Standalone - - - "Indicates MoorDyn run as standalone code if 1, coupled if 0" - # ============================== Inputs ============================================================================================================================================ From 5ccfb2f06762627271ae547ffcd8ccd1fec18560 Mon Sep 17 00:00:00 2001 From: RyanDavies19 Date: Thu, 2 Nov 2023 17:14:25 -0600 Subject: [PATCH 03/18] Smoother handling of standalone --- modules/moordyn/src/MoorDyn.f90 | 48 ++++++++++---------------- modules/moordyn/src/MoorDyn_Driver.f90 | 13 ++++--- 2 files changed, 25 insertions(+), 36 deletions(-) diff --git a/modules/moordyn/src/MoorDyn.f90 b/modules/moordyn/src/MoorDyn.f90 index 2f9f5821bd..a3f12e8399 100644 --- a/modules/moordyn/src/MoorDyn.f90 +++ b/modules/moordyn/src/MoorDyn.f90 @@ -1768,24 +1768,21 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er J = J + 1 rRef = m%BodyList(m%CpldBodyIs(l,iTurb))%r6 ! for now set reference position as per input file <<< - !OrMatRef = CALL MeshPositionNode(u%CoupledKinematics(iTurb), J, rRef(1:3), ErrStat2, ErrMsg2) ! defaults to identity orientation matrix - !TODO: >>> should also maybe set reference orientation (which might make part of a couple lines down redundant) <<< - - - OrMat2 = MATMUL(OrMat, TRANSPOSE( EulerConstruct( rRef(4:6)))) ! combine the Body's relative orientation with the turbine's initial orientation - u%CoupledKinematics(iTurb)%Orientation(:,:,J) = OrMat2 ! set the result as the current orientation of the body <<< ! set absolute initial positions in MoorDyn - IF (p%Standalone == 1) THEN - m%BodyList(m%CpldBodyIs(l,iTurb))%r6(1:3) = u%CoupledKinematics(iTurb)%Position(:,J) - ELSE + IF (p%Standalone /= 1) THEN + !TODO: >>> should also maybe set reference orientation (which might make part of a couple lines down redundant) <<< + OrMat2 = MATMUL(OrMat, TRANSPOSE( EulerConstruct( rRef(4:6)))) ! combine the Body's relative orientation with the turbine's initial orientation + u%CoupledKinematics(iTurb)%Orientation(:,:,J) = OrMat2 ! set the result as the current orientation of the body <<< + ! calculate initial point relative position, adjusted due to initial platform translations u%CoupledKinematics(iTurb)%TranslationDisp(:,J) = InitInp%PtfmInit(1:3,iTurb) - rRef(1:3) m%BodyList(m%CpldBodyIs(l,iTurb))%r6(1:3) = u%CoupledKinematics(iTurb)%Position(:,J) + u%CoupledKinematics(iTurb)%TranslationDisp(:,J) + p%TurbineRefPos(:,iTurb) + + m%BodyList(m%CpldBodyIs(l,iTurb))%r6(4:6) = EulerExtract(MATMUL(OrMat, TRANSPOSE( EulerConstruct( rRef(4:6))))) ! apply rotation from PtfmInit onto input file's body orientation to get its true initial orientation ENDIF - m%BodyList(m%CpldBodyIs(l,iTurb))%r6(4:6) = EulerExtract(MATMUL(OrMat, TRANSPOSE( EulerConstruct( rRef(4:6))))) ! apply rotation from PtfmInit onto input file's body orientation to get its true initial orientation CALL MeshConstructElement(u%CoupledKinematics(iTurb), ELEMENT_POINT, ErrStat2, ErrMsg2, J) ! set node as point element @@ -1798,29 +1795,24 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er J = J + 1 rRef = m%RodList(m%CpldRodIs(l,iTurb))%r6 ! for now set reference position as per input file <<< - OrMatRef = TRANSPOSE( m%RodList(m%CpldRodIs(l,iTurb))%OrMat ) ! for now set reference orientation as per input file <<< - CALL MeshPositionNode(u%CoupledKinematics(iTurb), J, rRef(1:3), ErrStat2, ErrMsg2, OrMatRef) ! assign the reference position and orientation - - OrMat2 = MATMUL(OrMat, TRANSPOSE( EulerConstruct( rRef(4:6)))) ! combine the Rod's relative orientation with the turbine's initial orientation - u%CoupledKinematics(iTurb)%Orientation(:,:,J) = OrMat2 ! set the result as the current orientation of the rod <<< - + ! set absolute initial positions in MoorDyn - IF (p%Standalone == 1) THEN - m%RodList(m%CpldRodIs(l,iTurb))%r6(1:3) = u%CoupledKinematics(iTurb)%Position(:,J) - ELSE + IF (p%Standalone /= 1) THEN + OrMatRef = TRANSPOSE( m%RodList(m%CpldRodIs(l,iTurb))%OrMat ) ! for now set reference orientation as per input file <<< + CALL MeshPositionNode(u%CoupledKinematics(iTurb), J, rRef(1:3), ErrStat2, ErrMsg2, OrMatRef) ! assign the reference position and orientation + OrMat2 = MATMUL(OrMat, TRANSPOSE( EulerConstruct( rRef(4:6)))) ! combine the Rod's relative orientation with the turbine's initial orientation + u%CoupledKinematics(iTurb)%Orientation(:,:,J) = OrMat2 ! set the result as the current orientation of the rod <<< + ! calculate initial point relative position, adjusted due to initial platform rotations and translations <<< could convert to array math u%CoupledKinematics(iTurb)%TranslationDisp(1,J) = InitInp%PtfmInit(1,iTurb) + OrMat(1,1)*rRef(1) + OrMat(2,1)*rRef(2) + OrMat(3,1)*rRef(3) - rRef(1) u%CoupledKinematics(iTurb)%TranslationDisp(2,J) = InitInp%PtfmInit(2,iTurb) + OrMat(1,2)*rRef(1) + OrMat(2,2)*rRef(2) + OrMat(3,2)*rRef(3) - rRef(2) u%CoupledKinematics(iTurb)%TranslationDisp(3,J) = InitInp%PtfmInit(3,iTurb) + OrMat(1,3)*rRef(1) + OrMat(2,3)*rRef(2) + OrMat(3,3)*rRef(3) - rRef(3) m%RodList(m%CpldRodIs(l,iTurb))%r6(1:3) = u%CoupledKinematics(iTurb)%Position(:,J) + u%CoupledKinematics(iTurb)%TranslationDisp(:,J) + p%TurbineRefPos(:,iTurb) + m%RodList(m%CpldRodIs(l,iTurb))%r6(4:6) = EulerExtract(MATMUL(OrMat, OrMatRef)) ! apply rotation from PtfmInit onto input file's rod orientation to get its true initial orientation ENDIF - m%RodList(m%CpldRodIs(l,iTurb))%r6(4:6) = EulerExtract(MATMUL(OrMat, OrMatRef)) ! apply rotation from PtfmInit onto input file's rod orientation to get its true initial orientation - - m%RodList(m%CpldRodIs(l,iTurb))%r6 = [0,0,-5,0,0,-1] ! Hack for testing the pinned rods - ! >>> still need to set Rod initial orientations accounting for PtfmInit rotation <<< - + CALL MeshConstructElement(u%CoupledKinematics(iTurb), ELEMENT_POINT, ErrStat2, ErrMsg2, J) ! lastly, do this to set the attached line endpoint positions: @@ -1832,12 +1824,10 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er ! set reference position as per input file <<< what about turbine positions in array? rRef(1:3) = m%PointList(m%CpldPointIs(l,iTurb))%r - CALL MeshPositionNode(u%CoupledKinematics(iTurb), J, rRef(1:3), ErrStat2, ErrMsg2) - + ! set absolute initial positions in MoorDyn - IF (p%Standalone == 1) THEN - m%PointList(m%CpldPointIs(l,iTurb))%r = u%CoupledKinematics(iTurb)%Position(:,J) - ELSE + IF (p%Standalone /= 1) THEN + CALL MeshPositionNode(u%CoupledKinematics(iTurb), J, rRef(1:3), ErrStat2, ErrMsg2) ! calculate initial point relative position, adjusted due to initial platform rotations and translations <<< could convert to array math u%CoupledKinematics(iTurb)%TranslationDisp(1,J) = InitInp%PtfmInit(1,iTurb) + OrMat(1,1)*rRef(1) + OrMat(2,1)*rRef(2) + OrMat(3,1)*rRef(3) - rRef(1) u%CoupledKinematics(iTurb)%TranslationDisp(2,J) = InitInp%PtfmInit(2,iTurb) + OrMat(1,2)*rRef(1) + OrMat(2,2)*rRef(2) + OrMat(3,2)*rRef(3) - rRef(2) diff --git a/modules/moordyn/src/MoorDyn_Driver.f90 b/modules/moordyn/src/MoorDyn_Driver.f90 index ca250b3585..5902736cd5 100644 --- a/modules/moordyn/src/MoorDyn_Driver.f90 +++ b/modules/moordyn/src/MoorDyn_Driver.f90 @@ -172,15 +172,14 @@ PROGRAM MoorDyn_Driver ! do OpenFAST vs FAST.Farm related setup MD_InitInp%FarmSize = drvrInitInp%FarmSize - IF (MD_InitInp%FarmSize < 0) THEN - MD_InitInp%Standalone = 1 - ELSE - MD_InitInp%Standalone = 0 - ENDIF + MD_InitInp%Standalone = 0 if (drvrInitInp%FarmSize > 0) then ! Check if this MoorDyn instance is being run from FAST.Farm (indicated by FarmSize > 0) nTurbines = drvrInitInp%FarmSize - else ! FarmSize==0 indicates normal, FAST module mode + else if (drvrInitInp%FarmSize < 0) then ! FarmSize<0 indicates standalone mode + MD_InitInp%Standalone = 1 + nTurbines = 1 ! to keep routines happy + else ! FarmSize==0 indicates normal, FAST module mode nTurbines = 1 ! if a regular FAST module mode, we treat it like a nTurbine=1 farm case end if @@ -589,7 +588,7 @@ PROGRAM MoorDyn_Driver MD_uTimes(2) = MD_uTimes(1) - dtC !MD_uTimes(3) = MD_uTimes(2) - dtC - ! update coupled object kinematics iff we're reading input time series + ! update coupled object kinematics if we're reading input time series if (drvrInitInp%InputsMod == 1 ) then DO iTurb = 1, MD_p%nTurbines From a733f8e3f0ef57411cb34d8c24ef28ea3062e7d1 Mon Sep 17 00:00:00 2001 From: RyanDavies19 Date: Mon, 6 Nov 2023 17:30:36 -0700 Subject: [PATCH 04/18] Coupled pinned bodies --- modules/moordyn/src/MoorDyn.f90 | 120 +++++++++++++------- modules/moordyn/src/MoorDyn_Body.f90 | 133 ++++++++++++++++------- modules/moordyn/src/MoorDyn_Registry.txt | 6 +- 3 files changed, 175 insertions(+), 84 deletions(-) diff --git a/modules/moordyn/src/MoorDyn.f90 b/modules/moordyn/src/MoorDyn.f90 index a3f12e8399..da79fe50a3 100644 --- a/modules/moordyn/src/MoorDyn.f90 +++ b/modules/moordyn/src/MoorDyn.f90 @@ -773,7 +773,7 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er else CALL SetErrStat( ErrID_Fatal, 'Body '//trim(Num2LStr(l))//' CG entry (col 10) must have 1 or 3 numbers.' , ErrStat, ErrMsg, RoutineName ) end if - ! process mements of inertia + ! process moments of inertia CALL SplitByBars(tempString3, N, tempStrings) if (N == 1) then ! if only one entry, use it for all directions READ(tempString3, *) m%BodyList(l)%BodyI(1) @@ -839,6 +839,20 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er m%CpldBodyIs(p%nCpldBodies(1),1) = l ! body initial position due to coupling will be adjusted later + + else if ((let1 == "VESSELPINNED") .or. (let1 == "VESPIN") .or. (let1 == "COUPLEDPINNED") .or. (let1 == "CPLDPIN")) then ! if a pinned coupled body, add to list and add + m%BodyList(l)%typeNum = 2 + + p%nCpldBodies(1)=p%nCpldBodies(1)+1 ! add + p%nFreeBodies =p%nFreeBodies+1 ! add this pinned body to the free list because it is half free + + m%BodyStateIs1(p%nFreeBodies) = Nx+1 + m%BodyStateIsN(p%nFreeBodies) = Nx+6 + Nx = Nx + 6 ! add 6 state variables for each pinned body + + m%CpldBodyIs(p%nCpldBodies(1),1) = l + m%FreeBodyIs(p%nFreeBodies) = l + ! TODO: add option for body coupling to different turbines in FAST.Farm <<< @@ -1010,7 +1024,7 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er ! TODO: add option for body coupling to different turbines in FAST.Farm <<< - else if ((let1 == "CONNECT") .or. (let1 == "CON") .or. (let1 == "FREE")) then + else if ((let1 == "ROD") .or. (let1 == "R") .or. (let1 == "FREE")) then m%RodList(l)%typeNum = 0 p%nFreeRods=p%nFreeRods+1 @@ -1949,7 +1963,7 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er ! >>> maybe this should be skipped <<<< - ! Go through Bodys and write the coordinates to the state vector + ! Go through free Bodys (including pinned) and write the coordinates to the state vector DO l = 1,p%nFreeBodies CALL Body_Initialize(m%BodyList(m%FreeBodyIs(l)), x%states(m%BodyStateIs1(l) : m%BodyStateIsN(l)), m) END DO @@ -2972,8 +2986,8 @@ SUBROUTINE MD_CalcContStateDeriv( t, u, p, x, xd, z, other, m, dxdt, ErrStat, Er DO iTurb = 1,p%nTurbines DO l = 1,p%nCpldPoints(iTurb) - ! >>>>>>>> here we should pass along accelerations and include inertial loads in the calculation!!! <<>>>>>>> here we should pass along accelerations and include inertial loads in the calculation!!! << 0) print *, "initializing Body ", Body%idNum + + ! the r6 and v6 vectors should have already been set + ! r and rd of ends have already been set by setup function or by parent object <<<<< right? <<<<< + + if (Body%typeNum == 0) then ! free body type + + ! assign initial body kinematics to state vector + states(1:6 ) = Body%v6 ! zero velocities for initialization (set to 0 in Body_Setup) + states(7:12) = Body%r6 + + else if (Body%typeNum ==2 ) then ! pinned rod type (coupled or attached to something previously via setPinKin) + + states(1:3) = Body%v6(4:6) ! zero velocities for initialization (set to 0 in Body_Setup) + states(4:6) = Body%r6(4:6) ! body orentations + + end if + ! set positions of any dependent points and rods now (before they are initialized) CALL Body_SetDependentKin(Body, 0.0_DbKi, m) @@ -203,12 +216,12 @@ END SUBROUTINE Body_InitializeUnfree ! set kinematics for Bodies if they are coupled (or ground) !-------------------------------------------------------------- - SUBROUTINE Body_SetKinematics(Body, r_in, v_in, a_in, t, m) + SUBROUTINE Body_SetKinematics(Body, r6_in, v6_in, a6_in, t, m) Type(MD_Body), INTENT(INOUT) :: Body ! the Body object - Real(DbKi), INTENT(IN ) :: r_in(6) ! 6-DOF position - Real(DbKi), INTENT(IN ) :: v_in(6) ! 6-DOF velocity - Real(DbKi), INTENT(IN ) :: a_in(6) ! 6-DOF acceleration (only used for coupled rods) + Real(DbKi), INTENT(IN ) :: r6_in(6) ! 6-DOF position + Real(DbKi), INTENT(IN ) :: v6_in(6) ! 6-DOF velocity + Real(DbKi), INTENT(IN ) :: a6_in(6) ! 6-DOF acceleration (only used for coupled rods) Real(DbKi), INTENT(IN ) :: t ! instantaneous time TYPE(MD_MiscVarType), INTENT(INOUT) :: m ! passing along all mooring objects (for simplicity, since Bodies deal with Rods and Points) @@ -218,26 +231,24 @@ SUBROUTINE Body_SetKinematics(Body, r_in, v_in, a_in, t, m) ! store current time Body%time = t - ! if (abs(Body%typeNum) == 2) then ! body coupled in 6 DOF, or ground - Body%r6 = r_in - Body%v6 = v_in - Body%a6 = a_in + if (Body%typeNum == 2) then ! body pinned to coupling point + + ! set Body translational kinematics based on BCs (linear model for now) + Body%r6(1:3) = r6_in(1:3) + Body%v6(1:3) = v6_in(1:3) + Body%a6(1:3) = a6_in(1:3) + + ! Body rotations are left alone and will be handled, along with passing kinematics to dependent objects, by separate call to setState + + else ! body rigidly coupled to coupling point + Body%r6 = r6_in + Body%v6 = v6_in + Body%a6 = a6_in ! since this body has no states and all DOFs have been set, pass its kinematics to dependent attachments CALL Body_SetDependentKin(Body, t, m) - - ! else if (abs(Body%typeNum) == 1) then ! body pinned at reference point - ! - ! ! set Body *end A only* kinematics based on BCs (linear model for now) - ! Body%r6(1:3) = r_in(1:3) - ! Body%v6(1:3) = v_in(1:3) - ! - ! ! Body is pinned so only ref point posiiton is specified, rotations are left alone and will be - ! ! handled, along with passing kinematics to attached objects, by separate call to setState - ! - ! else - ! print *, "Error: Body_SetKinematics called for a free Body." ! <<< - ! end if + + end if END SUBROUTINE Body_SetKinematics !-------------------------------------------------------------- @@ -257,14 +268,26 @@ SUBROUTINE Body_SetState(Body, X, t, m) ! store current time Body%time = t + if (Body%typeNum == 0) then ! free Body type - - Body%r6 = X(7:12) ! get positions - Body%v6 = X(1:6) ! get velocities - + Body%r6 = X(7:12) ! get positions + Body%v6 = X(1:6) ! get velocities + + ! set positions of any dependent points and rods + CALL Body_SetDependentKin(Body, t, m) + + else if (Body%typeNum == 2) then + + Body%r6(4:6) = X(4:6) ! get positions + Body%v6(4:6) = X(1:3) ! get velocities + - ! set positions of any dependent points and rods - CALL Body_SetDependentKin(Body, t, m) + ! set positions of any dependent points and rods + CALL Body_SetDependentKin(Body, t, m) + + else + print *, "Error: Body::setState called for a non-free Body type in MoorDyn" ! <<< + end if END SUBROUTINE Body_SetState !-------------------------------------------------------------- @@ -336,6 +359,8 @@ SUBROUTINE Body_GetStateDeriv(Body, Xd, m, p) INTEGER(IntKi) :: J ! index + Real(DbKi) :: Fnet (6) ! net force and moment about reference point + Real(DbKi) :: acc(6) ! 6DOF acceleration vector Real(DbKi) :: y_temp (6) ! temporary vector for LU decomposition @@ -349,15 +374,35 @@ SUBROUTINE Body_GetStateDeriv(Body, Xd, m, p) CALL Body_DoRHS(Body, m, p) - ! solve for accelerations in [M]{a}={f} using LU decomposition - CALL LUsolve(6, Body%M, LU_temp, Body%F6net, y_temp, acc) + IF (Body%typeNum == 0) THEN ! Free body + + ! solve for accelerations in [M]{a}={f} using LU decomposition + CALL LUsolve(6, Body%M, LU_temp, Body%F6net, y_temp, acc) - ! fill in state derivatives - Xd(7:12) = Body%v6 ! dxdt = V (velocities) - Xd(1:6) = acc ! dVdt = a (accelerations) + ! fill in state derivatives + Xd(7:12) = Body%v6 ! dxdt = V (velocities) + Xd(1:6) = acc ! dVdt = a (accelerations) - ! store accelerations in case they're useful as output - Body%a6 = acc + ! store accelerations in case they're useful as output + Body%a6 = acc + + ELSE ! Pinned Body, 6 states (rotational only) + + ! Account for moment response due to inertial coupling + Fnet = Body%F6net + Fnet(4:6) = Fnet(4:6) - MATMUL(Body%M(4:6,1:3), Body%a6(1:3)) + + ! solve for accelerations in [M]{a}={f} using LU decomposition + CALL LUsolve(3, Body%M(4:6,4:6), LU_temp(4:6,4:6), Fnet(4:6), y_temp(4:6), acc(4:6)) + + ! fill in state derivatives + Xd(4:6) = Body%v6(4:6) ! dxdt = V (velocities) + Xd(1:3) = acc(4:6) ! dVdt = a (accelerations) + + ! store accelerations in case they're useful as output + Body%a6(4:6) = acc(4:6) + + ENDIF ! check for NaNs (should check all state derivatives, not just first 6) DO J = 1, 6 @@ -477,9 +522,15 @@ SUBROUTINE Body_GetCoupledForce(Body, Fnet_out, m, p) ! add inertial loads as appropriate if (Body%typeNum == -1) then - F6_iner = 0.0_DbKi !-MATMUL(Body%M, Body%a6) <<<<<<<< why does including F6_iner cause instability??? + F6_iner = -MATMUL(Body%M, Body%a6) ! <<<<<<<< why does including F6_iner cause instability??? Fnet_out = Body%F6net + F6_iner ! add inertial loads - + + else if (Body%typeNum == 2) then ! pinned coupled body + ! inertial loads ... from input translational ... and solved rotational ... acceleration + F6_iner(1:3) = -MATMUL(Body%M6net(1:3,1:3), Body%a6(1:3)) - MATMUL(Body%M6net(1:3,4:6), Body%a6(4:6)) + Fnet_out(1:3) = Body%F6net(1:3) + F6_iner(1:3) ! add translational inertial loads + Fnet_out(4:6) = 0.0_DbKi + else print *, "ERROR, Body_GetCoupledForce called for wrong (non-coupled) body type in MoorDyn!" end if diff --git a/modules/moordyn/src/MoorDyn_Registry.txt b/modules/moordyn/src/MoorDyn_Registry.txt index 7f29fcb13d..a8406ef193 100644 --- a/modules/moordyn/src/MoorDyn_Registry.txt +++ b/modules/moordyn/src/MoorDyn_Registry.txt @@ -88,7 +88,7 @@ typedef ^ ^ DbKi CaEnd - # this is the Body type, which holds data for each body object typedef ^ MD_Body IntKi IdNum - - - "integer identifier of this Point" -typedef ^ ^ IntKi typeNum - - - "integer identifying the type. 0=free, 1=fixed, -1=vessel" +typedef ^ ^ IntKi typeNum - - - "integer identifying the type. 0=free, 1=fixed, -1=coupled, 2=coupledpinned" typedef ^ ^ IntKi AttachedC {30} - - "list of IdNums of points attached to this body" typedef ^ ^ IntKi AttachedR {30} - - "list of IdNums of rods attached to this body" typedef ^ ^ IntKi nAttachedC - 0 - "number of attached points" @@ -117,7 +117,7 @@ typedef ^ ^ DbKi rCG {3} # this is the Point type, which holds data for each point object typedef ^ MD_Point IntKi IdNum - - - "integer identifier of this point" typedef ^ ^ CHARACTER(10) type - - - "type of point: fix, vessel, point" -typedef ^ ^ IntKi typeNum - - - "integer identifying the type. 1=fixed, -1=vessel, 0=free" +typedef ^ ^ IntKi typeNum - - - "integer identifying the type. 1=fixed, -1=coupled, 0=free" typedef ^ ^ IntKi Attached {10} - - "list of IdNums of lines attached to this point node" typedef ^ ^ IntKi Top {10} - - "list of ints specifying whether each line is attached at 1 = top/fairlead(end B), 0 = bottom/anchor(end A)" typedef ^ ^ IntKi nAttached - 0 - "number of attached lines" @@ -143,7 +143,7 @@ typedef ^ ^ DbKi M {3}{3} typedef ^ MD_Rod IntKi IdNum - - - "integer identifier of this Line" typedef ^ ^ CHARACTER(10) type - - - "type of Rod. should match one of RodProp names" typedef ^ ^ IntKi PropsIdNum - - - "the IdNum of the associated rod properties" - -typedef ^ ^ IntKi typeNum - - - "integer identifying the type. 0=fixed, 1=vessel, 2=point, -1=coupledpinned" +typedef ^ ^ IntKi typeNum - - - "integer identifying the type. 0=free, 1=pinned, 2=fixed, -1=coupledpinned, -2=coupled" typedef ^ ^ IntKi AttachedA {10} - - "list of IdNums of lines attached to end A" typedef ^ ^ IntKi AttachedB {10} - - "list of IdNums of lines attached to end B" typedef ^ ^ IntKi TopA {10} - - "list of ints specifying whether each line is attached at 1 = top/fairlead(end B), 0 = bottom/anchor(end A)" From 0cebc49748ed4e239a73692e973ad4420c1da78d Mon Sep 17 00:00:00 2001 From: RyanDavies19 Date: Wed, 22 Nov 2023 15:08:19 -0800 Subject: [PATCH 05/18] Correction to force output --- modules/moordyn/src/MoorDyn_Body.f90 | 14 ++++++++------ modules/moordyn/src/MoorDyn_Driver.f90 | 12 ++++++------ modules/moordyn/src/MoorDyn_Rod.f90 | 9 +++++---- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/modules/moordyn/src/MoorDyn_Body.f90 b/modules/moordyn/src/MoorDyn_Body.f90 index 27bde873c7..f520265fae 100644 --- a/modules/moordyn/src/MoorDyn_Body.f90 +++ b/modules/moordyn/src/MoorDyn_Body.f90 @@ -221,7 +221,7 @@ SUBROUTINE Body_SetKinematics(Body, r6_in, v6_in, a6_in, t, m) Type(MD_Body), INTENT(INOUT) :: Body ! the Body object Real(DbKi), INTENT(IN ) :: r6_in(6) ! 6-DOF position Real(DbKi), INTENT(IN ) :: v6_in(6) ! 6-DOF velocity - Real(DbKi), INTENT(IN ) :: a6_in(6) ! 6-DOF acceleration (only used for coupled rods) + Real(DbKi), INTENT(IN ) :: a6_in(6) ! 6-DOF acceleration Real(DbKi), INTENT(IN ) :: t ! instantaneous time TYPE(MD_MiscVarType), INTENT(INOUT) :: m ! passing along all mooring objects (for simplicity, since Bodies deal with Rods and Points) @@ -386,7 +386,7 @@ SUBROUTINE Body_GetStateDeriv(Body, Xd, m, p) ! store accelerations in case they're useful as output Body%a6 = acc - ELSE ! Pinned Body, 6 states (rotational only) + ELSE ! Pinned Body, 3 states (rotational only) ! Account for moment response due to inertial coupling Fnet = Body%F6net @@ -523,13 +523,15 @@ SUBROUTINE Body_GetCoupledForce(Body, Fnet_out, m, p) if (Body%typeNum == -1) then F6_iner = -MATMUL(Body%M, Body%a6) ! <<<<<<<< why does including F6_iner cause instability??? - Fnet_out = Body%F6net + F6_iner ! add inertial loads + Body%F6net = Body%F6net + F6_iner ! add inertial loads + Fnet_out = Body%F6net else if (Body%typeNum == 2) then ! pinned coupled body ! inertial loads ... from input translational ... and solved rotational ... acceleration - F6_iner(1:3) = -MATMUL(Body%M6net(1:3,1:3), Body%a6(1:3)) - MATMUL(Body%M6net(1:3,4:6), Body%a6(4:6)) - Fnet_out(1:3) = Body%F6net(1:3) + F6_iner(1:3) ! add translational inertial loads - Fnet_out(4:6) = 0.0_DbKi + F6_iner(1:3) = -MATMUL(Body%M(1:3,1:3), Body%a6(1:3)) - MATMUL(Body%M(1:3,4:6), Body%a6(4:6)) + Body%F6net(1:3) = Body%F6net(1:3) + F6_iner(1:3) ! add translational inertial loads + Body%F6net(4:6) = 0.0_DbKi + Fnet_out = Body%F6net else print *, "ERROR, Body_GetCoupledForce called for wrong (non-coupled) body type in MoorDyn!" diff --git a/modules/moordyn/src/MoorDyn_Driver.f90 b/modules/moordyn/src/MoorDyn_Driver.f90 index 5902736cd5..219dfe0f2a 100644 --- a/modules/moordyn/src/MoorDyn_Driver.f90 +++ b/modules/moordyn/src/MoorDyn_Driver.f90 @@ -90,7 +90,7 @@ PROGRAM MoorDyn_Driver INTEGER(IntKi) :: nt ! number of coupling time steps to use in simulation REAL(DbKi) :: t ! current time (s) - REAL(DbKi) :: tMax ! sim end time (s) + REAL(DbKi) :: TMax ! sim end time (s) REAL(DbKi) :: dtC ! fixed/constant global time step REAL(DbKi) :: frac ! fraction used in interpolation @@ -304,7 +304,7 @@ PROGRAM MoorDyn_Driver ! specify stepping details - nt = tMax/dtC - 1 ! number of coupling time steps + nt = TMax/dtC - 1 ! number of coupling time steps ! allocate space for processed motion array @@ -451,11 +451,11 @@ PROGRAM MoorDyn_Driver else - nt = tMax/dtC - 1 ! number of coupling time steps + nt = TMax/dtC - 1 ! number of coupling time steps end if CALL WrScr(" ") - call WrScr("Tmax - "//trim(Num2LStr(tMax))//" and nt="//trim(Num2LStr(nt))) + call WrScr("Tmax - "//trim(Num2LStr(TMax))//" and nt="//trim(Num2LStr(nt))) CALL WrScr(" ") @@ -569,7 +569,7 @@ PROGRAM MoorDyn_Driver call WrScr("Doing time marching now...") - CALL SimStatus_FirstTime( PrevSimTime, PrevClockTime, SimStrtTime, SimStrtCPU, t, tMax ) + CALL SimStatus_FirstTime( PrevSimTime, PrevClockTime, SimStrtTime, SimStrtCPU, t, TMax ) DO i = 1,nt @@ -579,7 +579,7 @@ PROGRAM MoorDyn_Driver if ( MOD( i, 20 ) == 0 ) THEN - CALL SimStatus( PrevSimTime, PrevClockTime, t, tMax ) + CALL SimStatus( PrevSimTime, PrevClockTime, t, TMax ) end if ! shift older inputs back in the buffer diff --git a/modules/moordyn/src/MoorDyn_Rod.f90 b/modules/moordyn/src/MoorDyn_Rod.f90 index e0e9d7cb2c..7302214f9d 100644 --- a/modules/moordyn/src/MoorDyn_Rod.f90 +++ b/modules/moordyn/src/MoorDyn_Rod.f90 @@ -1016,14 +1016,15 @@ SUBROUTINE Rod_GetCoupledForce(Rod, Fnet_out, m, p) if (Rod%typeNum == -2) then F6_iner = -MATMUL(Rod%M6net, Rod%a6) ! inertial loads - Fnet_out = Rod%F6net + F6_iner ! add inertial loads - + Rod%F6net = Rod%F6net + F6_iner ! add inertial loads + Fnet_out = Rod%F6net ! pinned coupled rod else if (Rod%typeNum == -1) then ! inertial loads ... from input translational ... and solved rotational ... acceleration F6_iner(1:3) = -MATMUL(Rod%M6net(1:3,1:3), Rod%a6(1:3)) - MATMUL(Rod%M6net(1:3,4:6), Rod%a6(4:6)) - Fnet_out(1:3) = Rod%F6net(1:3) + F6_iner(1:3) ! add translational inertial loads - Fnet_out(4:6) = 0.0_DbKi + Rod%F6net(1:3) = Rod%F6net(1:3) + F6_iner(1:3) ! add translational inertial loads + Rod%F6net(4:6) = 0.0_DbKi + Fnet_out = Rod%F6net else print *, "ERROR, Rod_GetCoupledForce called for wrong (non-coupled) rod type!" end if From c7b0eeced993ac3f71ae3e42f679a79fd6ebd62e Mon Sep 17 00:00:00 2001 From: RyanDavies19 Date: Tue, 5 Dec 2023 14:38:47 -0700 Subject: [PATCH 06/18] Coupled bodies intialization fix --- modules/moordyn/src/MoorDyn.f90 | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/moordyn/src/MoorDyn.f90 b/modules/moordyn/src/MoorDyn.f90 index da79fe50a3..d0ab4b941c 100644 --- a/modules/moordyn/src/MoorDyn.f90 +++ b/modules/moordyn/src/MoorDyn.f90 @@ -1788,14 +1788,13 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er ! set absolute initial positions in MoorDyn IF (p%Standalone /= 1) THEN !TODO: >>> should also maybe set reference orientation (which might make part of a couple lines down redundant) <<< - OrMat2 = MATMUL(OrMat, TRANSPOSE( EulerConstruct( rRef(4:6)))) ! combine the Body's relative orientation with the turbine's initial orientation + OrMat2 = MATMUL(OrMat, ( EulerConstruct( rRef(4:6)))) ! combine the Body's relative orientation with the turbine's initial orientation u%CoupledKinematics(iTurb)%Orientation(:,:,J) = OrMat2 ! set the result as the current orientation of the body <<< ! calculate initial point relative position, adjusted due to initial platform translations u%CoupledKinematics(iTurb)%TranslationDisp(:,J) = InitInp%PtfmInit(1:3,iTurb) - rRef(1:3) m%BodyList(m%CpldBodyIs(l,iTurb))%r6(1:3) = u%CoupledKinematics(iTurb)%Position(:,J) + u%CoupledKinematics(iTurb)%TranslationDisp(:,J) + p%TurbineRefPos(:,iTurb) - - m%BodyList(m%CpldBodyIs(l,iTurb))%r6(4:6) = EulerExtract(MATMUL(OrMat, TRANSPOSE( EulerConstruct( rRef(4:6))))) ! apply rotation from PtfmInit onto input file's body orientation to get its true initial orientation + m%BodyList(m%CpldBodyIs(l,iTurb))%r6(4:6) = EulerExtract(OrMat2) ! apply rotation from PtfmInit onto input file's body orientation to get its true initial orientation ENDIF CALL MeshConstructElement(u%CoupledKinematics(iTurb), ELEMENT_POINT, ErrStat2, ErrMsg2, J) ! set node as point element From 33269e0f4a46cf624d73aa9bdb03ce7a56086ebd Mon Sep 17 00:00:00 2001 From: RyanDavies19 Date: Wed, 6 Dec 2023 12:33:13 -0700 Subject: [PATCH 07/18] Echo file removed from driver --- modules/moordyn/src/MoorDyn_Driver.f90 | 30 +++++++++++++------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/modules/moordyn/src/MoorDyn_Driver.f90 b/modules/moordyn/src/MoorDyn_Driver.f90 index 219dfe0f2a..27428eb326 100644 --- a/modules/moordyn/src/MoorDyn_Driver.f90 +++ b/modules/moordyn/src/MoorDyn_Driver.f90 @@ -28,7 +28,7 @@ PROGRAM MoorDyn_Driver IMPLICIT NONE TYPE MD_Drvr_InitInput - LOGICAL :: Echo + ! LOGICAL :: Echo REAL(DbKi) :: Gravity REAL(DbKi) :: rhoW REAL(DbKi) :: WtrDepth @@ -120,7 +120,7 @@ PROGRAM MoorDyn_Driver ErrMsg = "" ErrStat = ErrID_None - UnEcho=-1 + UnEcho=-1 ! set to -1 as echo is no longer used by MD UnIn =-1 ! TODO: Sort out error handling (two sets of flags currently used) @@ -162,7 +162,7 @@ PROGRAM MoorDyn_Driver MD_InitInp%RootName = drvrInitInp%OutRootName MD_InitInp%UsePrimaryInputFile = .TRUE. !MD_InitInp%PassedPrimaryInputData = - MD_InitInp%Echo = drvrInitInp%Echo + ! MD_InitInp%Echo = drvrInitInp%Echo !MD_InitInp%OutList = <<<< never used? MD_InitInp%Linearize = .FALSE. @@ -738,7 +738,7 @@ SUBROUTINE ReadDriverInputFile( inputFile, InitInp) ! Local variables INTEGER :: J ! generic integer for counting - CHARACTER(1024) :: EchoFile ! Name of MoorDyn echo file + ! CHARACTER(1024) :: EchoFile ! Name of MoorDyn echo file CHARACTER(1024) :: FileName ! Name of MoorDyn input file CHARACTER(1024) :: FilePath ! Name of path to MoorDyn input file @@ -756,17 +756,17 @@ SUBROUTINE ReadDriverInputFile( inputFile, InitInp) ! Read until "echo" CALL ReadCom( UnIn, FileName, 'MoorDyn Driver input file header line 1', ErrStat2, ErrMsg2); call AbortIfFailed() CALL ReadCom( UnIn, FileName, 'MoorDyn Driver input file header line 2', ErrStat2, ErrMsg2); call AbortIfFailed() - CALL ReadVar ( UnIn, FileName, InitInp%Echo, 'Echo', 'Echo Input', ErrStat2, ErrMsg2); call AbortIfFailed() - ! If we echo, we rewind - IF ( InitInp%Echo ) THEN - EchoFile = TRIM(FileName)//'.echo' - CALL GetNewUnit( UnEcho ) - CALL OpenEcho ( UnEcho, EchoFile, ErrStat2, ErrMsg2 ); call AbortIfFailed() - REWIND(UnIn) - CALL ReadCom( UnIn, FileName, 'MoorDyn Driver input file header line 1', ErrStat2, ErrMsg2, UnEcho); call AbortIfFailed() - CALL ReadCom( UnIn, FileName, 'MoorDyn Driver input file header line 2', ErrStat2, ErrMsg2, UnEcho); call AbortIfFailed() - CALL ReadVar ( UnIn, FileName, InitInp%Echo, 'Echo', 'Echo the input file data', ErrStat2, ErrMsg2, UnEcho); call AbortIfFailed() - END IF + ! CALL ReadVar ( UnIn, FileName, InitInp%Echo, 'Echo', 'Echo Input', ErrStat2, ErrMsg2); call AbortIfFailed() + ! ! If we echo, we rewind + ! IF ( InitInp%Echo ) THEN + ! EchoFile = TRIM(FileName)//'.echo' + ! CALL GetNewUnit( UnEcho ) + ! CALL OpenEcho ( UnEcho, EchoFile, ErrStat2, ErrMsg2 ); call AbortIfFailed() + ! REWIND(UnIn) + ! CALL ReadCom( UnIn, FileName, 'MoorDyn Driver input file header line 1', ErrStat2, ErrMsg2, UnEcho); call AbortIfFailed() + ! CALL ReadCom( UnIn, FileName, 'MoorDyn Driver input file header line 2', ErrStat2, ErrMsg2, UnEcho); call AbortIfFailed() + ! CALL ReadVar ( UnIn, FileName, InitInp%Echo, 'Echo', 'Echo the input file data', ErrStat2, ErrMsg2, UnEcho); call AbortIfFailed() + ! END IF !---------------------- ENVIRONMENTAL CONDITIONS ------------------------------------------------- CALL ReadCom( UnIn, FileName, 'Environmental conditions header', ErrStat2, ErrMsg2, UnEcho); call AbortIfFailed() CALL ReadVar( UnIn, FileName, InitInp%Gravity, 'Gravity', 'Gravity', ErrStat2, ErrMsg2, UnEcho); call AbortIfFailed() From 5cc5e19ceb5f68c2b56edd67ff0844b2e5cffbc9 Mon Sep 17 00:00:00 2001 From: RyanDavies19 Date: Wed, 6 Dec 2023 16:03:40 -0700 Subject: [PATCH 08/18] Indexing and building wave grid fix --- modules/moordyn/src/MoorDyn_Misc.f90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/moordyn/src/MoorDyn_Misc.f90 b/modules/moordyn/src/MoorDyn_Misc.f90 index ddc8bf25a6..d3c6ae542e 100644 --- a/modules/moordyn/src/MoorDyn_Misc.f90 +++ b/modules/moordyn/src/MoorDyn_Misc.f90 @@ -1736,9 +1736,9 @@ SUBROUTINE gridAxisCoords(coordtype, entries, coordarray, n, ErrStat, ErrMsg) else if (coordtype==2) then coordarray(1) = tempArray(1) coordarray(n) = tempArray(2) - dx = (coordarray(n)-coordarray(0))/REAL(n-1) - do i=2,n-1 - coordarray(i) = coordarray(1) + REAL(i)*dx + dx = (coordarray(n)-coordarray(1))/REAL(n-1) + do i=2,n + coordarray(i) = coordarray(i-1) + dx end do else From 4d0c65d4c318f925c30567da0921d3b08cd8a579 Mon Sep 17 00:00:00 2001 From: RyanDavies19 Date: Sun, 10 Dec 2023 16:39:05 -0700 Subject: [PATCH 09/18] Fix coupled rods initial orentation --- modules/moordyn/src/MoorDyn.f90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/moordyn/src/MoorDyn.f90 b/modules/moordyn/src/MoorDyn.f90 index d0ab4b941c..6e3f63272f 100644 --- a/modules/moordyn/src/MoorDyn.f90 +++ b/modules/moordyn/src/MoorDyn.f90 @@ -1811,9 +1811,9 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er ! set absolute initial positions in MoorDyn IF (p%Standalone /= 1) THEN - OrMatRef = TRANSPOSE( m%RodList(m%CpldRodIs(l,iTurb))%OrMat ) ! for now set reference orientation as per input file <<< + OrMatRef = ( m%RodList(m%CpldRodIs(l,iTurb))%OrMat ) ! for now set reference orientation as per input file <<< CALL MeshPositionNode(u%CoupledKinematics(iTurb), J, rRef(1:3), ErrStat2, ErrMsg2, OrMatRef) ! assign the reference position and orientation - OrMat2 = MATMUL(OrMat, TRANSPOSE( EulerConstruct( rRef(4:6)))) ! combine the Rod's relative orientation with the turbine's initial orientation + OrMat2 = MATMUL(OrMat, OrMatRef) ! combine the Rod's relative orientation with the turbine's initial orientation u%CoupledKinematics(iTurb)%Orientation(:,:,J) = OrMat2 ! set the result as the current orientation of the rod <<< ! calculate initial point relative position, adjusted due to initial platform rotations and translations <<< could convert to array math @@ -1821,7 +1821,7 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er u%CoupledKinematics(iTurb)%TranslationDisp(2,J) = InitInp%PtfmInit(2,iTurb) + OrMat(1,2)*rRef(1) + OrMat(2,2)*rRef(2) + OrMat(3,2)*rRef(3) - rRef(2) u%CoupledKinematics(iTurb)%TranslationDisp(3,J) = InitInp%PtfmInit(3,iTurb) + OrMat(1,3)*rRef(1) + OrMat(2,3)*rRef(2) + OrMat(3,3)*rRef(3) - rRef(3) m%RodList(m%CpldRodIs(l,iTurb))%r6(1:3) = u%CoupledKinematics(iTurb)%Position(:,J) + u%CoupledKinematics(iTurb)%TranslationDisp(:,J) + p%TurbineRefPos(:,iTurb) - m%RodList(m%CpldRodIs(l,iTurb))%r6(4:6) = EulerExtract(MATMUL(OrMat, OrMatRef)) ! apply rotation from PtfmInit onto input file's rod orientation to get its true initial orientation + m%RodList(m%CpldRodIs(l,iTurb))%r6(4:6) = MATMUL(OrMat2 , (/0.0, 0.0, 1.0/) ) ! apply rotation from PtfmInit onto input file's rod orientation to get its true initial orientation ENDIF ! >>> still need to set Rod initial orientations accounting for PtfmInit rotation <<< From 0f642c68588aa96d3e4f51a544a9b377f8283109 Mon Sep 17 00:00:00 2001 From: RyanDavies19 Date: Sun, 10 Dec 2023 18:30:45 -0700 Subject: [PATCH 10/18] Added error handling for wave grid coordinate strings --- modules/moordyn/src/MoorDyn_Misc.f90 | 98 ++++++++++++++++------------ 1 file changed, 55 insertions(+), 43 deletions(-) diff --git a/modules/moordyn/src/MoorDyn_Misc.f90 b/modules/moordyn/src/MoorDyn_Misc.f90 index d3c6ae542e..23189361f3 100644 --- a/modules/moordyn/src/MoorDyn_Misc.f90 +++ b/modules/moordyn/src/MoorDyn_Misc.f90 @@ -1387,14 +1387,17 @@ SUBROUTINE setupWaterKin(WaterKinString, p, Tmax, ErrStat, ErrMsg) READ(UnIn,*, IOSTAT=ErrStat2) coordtype ! get the entry type READ(UnIn,'(A)', IOSTAT=ErrStat2) entries2 ! get entries as string to be processed CALL gridAxisCoords(coordtype, entries2, p%pxWave, p%nxWave, ErrStat2, ErrMsg2) + Call SetErrStat(ErrStat2,ErrMsg2, ErrStat, ErrMsg, 'MD_getWaterKin') ! Y grid points READ(UnIn,*, IOSTAT=ErrStat2) coordtype ! get the entry type READ(UnIn,'(A)', IOSTAT=ErrStat2) entries2 ! get entries as string to be processed CALL gridAxisCoords(coordtype, entries2, p%pyWave, p%nyWave, ErrStat2, ErrMsg2) + Call SetErrStat(ErrStat2,ErrMsg2, ErrStat, ErrMsg, 'MD_getWaterKin') ! Z grid points READ(UnIn,*, IOSTAT=ErrStat2) coordtype ! get the entry type READ(UnIn,'(A)', IOSTAT=ErrStat2) entries2 ! get entries as string to be processed CALL gridAxisCoords(coordtype, entries2, p%pzWave, p%nzWave, ErrStat2, ErrMsg2) + Call SetErrStat(ErrStat2,ErrMsg2, ErrStat, ErrMsg, 'MD_getWaterKin') ! ----- current ----- CALL ReadCom( UnIn, FileName, 'current header', ErrStat2, ErrMsg2, UnEcho); if(Failed()) return CALL ReadVar( UnIn, FileName, p%Current, 'CurrentMod', 'CurrentMod', ErrStat2, ErrMsg2, UnEcho); if(Failed()) return @@ -1707,49 +1710,58 @@ SUBROUTINE gridAxisCoords(coordtype, entries, coordarray, n, ErrStat, ErrMsg) REAL(ReKi) :: tempArray (100) REAL(ReKi) :: dx INTEGER(IntKi) :: nEntries, I - - ! get array of coordinate entries - CALL stringToArray(entries, nEntries, tempArray) - - ! set number of coordinates - if ( coordtype==0) then ! 0: not used - make one grid point at zero - n = 1; - else if (coordtype==1) then ! 1: list values in ascending order - n = nEntries - else if (coordtype==2) then ! 2: uniform specified by -xlim, xlim, num - n = int(tempArray(3)) - else - print *, "Error: invalid coordinate type specified to gridAxisCoords" - end if - - ! allocate coordinate array - CALL AllocAry(coordarray, n, 'x,y, or z grid points' , ErrStat, ErrMsg) - !ALLOCATE ( coordarray(n), STAT=ErrStat) - - ! fill in coordinates - if ( coordtype==0) then - coordarray(1) = 0.0_ReKi - - else if (coordtype==1) then - coordarray(1:n) = tempArray(1:n) - - else if (coordtype==2) then - coordarray(1) = tempArray(1) - coordarray(n) = tempArray(2) - dx = (coordarray(n)-coordarray(1))/REAL(n-1) - do i=2,n - coordarray(i) = coordarray(i-1) + dx - end do - - else - print *, "Error: invalid coordinate type specified to gridAxisCoords" - end if - - print *, "Set water grid coordinates to :" - DO i=1,n - print *, " ", coordarray(i) - end do - + + IF (len(trim(entries)) == len(entries)) THEN + print*, "Warning: Only 120 characters read from wave grid coordinates" + END IF + + IF (entries(len(entries):len(entries)) == ',') THEN + ErrStat = ErrID_Fatal + ErrMsg = 'Last character of wave grid coordinate list cannot be comma' + ELSE + ! get array of coordinate entries + CALL stringToArray(entries, nEntries, tempArray) + + ! set number of coordinates + if ( coordtype==0) then ! 0: not used - make one grid point at zero + n = 1; + else if (coordtype==1) then ! 1: list values in ascending order + n = nEntries + else if (coordtype==2) then ! 2: uniform specified by -xlim, xlim, num + n = int(tempArray(3)) + else + print *, "Error: invalid coordinate type specified to gridAxisCoords" + end if + + ! allocate coordinate array + CALL AllocAry(coordarray, n, 'x,y, or z grid points' , ErrStat, ErrMsg) + !ALLOCATE ( coordarray(n), STAT=ErrStat) + + ! fill in coordinates + if ( coordtype==0) then + coordarray(1) = 0.0_ReKi + + else if (coordtype==1) then + coordarray(1:n) = tempArray(1:n) + + else if (coordtype==2) then + coordarray(1) = tempArray(1) + coordarray(n) = tempArray(2) + dx = (coordarray(n)-coordarray(1))/REAL(n-1) + do i=2,n + coordarray(i) = coordarray(i-1) + dx + end do + + else + print *, "Error: invalid coordinate type specified to gridAxisCoords" + end if + + ! print *, "Set water grid coordinates to :" + ! DO i=1,n + ! print *, " ", coordarray(i) + ! end do + END IF + END SUBROUTINE gridAxisCoords From 18faddf3a830e009daad22edfe5bd313174ef29e Mon Sep 17 00:00:00 2001 From: RyanDavies19 Date: Thu, 28 Dec 2023 14:51:14 -0700 Subject: [PATCH 11/18] Revamped log file. Still needs runtime outputs --- modules/moordyn/src/MoorDyn.f90 | 221 ++++++++++++++++++++++----- modules/moordyn/src/MoorDyn_Line.f90 | 19 --- modules/moordyn/src/MoorDyn_Misc.f90 | 6 +- modules/moordyn/src/MoorDyn_Rod.f90 | 18 --- 4 files changed, 185 insertions(+), 79 deletions(-) diff --git a/modules/moordyn/src/MoorDyn.f90 b/modules/moordyn/src/MoorDyn.f90 index 6e3f63272f..c3279f4893 100644 --- a/modules/moordyn/src/MoorDyn.f90 +++ b/modules/moordyn/src/MoorDyn.f90 @@ -249,29 +249,29 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er ! ----------------------------------------------------------------- ! Read the primary MoorDyn input file, or copy from passed input - if (InitInp%UsePrimaryInputFile) then - ! Read the entire input file, minus any comment lines, into the FileInfo_In - ! data structure in memory for further processing. - call ProcessComFile( InitInp%FileName, FileInfo_In, ErrStat2, ErrMsg2 ) - CALL GetPath( InitInp%FileName, p%PriPath ) ! Input files will be relative to the path where the primary input file is located. - else - call NWTC_Library_CopyFileInfoType( InitInp%PassedPrimaryInputData, FileInfo_In, MESH_NEWCOPY, ErrStat2, ErrMsg2 ) - p%PriPath = "" - endif - if (Failed()) return; - - ! For diagnostic purposes, the following can be used to display the contents - ! of the FileInfo_In data structure. - !call Print_FileInfo_Struct( CU, FileInfo_In ) ! CU is the screen -- different number on different systems. + if (InitInp%UsePrimaryInputFile) then + ! Read the entire input file, minus any comment lines, into the FileInfo_In + ! data structure in memory for further processing. + call ProcessComFile( InitInp%FileName, FileInfo_In, ErrStat2, ErrMsg2 ) + CALL GetPath( InitInp%FileName, p%PriPath ) ! Input files will be relative to the path where the primary input file is located. + else + call NWTC_Library_CopyFileInfoType( InitInp%PassedPrimaryInputData, FileInfo_In, MESH_NEWCOPY, ErrStat2, ErrMsg2 ) + p%PriPath = "" + endif + if (Failed()) return; + + ! For diagnostic purposes, the following can be used to display the contents + ! of the FileInfo_In data structure. + !call Print_FileInfo_Struct( CU, FileInfo_In ) ! CU is the screen -- different number on different systems. ! Parse the FileInfo_In structure of data from the inputfile into the InitInp%InputFile structure -! CALL ParsePrimaryFileInfo_BuildModel( PriPath, InitInp, FileInfo_In, InputFileDat, p, m, UnEc, ErrStat2, ErrMsg2 ) -! if (Failed()) return; + ! CALL ParsePrimaryFileInfo_BuildModel( PriPath, InitInp, FileInfo_In, InputFileDat, p, m, UnEc, ErrStat2, ErrMsg2 ) + ! if (Failed()) return; -!NOTE: This could be split into a separate routine for easier to read code + !NOTE: This could be split into a separate routine for easier to read code !------------------------------------------------------------------------------------------------- ! Parsing of input file from the FileInfo_In data structure ! - FileInfo_Type is essentially a string array with some metadata. @@ -429,6 +429,7 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er END IF write(p%UnLog,'(A)', IOSTAT=ErrStat2) "MoorDyn v2 log file with output level "//TRIM(Num2LStr(p%writeLog)) write(p%UnLog,'(A)', IOSTAT=ErrStat2) "Note: options above the writeLog line in the input file will not be recorded." + write(p%UnLog,'(A)', IOSTAT=ErrStat2) " Input File Summary:" end if else if ( OptString == 'DTM') THEN read (OptValue,*) p%dtM0 @@ -468,8 +469,28 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er nOpts = nOpts + 1 Line = NextLine(i) + END DO + if (p%writeLog > 1) then + write(p%UnLog, '(A)' ) " - Options List:" + write(p%UnLog, '(A17,f12.4)') " dtm : ", p%dtM0 + write(p%UnLog, '(A17,f12.4)') " g : ", p%g + write(p%UnLog, '(A17,f12.4)') " rhoW : ", p%rhoW + write(p%UnLog, '(A17,A)' ) " Depth : ", DepthValue ! water depth input read in as a string to be processed by setupBathymetry + write(p%UnLog, '(A17,f12.4)') " kBot : ", p%kBot + write(p%UnLog, '(A17,f12.4)') " cBot : ", p%cBot + write(p%UnLog, '(A17,f12.4)') " dtIC : ", InputFileDat%dtIC + write(p%UnLog, '(A17,f12.4)') " TMaxIC : ", InputFileDat%TMaxIC + write(p%UnLog, '(A17,f12.4)') " CdScaleIC: ", InputFileDat%CdScaleIC + write(p%UnLog, '(A17,f12.4)') " threshIC : ", InputFileDat%threshIC + write(p%UnLog, '(A17,A)' ) " WaterKin : ", WaterKinValue + write(p%UnLog, '(A17,f12.4)') " dtOut : ", p%dtOut + write(p%UnLog, '(A17,f12.4)') " mu_kT : ", p%mu_kT + write(p%UnLog, '(A17,f12.4)') " mu_kA : ", p%mu_kA + write(p%UnLog, '(A17,f12.4)') " mc : ", p%mc + write(p%UnLog, '(A17,f12.4)') " cv : ", p%cv + end if else if (INDEX(Line, "OUTPUT") > 0) then ! if output header @@ -588,8 +609,8 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er Line = NextLine(i) Line = NextLine(i) - ! process each line - DO l = 1,p%nLineTypes + ! process each line + DO l = 1,p%nLineTypes !read into a line Line = NextLine(i) @@ -641,6 +662,9 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er read(tempStrings(2), *) m%LineTypeList(l)%BA_D else if (m%LineTypeList(l)%ElasticMod == 2) then ! case where there is no dynamic damping for viscoelastic model (will it work)? CALL WrScr("Warning, viscoelastic model being used with zero damping on the dynamic stiffness.") + if (p%writeLog > 0) then + write(p%UnLog,'(A)') "Warning, viscoelastic model being used with zero damping on the dynamic stiffness." + end if end if ! get the regular/static coefficient or relation in all cases (can be from a lookup table?) CALL getCoefficientOrCurve(tempStrings(1), m%LineTypeList(l)%BA, & @@ -658,16 +682,16 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er m%LineTypeList(l)%IdNum = l ! write lineType information to log file - if (p%writeLog > 1) then - write(p%UnLog, '(A12,A20)' ) " LineType"//trim(num2lstr(l))//":" - write(p%UnLog, '(A12,A20)' ) " name: ", m%LineTypeList(l)%name - write(p%UnLog, '(A12,f12.4)') " d : ", m%LineTypeList(l)%d - write(p%UnLog, '(A12,f12.4)') " w : ", m%LineTypeList(l)%w - write(p%UnLog, '(A12,f12.4)') " Cdn : ", m%LineTypeList(l)%Cdn - write(p%UnLog, '(A12,f12.4)') " Can : ", m%LineTypeList(l)%Can - write(p%UnLog, '(A12,f12.4)') " Cdt : ", m%LineTypeList(l)%Cdt - write(p%UnLog, '(A12,f12.4)') " Cat : ", m%LineTypeList(l)%Cat - end if + if (p%writeLog > 1) then + write(p%UnLog, '(A)' ) " - LineType"//trim(num2lstr(l))//":" + write(p%UnLog, '(A12,A)' ) " name: ", trim(m%LineTypeList(l)%name) + write(p%UnLog, '(A12,f12.4)') " d : ", m%LineTypeList(l)%d + write(p%UnLog, '(A12,f12.4)') " w : ", m%LineTypeList(l)%w + write(p%UnLog, '(A12,f12.4)') " Cdn : ", m%LineTypeList(l)%Cdn + write(p%UnLog, '(A12,f12.4)') " Can : ", m%LineTypeList(l)%Can + write(p%UnLog, '(A12,f12.4)') " Cdt : ", m%LineTypeList(l)%Cdt + write(p%UnLog, '(A12,f12.4)') " Cat : ", m%LineTypeList(l)%Cat + end if IF ( ErrStat2 /= ErrID_None ) THEN CALL SetErrStat( ErrID_Fatal, ErrMsg2, ErrStat, ErrMsg, RoutineName ) @@ -712,16 +736,16 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er ! specify IdNum of rod type for error checking m%RodTypeList(l)%IdNum = l - ! write lineType information to log file + ! write rodType information to log file if (p%writeLog > 1) then - write(p%UnLog, '(A12,A20)' ) " RodType"//trim(num2lstr(l))//":" - write(p%UnLog, '(A12,A20)' ) " name: ", m%RodTypeList(l)%name - write(p%UnLog, '(A12,f12.4)') " d : ", m%RodTypeList(l)%d - write(p%UnLog, '(A12,f12.4)') " w : ", m%RodTypeList(l)%w - write(p%UnLog, '(A12,f12.4)') " Cdn : ", m%RodTypeList(l)%Cdn - write(p%UnLog, '(A12,f12.4)') " Can : ", m%RodTypeList(l)%Can - write(p%UnLog, '(A12,f12.4)') " Cdt : ", m%RodTypeList(l)%CdEnd - write(p%UnLog, '(A12,f12.4)') " Cat : ", m%RodTypeList(l)%CaEnd + write(p%UnLog, '(A)' ) " - RodType"//trim(num2lstr(l))//":" + write(p%UnLog, '(A14,A)' ) " name: ", trim(m%RodTypeList(l)%name) + write(p%UnLog, '(A14,f12.4)') " d : ", m%RodTypeList(l)%d + write(p%UnLog, '(A14,f12.4)') " w : ", m%RodTypeList(l)%w + write(p%UnLog, '(A14,f12.4)') " Cdn : ", m%RodTypeList(l)%Cdn + write(p%UnLog, '(A14,f12.4)') " Can : ", m%RodTypeList(l)%Can + write(p%UnLog, '(A14,f12.4)') " CdEnd : ", m%RodTypeList(l)%CdEnd + write(p%UnLog, '(A14,f12.4)') " CaEnd : ", m%RodTypeList(l)%CaEnd end if IF ( ErrStat2 /= ErrID_None ) THEN @@ -818,6 +842,10 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er CALL WrScr(' Unable to parse Body '//trim(Num2LStr(l))//' on row '//trim(Num2LStr(i))//' in input file.') ! Specific screen output because errors likely CALL WrScr(' Ensure row has all 13 columns needed in MDv2 input file (13th Dec 2021).') CALL SetErrStat( ErrID_Fatal, 'Failed to read bodies.' , ErrStat, ErrMsg, RoutineName ) + if (p%writeLog > 0) then + write(p%UnLog,'(A)') ' Unable to parse Body '//trim(Num2LStr(l))//' on row '//trim(Num2LStr(i))//' in input file.' + write(p%UnLog,'(A)') ' Ensure row has all 13 columns needed in MDv2 input file (13th Dec 2021).' + end if CALL CleanUp() RETURN END IF @@ -893,6 +921,19 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er CALL CleanUp() RETURN END IF + + ! write body information to log file + if (p%writeLog > 1) then + write(p%UnLog, '(A)' ) " - Body"//trim(num2lstr(l))//":" + write(p%UnLog, '(A14,I2)' ) " id : ", m%BodyList(l)%IdNum + write(p%UnLog, '(A14,A)' ) " attach: ", trim(tempString1) + write(p%UnLog, '(A14,f12.4)') " v : ", m%BodyList(l)%bodyV + write(p%UnLog, '(A14,f12.4)') " m : ", m%BodyList(l)%bodyM + write(p%UnLog, '(A14,A)' ) " I : ", trim(num2lstr(m%BodyList(l)%BodyI(1)))//", "//trim(num2lstr(m%BodyList(l)%BodyI(2)))//", "//trim(num2lstr(m%BodyList(l)%BodyI(3))) + write(p%UnLog, '(A14,A)' ) " rCG : ", trim(num2lstr(m%BodyList(l)%rCG(1)))//", "//trim(num2lstr(m%BodyList(l)%rCG(2)))//", "//trim(num2lstr(m%BodyList(l)%rCG(3))) + write(p%UnLog, '(A14,A)' ) " CdA : ", trim(num2lstr(m%BodyList(l)%BodyCdA(1)))//", "//trim(num2lstr(m%BodyList(l)%BodyCdA(2)))//", "//trim(num2lstr(m%BodyList(l)%BodyCdA(3)))//", "//trim(num2lstr(m%BodyList(l)%BodyCdA(4)))//", "//trim(num2lstr(m%BodyList(l)%BodyCdA(5)))//", "//trim(num2lstr(m%BodyList(l)%BodyCdA(6))) + write(p%UnLog, '(A14,A)' ) " Ca : ", trim(num2lstr(m%BodyList(l)%BodyCa(1)))//", "//trim(num2lstr(m%BodyList(l)%BodyCa(2)))//", "//trim(num2lstr(m%BodyList(l)%BodyCa(3)))//", "//trim(num2lstr(m%BodyList(l)%BodyCa(4)))//", "//trim(num2lstr(m%BodyList(l)%BodyCa(5)))//", "//trim(num2lstr(m%BodyList(l)%BodyCa(6))) + end if IF (wordy > 1) print *, "Set up body ", l, " of type ", m%BodyList(l)%typeNum @@ -1069,6 +1110,14 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er ! specify IdNum of line for error checking m%RodList(l)%IdNum = l + if (p%writeLog > 1) then + write(p%UnLog, '(A)' ) " - Rod"//trim(num2lstr(m%RodList(l)%IdNum))//":" + write(p%UnLog, '(A15,I2)' ) " ID : ", m%RodList(l)%IdNum + write(p%UnLog, '(A15,A)' ) " Type : ", trim(m%RodTypeList(m%RodList(l)%PropsIdNum)%name) + write(p%UnLog, '(A15,A)' ) " Attach : ", trim(tempString2) + write(p%UnLog, '(A15,I2)' ) " NumSegs: ", m%RodList(l)%N + end if + ! check for sequential IdNums IF ( m%RodList(l)%IdNum .NE. l ) THEN CALL SetErrStat( ErrID_Fatal, 'Line numbers must be sequential starting from 1.', ErrStat, ErrMsg, RoutineName ) @@ -1124,6 +1173,9 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er if ((INDEX(tempString4, "SEABED") > 0 ) .or. (INDEX(tempString4, "GROUND") > 0 ) .or. (INDEX(tempString4, "FLOOR") > 0 )) then ! if keyword used CALL WrScr('Point '//trim(Num2LStr(l))//' depth set to be on the seabed; finding z location based on depth/bathymetry') ! interpret the anchor depth value as a 'seabed' input + if (p%writeLog > 0) then + write(p%UnLog,'(A)') 'Point '//trim(Num2LStr(l))//' depth set to be on the seabed; finding z location based on depth/bathymetry' + end if CALL getDepthFromBathymetry(m%BathymetryGrid, m%BathGrid_Xs, m%BathGrid_Ys, tempArray(1), tempArray(2), depth, nvec) ! meaning the anchor should be at the depth of the local bathymetry tempArray(3) = -depth else ! if the anchor depth input isn't one of the supported keywords, @@ -1143,6 +1195,10 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er CALL WrScr(' Unable to parse Point '//trim(Num2LStr(l))//' row in input file.') ! Specific screen output because errors likely CALL WrScr(' Ensure row has all 9 columns, including CdA and Ca.') ! to be caused by non-updated input file formats. CALL SetErrStat( ErrID_Fatal, 'Failed to read points.' , ErrStat, ErrMsg, RoutineName ) ! would be nice to specify which line <<<<<<<<< + if (p%writeLog > 0) then + write(p%UnLog,'(A)') ' Unable to parse Point '//trim(Num2LStr(l))//' row in input file.' + write(p%UnLog,'(A)') ' Ensure row has all 9 columns, including CdA and Ca.' + end if CALL CleanUp() RETURN END IF @@ -1207,6 +1263,9 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er p%nCpldPoints(J) = p%nCpldPoints(J) + 1 ! increment counter for the appropriate turbine m%CpldPointIs(p%nCpldPoints(J),J) = l CALL WrScr(' added point '//TRIM(int2lstr(l))//' as fairlead for turbine '//trim(int2lstr(J))) + if (p%writeLog > 0) then + write(p%UnLog,'(A)') ' added point '//TRIM(int2lstr(l))//' as fairlead for turbine '//trim(int2lstr(J)) + end if else @@ -1231,6 +1290,16 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er !also set number of attached lines to zero initially m%PointList(l)%nAttached = 0 + ! write body information to log file + if (p%writeLog > 1) then + write(p%UnLog, '(A)' ) " - Point"//trim(num2lstr(l))//":" + write(p%UnLog, '(A12,I2)' ) " id : ", m%PointList(l)%IdNum + write(p%UnLog, '(A12,I2)' ) " type: ", m%PointList(l)%typeNum + write(p%UnLog, '(A12,f12.4)') " v : ", m%PointList(l)%pointV + write(p%UnLog, '(A12,f12.4)') " m : ", m%PointList(l)%pointM + write(p%UnLog, '(A12,f12.4)') " CdA : ", m%PointList(l)%pointCdA + write(p%UnLog, '(A12,f12.4)') " Ca : ", m%PointList(l)%pointCa + end if ! check for sequential IdNums IF ( m%PointList(l)%IdNum .NE. l ) THEN @@ -1409,6 +1478,15 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er ! specify IdNum of line for error checking m%LineList(l)%IdNum = l + if (p%writeLog > 1) then + write(p%UnLog, '(A)' ) " - Line"//trim(num2lstr(m%LineList(l)%IdNum))//":" + write(p%UnLog, '(A15,I2)' ) " ID : ", m%LineList(l)%IdNum + write(p%UnLog, '(A15,A)' ) " Type : ", trim(m%LineTypeList(m%LineList(l)%PropsIdNum)%name) + write(p%UnLog, '(A15,f12.4)') " Len : ", m%LineList(l)%UnstrLen + write(p%UnLog, '(A15,A)' ) " Node A : ", " "//tempString2 + write(p%UnLog, '(A15,A)' ) " Node B : ", " "//tempString3 + write(p%UnLog, '(A15,I2)' ) " NumSegs: ", m%LineList(l)%N + end if ! check for sequential IdNums IF ( m%LineList(l)%IdNum .NE. l ) THEN @@ -1462,11 +1540,20 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er if (m%LineList( TempIDnums(J) )%CtrlChan == 0) then ! ensure line doesn't already have a CtrlChan assigned m%LineList( TempIDnums(J) )%CtrlChan = Itemp CALL WrScr('Assigned Line '//TRIM(Int2LStr(TempIDnums(J)))//' to control channel '//TRIM(Int2LStr(Itemp))) + if (p%writeLog > 0) then + write(p%UnLog,'(A)') 'Assigned Line '//TRIM(Int2LStr(TempIDnums(J)))//' to control channel '//TRIM(Int2LStr(Itemp)) + end if else CALL WrScr('Error: Line '//TRIM(Int2LStr(TempIDnums(J)))//' already is assigned to control channel '//TRIM(Int2LStr(m%LineList( TempIDnums(J) )%CtrlChan))//' so cannot also be assigned to channel '//TRIM(Int2LStr(Itemp))) + if (p%writeLog > 0) then + write(p%UnLog,'(A)') 'Error: Line '//TRIM(Int2LStr(TempIDnums(J)))//' already is assigned to control channel '//TRIM(Int2LStr(m%LineList( TempIDnums(J) )%CtrlChan))//' so cannot also be assigned to channel '//TRIM(Int2LStr(Itemp)) + end if end if else CALL WrScr('Error: Line ID '//TRIM(Int2LStr(TempIDnums(J)))//' of CtrlChan '//TRIM(Int2LStr(Itemp))//' is out of range') + if (p%writeLog > 0) then + write(p%UnLog,'(A)') 'Error: Line ID '//TRIM(Int2LStr(TempIDnums(J)))//' of CtrlChan '//TRIM(Int2LStr(Itemp))//' is out of range' + end if end if END DO @@ -1478,6 +1565,9 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er else if (INDEX(Line, "FAILURE") > 0) then ! if failure conditions header CALL WrScr(" Warning: Failure capabilities are not yet implemented in MoorDyn.") + if (p%writeLog > 0) then + write(p%UnLog,'(A)') " Warning: Failure capabilities are not yet implemented in MoorDyn." + end if ! skip following two lines (label line and unit line) Line = NextLine(i) @@ -1553,7 +1643,12 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er CALL CheckError( ErrStat2, ErrMsg2 ) IF (ErrStat >= AbortErrLev) RETURN - + if (p%writeLog > 1) then + write(p%UnLog, '(A)' ) " - Outputs List:" + DO J = 1, SIZE(Outlist) + write(p%UnLog, '(A)' ) " "//OutList(J) + END DO + end if !------------------------------------------------------------------------------------------- else ! otherwise ignore this line that isn't a recognized header line and read the next line Line = NextLine(i) @@ -1592,7 +1687,9 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er ! p%NAnchs = 0 ! this is the number of "fixed" type Points. <<<<<<<<<<<<<< CALL WrScr(trim(Num2LStr(p%nLines))//' lines, '//trim(Num2LStr(p%NPoints))//' points, '//trim(Num2LStr(p%nRods))//' rods, '//trim(Num2LStr(p%nBodies))//' bodies.') - + if (p%writeLog > 0) then + write(p%UnLog,'(A)') trim(Num2LStr(p%nLines))//' lines, '//trim(Num2LStr(p%NPoints))//' points, '//trim(Num2LStr(p%nRods))//' rods, '//trim(Num2LStr(p%nBodies))//' bodies.' + end if @@ -2091,6 +2188,9 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er if (InputFileDat%TMaxIC > 0.0_DbKi) then CALL WrScr(" Finalizing initial conditions using dynamic relaxation."//NewLine) ! newline because next line writes over itself + if (p%writeLog > 0) then + write(p%UnLog,'(A)') " Finalizing initial conditions using dynamic relaxation."//NewLine + end if ! boost drag coefficient of each line type <<<<<<<< does this actually do anything or do lines hold these coefficients??? DO I = 1, p%nLines @@ -2159,6 +2259,10 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er IF (ErrStat == ErrID_Fatal) THEN CALL WrScr("NaN detected at time "//TRIM(Num2LStr(t))//" during MoorDyn's dynamic relaxation process.") + if (p%writeLog > 0) then + write(p%UnLog,'(A)') "NaN detected at time "//TRIM(Num2LStr(t))//" during MoorDyn's dynamic relaxation process."//NewLine + end if + IF (wordy > 1) THEN print *, "Here is the state vector: " print *, x%states @@ -2212,9 +2316,17 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er IF (Converged == 1) THEN ! if we made it with all cases satisfying the threshold CALL WrScr('') ! serves as line break from write over command in previous printed line CALL WrScr(' Fairlead tensions converged to '//trim(Num2LStr(100.0*InputFileDat%threshIC))//'% after '//trim(Num2LStr(t))//' seconds.') + if (p%writeLog > 0) then + write(p%UnLog,'(A)') '' + write(p%UnLog,'(A)') ' Fairlead tensions converged to '//trim(Num2LStr(100.0*InputFileDat%threshIC))//'% after '//trim(Num2LStr(t))//' seconds.'//NewLine + end if DO l = 1, p%nLines CALL WrScr(' Fairlead tension: '//trim(Num2LStr(FairTensIC(l,1)))) CALL WrScr(' Fairlead forces: '//trim(Num2LStr(m%LineList(l)%Fnet(1, m%LineList(l)%N)))//', '//trim(Num2LStr(m%LineList(l)%Fnet(2, m%LineList(l)%N)))//', '//trim(Num2LStr(m%LineList(l)%Fnet(3, m%LineList(l)%N)))) + if (p%writeLog > 0) then + write(p%UnLog,'(A)') ' Fairlead tension: '//trim(Num2LStr(FairTensIC(l,1))) + write(p%UnLog,'(A)') ' Fairlead forces: '//trim(Num2LStr(m%LineList(l)%Fnet(1, m%LineList(l)%N)))//', '//trim(Num2LStr(m%LineList(l)%Fnet(2, m%LineList(l)%N)))//', '//trim(Num2LStr(m%LineList(l)%Fnet(3, m%LineList(l)%N))) + end if ENDDO EXIT ! break out of the time stepping loop END IF @@ -2223,6 +2335,11 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er IF (I == ceiling(InputFileDat%TMaxIC/InputFileDat%dtIC) ) THEN CALL WrScr('') ! serves as line break from write over command in previous printed line CALL WrScr(' Fairlead tensions did not converge within TMaxIC='//trim(Num2LStr(InputFileDat%TMaxIC))//' seconds.') + if (p%writeLog > 0) then + write(p%UnLog,'(A)') '' + write(p%UnLog,'(A)') ' Fairlead tensions did not converge within TMaxIC='//trim(Num2LStr(InputFileDat%TMaxIC))//' seconds.' + end if + !ErrStat = ErrID_Warn !ErrMsg = ' MD_Init: ran dynamic convergence to TMaxIC without convergence' END IF @@ -2267,6 +2384,9 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er endif CALL WrScr(' MoorDyn initialization completed.') + if (p%writeLog > 0) then + write(p%UnLog,'(A)') ' MoorDyn initialization completed.' + end if m%LastOutTime = -1.0_DbKi ! set to nonzero to ensure that output happens at the start of simulation at t=0 @@ -2460,6 +2580,9 @@ SUBROUTINE MD_UpdateStates( t, n, u, t_array, p, x, xd, z, other, m, ErrStat, Er IF (ErrStat == ErrID_Fatal) THEN CALL WrScr("NaN detected at time "//TRIM(Num2LStr(t2))//" in MoorDyn.") + if (p%writeLog > 0) then + write(p%UnLog,'(A)') "NaN detected at time "//TRIM(Num2LStr(t2))//" in MoorDyn." + end if IF (wordy > 1) THEN print *, ". Here is the state vector: " print *, x%states @@ -2491,6 +2614,9 @@ SUBROUTINE MD_UpdateStates( t, n, u, t_array, p, x, xd, z, other, m, ErrStat, Er IF (ErrStat == ErrID_Fatal) THEN CALL WrScr("NaN detected at time "//TRIM(Num2LStr(t2))//" in MoorDyn.") + if (p%writeLog > 0) then + write(p%UnLog,'(A)') "NaN detected at time "//TRIM(Num2LStr(t2))//" in MoorDyn." + end if IF (wordy > 1) THEN print *, ". Here is the state vector: " print *, x%states @@ -2513,6 +2639,9 @@ SUBROUTINE CheckError(ErrId, Msg) ErrStat = MAX(ErrStat, ErrID) CALL WrScr( ErrMsg ) ! do this always or only if warning level? + if (p%writeLog > 0) then + write(p%UnLog,'(A)') ErrMsg + end if IF( ErrStat > ErrID_Warn ) THEN ! CALL MD_DestroyInput( u_interp, ErrStat, ErrMsg ) @@ -2717,6 +2846,9 @@ SUBROUTINE CheckError(ErrId, Msg) ErrStat = MAX(ErrStat, ErrID) CALL WrScr( ErrMsg ) ! do this always or only if warning level? <<<<<<<<<<<<<<<<<<<<<< probably should remove all instances + if (p%writeLog > 0) then + write(p%UnLog,'(A)') ErrMsg + end if ! IF( ErrStat > ErrID_Warn ) THEN ! CALL MD_DestroyContState( dxdt, ErrStat2, ErrMsg2) @@ -2869,6 +3001,9 @@ SUBROUTINE MD_CalcContStateDeriv( t, u, p, x, xd, z, other, m, dxdt, ErrStat, Er ErrStat = ErrID_Fatal ErrMsg = ' Active tension command will make a segment longer than the limit of twice its original length.' call WrScr(trim(Num2LStr(u%DeltaL(m%LineList(L)%CtrlChan)))//" is an increase of more than "//trim(Num2LStr(m%LineList(L)%UnstrLen / m%LineList(L)%N))) + if (p%writeLog > 0) then + write(p%UnLog,'(A)') trim(Num2LStr(u%DeltaL(m%LineList(L)%CtrlChan)))//" is an increase of more than "//trim(Num2LStr(m%LineList(L)%UnstrLen / m%LineList(L)%N)) + end if IF (wordy > 0) print *, u%DeltaL IF (wordy > 0) print*, m%LineList(L)%CtrlChan RETURN @@ -2877,6 +3012,9 @@ SUBROUTINE MD_CalcContStateDeriv( t, u, p, x, xd, z, other, m, dxdt, ErrStat, Er ErrStat = ErrID_Fatal ErrMsg = ' Active tension command will make a segment shorter than the limit of half its original length.' call WrScr(trim(Num2LStr(u%DeltaL(m%LineList(L)%CtrlChan)))//" is a reduction of more than half of "//trim(Num2LStr(m%LineList(L)%UnstrLen / m%LineList(L)%N))) + if (p%writeLog > 0) then + write(p%UnLog,'(A)') trim(Num2LStr(u%DeltaL(m%LineList(L)%CtrlChan)))//" is a reduction of more than half of "//trim(Num2LStr(m%LineList(L)%UnstrLen / m%LineList(L)%N)) + end if IF (wordy > 0) print *, u%DeltaL IF (wordy > 0) print*, m%LineList(L)%CtrlChan RETURN @@ -3090,6 +3228,9 @@ SUBROUTINE CheckError(ErrId, Msg) ErrStat = MAX(ErrStat, ErrID) CALL WrScr( ErrMsg ) ! do this always or only if warning level? + if (p%writeLog > 0) then + write(p%UnLog,'(A)') ErrMsg + end if END IF diff --git a/modules/moordyn/src/MoorDyn_Line.f90 b/modules/moordyn/src/MoorDyn_Line.f90 index 37f406486a..190cc4d7eb 100644 --- a/modules/moordyn/src/MoorDyn_Line.f90 +++ b/modules/moordyn/src/MoorDyn_Line.f90 @@ -213,25 +213,6 @@ SUBROUTINE SetupLine (Line, LineProp, p, ErrStat, ErrMsg) RETURN END IF - - if (p%writeLog > 1) then - write(p%UnLog, '(A)') " - Line"//trim(num2lstr(Line%IdNum)) - write(p%UnLog, '(A)') " ID: "//trim(num2lstr(Line%IdNum)) - write(p%UnLog, '(A)') " UnstrLen: "//trim(num2lstr(Line%UnstrLen)) - write(p%UnLog, '(A)') " N : "//trim(num2lstr(Line%N )) - write(p%UnLog, '(A)') " d : "//trim(num2lstr(Line%d )) - write(p%UnLog, '(A)') " rho : "//trim(num2lstr(Line%rho )) - write(p%UnLog, '(A)') " E : "//trim(num2lstr(Line%EA )) - write(p%UnLog, '(A)') " EI : "//trim(num2lstr(Line%EI )) - !write(p%UnLog, '(A)') " BAin: "//trim(num2lstr(Line%BAin)) - write(p%UnLog, '(A)') " Can : "//trim(num2lstr(Line%Can )) - write(p%UnLog, '(A)') " Cat : "//trim(num2lstr(Line%Cat )) - write(p%UnLog, '(A)') " Cdn : "//trim(num2lstr(Line%Cdn )) - write(p%UnLog, '(A)') " Cdt : "//trim(num2lstr(Line%Cdt )) - !write(p%UnLog, '(A)') " ww_l: " << ( (rho - env->rho_w)*(pi/4.*d*d) )*9.81 << endl; - end if - - ! need to add cleanup sub <<< diff --git a/modules/moordyn/src/MoorDyn_Misc.f90 b/modules/moordyn/src/MoorDyn_Misc.f90 index 23189361f3..7c0e26c203 100644 --- a/modules/moordyn/src/MoorDyn_Misc.f90 +++ b/modules/moordyn/src/MoorDyn_Misc.f90 @@ -151,8 +151,10 @@ subroutine GetOrientationAngles(vec, phi, sinPhi, cosPhi, tanPhi, beta, sinBeta, vecLen = SQRT(Dot_Product(vec,vec)) vecLen2D = SQRT(vec(1)**2+vec(2)**2) if ( vecLen < 0.000001 ) then - print *, "ERROR in GetOrientationAngles in MoorDyn. Supplied vector is near zero" - print *, vec + if (wordy > 0) then + print *, "ERROR in GetOrientationAngles in MoorDyn. Supplied vector is near zero" + print *, vec + endif k_hat = NaN ! 1.0/0.0 else k_hat = vec / vecLen diff --git a/modules/moordyn/src/MoorDyn_Rod.f90 b/modules/moordyn/src/MoorDyn_Rod.f90 index 7302214f9d..49c61a5c56 100644 --- a/modules/moordyn/src/MoorDyn_Rod.f90 +++ b/modules/moordyn/src/MoorDyn_Rod.f90 @@ -151,24 +151,6 @@ SUBROUTINE Rod_Setup(Rod, RodProp, endCoords, p, ErrStat, ErrMsg) IF (wordy > 0) print *, "Set up Rod ",Rod%IdNum, ", type ", Rod%typeNum - - if (p%writeLog > 1) then - write(p%UnLog, '(A)') " - Rod "//trim(num2lstr(Rod%IdNum)) - write(p%UnLog, '(A)') " ID: "//trim(num2lstr(Rod%IdNum)) - write(p%UnLog, '(A)') " UnstrLen: "//trim(num2lstr(Rod%UnstrLen)) - write(p%UnLog, '(A)') " N : "//trim(num2lstr(Rod%N )) - write(p%UnLog, '(A)') " d : "//trim(num2lstr(Rod%d )) - write(p%UnLog, '(A)') " rho : "//trim(num2lstr(Rod%rho )) - write(p%UnLog, '(A)') " Can : "//trim(num2lstr(Rod%Can )) - write(p%UnLog, '(A)') " Cat : "//trim(num2lstr(Rod%Cat )) - write(p%UnLog, '(A)') " CaEnd: "//trim(num2lstr(Rod%CaEnd )) - write(p%UnLog, '(A)') " Cdn : "//trim(num2lstr(Rod%Cdn )) - write(p%UnLog, '(A)') " Cdt : "//trim(num2lstr(Rod%Cdt )) - write(p%UnLog, '(A)') " CdEnd: "//trim(num2lstr(Rod%CdEnd )) - !write(p%UnLog, '(A)') " ww_l: " << ( (rho - env->rho_w)*(pi/4.*d*d) )*9.81 << endl; - end if - - ! need to add cleanup sub <<< From d0a75b64ba329db8fe564683b585d8c5312af721 Mon Sep 17 00:00:00 2001 From: RyanDavies19 Date: Thu, 4 Jan 2024 14:55:46 -0700 Subject: [PATCH 12/18] Better driver handling and updated log --- modules/moordyn/src/MoorDyn.f90 | 28 +++++++++++++++----------- modules/moordyn/src/MoorDyn_Driver.f90 | 9 +++++++-- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/modules/moordyn/src/MoorDyn.f90 b/modules/moordyn/src/MoorDyn.f90 index c3279f4893..e3881e7f1b 100644 --- a/modules/moordyn/src/MoorDyn.f90 +++ b/modules/moordyn/src/MoorDyn.f90 @@ -1645,7 +1645,7 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er if (p%writeLog > 1) then write(p%UnLog, '(A)' ) " - Outputs List:" - DO J = 1, SIZE(Outlist) + DO J = 1, p%NumOuts write(p%UnLog, '(A)' ) " "//OutList(J) END DO end if @@ -1688,7 +1688,8 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er CALL WrScr(trim(Num2LStr(p%nLines))//' lines, '//trim(Num2LStr(p%NPoints))//' points, '//trim(Num2LStr(p%nRods))//' rods, '//trim(Num2LStr(p%nBodies))//' bodies.') if (p%writeLog > 0) then - write(p%UnLog,'(A)') trim(Num2LStr(p%nLines))//' lines, '//trim(Num2LStr(p%NPoints))//' points, '//trim(Num2LStr(p%nRods))//' rods, '//trim(Num2LStr(p%nBodies))//' bodies.' + write(p%UnLog, '(A)') NewLine + write(p%UnLog, '(A)') ' Created mooring system: '//trim(Num2LStr(p%nLines))//' lines, '//trim(Num2LStr(p%NPoints))//' points, '//trim(Num2LStr(p%nRods))//' rods, '//trim(Num2LStr(p%nBodies))//' bodies.' end if @@ -1730,7 +1731,7 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er ! write system description to log file if (p%writeLog > 1) then - write(p%UnLog, '(A)') "----- MoorDyn Model Summary (to be written) -----" + write(p%UnLog, '(A)') "----- MoorDyn Model Summary (unfinished) -----" end if @@ -2152,7 +2153,7 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er ! if log file, compute and write some object properties ! ------------------------------------------------------------------- if (p%writeLog > 1) then - + write(p%UnLog, '(A)' ) "Values after intialization before dynamic relaxation" write(p%UnLog, '(A)' ) " Bodies:" DO l = 1,p%nBodies write(p%UnLog, '(A)' ) " Body"//trim(num2lstr(l))//":" @@ -2162,21 +2163,21 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er write(p%UnLog, '(A)' ) " Rods:" DO l = 1,p%nRods write(p%UnLog, '(A)' ) " Rod"//trim(num2lstr(l))//":" - ! m%RodList(l) + write(p%UnLog, '(A12, f12.4)') " mass: ", m%RodList(l)%M6net(1,1) + write(p%UnLog, '(A17, A)') " direction: ", trim(num2lstr(m%RodList(l)%q(1)))//", "//trim(num2lstr(m%RodList(l)%q(2)))//", "//trim(num2lstr(m%RodList(l)%q(3))) END DO write(p%UnLog, '(A)' ) " Points:" DO l = 1,p%nFreePoints write(p%UnLog, '(A)' ) " Point"//trim(num2lstr(l))//":" - ! m%PointList(l) + write(p%UnLog, '(A12, f12.4)') " mass: ", m%PointList(l)%M END DO write(p%UnLog, '(A)' ) " Lines:" DO l = 1,p%nLines write(p%UnLog, '(A)' ) " Line"//trim(num2lstr(l))//":" - ! m%LineList(l) END DO - + write(p%UnLog, '(A)') "--------- End of Model Summary --------- "//NewLine end if @@ -2189,7 +2190,7 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er CALL WrScr(" Finalizing initial conditions using dynamic relaxation."//NewLine) ! newline because next line writes over itself if (p%writeLog > 0) then - write(p%UnLog,'(A)') " Finalizing initial conditions using dynamic relaxation."//NewLine + write(p%UnLog,'(A)') "Finalizing initial conditions using dynamic relaxation."//NewLine end if ! boost drag coefficient of each line type <<<<<<<< does this actually do anything or do lines hold these coefficients??? @@ -2314,7 +2315,6 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er END DO IF (Converged == 1) THEN ! if we made it with all cases satisfying the threshold - CALL WrScr('') ! serves as line break from write over command in previous printed line CALL WrScr(' Fairlead tensions converged to '//trim(Num2LStr(100.0*InputFileDat%threshIC))//'% after '//trim(Num2LStr(t))//' seconds.') if (p%writeLog > 0) then write(p%UnLog,'(A)') '' @@ -2385,7 +2385,12 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er CALL WrScr(' MoorDyn initialization completed.') if (p%writeLog > 0) then - write(p%UnLog,'(A)') ' MoorDyn initialization completed.' + write(p%UnLog, '(A)') NewLine//"MoorDyn initialization completed."//NewLine + if (ErrStat /= ErrID_None) then + write(p%UnLog, '(A34)') "Initalization Errors and Warnings:" + write(p%UnLog, '(A)' ) ErrMsg + end if + write(p%UnLog, '(A)') NewLine end if m%LastOutTime = -1.0_DbKi ! set to nonzero to ensure that output happens at the start of simulation at t=0 @@ -2468,7 +2473,6 @@ END SUBROUTINE CheckError SUBROUTINE CleanUp() ! ErrStat = ErrID_Fatal call MD_DestroyInputFileType( InputFileDat, ErrStat2, ErrMsg2 ) ! Ignore any error messages from this - IF (p%UnLog > 0_IntKi) CLOSE( p%UnLog ) ! Remove this when the log file is kept open during the full simulation END SUBROUTINE !> If for some reason the file is truncated, it is possible to get into an infinite loop diff --git a/modules/moordyn/src/MoorDyn_Driver.f90 b/modules/moordyn/src/MoorDyn_Driver.f90 index 27428eb326..b83842dba9 100644 --- a/modules/moordyn/src/MoorDyn_Driver.f90 +++ b/modules/moordyn/src/MoorDyn_Driver.f90 @@ -697,6 +697,11 @@ PROGRAM MoorDyn_Driver call MD_DestroyInput( MD_u(j), ErrStat2, ErrMsg2) end do + if ( ErrStat /= ErrID_None ) THEN ! Display all errors + CALL WrScr1( "Errors: " ) + CALL WrScr( trim(GetErrStr(ErrStat))//': '//trim(ErrMsg) ) + endif + !close (un) call CleanUp() CALL NormStop() @@ -711,8 +716,8 @@ SUBROUTINE AbortIfFailed() if (ErrStat >= AbortErrLev) then call CleanUp() Call ProgAbort(trim(ErrMsg)) - elseif ( ErrStat /= ErrID_None ) THEN - CALL WrScr1( trim(GetErrStr(ErrStat))//': '//trim(ErrMsg) ) + elseif ( ErrStat2 /= ErrID_None ) THEN + CALL WrScr1( trim(GetErrStr(ErrStat2))//': '//trim(ErrMsg2)//NewLine) end if END SUBROUTINE AbortIfFailed From 41810273103046a0361ffe79408070b7bdd47bbe Mon Sep 17 00:00:00 2001 From: RyanDavies19 Date: Mon, 8 Jan 2024 12:50:13 -0700 Subject: [PATCH 13/18] Add option to disable inertial forces in 6DOF coupling --- modules/moordyn/src/MoorDyn.f90 | 2 ++ modules/moordyn/src/MoorDyn_Body.f90 | 20 ++++++++++++++++---- modules/moordyn/src/MoorDyn_Registry.txt | 1 + modules/moordyn/src/MoorDyn_Rod.f90 | 20 +++++++++++++++----- modules/moordyn/src/MoorDyn_Types.f90 | 1 + 5 files changed, 35 insertions(+), 9 deletions(-) diff --git a/modules/moordyn/src/MoorDyn.f90 b/modules/moordyn/src/MoorDyn.f90 index e3881e7f1b..22167aee53 100644 --- a/modules/moordyn/src/MoorDyn.f90 +++ b/modules/moordyn/src/MoorDyn.f90 @@ -463,6 +463,8 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er read (OptValue,*) p%mc else if ( OptString == 'CV') then read (OptValue,*) p%cv + else if ( OptString == 'INERTIALF') then + read (OptValue,*) p%inertialF else CALL SetErrStat( ErrID_Warn, 'Unable to interpret input '//trim(OptString)//' in OPTIONS section.', ErrStat, ErrMsg, RoutineName ) end if diff --git a/modules/moordyn/src/MoorDyn_Body.f90 b/modules/moordyn/src/MoorDyn_Body.f90 index f520265fae..2a1b2df68c 100644 --- a/modules/moordyn/src/MoorDyn_Body.f90 +++ b/modules/moordyn/src/MoorDyn_Body.f90 @@ -522,13 +522,25 @@ SUBROUTINE Body_GetCoupledForce(Body, Fnet_out, m, p) ! add inertial loads as appropriate if (Body%typeNum == -1) then - F6_iner = -MATMUL(Body%M, Body%a6) ! <<<<<<<< why does including F6_iner cause instability??? + if (p%inertialF == 1) then ! include inertial components + F6_iner = -MATMUL(Body%M, Body%a6) ! unstable in OpenFAST v4 and below becasue of loose coupling with ED and SD. Transients in acceleration can cause issues + else + ! When OpenFAST v5 is released w/ tight coupling, remove this hack and just use the inertial term above + F6_iner = 0.0 + endif + Body%F6net = Body%F6net + F6_iner ! add inertial loads Fnet_out = Body%F6net - else if (Body%typeNum == 2) then ! pinned coupled body - ! inertial loads ... from input translational ... and solved rotational ... acceleration - F6_iner(1:3) = -MATMUL(Body%M(1:3,1:3), Body%a6(1:3)) - MATMUL(Body%M(1:3,4:6), Body%a6(4:6)) + else if (Body%typeNum == 2) then ! pinned coupled body + + if (p%inertialF == 1) then ! include inertial components + ! inertial loads ... from input translational ... and solved rotational ... acceleration + F6_iner(1:3) = -MATMUL(Body%M(1:3,1:3), Body%a6(1:3)) - MATMUL(Body%M(1:3,4:6), Body%a6(4:6)) + else + F6_iner(1:3) = 0.0 + endif + Body%F6net(1:3) = Body%F6net(1:3) + F6_iner(1:3) ! add translational inertial loads Body%F6net(4:6) = 0.0_DbKi Fnet_out = Body%F6net diff --git a/modules/moordyn/src/MoorDyn_Registry.txt b/modules/moordyn/src/MoorDyn_Registry.txt index a8406ef193..8dbfcd08b3 100644 --- a/modules/moordyn/src/MoorDyn_Registry.txt +++ b/modules/moordyn/src/MoorDyn_Registry.txt @@ -423,6 +423,7 @@ typedef ^ ^ Integer dxIdx_map2_xStateIdx {:} typedef ^ ^ Logical VisMeshes - - - "Using visualization meshes as requested by glue code" - typedef ^ ^ VisDiam VisRodsDiam {:} - - "Diameters for visualization of rods" - typedef ^ ^ IntKi Standalone - - - "Indicates MoorDyn run as standalone code if 1, coupled if 0" - +typedef ^ ^ IntKi inertialF - 1 - "Indicates MoorDyn returning inertial moments for coupled 6DOF objects. 1 if yes, 0 if no" - # ============================== Inputs ============================================================================================================================================ diff --git a/modules/moordyn/src/MoorDyn_Rod.f90 b/modules/moordyn/src/MoorDyn_Rod.f90 index 49c61a5c56..8e8b274d77 100644 --- a/modules/moordyn/src/MoorDyn_Rod.f90 +++ b/modules/moordyn/src/MoorDyn_Rod.f90 @@ -996,14 +996,24 @@ SUBROUTINE Rod_GetCoupledForce(Rod, Fnet_out, m, p) ! add inertial loads as appropriate (written out in a redundant way just for clarity, and to support load separation in future) ! fixed coupled rod if (Rod%typeNum == -2) then - - F6_iner = -MATMUL(Rod%M6net, Rod%a6) ! inertial loads + + if (p%inertialF == 1) then ! include inertial components + F6_iner = -MATMUL(Rod%M6net, Rod%a6) ! inertial loads + else + F6_iner = 0.0 + endif Rod%F6net = Rod%F6net + F6_iner ! add inertial loads Fnet_out = Rod%F6net ! pinned coupled rod - else if (Rod%typeNum == -1) then - ! inertial loads ... from input translational ... and solved rotational ... acceleration - F6_iner(1:3) = -MATMUL(Rod%M6net(1:3,1:3), Rod%a6(1:3)) - MATMUL(Rod%M6net(1:3,4:6), Rod%a6(4:6)) + else if (Rod%typeNum == -1) then + + if (p%inertialF == 1) then ! include inertial components + ! inertial loads ... from input translational ... and solved rotational ... acceleration + F6_iner(1:3) = -MATMUL(Rod%M6net(1:3,1:3), Rod%a6(1:3)) - MATMUL(Rod%M6net(1:3,4:6), Rod%a6(4:6)) + else + F6_iner(1:3) = 0.0 + endif + Rod%F6net(1:3) = Rod%F6net(1:3) + F6_iner(1:3) ! add translational inertial loads Rod%F6net(4:6) = 0.0_DbKi Fnet_out = Rod%F6net diff --git a/modules/moordyn/src/MoorDyn_Types.f90 b/modules/moordyn/src/MoorDyn_Types.f90 index 125834a561..713a64b0fd 100644 --- a/modules/moordyn/src/MoorDyn_Types.f90 +++ b/modules/moordyn/src/MoorDyn_Types.f90 @@ -456,6 +456,7 @@ MODULE MoorDyn_Types LOGICAL :: VisMeshes !< Using visualization meshes as requested by glue code [-] TYPE(VisDiam) , DIMENSION(:), ALLOCATABLE :: VisRodsDiam !< Diameters for visualization of rods [-] INTEGER(IntKi) :: Standalone !< Indicates MoorDyn run as standalone code if 1, coupled if 0 [-] + INTEGER(IntKi) :: inertialF = 1 !< Indicates MoorDyn returning inertial moments for coupled 6DOF objects. 1 if yes, 0 if no [-] END TYPE MD_ParameterType ! ======================= ! ========= MD_InputType ======= From acc20caade8b2f5f652aabb93992082761fa19f2 Mon Sep 17 00:00:00 2001 From: RyanDavies19 Date: Tue, 9 Jan 2024 16:28:02 -0700 Subject: [PATCH 14/18] Add error handling to opening line EA file --- modules/moordyn/src/MoorDyn_IO.f90 | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/modules/moordyn/src/MoorDyn_IO.f90 b/modules/moordyn/src/MoorDyn_IO.f90 index 271d9791d9..245c9afa1f 100644 --- a/modules/moordyn/src/MoorDyn_IO.f90 +++ b/modules/moordyn/src/MoorDyn_IO.f90 @@ -242,8 +242,7 @@ SUBROUTINE getCoefficientOrCurve(inputString, LineProp_c, LineProp_npoints, Line LineProp_npoints = 0; else ! otherwise interpet the input as a file name to load stress-strain lookup data from - - CALL WrScr("found A letter in the line coefficient value so will try to load the filename.") + CALL WrScr1(" Found a letter in the line EA coefficient value so will try to load the filename.") LineProp_c = 0.0 @@ -251,8 +250,13 @@ SUBROUTINE getCoefficientOrCurve(inputString, LineProp_c, LineProp_npoints, Line CALL GetNewUnit( UnCoef ) CALL OpenFInpFile( UnCoef, TRIM(inputString), ErrStat4, ErrMsg4 ) ! add error handling? + IF (ErrStat4 == ErrID_Fatal) then + ErrStat3 = ErrStat4 + ErrMsg3 = ErrMsg4 + RETURN + ENDIF - READ(UnCoef,'(A)',IOSTAT=ErrStat4) Line2 ! skip the first two lines (title, names, and units) then parse + READ(UnCoef,'(A)',IOSTAT=ErrStat4) Line2 ! skip the first three lines (title, names, and units) then parse READ(UnCoef,'(A)',IOSTAT=ErrStat4) Line2 READ(UnCoef,'(A)',IOSTAT=ErrStat4) Line2 From 387857b1f6dbb5153a569ab70e5f547d06af492a Mon Sep 17 00:00:00 2001 From: RyanDavies19 Date: Tue, 9 Jan 2024 16:33:42 -0700 Subject: [PATCH 15/18] Change default inertialF to 0 --- modules/moordyn/src/MoorDyn_Registry.txt | 2 +- modules/moordyn/src/MoorDyn_Types.f90 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/moordyn/src/MoorDyn_Registry.txt b/modules/moordyn/src/MoorDyn_Registry.txt index 8dbfcd08b3..6ebabf21c5 100644 --- a/modules/moordyn/src/MoorDyn_Registry.txt +++ b/modules/moordyn/src/MoorDyn_Registry.txt @@ -423,7 +423,7 @@ typedef ^ ^ Integer dxIdx_map2_xStateIdx {:} typedef ^ ^ Logical VisMeshes - - - "Using visualization meshes as requested by glue code" - typedef ^ ^ VisDiam VisRodsDiam {:} - - "Diameters for visualization of rods" - typedef ^ ^ IntKi Standalone - - - "Indicates MoorDyn run as standalone code if 1, coupled if 0" - -typedef ^ ^ IntKi inertialF - 1 - "Indicates MoorDyn returning inertial moments for coupled 6DOF objects. 1 if yes, 0 if no" - +typedef ^ ^ IntKi inertialF - 0 - "Indicates MoorDyn returning inertial moments for coupled 6DOF objects. 1 if yes, 0 if no" - # ============================== Inputs ============================================================================================================================================ diff --git a/modules/moordyn/src/MoorDyn_Types.f90 b/modules/moordyn/src/MoorDyn_Types.f90 index 713a64b0fd..1e640d4098 100644 --- a/modules/moordyn/src/MoorDyn_Types.f90 +++ b/modules/moordyn/src/MoorDyn_Types.f90 @@ -456,7 +456,7 @@ MODULE MoorDyn_Types LOGICAL :: VisMeshes !< Using visualization meshes as requested by glue code [-] TYPE(VisDiam) , DIMENSION(:), ALLOCATABLE :: VisRodsDiam !< Diameters for visualization of rods [-] INTEGER(IntKi) :: Standalone !< Indicates MoorDyn run as standalone code if 1, coupled if 0 [-] - INTEGER(IntKi) :: inertialF = 1 !< Indicates MoorDyn returning inertial moments for coupled 6DOF objects. 1 if yes, 0 if no [-] + INTEGER(IntKi) :: inertialF = 0 !< Indicates MoorDyn returning inertial moments for coupled 6DOF objects. 1 if yes, 0 if no [-] END TYPE MD_ParameterType ! ======================= ! ========= MD_InputType ======= From f814dba80d1fa25a2aa5f7dd53aadd35877e474a Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Tue, 9 Jan 2024 17:07:29 -0700 Subject: [PATCH 16/18] MD reg test: update input files --- reg_tests/r-test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reg_tests/r-test b/reg_tests/r-test index 7709178aed..49b70806aa 160000 --- a/reg_tests/r-test +++ b/reg_tests/r-test @@ -1 +1 @@ -Subproject commit 7709178aed58df8f5df3b86a41c275cbaac5f70e +Subproject commit 49b70806aa1d9d5dc1698075e89660cad69c38d7 From 5c67b9989365c458b036d7838727908a15e91102 Mon Sep 17 00:00:00 2001 From: RyanDavies19 Date: Wed, 10 Jan 2024 10:57:48 -0700 Subject: [PATCH 17/18] Replace print w WrScr and minor organize of registry --- modules/moordyn/src/MoorDyn_Body.f90 | 4 ++-- modules/moordyn/src/MoorDyn_Misc.f90 | 20 ++++++++++---------- modules/moordyn/src/MoorDyn_Point.f90 | 4 ++-- modules/moordyn/src/MoorDyn_Registry.txt | 4 ++-- modules/moordyn/src/MoorDyn_Rod.f90 | 8 ++++---- modules/moordyn/src/MoorDyn_Types.f90 | 4 ++-- 6 files changed, 22 insertions(+), 22 deletions(-) diff --git a/modules/moordyn/src/MoorDyn_Body.f90 b/modules/moordyn/src/MoorDyn_Body.f90 index 2a1b2df68c..acf6f92098 100644 --- a/modules/moordyn/src/MoorDyn_Body.f90 +++ b/modules/moordyn/src/MoorDyn_Body.f90 @@ -570,7 +570,7 @@ SUBROUTINE Body_AddPoint(Body, pointID, coords) Body%AttachedC(Body%nAttachedC) = pointID Body%rPointRel(:,Body%nAttachedC) = coords ! store relative position of point on body ELSE - Print*, "too many Points attached to Body ", Body%IdNum, " in MoorDyn!" + call WrScr("too many Points attached to Body "//trim(num2lstr(Body%IdNum))//" in MoorDyn!") END IF END SUBROUTINE Body_AddPoint @@ -601,7 +601,7 @@ SUBROUTINE Body_AddRod(Body, rodID, coords) Body%r6RodRel(4:6, Body%nAttachedR) = tempUnitVec ELSE - Print*, "too many rods attached to Body ", Body%IdNum, " in MoorDyn" + call WrScr("too many rods attached to Body "//trim(num2lstr(Body%IdNum))//" in MoorDyn") END IF END SUBROUTINE Body_AddRod diff --git a/modules/moordyn/src/MoorDyn_Misc.f90 b/modules/moordyn/src/MoorDyn_Misc.f90 index 7c0e26c203..8fb91cf218 100644 --- a/modules/moordyn/src/MoorDyn_Misc.f90 +++ b/modules/moordyn/src/MoorDyn_Misc.f90 @@ -1350,7 +1350,7 @@ SUBROUTINE setupWaterKin(WaterKinString, p, Tmax, ErrStat, ErrMsg) ELSE IF (SCAN(WaterKinString, "abcdfghijklmnopqrstuvwxyzABCDFGHIJKLMNOPQRSTUVWXYZ") == 0) THEN ! If the input has no letters, let's assume it's a number - print *, "ERROR WaveKin option does not currently support numeric entries. It must be a filename." + call WrScr( "ERROR WaveKin option does not currently support numeric entries. It must be a filename." ) p%WaveKin = 0 p%Current = 0 return @@ -1358,7 +1358,7 @@ SUBROUTINE setupWaterKin(WaterKinString, p, Tmax, ErrStat, ErrMsg) ! otherwise interpret the input as a file name to load the bathymetry lookup data from - print *, " The waterKin input contains letters so will load a water kinematics input file" + call WrScr( " The waterKin input contains letters so will load a water kinematics input file" ) ! -------- load water kinematics input file ------------- @@ -1413,7 +1413,7 @@ SUBROUTINE setupWaterKin(WaterKinString, p, Tmax, ErrStat, ErrMsg) EXIT ! break out of the loop if it couldn't read the line (i.e. if at end of file) end if if (i == 100) then - print*,"WARNING: MD can handle a maximum of 100 current profile points" + call WrScr("WARNING: MD can handle a maximum of 100 current profile points") exit end if END DO @@ -1449,7 +1449,7 @@ SUBROUTINE setupWaterKin(WaterKinString, p, Tmax, ErrStat, ErrMsg) ! --------------------- set from inputted wave elevation time series, grid approach ------------------- if (p%WaveKin == 3) then - print *, 'Setting up WaveKin 3 option: read wave elevation time series from file' + call WrScr( 'Setting up WaveKin 3 option: read wave elevation time series from file' ) IF ( LEN_TRIM( WaveKinFile ) == 0 ) THEN CALL SetErrStat( ErrID_Fatal,'WaveKinFile must not be an empty string.',ErrStat, ErrMsg, RoutineName); return @@ -1467,7 +1467,7 @@ SUBROUTINE setupWaterKin(WaterKinString, p, Tmax, ErrStat, ErrMsg) CALL OpenFInpFile ( UnElev, WaveKinFile, ErrStat2, ErrMsg2 ); if(Failed()) return - print *, 'Reading wave elevation data from ', trim(WaveKinFile) + call WrScr( 'Reading wave elevation data from '//trim(WaveKinFile) ) ! Read through length of file to find its length i = 1 ! start counter @@ -1502,7 +1502,7 @@ SUBROUTINE setupWaterKin(WaterKinString, p, Tmax, ErrStat, ErrMsg) ! Close the inputs file CLOSE ( UnElev ) - print *, "Read ", ntIn, " time steps from input file." + call WrScr( "Read "//trim(num2lstr(ntIn))//" time steps from input file." ) ! if (WaveTimeIn(ntIn) < TMax) then <<<< need to handle if time series is too short? @@ -1714,7 +1714,7 @@ SUBROUTINE gridAxisCoords(coordtype, entries, coordarray, n, ErrStat, ErrMsg) INTEGER(IntKi) :: nEntries, I IF (len(trim(entries)) == len(entries)) THEN - print*, "Warning: Only 120 characters read from wave grid coordinates" + call WrScr("Warning: Only 120 characters read from wave grid coordinates") END IF IF (entries(len(entries):len(entries)) == ',') THEN @@ -1732,7 +1732,7 @@ SUBROUTINE gridAxisCoords(coordtype, entries, coordarray, n, ErrStat, ErrMsg) else if (coordtype==2) then ! 2: uniform specified by -xlim, xlim, num n = int(tempArray(3)) else - print *, "Error: invalid coordinate type specified to gridAxisCoords" + call WrScr("Error: invalid coordinate type specified to gridAxisCoords") end if ! allocate coordinate array @@ -1755,7 +1755,7 @@ SUBROUTINE gridAxisCoords(coordtype, entries, coordarray, n, ErrStat, ErrMsg) end do else - print *, "Error: invalid coordinate type specified to gridAxisCoords" + call WrScr("Error: invalid coordinate type specified to gridAxisCoords") end if ! print *, "Set water grid coordinates to :" @@ -1791,7 +1791,7 @@ SUBROUTINE stringToArray(instring, n, outarray) END IF n = n + 1 if (n > 100) then - print *, "ERROR - stringToArray cannot do more than 100 entries" + call WrScr( "ERROR - stringToArray cannot do more than 100 entries") end if READ(instring(pos1:pos1+pos2-2), *) outarray(n) diff --git a/modules/moordyn/src/MoorDyn_Point.f90 b/modules/moordyn/src/MoorDyn_Point.f90 index f79d86858b..9328f4805d 100644 --- a/modules/moordyn/src/MoorDyn_Point.f90 +++ b/modules/moordyn/src/MoorDyn_Point.f90 @@ -362,7 +362,7 @@ SUBROUTINE Point_AddLine(Point, lineID, TopOfLine) Point%Attached(Point%nAttached) = lineID Point%Top(Point%nAttached) = TopOfLine ! attached to line ... 1 = top/fairlead(end B), 0 = bottom/anchor(end A) ELSE - Print*, "Too many lines connected to Point ", Point%IdNum, " in MoorDyn!" + call WrScr("Too many lines connected to Point "//trim(num2lstr(Point%IdNum))//" in MoorDyn!") END IF END SUBROUTINE Point_AddLine @@ -399,7 +399,7 @@ SUBROUTINE Point_RemoveLine(Point, lineID, TopOfLine, rEnd, rdEnd) rdEnd(J) = Point%rd(J) END DO - print*, "Detached line ", lineID, " from Point ", Point%IdNum + call WrScr( "Detached line "//trim(num2lstr(lineID))//" from Point "//trim(num2lstr(Point%IdNum))) EXIT END DO diff --git a/modules/moordyn/src/MoorDyn_Registry.txt b/modules/moordyn/src/MoorDyn_Registry.txt index 6ebabf21c5..9c4d84e6d4 100644 --- a/modules/moordyn/src/MoorDyn_Registry.txt +++ b/modules/moordyn/src/MoorDyn_Registry.txt @@ -391,6 +391,8 @@ typedef ^ ^ DbKi mu_kT - typedef ^ ^ DbKi mu_kA - - - "axial kinetic friction coefficient" "(-)" typedef ^ ^ DbKi mc - - - "ratio of the static friction coefficient to the kinetic friction coefficient" "(-)" typedef ^ ^ DbKi cv - - - "saturated damping coefficient" "(-)" +typedef ^ ^ IntKi Standalone - - - "Indicates MoorDyn run as standalone code if 1, coupled if 0" - +typedef ^ ^ IntKi inertialF - 0 - "Indicates MoorDyn returning inertial moments for coupled 6DOF objects. 1 if yes, 0 if no" - # --- parameters for wave and current --- typedef ^ ^ IntKi nxWave - - - "number of x wave grid points" - typedef ^ ^ IntKi nyWave - - - "number of y wave grid points" - @@ -422,8 +424,6 @@ typedef ^ ^ Integer Jac_nx - typedef ^ ^ Integer dxIdx_map2_xStateIdx {:} - - "Mapping array from index of dX array to corresponding state index" - typedef ^ ^ Logical VisMeshes - - - "Using visualization meshes as requested by glue code" - typedef ^ ^ VisDiam VisRodsDiam {:} - - "Diameters for visualization of rods" - -typedef ^ ^ IntKi Standalone - - - "Indicates MoorDyn run as standalone code if 1, coupled if 0" - -typedef ^ ^ IntKi inertialF - 0 - "Indicates MoorDyn returning inertial moments for coupled 6DOF objects. 1 if yes, 0 if no" - # ============================== Inputs ============================================================================================================================================ diff --git a/modules/moordyn/src/MoorDyn_Rod.f90 b/modules/moordyn/src/MoorDyn_Rod.f90 index 8e8b274d77..f5f718198a 100644 --- a/modules/moordyn/src/MoorDyn_Rod.f90 +++ b/modules/moordyn/src/MoorDyn_Rod.f90 @@ -1081,7 +1081,7 @@ SUBROUTINE Rod_AddLine(Rod, lineID, TopOfLine, endB) Rod%AttachedB(Rod%nAttachedB) = lineID Rod%TopB(Rod%nAttachedB) = TopOfLine ! attached to line ... 1 = top/fairlead(end B), 0 = bottom/anchor(end A) ELSE - Print*, "too many lines connected to Rod ", Rod%IdNum, " in MoorDyn!" + call WrScr("too many lines connected to Rod "//trim(num2lstr(Rod%IdNum))//" in MoorDyn!") END IF else ! attaching to end A @@ -1093,7 +1093,7 @@ SUBROUTINE Rod_AddLine(Rod, lineID, TopOfLine, endB) Rod%AttachedA(Rod%nAttachedA) = lineID Rod%TopA(Rod%nAttachedA) = TopOfLine ! attached to line ... 1 = top/fairlead(end B), 0 = bottom/anchor(end A) ELSE - Print*, "too many lines connected to Rod ", Rod%IdNum, " in MoorDyn!" + call WrScr("too many lines connected to Rod "//trim(num2lstr(Rod%IdNum))//" in MoorDyn!") END IF end if @@ -1135,7 +1135,7 @@ SUBROUTINE Rod_RemoveLine(Rod, lineID, TopOfLine, endB, rEnd, rdEnd) rdEnd(J) = Rod%rd(J,Rod%N) END DO - print*, "Detached line ", lineID, " from Rod ", Rod%IdNum, " end B" + call WrScr( "Detached line "//trim(num2lstr(lineID))//" from Rod "//trim(num2lstr(Rod%IdNum))//" end B") EXIT END DO @@ -1167,7 +1167,7 @@ SUBROUTINE Rod_RemoveLine(Rod, lineID, TopOfLine, endB, rEnd, rdEnd) rdEnd(J) = Rod%rd(J,0) END DO - print*, "Detached line ", lineID, " from Rod ", Rod%IdNum, " end A" + call WrScr( "Detached line "//trim(num2lstr(lineID))//" from Rod "//trim(num2lstr(Rod%IdNum))//" end A") EXIT END DO diff --git a/modules/moordyn/src/MoorDyn_Types.f90 b/modules/moordyn/src/MoorDyn_Types.f90 index 1e640d4098..82a6096104 100644 --- a/modules/moordyn/src/MoorDyn_Types.f90 +++ b/modules/moordyn/src/MoorDyn_Types.f90 @@ -426,6 +426,8 @@ MODULE MoorDyn_Types REAL(DbKi) :: mu_kA !< axial kinetic friction coefficient [(-)] REAL(DbKi) :: mc !< ratio of the static friction coefficient to the kinetic friction coefficient [(-)] REAL(DbKi) :: cv !< saturated damping coefficient [(-)] + INTEGER(IntKi) :: Standalone !< Indicates MoorDyn run as standalone code if 1, coupled if 0 [-] + INTEGER(IntKi) :: inertialF = 0 !< Indicates MoorDyn returning inertial moments for coupled 6DOF objects. 1 if yes, 0 if no [-] INTEGER(IntKi) :: nxWave !< number of x wave grid points [-] INTEGER(IntKi) :: nyWave !< number of y wave grid points [-] INTEGER(IntKi) :: nzWave !< number of z wave grid points [-] @@ -455,8 +457,6 @@ MODULE MoorDyn_Types INTEGER(IntKi) , DIMENSION(:), ALLOCATABLE :: dxIdx_map2_xStateIdx !< Mapping array from index of dX array to corresponding state index [-] LOGICAL :: VisMeshes !< Using visualization meshes as requested by glue code [-] TYPE(VisDiam) , DIMENSION(:), ALLOCATABLE :: VisRodsDiam !< Diameters for visualization of rods [-] - INTEGER(IntKi) :: Standalone !< Indicates MoorDyn run as standalone code if 1, coupled if 0 [-] - INTEGER(IntKi) :: inertialF = 0 !< Indicates MoorDyn returning inertial moments for coupled 6DOF objects. 1 if yes, 0 if no [-] END TYPE MD_ParameterType ! ======================= ! ========= MD_InputType ======= From 7bdeeb35eb588aaee40c60e9dd08190f8b0d2653 Mon Sep 17 00:00:00 2001 From: RyanDavies19 Date: Wed, 10 Jan 2024 11:40:19 -0700 Subject: [PATCH 18/18] Removed unecessary standalone variable and cleaned logic --- modules/moordyn/src/MoorDyn.f90 | 4 -- modules/moordyn/src/MoorDyn_Driver.f90 | 55 +++++++----------------- modules/moordyn/src/MoorDyn_Registry.txt | 1 - modules/moordyn/src/MoorDyn_Types.f90 | 1 - 4 files changed, 16 insertions(+), 45 deletions(-) diff --git a/modules/moordyn/src/MoorDyn.f90 b/modules/moordyn/src/MoorDyn.f90 index 22167aee53..ebde8cf519 100644 --- a/modules/moordyn/src/MoorDyn.f90 +++ b/modules/moordyn/src/MoorDyn.f90 @@ -200,10 +200,6 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er m%PtfmInit = InitInp%PtfmInit(:,1) ! is this copying necssary in case this is an individual instance in FAST.Farm? - p%Standalone = InitInp%Standalone - - - ! Check if this MoorDyn instance is being run from FAST.Farm (indicated by FarmSize > 0) if (InitInp%FarmSize > 0) then CALL WrScr(' >>> MoorDyn is running in array mode <<< ') diff --git a/modules/moordyn/src/MoorDyn_Driver.f90 b/modules/moordyn/src/MoorDyn_Driver.f90 index b83842dba9..3fbe8b580a 100644 --- a/modules/moordyn/src/MoorDyn_Driver.f90 +++ b/modules/moordyn/src/MoorDyn_Driver.f90 @@ -173,13 +173,9 @@ PROGRAM MoorDyn_Driver MD_InitInp%FarmSize = drvrInitInp%FarmSize - MD_InitInp%Standalone = 0 if (drvrInitInp%FarmSize > 0) then ! Check if this MoorDyn instance is being run from FAST.Farm (indicated by FarmSize > 0) nTurbines = drvrInitInp%FarmSize - else if (drvrInitInp%FarmSize < 0) then ! FarmSize<0 indicates standalone mode - MD_InitInp%Standalone = 1 - nTurbines = 1 ! to keep routines happy - else ! FarmSize==0 indicates normal, FAST module mode + else ! FarmSize==0 indicates normal, FAST module mode; FarmSize<0 indicates standalone mode nTurbines = 1 ! if a regular FAST module mode, we treat it like a nTurbine=1 farm case end if @@ -494,13 +490,14 @@ PROGRAM MoorDyn_Driver i = 1 ! read first timestep data K = 1 ! the index of the coupling points in the input mesh CoupledKinematics J = 1 ! the starting index of the relevant DOFs in the input array + + IF (MD_InitInp%FarmSize < 0) THEN + MD_p%TurbineRefPos(:,iTurb) = 0.0 + ENDIF + ! any coupled bodies (type -1) DO l = 1,MD_p%nCpldBodies(iTurb) - IF (MD_InitInp%Standalone == 1) THEN - MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) - ELSE - MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) - MD_p%TurbineRefPos(:,iTurb) - ENDIF + MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) - MD_p%TurbineRefPos(:,iTurb) MD_u(1)%CoupledKinematics(iTurb)%Orientation( :,:,K) = EulerConstruct( r_in(i, J+3:J+5) ) ! full Euler angle approach MD_u(1)%CoupledKinematics(iTurb)%TranslationVel( :,K) = rd_in(i, J:J+2) MD_u(1)%CoupledKinematics(iTurb)%RotationVel( :,K) = rd_in(i, J+3:J+5) @@ -513,12 +510,7 @@ PROGRAM MoorDyn_Driver ! any coupled rods (type -1 or -2) >>> need to make rotations ignored if it's a pinned rod <<< DO l = 1,MD_p%nCpldRods(iTurb) - - IF (MD_InitInp%Standalone == 1) THEN - MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) - ELSE - MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) - MD_p%TurbineRefPos(:,iTurb) - ENDIF + MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) - MD_p%TurbineRefPos(:,iTurb) MD_u(1)%CoupledKinematics(iTurb)%Orientation( :,:,K) = EulerConstruct( r_in(i, J+3:J+5) ) MD_u(1)%CoupledKinematics(iTurb)%TranslationVel( :,K) = rd_in(i, J:J+2) MD_u(1)%CoupledKinematics(iTurb)%RotationVel( :,K) = rd_in(i, J+3:J+5) @@ -531,12 +523,7 @@ PROGRAM MoorDyn_Driver ! any coupled points (type -1) DO l = 1, MD_p%nCpldPoints(iTurb) - - IF (MD_InitInp%Standalone == 1) THEN - MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) - ELSE - MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) - MD_p%TurbineRefPos(:,iTurb) - ENDIF + MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) - MD_p%TurbineRefPos(:,iTurb) MD_u(1)%CoupledKinematics(iTurb)%TranslationVel( :,K) = rd_in(i, J:J+2) MD_u(1)%CoupledKinematics(iTurb)%TranslationAcc( :,K) = 0.0_DbKi !rdd_in(i, J:J+2) @@ -595,13 +582,13 @@ PROGRAM MoorDyn_Driver K = 1 ! the index of the coupling points in the input mesh CoupledKinematics J = 1 ! the starting index of the relevant DOFs in the input array + IF (MD_InitInp%FarmSize < 0) THEN + MD_p%TurbineRefPos(:,iTurb) = 0.0 + ENDIF + ! any coupled bodies (type -1) DO l = 1,MD_p%nCpldBodies(iTurb) - IF (MD_InitInp%Standalone == 1) THEN - MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) - ELSE - MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) - MD_p%TurbineRefPos(:,iTurb) - ENDIF + MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) - MD_p%TurbineRefPos(:,iTurb) MD_u(1)%CoupledKinematics(iTurb)%Orientation( :,:,K) = EulerConstruct( r_in(i, J+3:J+5) ) ! full Euler angle approach MD_u(1)%CoupledKinematics(iTurb)%TranslationVel( :,K) = rd_in(i, J:J+2) MD_u(1)%CoupledKinematics(iTurb)%RotationVel( :,K) = rd_in(i, J+3:J+5) @@ -614,12 +601,7 @@ PROGRAM MoorDyn_Driver ! any coupled rods (type -1 or -2) >>> need to make rotations ignored if it's a pinned rod <<< DO l = 1,MD_p%nCpldRods(iTurb) - - IF (MD_InitInp%Standalone == 1) THEN - MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) - ELSE - MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) - MD_p%TurbineRefPos(:,iTurb) - ENDIF + MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) - MD_p%TurbineRefPos(:,iTurb) MD_u(1)%CoupledKinematics(iTurb)%Orientation( :,:,K) = EulerConstruct( r_in(i, J+3:J+5) ) MD_u(1)%CoupledKinematics(iTurb)%TranslationVel( :,K) = rd_in(i, J:J+2) MD_u(1)%CoupledKinematics(iTurb)%RotationVel( :,K) = rd_in(i, J+3:J+5) @@ -632,12 +614,7 @@ PROGRAM MoorDyn_Driver ! any coupled points (type -1) DO l = 1, MD_p%nCpldPoints(iTurb) - - IF (MD_InitInp%Standalone == 1) THEN - MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) - ELSE - MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) - MD_p%TurbineRefPos(:,iTurb) - ENDIF + MD_u(1)%CoupledKinematics(iTurb)%TranslationDisp(:,K) = r_in(i, J:J+2) - MD_u(1)%CoupledKinematics(iTurb)%Position(:,K) - MD_p%TurbineRefPos(:,iTurb) MD_u(1)%CoupledKinematics(iTurb)%TranslationVel( :,K) = rd_in(i, J:J+2) MD_u(1)%CoupledKinematics(iTurb)%TranslationAcc( :,K) = 0.0_DbKi !rdd_in(i, J:J+2) diff --git a/modules/moordyn/src/MoorDyn_Registry.txt b/modules/moordyn/src/MoorDyn_Registry.txt index 9c4d84e6d4..d4df4982c8 100644 --- a/modules/moordyn/src/MoorDyn_Registry.txt +++ b/modules/moordyn/src/MoorDyn_Registry.txt @@ -25,7 +25,6 @@ typedef ^ ^ ReKi rhoW - -99 typedef ^ ^ ReKi WtrDepth - -999.9 - "depth of water" "[m]" typedef ^ ^ ReKi PtfmInit {:}{:} - - "initial position of platform(s) shape: 6, nTurbines" - typedef ^ ^ IntKi FarmSize - 0 - "Indicates normal FAST module mode if 0, FAST.Farm coupled mode and =nTurbines if >0, standalone mode if -1" - -typedef ^ ^ IntKi Standalone - 0 - "Indicates MoorDyn run as standalone code if 1, coupled if 0" - typedef ^ ^ ReKi TurbineRefPos {:}{:} - - "reference position of turbines in farm, shape: 3, nTurbines" - typedef ^ ^ ReKi Tmax - - - "simulation duration" "[s]" typedef ^ ^ CHARACTER(1024) FileName - "" - "MoorDyn input file" diff --git a/modules/moordyn/src/MoorDyn_Types.f90 b/modules/moordyn/src/MoorDyn_Types.f90 index 82a6096104..c6a3e38d67 100644 --- a/modules/moordyn/src/MoorDyn_Types.f90 +++ b/modules/moordyn/src/MoorDyn_Types.f90 @@ -48,7 +48,6 @@ MODULE MoorDyn_Types REAL(ReKi) :: WtrDepth = -999.9 !< depth of water [[m]] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: PtfmInit !< initial position of platform(s) shape: 6, nTurbines [-] INTEGER(IntKi) :: FarmSize = 0 !< Indicates normal FAST module mode if 0, FAST.Farm coupled mode and =nTurbines if >0 [-] - INTEGER(IntKi) :: Standalone = 0 !< Indicates MoorDyn run as standalone code if 1, coupled if 0, standalone mode if -1 [-] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: TurbineRefPos !< reference position of turbines in farm, shape: 3, nTurbines [-] REAL(ReKi) :: Tmax !< simulation duration [[s]] CHARACTER(1024) :: FileName !< MoorDyn input file [-]