FAST and wind loads on tower

Tower Wind Loads due to External Aerodynamic Drag Forces

I have a check, to ensure that the deflected position of the middle of the current tower element is above the water level.

IF ( TwrPos(3) > 0.0 ) THEN ENDIF

When I looked at MorisonTwrLd, the same check is more precise. The current water level is calculated including the time-varying wave height. I don’t understand the definition of all the required parameters. The definitions in the MODULE block are as follows.

! WaveKinzi0(:) -- zi-coordinates for points along a vertical line passing through the platform reference point ! where the incident wave kinematics will be computed; these are relative to the mean see ! level (meters) ! DZNodes(:) -- Length of variable-length tower or platform elements for the points along a vertical line ! passing through the platform reference point where the incident wave kinematics will be ! computed (meters) ! WaveElevation0 -- Elevation of incident waves at the platform reference point and current time (meters)

Can you send me a diagram or sketch, please? Many thanks.

Kind Regards,

Mark


Dear Mark,

I don’t have the time to develop a diagram, but these variables should be easy to explain:

WaveKinzi0 is simply a 1D array containing the heights of nodes where the wave kinematics are calculated. The heights (zi-coordinates) are defined relative to the mean still water (MSL), positive vertically upward. So a node at the MSL would have WaveKinzi0 = 0 and a node at the mudline would have WaveKinzi0 = -WtrDpth.

DZNodes is simply 1D array containing the undeformed lengths of each tower element. Because the nodes are located at the centers of the elements, the undeformed distance between node i and node i+1 would equal ( DZNodes(i) + DZNoes(i+1) )/2.

WaveElevation0 is simply the instaneous elevation of the free surface relative to the MSL, positive vertically upward.

I hope that helps.

Best regards,

Thanks a lot Jason. That makes a lot of sense.

  1. The index into DZNodes is JNode (passed to MorisonTwrLd from TwrLoading), which is the node number under consideration.
  2. The index into WaveKinzi0 is also JNode. But WaveKinzi0 is defined as an array of length NWaveKin0 (i.e. WaveKinzi0 ). I don’t know how it can be indexed by JNode (from inside MorisonTwrLd). Is NWaveKin0 currently restricted to be equal to TwrNodes? So that wave kinematics may be calculated at any of the nodes on the tower and sub-structure?
  3. The function, WaveElevation is always called from MorisonTwrLd with 1 as the first argument (definition as follows). Is this point on the incident wave different at different points in time, ZTime?
IWaveElev     ! Index of the point on the still water level plane where the elevation of incident waves is to be computed (-)

I am working on an update to the diagram posted previously. I will upload when it’s ready. Please can you confirm [YES/NO] if it’s correct? I need to make sure it contains all the relevant parameters because in my input files, many are set to zero (or equal to other parameters).

Kind Regards,

Mark

so the following statement is always true?

WaveKinzi0(JNode) == TwrRBHt + ( JNode – ½ ) • [ ( TowerHt + TwrDraft – TwrRBHt ) / TwrNodes 

Hi, Jason,

Thanks for your prompt reply earlier this afternoon. I have updated the diagram I uploaded earlier so that the mid-point of the “current element” is now indicated along with the current values of velocity and position (TwrVel and TwrPos). Is this point also called “the point T” in the FAST manual?

I think I will now change the condition, which I had previously intended to verify that the point was above the water to a new condition, which checks that the entire length of the current element is above the water.

IF ( WaveStMod == 0 ) THEN ! .TRUE. if we have no stretching; therefore, integrate up to the MSL, regardless of the instantaneous free surface elevation. IF ( ( WaveKinzi0(JNode) - 0.5*DZNodes(JNode) ) >= 0.0 ) THEN ! .TRUE. if the current tower element lies entirely above the MSL. OK2CalcAeroDrag = .TRUE. ELSE OK2CalcAeroDrag = .FALSE. ENDIF ELSE ! We must have some sort of stretching. WaveElevation0 = WaveElevation ( 1, ZTime ) ! compute the local wave elevation IF ( ( WaveKinzi0(JNode) - 0.5*DZNodes(JNode) ) >= WaveElevation0 ) THEN ! .TRUE. if the current tower element lies entirely above the free surface of the incident wave. OK2CalcAeroDrag = .TRUE. ELSE OK2CalcAeroDrag = .FALSE. ENDIF ENDIF

Kind Regards,

Mark

Dear Mark,

In the current version of FAST for a fixed-bottom monopile, “yes,” NWaveKin0 = TwrNodes. (That is, the hydrodynamic and structural discretizations are identical.) Also, WaveKinzi0(JNode) == TwrRBHt - TwrDraft + ( JNode – ½ ) • [ ( TowerHt + TwrDraft – TwrRBHt ) / TwrNodes (Note that I added “-TwrDraft” to your expression to show that WaveKinzi0 is relative to the MSL, not the tower base.)

The node identified by IWaveElev in FUNCTION WaveElevation is a node that is fixed in space. Node 1 is the point along the undeflected tower centerline at MSL.

“Yes,” your updated graphic looks correct, but please note that there wouldn’t be tower analysis nodes in the rigid base section of the tower.

Best regards,

Dear Jason,

Thanks for your comprehensive reply. Yes, I understand that there may not be nodes defined within the rigid section of the tower. I have modified the diagram accordingly.

I am trying to test the new functionality numerically and would like to be able to calculate the tower base bending moment, outside FAST, in a spreadsheet. I expect that the base bending moment at any point in time depends on the tower top thrust, the external loads on the tower (due to wind and waves) and the inertial loads arising due to tower dynamics. I would like to ignore the tower dynamics at the moment, so I will switch them off by setting all degrees of freedom to FALSE as follows.

FALSE FlapDOF1 First flapwise blade mode DOF (flag) FALSE FlapDOF2 Second flapwise blade mode DOF (flag) FALSE EdgeDOF First edgewise blade mode DOF (flag) FALSE TeetDOF Rotor-teeter DOF (flag) [unused for 3 blades] FALSE DrTrDOF Drivetrain rotational-flexibility DOF (flag) FALSE GenDOF Generator DOF (flag) FALSE YawDOF Yaw DOF (flag) FALSE TwFADOF1 First fore-aft tower bending-mode DOF (flag) FALSE TwFADOF2 Second fore-aft tower bending-mode DOF (flag) FALSE TwSSDOF1 First side-to-side tower bending-mode DOF (flag) FALSE TwSSDOF2 Second side-to-side tower bending-mode DOF (flag) TRUE CompAero Compute aerodynamic forces (flag) FALSE CompNoise Compute aerodynamic noise (flag)

However, I do not get agreement, when I calculate the base bending moments from the rotor thrust and the external forces on the tower (due, in this case just to aerodynamic drag). Am I missing something?

Looking at the code, there appear to be two places where the aerodynamic forces are integrated to give the base bending moment. Am I double-accounting here?

Kind Regards,

Mark

[code] FTHydrot(J,:slight_smile: = z1*( TwrFt(DOF_Sg) - TwrAM(DOF_Sg,DOF_Sg)*LinAccETt(J,1) &
+ TwrAM(DOF_Sg,DOF_Sw)*LinAccETt(J,3) &
- TwrAM(DOF_Sg,DOF_Hv)*LinAccETt(J,2) &
- TwrAM(DOF_Sg,DOF_R )*AngAccEFt(J,1) &
+ TwrAM(DOF_Sg,DOF_P )*AngAccEFt(J,3) &
- TwrAM(DOF_Sg,DOF_Y )AngAccEFt(J,2) ) &
- z3
( TwrFt(DOF_Sw) - TwrAM(DOF_Sw,DOF_Sg)*LinAccETt(J,1) &
+ TwrAM(DOF_Sw,DOF_Sw)*LinAccETt(J,3) &
- TwrAM(DOF_Sw,DOF_Hv)*LinAccETt(J,2) &
- TwrAM(DOF_Sw,DOF_R )*AngAccEFt(J,1) &
+ TwrAM(DOF_Sw,DOF_P )*AngAccEFt(J,3) &
- TwrAM(DOF_Sw,DOF_Y )AngAccEFt(J,2) ) &
+ z2
( TwrFt(DOF_Hv) - TwrAM(DOF_Hv,DOF_Sg)*LinAccETt(J,1) &
+ TwrAM(DOF_Hv,DOF_Sw)*LinAccETt(J,3) &
- TwrAM(DOF_Hv,DOF_Hv)*LinAccETt(J,2) &
- TwrAM(DOF_Hv,DOF_R )*AngAccEFt(J,1) &
+ TwrAM(DOF_Hv,DOF_P )*AngAccEFt(J,3) &
- TwrAM(DOF_Hv,DOF_Y )AngAccEFt(J,2) )
MFHydrot(J,:slight_smile: = z1
( TwrFt(DOF_R ) - TwrAM(DOF_R ,DOF_Sg)*LinAccETt(J,1) &
+ TwrAM(DOF_R ,DOF_Sw)*LinAccETt(J,3) &
- TwrAM(DOF_R ,DOF_Hv)*LinAccETt(J,2) &
- TwrAM(DOF_R ,DOF_R )*AngAccEFt(J,1) &
+ TwrAM(DOF_R ,DOF_P )*AngAccEFt(J,3) &
- TwrAM(DOF_R ,DOF_Y )AngAccEFt(J,2) ) &
- z3
( TwrFt(DOF_P ) - TwrAM(DOF_P ,DOF_Sg)*LinAccETt(J,1) &
+ TwrAM(DOF_P ,DOF_Sw)*LinAccETt(J,3) &
- TwrAM(DOF_P ,DOF_Hv)*LinAccETt(J,2) &
- TwrAM(DOF_P ,DOF_R )*AngAccEFt(J,1) &
+ TwrAM(DOF_P ,DOF_P )*AngAccEFt(J,3) &
- TwrAM(DOF_P ,DOF_Y )AngAccEFt(J,2) ) &
+ z2
( TwrFt(DOF_Y ) - TwrAM(DOF_Y ,DOF_Sg)*LinAccETt(J,1) &
+ TwrAM(DOF_Y ,DOF_Sw)*LinAccETt(J,3) &
- TwrAM(DOF_Y ,DOF_Hv)*LinAccETt(J,2) &
- TwrAM(DOF_Y ,DOF_R )*AngAccEFt(J,1) &
+ TwrAM(DOF_Y ,DOF_P )*AngAccEFt(J,3) &
- TwrAM(DOF_Y ,DOF_Y )*AngAccEFt(J,2) )

! Calculate the mass of the current element:

ElmntMass = MassT(J)*DHNodes(J) ! Mass of tower element J

! Integrate to find the total partial forces and moments (including those
! associated with the QD2T()'s and those that are not) at the tower base
! (point T(0)):

DO I = 1,NPTE ! Loop through all active (enabled) DOFs that contribute to the QD2T-related linear accelerations of the tower

  TmpVec1 = PFTHydro(J,PTE(I),:)*DHNodes(J) &
          - ElmntMass*PLinVelET(J,PTE(I),0,:)           ! The portion of PFrcT0Trb associated with tower element J
  CALL CrossProd( TmpVec2, rT0T(J,:), TmpVec1 )         ! The portion of PMomX0Trb associated with tower element J
  TmpVec3 = PMFHydro(J,PTE(I),:)*DHNodes(J)             ! The added moment applied at tower element J

  PFrcT0Trb(PTE(I),:) = PFrcT0Trb(PTE(I),:) + TmpVec1

  PMomX0Trb(PTE(I),:) = PMomX0Trb(PTE(I),:) + TmpVec2 + TmpVec3

ENDDO ! I - All active (enabled) DOFs that contribute to the QD2T-related linear accelerations of the tower

TmpVec1 = ( FTAero(J,:slight_smile: + FTHydrot(J,:slight_smile: )DHNodes(J) &
- ElmntMass
( Gravity*z2 + LinAccETt(J,:slight_smile: ) ! The portion of FrcT0Trbt associated with tower element J
CALL CrossProd( TmpVec2, rT0T(J,:), TmpVec1 ) ! The portion of MomX0Trbt associated with tower element J
TmpVec3 = ( MFAero(J,:slight_smile: + MFHydrot(J,:slight_smile: )*DHNodes(J) ! The external moment applied to tower element J

FrcT0Trbt = FrcT0Trbt + TmpVec1

MomX0Trbt = MomX0Trbt + TmpVec2 + TmpVec3
[/code]

so TwrFt and FTAero both contribute to the tower base bending moment MomX0Trbt, even though they have previously been set to same values in the subroutine TwrLoading (see below).

[code]SUBROUTINE TwrLoading ( JNode, X1 , X2 , X3 , X4 , X5 , X6 , &
XD1, XD2, XD3, XD4, XD5, XD6 )

! This routine computes the tower hydrodynamic loading; that is
! TwrAM(1:6,1:6) and TwrFt(1:6).

USE General

! Compute the tower aerodynamic loading for the current tower node/ element:

IF ( CompAero ) THEN ! AeroDyn has been used
CALL CalcAeroDrag ( JNode, X, XD, ZTime, DirRoot, TwrAM, TwrFt )
FTAero(JNode,1) = TwrFt(1) !
FTAero(JNode,2) = TwrFt(2) !
FTAero(JNode,3) = TwrFt(3) ! write output tower forces and moments into
MFAero(JNode,1) = TwrFt(4) ! FTAero and MFAero
MFAero(JNode,2) = TwrFt(5) !
MFAero(JNode,3) = TwrFt(6) !
ENDIF[/code]

Dear Mark,

I’m not sure whether you are double counting the aerodynamic load or not. You set FTAero/MFAero equat to TwrFt in routine TwrLoading, but I’m guessing that TwrFt is redefined as the hydrodynamic load later on in TwrLoading.

In the standard version of FAST, the load TwrFt is used to store the hydrodynamic load applied on the tower independent of the structural acceleration. In the first part of the source code you copied in your post, TwrFt – along with the added mass TwrAM and the nonlinear structural acceleration (that is, the acceleration independent of QD2T) – is used to form FTHydroT and MFHydroT, which are the hydrodynamic loads independent of the linear structural acceleration (the QD2T term). Hydrodynamic loads FTHydroT and MFHydroT are then added to the aerodynamic loads FTAero and MFAero to determine the total applied load on the tower.

When you compute the aerodynamic (drag) loads on the tower, I suggest that you avoid using variable TwrFt and simply define FTAero and MFAero directly.

I hope that helps.

Best regards,

Dear Jason,

Thanks for your prompt reply. Thanks too for your suggestion. The code I snipped and inserted into my post above was from TwrLoading. I passed TwrAM and TwrFt to the new subroutine (which calculates external loads on the tower due to aerodynamic drag) because that was how MorisonTwrLd and UserTwrLd were set up. I will change the code so that a local array is used to store an intemediate value of the external tower load and then copied to FTAero (containing only the aerodynamic force per unit length).

Kind Regards,

Mark

[code]SUBROUTINE TwrLoading ( JNode, X1 , X2 , X3 , X4 , X5 , X6 , &
XD1, XD2, XD3, XD4, XD5, XD6 )

! This routine computes the tower hydrodynamic loading; that is
! TwrAM(1:6,1:6) and TwrFt(1:6).

USE General
USE FixedBottomSupportStructure, ONLY:MorisonTwrLd
USE SimCont
USE Tower
USE Features, ONLY: CompAero
USE RtHndSid, ONLY: FTAero, MFAero

IMPLICIT NONE

! Passed Variables:

REAL(ReKi), INTENT(IN ) :: X1 ! The xi-component of the translational displacement (in m ) of the current tower node relative to the inertial frame origin at ground level [onshore] or MSL [offshore].
REAL(ReKi), INTENT(IN ) :: X2 ! The yi-component of the translational displacement (in m ) of the current tower node relative to the inertial frame origin at ground level [onshore] or MSL [offshore].
REAL(ReKi), INTENT(IN ) :: X3 ! The zi-component of the translational displacement (in m ) of the current tower node relative to the inertial frame origin at ground level [onshore] or MSL [offshore].
REAL(ReKi), INTENT(IN ) :: X4 ! The xi-component of the rotational displacement (in rad ) of the current tower element relative to the inertial frame origin at ground level [onshore] or MSL [offshore].
REAL(ReKi), INTENT(IN ) :: X5 ! The yi-component of the rotational displacement (in rad ) of the current tower element relative to the inertial frame origin at ground level [onshore] or MSL [offshore].
REAL(ReKi), INTENT(IN ) :: X6 ! The zi-component of the rotational displacement (in rad ) of the current tower element relative to the inertial frame origin at ground level [onshore] or MSL [offshore].
REAL(ReKi), INTENT(IN ) :: XD1 ! The xi-component of the translational velocity (in m/s ) of the current tower node relative to the inertial frame origin at ground level [onshore] or MSL [offshore].
REAL(ReKi), INTENT(IN ) :: XD2 ! The yi-component of the translational velocity (in m/s ) of the current tower node relative to the inertial frame origin at ground level [onshore] or MSL [offshore].
REAL(ReKi), INTENT(IN ) :: XD3 ! The zi-component of the translational velocity (in m/s ) of the current tower node relative to the inertial frame origin at ground level [onshore] or MSL [offshore].
REAL(ReKi), INTENT(IN ) :: XD4 ! The xi-component of the rotational (angular) velocity (in rad/s) of the current tower element relative to the inertial frame origin at ground level [onshore] or MSL [offshore].
REAL(ReKi), INTENT(IN ) :: XD5 ! The yi-component of the rotational (angular) velocity (in rad/s) of the current tower element relative to the inertial frame origin at ground level [onshore] or MSL [offshore].
REAL(ReKi), INTENT(IN ) :: XD6 ! The zi-component of the rotational (angular) velocity (in rad/s) of the current tower element relative to the inertial frame origin at ground level [onshore] or MSL [offshore].

INTEGER(4), INTENT(IN ) :: JNode ! The number of the current tower node / element. [1 to TwrNodes]

! Local variables:

REAL(ReKi), PARAMETER :: SymTol = 9.999E-4 ! Tolerance used to determine if matrix PtfmAM is symmetric.
REAL(ReKi) :: X (6) ! The 3 components of the translational displacement (in m ) of the current tower node and the 3 components of the rotational displacement (in rad ) of the current tower element relative to the inertial frame origin at ground level [onshore] or MSL [offshore].
REAL(ReKi) :: XD (6) ! The 3 components of the translational velocity (in m/s) of the current tower node and the 3 components of the rotational (angular) velocity (in rad/s) of the current tower element relative to the inertial frame origin at ground level [onshore] or MSL [offshore].
REAL(ReKi) :: LocTwrFrc(6) ! local copy of tower forces to ensure that hydrodynamic effects are superposed on top of aerodynamic effects

INTEGER(4) :: I ! Loops through all platform DOFs.
INTEGER(4) :: J ! Loops through all platform DOFs.

! Place the displacement and velocity arguments into the local arrays,
! X(1:6) and XD(1:6), respectively:

X (1) = X1
X (2) = X2
X (3) = X3
X (4) = X4
X (5) = X5
X (6) = X6
XD(1) = XD1
XD(2) = XD2
XD(3) = XD3
XD(4) = XD4
XD(5) = XD5
XD(6) = XD6

! Compute the tower aerodynamic loading for the current tower node/ element:

IF ( CompAero ) THEN ! AeroDyn has been used
CALL CalcAeroDrag ( JNode, X, XD, ZTime, DirRoot, TwrAM, LocTwrFrc )
FTAero(JNode,1) = LocTwrFrc(1) !
FTAero(JNode,2) = LocTwrFrc(2) !
FTAero(JNode,3) = LocTwrFrc(3) ! write output tower forces and moments into
MFAero(JNode,1) = LocTwrFrc(4) ! FTAero and MFAero
MFAero(JNode,2) = LocTwrFrc(5) !
MFAero(JNode,3) = LocTwrFrc(6) !
ENDIF

! Compute the tower hydrodynamic loading for the current tower node/ element:

SELECT CASE ( PtfmModel ) ! Which platform model are we using?

CASE ( 0 ) ! None!

! user has selected not to calculate loads on the platform.
! no calculation required here, since TwrAM and TwrFt are all initialized to zero.

CASE ( 1 ) ! Onshore.

! user has selected not to calculate loads on the platform.
! no calculation required here, since TwrAM and TwrFt are all initialized to zero.

CASE ( 2 ) ! Fixed bottom offshore.

SELECT CASE ( TwrLdMod ) ! Which tower loading model are we using?

CASE ( 0 ) ! None!

  ! user has selected not to calculate loads on the tower.
  ! no calculation required here, since TwrAM and TwrFt are all initialized to zero.

CASE ( 1 ) ! Undocumented hydrodynamic loading using Morison’s equation.

  ! CALL the undocumented Morison's equation tower loading model:

  LocTwrFrc(1) = TwrFt(1)
  LocTwrFrc(2) = TwrFt(2)
  LocTwrFrc(3) = TwrFt(3)

  CALL MorisonTwrLd ( JNode, DiamT(JNode), CAT(JNode), CDT(JNode), X, XD, ZTime, TwrAM, TwrFt )

  IF ( ( TwrFt(1) /= 0 .AND. LocTwrFrc(1) /= 0 ) .OR. ( TwrFt(2) /= 0 .AND. LocTwrFrc(2) /= 0 ) .OR. ( TwrFt(3) /= 0 .AND. LocTwrFrc(3) /= 0 ) ) THEN
     CALL ProgWarn( ' Warning: both aerodynamic tower loads (CalcAeroDrag) and hydrodynamic loads (MorisonTwrLd) are simultaneously non-zero.' )
  ENDIF
  TwrFt(1) = TwrFt(1) + LocTwrFrc(1)
  TwrFt(2) = TwrFt(2) + LocTwrFrc(2)
  TwrFt(3) = TwrFt(3) + LocTwrFrc(3)

CASE ( 2 ) ! User-defined tower loading.

  ! CALL the user-defined tower loading model:
  CALL UserTwrLd ( JNode, X, XD, ZTime, DirRoot, TwrAM, TwrFt )


  ! Ensure that the tower element added mass matrix returned by UserTwrLd,
  !   TwrAM, is symmetric; Abort if necessary:

  DO I = 1,5        ! Loop through the 1st 5 rows (columns) of TwrAM

     DO J = (I+1),6 ! Loop through all columns (rows) passed I

        IF ( ABS( TwrAM(I,J) - TwrAM(J,I) ) > SymTol )  &
           CALL ProgAbort ( ' The user-defined tower element added mass matrix is unsymmetric.'// &
                            '  Make sure TwrAM returned by UserTwrLd() is symmetric.'               )

     ENDDO          ! J - All columns (rows) passed I

  ENDDO             ! I - The 1st 5 rows (columns) of TwrAM

ENDSELECT

CASE ( 3 ) ! Floating offshore.

! Do nothing here since TwrAM and TwrFt are all initialized to zero.

ENDSELECT

RETURN
END SUBROUTINE TwrLoading
!=======================================================================
SUBROUTINE CalcAeroDrag ( JNode, X, XD, ZTime, DirRoot, TwrAM, TwrFt )

! CalcAeroDrag has been written to calculate aerodynamic drag loads
! on the tower (the portion of the support structure above the current
! water level and below the yaw bearing).
!
! The tower loads returned by this routine contain contributions from
! any external load acting on the current tower element (indicated by
! JNode) other than loads transmitted from tower aerodynamics.
!
! No contribution to the local tower mass has been calculated below.
!
! This routine was originally written assuming that the tower loads are
! transmitted through a medium like soil [foundation] and/or water
! [offshore], so that added mass effects are important. Consequently,
! the routine assumes that the total load per unit length on the current
! tower element can be written as:
!
! TwrF(i) = SUM( -TwrAM(i,j)*XDD(j), j=1,2,…,6) + TwrFt(i) for i=1,2,…,6
!
! where,
! TwrF(i) = the i’th component of the total load per unit length
! applied on the current tower element; positive in the
! direction of positive motion of the i’th DOF of the current
! tower element
! TwrAM(i,j) = the (i,j) component of the tower added mass matrix per unit
! length (output by this routine)
! XDD(j) = the j’th component of the current tower element
! acceleration vector
! TwrFt(i) = the i’th component of the portion of the current tower
! element load per unit length associated with everything but
! the added mass effects; positive in the direction of
! positive motion of the i’th DOF of the current tower
! element (output by this routine)

! The order of indices in all arrays passed to and from this routine is as
! follows:
! 1 = Current tower element surge / xi-component of translation
! 3 = Current tower element sway / yi-component of translation
! 3 = Current tower element heave / zi-component of translation
! 4 = Current tower element roll / xi-component of rotation
! 5 = Current tower element pitch / yi-component of rotation
! 6 = Current tower element yaw / zi-component of rotation

! NOTE: The added mass matrix returned by this routine, TwrAM, must be
! symmetric. FAST and ADAMS will abort otherwise.
!
! Please also note that the hydrostatic restoring contribution to the
! hydrodynamic force returned by this routine should not contain the
! effects of body weight, as is often done in classical marine
! hydrodynamics. The effects of body weight are included within FAST
! and ADAMS.

USE AeroDyn, ONLY: TwrAeroDrag
USE Tower, ONLY: TwrNodes
USE TurbConf, ONLY: TowerHt, TwrRBHT, TwrDraft
USE Waves, ONLY: WaveElevation, WaveKinzi0, DZNodes, WaveStMod

IMPLICIT NONE

! Passed Variables:

REAL(ReKi), INTENT(OUT) :: TwrAM (6,6) ! Added mass matrix per unit length of current tower element, kg/m, kg-m/m, kg-m^2/m.
REAL(ReKi), INTENT(OUT) :: TwrFt (6) ! The surge/xi (1), sway/yi (2), and heave/zi (3)-components of the portion of the tower force per unit length (in N/m) at the current tower element and the roll/xi (4), pitch/yi (5), and yaw/zi (6)-components of the portion of the tower moment per unit length (in N-m/m) acting at the current tower element associated with everything but the added-mass effects; positive forces are in the direction of motion.
REAL(ReKi), INTENT(IN ) :: X (6) ! The 3 components of the translational displacement (in m ) of the current tower node and the 3 components of the rotational displacement (in rad ) of the current tower element relative to the inertial frame origin at ground level [onshore] or MSL [offshore].
REAL(ReKi), INTENT(IN ) :: XD (6) ! The 3 components of the translational velocity (in m/s) of the current tower node and the 3 components of the rotational (angular) velocity (in rad/s) of the current tower element relative to the inertial frame origin at ground level [onshore] or MSL [offshore].
REAL(ReKi), INTENT(IN ) :: ZTime ! Current simulation time, sec.
INTEGER, INTENT(IN ) :: JNode ! The number of the current tower node / element, (-). [1 to TwrNodes]
CHARACTER(1024), INTENT(IN ) :: DirRoot ! The name of the root file including the full path to the current working directory. This may be useful if you want this routine to write a permanent record of what it does to be stored with the simulation results: the results should be stored in a file whose name (including path) is generated by appending any suitable extension to DirRoot.

! Local Variables:

REAL(ReKi) :: Damp (6,6) ! Damping matrix.
REAL(ReKi) :: Stff (6,6) ! Stiffness/restoring matrix.
REAL(ReKi), DIMENSION(1:3) :: TwrVel ! The surge/xi (1), sway/yi (2), and heave/zi (3)-components of local tower linear velocity [m/s]
REAL(ReKi), DIMENSION(1:3) :: TwrFrc ! The surge/xi (1), sway/yi (2), and heave/zi (3)-components of the external drag force on the tower node, JNode
REAL(ReKi), DIMENSION(1:3) :: TwrPos ! The surge/xi (1), sway/yi (2), and heave/zi (3)-components of the current deflection of the tower node, JNode
REAL(ReKi), DIMENSION(1:3) :: TwrGeom ! The three components of tower geometry required by TwrAeroDrag (TwrRBHt, TwrDraft and TowerHt)
INTEGER(4) :: I ! Generic index.
INTEGER(4) :: J ! Generic index.
LOGICAL :: OK2CalcAeroDrag ! .TRUE. if entire element is above the water level (including the height of any incident wave)
REAL(ReKi) :: WaveElevation0 ! current local value of wave elevation

TwrPos(1) = X(1)
TwrPos(2) = X(2)
TwrPos(3) = X(3)
TwrFrc = 0.0

! calculate aerodynamic drag on tower if the local tower element mid-point is above the instantaneous water height
!
! some definitions:-
!
! (1) WaveStMod – Model for stretching incident wave kinematics to instantaneous free surface
! {0: none=no stretching, 1: vertical stretching, 2: extrapolation stretching, 3: Wheeler stretching}
! (2) WaveKinzi0(1:NWaveKin0) – zi-coordinates for points along a vertical line passing through the platform reference point
! where the incident wave kinematics will be computed; these are relative to the mean see
! level (meters)
! (3) DZNodes(1:NWaveKin0) – Length of variable-length tower or platform elements for the points along a vertical line
! passing through the platform reference point where the incident wave kinematics will be
! computed (meters)
! (4) WaveElevation0 – Elevation of incident waves at the platform reference point and current time (meters)

! .TRUE. if we have no stretching; therefore, integrate up to the MSL, regardless of the instantaneous free surface elevation.
IF ( WaveStMod == 0 ) THEN
! .TRUE. if the current tower element lies entirely above the MSL.
IF ( ( ( WaveKinzi0(JNode) - 0.5DZNodes(JNode) ) >= 0.0 ) .AND. ( TwrPos(3) - 0.5DZNodes(JNode) > 0.0 ) ) THEN
OK2CalcAeroDrag = .TRUE.
ELSE
OK2CalcAeroDrag = .FALSE.
ENDIF
ELSE ! We must have some sort of stretching.
WaveElevation0 = WaveElevation ( 1, ZTime ) ! compute the local wave elevation
! .TRUE. if the current tower element lies entirely above the free surface of the incident wave.
IF ( ( ( WaveKinzi0(JNode) - 0.5DZNodes(JNode) ) >= WaveElevation0 ) .AND. ( TwrPos(3) - 0.5DZNodes(JNode) > 0.0 ) ) THEN
OK2CalcAeroDrag = .TRUE.
ELSE
OK2CalcAeroDrag = .FALSE.
ENDIF
ENDIF

IF ( OK2CalcAeroDrag ) THEN
TwrGeom(1) = TwrRBHt
TwrGeom(2) = TwrDraft
TwrGeom(3) = TowerHt
TwrVel(1) = XD(1)
TwrVel(2) = XD(2)
TwrVel(3) = XD(3)
! get tower local diameter and drag coefficient
CALL TwrAeroDrag(ZTime, TwrPos, TwrVel, TwrFrc, JNode, TwrNodes, TwrGeom)
ELSE
TwrFrc(1) = 0.0
TwrFrc(2) = 0.0
TwrFrc(3) = 0.0
ENDIF

Damp (1,:slight_smile: = (/ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 /)
Damp (2,:slight_smile: = (/ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 /)
Damp (3,:slight_smile: = (/ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 /)
Damp (4,:slight_smile: = (/ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 /)
Damp (5,:slight_smile: = (/ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 /)
Damp (6,:slight_smile: = (/ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 /)

Stff (1,:slight_smile: = (/ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 /)
Stff (2,:slight_smile: = (/ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 /)
Stff (3,:slight_smile: = (/ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 /)
Stff (4,:slight_smile: = (/ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 /)
Stff (5,:slight_smile: = (/ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 /)
Stff (6,:slight_smile: = (/ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 /)

TwrAM(1,:slight_smile: = (/ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 /)
TwrAM(2,:slight_smile: = (/ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 /)
TwrAM(3,:slight_smile: = (/ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 /)
TwrAM(4,:slight_smile: = (/ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 /)
TwrAM(5,:slight_smile: = (/ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 /)
TwrAM(6,:slight_smile: = (/ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 /)

TwrFt(1) = TwrFrc(1)
TwrFt(2) = TwrFrc(2)
TwrFt(3) = TwrFrc(3)
TwrFt(4) = 0.0 ! no bending moments applied due to aerodynamic drag on the tower
TwrFt(5) = 0.0
TwrFt(6) = 0.0

DO J = 1,6
DO I = 1,6
TwrFt(I) = TwrFt(I) - Damp(I,J)*XD(J) - Stff(I,J)*X(J)
ENDDO
ENDDO

RETURN
END SUBROUTINE CalcAeroDrag
!=======================================================================
END MODULE FASTSubs
[/code]

Dear Jason,

I have written a new subroutine CalcAerDrag in FAST, which calls a new subroutine TwrAeroDrag in AeroDyn to compute aerodynamic drag forces on the tower. I have been testing FAST with an onshore turbine (NREL 5MW) and subsequently with an offshore turbine on a monopile (NREL 5MW). I have been using the following code (recycled from HydroCalc) to calculate the location of the element at current water level. I want to calculate aerodynamic forces only if an element is wholly above the current water level. The calculation is the same as in HydroCalc. The logical switch OK2CalcAeroDrag is .TRUE. if the current element is above the current water level.

IF ( WaveStMod == 0 ) THEN ! .TRUE. if the current tower element lies entirely above the MSL. IF ( ( ( WaveKinzi0(JNode) - 0.5*DZNodes(JNode) ) >= 0.0 ) .AND. ( TwrPos(3) - 0.5*DZNodes(JNode) > 0.0 ) ) THEN OK2CalcAeroDrag = .TRUE. ELSE OK2CalcAeroDrag = .FALSE. ENDIF ELSE ! We must have some sort of stretching. WaveElevation0 = WaveElevation ( 1, ZTime ) ! compute the local wave elevation ! .TRUE. if the current tower element lies entirely above the free surface of the incident wave. IF ( ( ( WaveKinzi0(JNode) - 0.5*DZNodes(JNode) ) >= WaveElevation0 ) .AND. ( TwrPos(3) - 0.5*DZNodes(JNode) > 0.0 ) ) THEN OK2CalcAeroDrag = .TRUE. ELSE OK2CalcAeroDrag = .FALSE. ENDIF ENDIF

My colleague, Rebecca Sykes recently tested FAST with an input file, to define wave elevations and water kinematics. Now my subroutine CalcAerDrag in FAST.F90 doesn’t work because the following are undefined. Are they not used when you select WaveMod = 4?

WaveKinzi0, DZnodes 

I would like to use a test for the position of the first “dry” tower element, which is independent of WaveMod and always contains defined variables. Is the following equivalent to the code above? Is WaveElevation0 always defined (for all selected values of WaveMod)?

ElemLowHeight = TwrRBHt + ((JNode-1)*(TowerHt + TwrDraft - TwrRBHt))/TwrNodes TwrElemLen = (TowerHt + TwrDraft - TwrRBHt))/TwrNodes IF ( WaveStMod == 0 ) THEN ! .TRUE. if the current tower element lies entirely above the MSL. IF ( ( ElemLowHeight >= TwrDraft ) .AND. ( TwrPos(3) - 0.5*TwrElemLen > 0.0 ) ) THEN OK2CalcAeroDrag = .TRUE. ELSE OK2CalcAeroDrag = .FALSE. ENDIF ELSE ! We must have some sort of stretching. WaveElevation0 = WaveElevation ( 1, ZTime ) ! compute the local wave elevation ! .TRUE. if the current tower element lies entirely above the free surface of the incident wave. IF ( ( ElemLowHeight >= TwrDraft + WaveElevation0 ) .AND. ( TwrPos(3) - 0.5*TwrElemLen > 0.0 ) ) THEN OK2CalcAeroDrag = .TRUE. ELSE OK2CalcAeroDrag = .FALSE. ENDIF ENDIF

With this change, I am no longer allowing “variable length tower or platform elements” to be defined in FAST in the future (DZNodes(:)). Thanks for your help.

Kind Regards,

Mark

Dear Mark,

Yes, WaveKinzi0 and DZNodes are defined/used in FAST when WaveMod = 4. I’m not sure why you’re saying their undefined.

Yes, from what I can tell, your two code snippets look identical (except that the top code allows for variable-length elements and bottom code assumes equal-length elements).

Yes, WaveElevation0 is defined for all selected values of WaveMod.

What is TwrPos defined as in your code? (I’m not sure what the second condition in your IF…THEN tests is checking for.)

Best regards,

The idea was to ensure that the local element of interest was above ground level before calculating aerodynamic drag loads.

Dear Jason,
Dear Mark,
I’m back on the subject after a while. I would like to know if the “wind loads on tower” is an official feature of FAST 8 as stated in the README(and eventually what I have to do to test it) or it still remain undocumented and the loads have to be added, for example at tower base, in the post-processing.

Thank you very much.

Ste

Dear Stefano,

Wind drag loading on the tower is now a standard feature of FAST v8. You can read about in the documentation supplied with AeroDyn v14.02.00c-mlb: wind.nrel.gov/designcodes/simula … wTower.pdf.

Best regards,

Thank you very much.

Stefano

Dear all,

I recently downloaded FAST v8. and AeroDyn v14. in order to calculate tower drag forces. Following the instructions of the NewTower feature I created the new ipt. file ‘’ NRELOffshrBsline5MW_AeroDyn_DT5_TwrDrag.ipt’’ based on‘’ NRELOffshrBsline5MW_AeroDyn_DT5.ipt’’ file witch is compatible with all the other input files need to run Test18 of the CertTests.

After running Test18.fst file (with the new ipt. file) I expected it to have computed local forces on each tower node. However, only YawBr and TwrBs forces and moments were produced.

What do I have to do in order to compute local tower outputs?

Best regards,
Gia

Dear Gia,

I current version of AeroDyn cannot output the tower drag to a file. I am writing new I/O routines for AeroDyn now and the new version will be able to output tower-element data similar to how it currently generates blade-element data. The components of force will be optional outputs.

It will probably be months before this is ready. If you need it now, I suggest you modify the code yourself. Sorry.

Marshall

Dear Marshall,

Thank you very much for your reply.

In my attempt to calculate drag forces on tower, apart from modifying the Aerodyn input file, I also tried to modify the ‘’NRELOffshrBsline5MW_Onshore_ElastoDyn.dat.’’ file for Test18. In the OUTPUT section of the .dat file, I set NTwgages = 2 and in line below, I named the two tower nodes that have strain gages. Then, in the OUTLIST, I requested TwHt1ML, TwHt2ML, TwHt1FL, TwHt2FL. FAST v8 terminated normally and the output file created, showed results for TwHt1ML, TwHt2ML, TwHt1FL, TwHt2FL. Are these the internal forces and moments on each tower gage?

According to your reply, I understood that Aerodyn v14 cannot output the tower drag load. However, is tower drag load taken into account in the computation of the internal forces described above?

Best regards,

Gia

Dear Gia,

The ElastoDyn outputs should give you the local tower reaction loads, including the applied tower drag load from AeroDyn v14.

You should note, however a few problems that we have found with Test18 in the FAST v8.3 archive:

  1. We accidently didn’t include the AeroDyn input file that uses tower drag in the archive – though it looks like you have created your own.
  2. The wind file does not contain all of the points it needs on the tower (InflowWind is not reporting the error that occurs when it can’t calculate the wind at a point off the grid; it’s returning 0 velocity), so you should set WrADTWR to TRUE in the TurbSim input file (./CertTest/5MW_Baseline/Wind/90m_12mps.inp) and regenerate the wind file. Right now, everything below 17.5 meters will have no wind loading on it.
  3. The NTwrRe parameter in the AeroDyn Tower TwrDrag input file should be set to 16 instead of 1 (otherwise it reads only the first row in the Re vs CD properties table).

Sorry for all the problems with that test. We’ve fixed those issues for the next release.

Dear Bonnie,

Thank you very much for your help.

I made all changes you mentioned above and run FAST again, this time for the offshore monopile, modifying the input files of Test 19. In the OUTPUT section of the Elastodyn .dat file I set NTwrGages = 9 and in line below I named 9 Twrnodes that have strain gages. Then I requested, among others, TwHtJMl outputs and TwHtJFl outputs for the 9 gages. FAST terminated and I plotted TwHtJFlx (kN) for the 9 gages and also the top and the base of the tower as shown in Chart_1. Given that wind loads are taken into account in the computation of the forces, I deducted the results of Fx in each node from the results produced for the node below, for example: TwHt9Flxt –YawBrFxp, TwHt8Flxt-TwHt9Flxt etc., in order to approximately evaluate tower wind loads in every part of the tower, between two nodes. Then, I plotted these results in Chart_2, for 3 representative parts on the tower and calculated the average value of the time series for all parts. In the results, I noticed negative values, as you can also see in Chart_2, which was not expected since, as we are moving from the top of the tower to the base, wind load along tower should be added.

How would you explain those negative average values occurred for the Fx force (in wind direction) in most parts of the tower? The only parts with positive average value are those closer to the top, particularly between nodes: G9-TOP, G8-G9, G7-G8.

Kind regards,
Gia