Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Visualization of HydroDyn Morison mesh and MoorDyn lines #1768

Merged
merged 6 commits into from
Sep 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions modules/hydrodyn/src/HydroDyn.f90
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,11 @@ SUBROUTINE HydroDyn_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, I
InputFileData%Waves%WaveFieldMod = InitInp%WaveFieldMod
InputFileData%Waves%PtfmLocationX = InitInp%PtfmLocationX
InputFileData%Waves%PtfmLocationY = InitInp%PtfmLocationY


! Were visualization meshes requested?
p%VisMeshes = InitInp%VisMeshes


! Now call each sub-module's *_Init subroutine
! to fully initialize each sub-module based on the necessary initialization data

Expand Down Expand Up @@ -1367,9 +1371,11 @@ SUBROUTINE HydroDyn_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, I
ELSE
InputFileData%Morison%OutSwtch = 0
END IF

! Were visualization meshes requested?
InputFileData%Morison%VisMeshes = p%VisMeshes

! Initialize the Morison Element Calculations

CALL Morison_Init(InputFileData%Morison, u%Morison, p%Morison, x%Morison, xd%Morison, z%Morison, OtherState%Morison, &
y%Morison, m%Morison, Interval, InitOut%Morison, ErrStat2, ErrMsg2 )
CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName)
Expand Down
2 changes: 2 additions & 0 deletions modules/hydrodyn/src/HydroDyn.txt
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ typedef ^ ^ SiKi
typedef ^ ^ INTEGER WaveFieldMod - - - "Wave field handling (-) (switch) 0: use individual HydroDyn inputs without adjustment, 1: adjust wave phases based on turbine offsets from farm origin" -
typedef ^ ^ ReKi PtfmLocationX - - - "Supplied by Driver: X coordinate of platform location in the wave field" "m"
typedef ^ ^ ReKi PtfmLocationY - - - "Supplied by Driver: Y coordinate of platform location in the wave field" "m"
typedef ^ ^ logical VisMeshes - .false. - "Output visualization meshes" -
#
#
# Define outputs from the initialization routine here:
Expand Down Expand Up @@ -218,6 +219,7 @@ typedef ^ ^ Integer
typedef ^ ^ R8Ki du {:} - - "vector that determines size of perturbation for u (inputs)" -
typedef ^ ^ R8Ki dx {:} - - "vector that determines size of perturbation for x (continuous states)" -
typedef ^ ^ Integer Jac_ny - - - "number of outputs in jacobian matrix" -
typedef ^ ^ logical VisMeshes - .false. - "Output visualization meshes" -
#
#
# ..... Inputs ....................................................................................................................
Expand Down
14 changes: 14 additions & 0 deletions modules/hydrodyn/src/HydroDyn_Types.f90
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ MODULE HydroDyn_Types
INTEGER(IntKi) :: WaveFieldMod !< Wave field handling (-) (switch) 0: use individual HydroDyn inputs without adjustment, 1: adjust wave phases based on turbine offsets from farm origin [-]
REAL(ReKi) :: PtfmLocationX !< Supplied by Driver: X coordinate of platform location in the wave field [m]
REAL(ReKi) :: PtfmLocationY !< Supplied by Driver: Y coordinate of platform location in the wave field [m]
LOGICAL :: VisMeshes = .false. !< Output visualization meshes [-]
END TYPE HydroDyn_InitInputType
! =======================
! ========= HydroDyn_InitOutputType =======
Expand Down Expand Up @@ -224,6 +225,7 @@ MODULE HydroDyn_Types
REAL(R8Ki) , DIMENSION(:), ALLOCATABLE :: du !< vector that determines size of perturbation for u (inputs) [-]
REAL(R8Ki) , DIMENSION(:), ALLOCATABLE :: dx !< vector that determines size of perturbation for x (continuous states) [-]
INTEGER(IntKi) :: Jac_ny !< number of outputs in jacobian matrix [-]
LOGICAL :: VisMeshes = .false. !< Output visualization meshes [-]
END TYPE HydroDyn_ParameterType
! =======================
! ========= HydroDyn_InputType =======
Expand Down Expand Up @@ -1963,6 +1965,7 @@ SUBROUTINE HydroDyn_CopyInitInput( SrcInitInputData, DstInitInputData, CtrlCode,
DstInitInputData%WaveFieldMod = SrcInitInputData%WaveFieldMod
DstInitInputData%PtfmLocationX = SrcInitInputData%PtfmLocationX
DstInitInputData%PtfmLocationY = SrcInitInputData%PtfmLocationY
DstInitInputData%VisMeshes = SrcInitInputData%VisMeshes
END SUBROUTINE HydroDyn_CopyInitInput

SUBROUTINE HydroDyn_DestroyInitInput( InitInputData, ErrStat, ErrMsg, DEALLOCATEpointers )
Expand Down Expand Up @@ -2064,6 +2067,7 @@ SUBROUTINE HydroDyn_PackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat,
Int_BufSz = Int_BufSz + 1 ! WaveFieldMod
Re_BufSz = Re_BufSz + 1 ! PtfmLocationX
Re_BufSz = Re_BufSz + 1 ! PtfmLocationY
Int_BufSz = Int_BufSz + 1 ! VisMeshes
IF ( Re_BufSz .GT. 0 ) THEN
ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 )
IF (ErrStat2 /= 0) THEN
Expand Down Expand Up @@ -2169,6 +2173,8 @@ SUBROUTINE HydroDyn_PackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat,
Re_Xferred = Re_Xferred + 1
ReKiBuf(Re_Xferred) = InData%PtfmLocationY
Re_Xferred = Re_Xferred + 1
IntKiBuf(Int_Xferred) = TRANSFER(InData%VisMeshes, IntKiBuf(1))
Int_Xferred = Int_Xferred + 1
END SUBROUTINE HydroDyn_PackInitInput

SUBROUTINE HydroDyn_UnPackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg )
Expand Down Expand Up @@ -2292,6 +2298,8 @@ SUBROUTINE HydroDyn_UnPackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrSta
Re_Xferred = Re_Xferred + 1
OutData%PtfmLocationY = ReKiBuf(Re_Xferred)
Re_Xferred = Re_Xferred + 1
OutData%VisMeshes = TRANSFER(IntKiBuf(Int_Xferred), OutData%VisMeshes)
Int_Xferred = Int_Xferred + 1
END SUBROUTINE HydroDyn_UnPackInitInput

SUBROUTINE HydroDyn_CopyInitOutput( SrcInitOutputData, DstInitOutputData, CtrlCode, ErrStat, ErrMsg )
Expand Down Expand Up @@ -8122,6 +8130,7 @@ SUBROUTINE HydroDyn_CopyParam( SrcParamData, DstParamData, CtrlCode, ErrStat, Er
DstParamData%dx = SrcParamData%dx
ENDIF
DstParamData%Jac_ny = SrcParamData%Jac_ny
DstParamData%VisMeshes = SrcParamData%VisMeshes
END SUBROUTINE HydroDyn_CopyParam

SUBROUTINE HydroDyn_DestroyParam( ParamData, ErrStat, ErrMsg, DEALLOCATEpointers )
Expand Down Expand Up @@ -8421,6 +8430,7 @@ SUBROUTINE HydroDyn_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrM
Db_BufSz = Db_BufSz + SIZE(InData%dx) ! dx
END IF
Int_BufSz = Int_BufSz + 1 ! Jac_ny
Int_BufSz = Int_BufSz + 1 ! VisMeshes
IF ( Re_BufSz .GT. 0 ) THEN
ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 )
IF (ErrStat2 /= 0) THEN
Expand Down Expand Up @@ -8897,6 +8907,8 @@ SUBROUTINE HydroDyn_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrM
END IF
IntKiBuf(Int_Xferred) = InData%Jac_ny
Int_Xferred = Int_Xferred + 1
IntKiBuf(Int_Xferred) = TRANSFER(InData%VisMeshes, IntKiBuf(1))
Int_Xferred = Int_Xferred + 1
END SUBROUTINE HydroDyn_PackParam

SUBROUTINE HydroDyn_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg )
Expand Down Expand Up @@ -9479,6 +9491,8 @@ SUBROUTINE HydroDyn_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, E
END IF
OutData%Jac_ny = IntKiBuf(Int_Xferred)
Int_Xferred = Int_Xferred + 1
OutData%VisMeshes = TRANSFER(IntKiBuf(Int_Xferred), OutData%VisMeshes)
Int_Xferred = Int_Xferred + 1
END SUBROUTINE HydroDyn_UnPackParam

SUBROUTINE HydroDyn_CopyInput( SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg )
Expand Down
119 changes: 117 additions & 2 deletions modules/hydrodyn/src/Morison.f90
Original file line number Diff line number Diff line change
Expand Up @@ -1892,6 +1892,7 @@ SUBROUTINE Morison_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, In
p%NMOutputs = InitInp%NMOutputs ! Number of members to output [ >=0 and <10]
p%OutSwtch = InitInp%OutSwtch
p%MSL2SWL = InitInp%MSL2SWL
p%VisMeshes = InitInp%VisMeshes ! visualization mesh for morison elements

ALLOCATE ( p%MOutLst(p%NMOutputs), STAT = errStat )
IF ( errStat /= ErrID_None ) THEN
Expand Down Expand Up @@ -2180,11 +2181,18 @@ SUBROUTINE Morison_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, In

END IF

! visualization Line2 mesh
if (p%VisMeshes) then
call VisMeshSetup(u,p,y,m,InitOut,ErrStat2,ErrMsg2); call SetErrStat( ErrStat2, ErrMsg2, errStat, errMsg, 'Morison_Init' )
if ( errStat >= AbortErrLev ) return
endif

! We will call CalcOutput to compute the loads for the initial reference position
! Then we can use the computed load components in the Summary File
! NOTE: Morison module has no states, otherwise we could no do this. GJH

call Morison_CalcOutput(0.0_DbKi, u, p, x, xd, z, OtherState, y, m, errStat, errMsg )
IF ( errStat > AbortErrLev ) RETURN

! Write Summary information now that everything has been initialized.
CALL WriteSummaryFile( InitInp%UnSum, InitInp%Gravity, InitInp%MSL2SWL, InitInp%WtrDpth, InitInp%NJoints, InitInp%NNodes, InitInp%Nodes, p%NMembers, p%Members, &
Expand All @@ -2198,6 +2206,106 @@ SUBROUTINE Morison_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, In
! END SUBROUTINE

END SUBROUTINE Morison_Init
subroutine VisMeshSetup(u,p,y,m,InitOut,ErrStat,ErrMsg)
type(Morison_InputType), intent(inout) :: u
type(Morison_ParameterType), intent(in ) :: p
type(Morison_OutputType), intent(inout) :: y
type(Morison_MiscVarType), intent(inout) :: m
type(Morison_InitOutputType), intent(inout) :: InitOut
integer(IntKi), intent( out) :: ErrStat
character(*), intent( out) :: ErrMsg

integer(IntKi) :: TotNodes ! total nodes in all elements (may differ from p%NNodes due to overlaps)
integer(IntKi) :: TotElems ! total number of elements
integer(IntKi) :: NdIdx, iMem, iNd, NdNum ! indexing
real(ReKi) :: NdPos(3),Pos1(3),Pos2(3)
real(R8Ki) :: MemberOrient(3,3)
real(R8Ki) :: Theta(3) ! Euler rotations
integer(IntKi) :: ErrStat2
character(ErrMsgLen) :: ErrMsg2
character(*), parameter :: RoutineName = 'VisMeshSetup'

ErrStat = ErrID_None
ErrMsg = ""

! Total number of nodes = sum of all member nodes
! Total number of elements = sum of all member elements
TotNodes=0
TotElems=0
do iMem=1,size(p%Members)
TotElems = TotElems + p%Members(iMem)%NElements
TotNodes = TotNodes + size(p%Members(iMem)%NodeIndx)
enddo

! Storage for the radius associated with each node
call AllocAry( InitOut%MorisonVisRad, TotNodes, 'MorisonVisRad', ErrStat2, ErrMsg2)
if (Failed()) return

call MeshCreate( BlankMesh = y%VisMesh, &
IOS = COMPONENT_OUTPUT, &
Nnodes = TotNodes, &
ErrStat = ErrStat2, &
ErrMess = ErrMsg2, &
TranslationDisp = .TRUE., &
Orientation = .TRUE. )
Copy link
Collaborator

@jjonkman jjonkman Sep 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be better if this VisMesh had the same fields as the Morison input point mesh (including velocities and accelerations)?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect we don't need the velocities in the VisMesh -- it's pretty rare to use them during visualization and they still exist in the Morison mesh. Switching to adding the connectivity to the point meshes will include that information at that point.

if (Failed()) return

! Position the nodes
NdNum=0 ! node number in y%VisMesh
do iMem=1,size(p%Members)

!FIXME:MemberOrient This is not correct for non-circular or curved members
! calculate an orientation using yaw-pitch-roll sequence with roll defined as zero (insufficient info)
Pos1=u%Mesh%Position(:,p%Members(iMem)%NodeIndx(1)) ! start node position of member
Pos2=u%Mesh%Position(:,p%Members(iMem)%NodeIndx(size(p%Members(iMem)%NodeIndx))) ! end node position of member
Theta(1) = 0.0_R8Ki ! roll (assumed since insufficient info)
Theta(2) = acos(real((Pos2(3)-Pos1(3))/norm2(Pos2-Pos1),R8Ki)) ! pitch
Theta(3) = atan2(real(Pos2(2)-Pos1(2),R8Ki),real(Pos2(1)-Pos1(1),R8Ki)) ! yaw
MemberOrient=EulerConstructZYX(Theta) ! yaw-pitch-roll sequence

! Set mesh postion, orientation, and radius
do iNd=1,size(p%Members(iMem)%NodeIndx)
NdNum=NdNum+1 ! node number in y%VisMesh
NdIdx = p%Members(iMem)%NodeIndx(iNd) ! node number in u%Mesh
NdPos = u%Mesh%Position(:,NdIdx) ! node position
call MeshPositionNode (y%VisMesh, NdNum, u%Mesh%Position(:,NdIdx), ErrStat2, ErrMsg2, Orient=MemberOrient)
if (Failed()) return
InitOut%MorisonVisRad(NdNum) = p%Members(iMem)%RMG(iNd) ! radius (including marine growth) for visualization
enddo
enddo

! make elements (line nodes start at 0 index, so N+1 total nodes)
NdNum=0 ! node number in y%VisMesh
do iMem=1,size(p%Members)
do iNd=1,size(p%Members(iMem)%NodeIndx)
NdNum=NdNum+1 ! node number in y%VisMesh
if (iNd==1) cycle
call MeshConstructElement ( Mesh = y%VisMesh, &
Xelement = ELEMENT_LINE2, &
P1=NdNum-1, P2=NdNum, & ! nodes to connect
errStat = ErrStat2, &
ErrMess = ErrMsg2 )
if (Failed()) return
enddo
enddo

! commit the assembled mesh
call MeshCommit ( y%VisMesh, ErrStat2, ErrMsg2)
if (Failed()) return

! map the mesh to u%Mesh
call MeshMapCreate( u%Mesh, y%VisMesh, m%VisMeshMap, ErrStat2, ErrMsg2 )
if (Failed()) return

contains
logical function Failed()
CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName )
Failed = ErrStat >= AbortErrLev
!if (Failed) then
! call FailCleanup()
!endif
end function Failed
end subroutine VisMeshSetup


SUBROUTINE RodrigMat(a, R, errStat, errMsg)
Expand Down Expand Up @@ -3313,8 +3421,15 @@ SUBROUTINE Morison_CalcOutput( Time, u, p, x, xd, z, OtherState, y, m, errStat,
CALL MrsnOut_WriteOutputs( p%UnOutFile, Time, y, p, errStat, errMsg )
END IF
END IF




! map the motion to the visulization mesh
if (p%VisMeshes) then
!FIXME: error handling is incorrect here (overwrites all previous errors/warnings)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be fixed before merging?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a significant amount of reworking of the error handling in Morison required to really address this. Since there are more HydroDyn changes in the dev and dev-unstable branches, I would rather wait and deal with error handling there instead of introduce potential merge conflicts now.

call Transfer_Point_to_Line2( u%Mesh, y%VisMesh, m%VisMeshMap, ErrStat, ErrMsg )
endif


END SUBROUTINE Morison_CalcOutput

subroutine LumpDistrHydroLoads( f_hydro, k_hat, dl, h_c, lumpedLoad )
Expand Down
6 changes: 5 additions & 1 deletion modules/hydrodyn/src/Morison.txt
Original file line number Diff line number Diff line change
Expand Up @@ -256,12 +256,13 @@ typedef ^ ^ SiKi
typedef ^ ^ SiKi WaveDynP {:}{:} - - "" -
typedef ^ ^ SiKi WaveVel {:}{:}{:} - - "" -
typedef ^ ^ INTEGER nodeInWater {:}{:} - - "Logical flag indicating if the node at the given time step is in the water, and hence needs to have hydrodynamic forces calculated" -
typedef ^ ^ logical VisMeshes - .false. - "Output visualization meshes" -
#
#
# Define outputs from the initialization routine here:
#
#typedef ^ InitOutputType MeshType Mesh - - - "Unused?" -
#typedef ^ ^ SiKi Morison_Rad {:} - - "radius of node (for FAST visualization)" (m)
typedef ^ InitOutputType SiKi MorisonVisRad {:} - - "radius of node (for FAST visualization)" (m)
typedef ^ InitOutputType CHARACTER(ChanLen) WriteOutputHdr {:} - - "User-requested Output channel names" -
typedef ^ ^ CHARACTER(ChanLen) WriteOutputUnt {:} - - "" -
#
Expand Down Expand Up @@ -310,6 +311,7 @@ typedef ^ ^ ReKi
typedef ^ ^ ReKi F_A_End {:}{:} - - "Lumped added mass loads at time t, which may not correspond to the WaveTime array of times" -
typedef ^ ^ ReKi F_BF_End {:}{:} - - "" -
typedef ^ ^ INTEGER LastIndWave - - - "Last time index used in the wave kinematics arrays" -
typedef ^ ^ MeshMapType VisMeshMap - - - "Mesh mapping for visualization mesh" -

# ..... Parameters ................................................................................................................
# Define parameters here:
Expand Down Expand Up @@ -349,6 +351,7 @@ typedef ^ ^ INTEGER
typedef ^ ^ CHARACTER(20) OutFmt - - - "" -
typedef ^ ^ CHARACTER(20) OutSFmt - - - "" -
typedef ^ ^ CHARACTER(ChanLen) Delim - - - "" -
typedef ^ ^ logical VisMeshes - .false. - "Output visualization meshes" -
#
#
# ..... Inputs ....................................................................................................................
Expand All @@ -360,4 +363,5 @@ typedef ^ InputType MeshType
# ..... Outputs ...................................................................................................................
# Define outputs that are contained on the mesh here:
typedef ^ OutputType MeshType Mesh - - - "Loads on each node output mesh" -
typedef ^ ^ MeshType VisMesh - - - "Line mesh for visualization" -
typedef ^ ^ ReKi WriteOutput {:} - - "" -
Loading
Loading