Skip to content
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
120 changes: 111 additions & 9 deletions modules/awae/src/AWAE.f90
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,7 @@ subroutine LowResGridCalcOutput(n, u, p, xd, y, m, errStat, errMsg)
integer(IntKi) :: maxN_wake
integer(IntKi) :: WAT_iT,WAT_iY,WAT_iZ !< indexes for WAT point (Time interchangeable with X)
integer(IntKi) :: errStat2
character(ErrMsgLen):: errMsg2
character(*), parameter :: RoutineName = 'LowResGridCalcOutput'
logical :: within
real(ReKi) :: yHat_plane(3), zHat_plane(3)
Expand Down Expand Up @@ -507,15 +508,6 @@ subroutine LowResGridCalcOutput(n, u, p, xd, y, m, errStat, errMsg)
ELSE ! All subsequent calls to AWAE_CalcOutput


! Warn our kind users if wake planes leave the low-resolution domain:
if ( u%p_plane(1,np,nt) < p%Grid_Low(1, 1) ) call SetErrStat(ErrID_Warn, 'The center of wake plane #'//trim(num2lstr(np))//' for turbine #'//trim(num2lstr(nt))//' has passed the lowest-most X boundary of the low-resolution domain.', errStat, errMsg, RoutineName)
if ( u%p_plane(1,np,nt) > p%Grid_Low(1,p%NumGrid_low) ) call SetErrStat(ErrID_Warn, 'The center of wake plane #'//trim(num2lstr(np))//' for turbine #'//trim(num2lstr(nt))//' has passed the upper-most X boundary of the low-resolution domain.' , errStat, errMsg, RoutineName)
if ( u%p_plane(2,np,nt) < p%Grid_Low(2, 1) ) call SetErrStat(ErrID_Warn, 'The center of wake plane #'//trim(num2lstr(np))//' for turbine #'//trim(num2lstr(nt))//' has passed the lowest-most Y boundary of the low-resolution domain.', errStat, errMsg, RoutineName)
if ( u%p_plane(2,np,nt) > p%Grid_Low(2,p%NumGrid_low) ) call SetErrStat(ErrID_Warn, 'The center of wake plane #'//trim(num2lstr(np))//' for turbine #'//trim(num2lstr(nt))//' has passed the upper-most Y boundary of the low-resolution domain.' , errStat, errMsg, RoutineName)
if ( u%p_plane(3,np,nt) < p%Grid_Low(3, 1) ) call SetErrStat(ErrID_Warn, 'The center of wake plane #'//trim(num2lstr(np))//' for turbine #'//trim(num2lstr(nt))//' has passed the lowest-most Z boundary of the low-resolution domain.', errStat, errMsg, RoutineName)
if ( u%p_plane(3,np,nt) > p%Grid_Low(3,p%NumGrid_low) ) call SetErrStat(ErrID_Warn, 'The center of wake plane #'//trim(num2lstr(np))//' for turbine #'//trim(num2lstr(nt))//' has passed the upper-most Z boundary of the low-resolution domain.' , errStat, errMsg, RoutineName)


xplane_sq = u%xhat_plane(1,np,nt)**2.0_ReKi
yplane_sq = u%xhat_plane(2,np,nt)**2.0_ReKi
xysq_Z = (/0.0_ReKi, 0.0_ReKi, xplane_sq+yplane_sq/)
Expand Down Expand Up @@ -587,6 +579,14 @@ subroutine LowResGridCalcOutput(n, u, p, xd, y, m, errStat, errMsg)
wsum_tmp = 0.0_ReKi
n_r_polar = FLOOR((p%C_ScaleDiam*u%D_wake(np,nt))/p%dpol)

! if a wake plane exits domain, velocity is set differently, so skip remaining velocity logic after this
! - no messages if inside bounds, so put error handling inside if
call PlaneOutOfDomain(u%D_wake(np,nt),u%p_plane(:,np,nt),y%V_plane(:,np,nt),m%planeDomainExit(np,nt),ErrStat2,ErrMsg2)
if (m%planeDomainExit(np,nt) /= 0_IntKi) then
call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName)
cycle
endif

do nr = 0, n_r_polar

r_polar = REAL(nr,ReKi)*p%dpol
Expand Down Expand Up @@ -631,6 +631,103 @@ subroutine LowResGridCalcOutput(n, u, p, xd, y, m, errStat, errMsg)
if (allocated(wk_V)) deallocate(wk_V)
if (allocated(wk_WAT_k)) deallocate(wk_WAT_k)

contains

!> Check if the center of this wwake plane has left the domain.
!! If a plane exits the domain, or previously exited the domain:
!! - Set warning about first time this plane leaves.
!! - Set component perpendicular to plane exit direction to kick it outside the domain entirely
!! - Target distance outside boundary = D. Use a quadratic asymptotic distance per step to approach target distance.
!! - Add background flow in X or Y to keep the plane moving with others parallel to boundary it crossed (only using X and Y velocity)
!! NOTE: using m%planeDomainExit to track which boundary a plane crossed.
!! 0: Still in domain
!! +/-1: +/-X
!! +/-2: +/-Y
!! +/-3: +/-Z
!! To understand intent, consider 2 cases for mean velocity in +X direction:
!! plane exits +Y boundary:
!! 1. plane with get a kick towards one wake diameter outside +Y boundary
!! 2. overall farm velocity added to keep plane drifting in +X following the target Y location (some jitter due to farm level Y velocity term)
!! plane exits +X boundary (travels beyond domain end in direction of overall flow)
!! 1. plane will get a kick outside the end of the domain towards +X boundary plus wake diameter
!! 2. farm velocity added will keep trying to push this plane further downstream, but step 1. will try to force it back.
!! --> effectively 1. and 2. will constant be working against each other to hold the plane somewhere near the target location beyond +X boundary,
!! but this shouldn't really matter as the plane will get dropped at some point. Even if multiple planes end up there, it shouldn't affect
!! any planes still in bounds -- so we really don't care if it jitters around at all
subroutine PlaneOutOfDomain(D_Wake,p_plane,V_plane,planeDomainExit,ErrStat3,ErrMsg3)
real(ReKi), intent(in ) :: D_wake !< u%D_wake(np,nt)
real(ReKi), intent(in ) :: p_plane(3) !< u%p_plane(:,np,nt)
real(ReKi), intent(inout) :: V_plane(3) !< y%V_plane(:,np,nt)
integer(IntKi), intent(inout) :: planeDomainExit !< m%planeDomainExit(np,nt)
integer(IntKi), intent( out) :: ErrStat3 !< Error status of the operation
character(ErrMsgLen), intent( out) :: ErrMsg3 !< Error message if errStat /= ErrID_None
character(12) :: tmpStr12 !< for constructing error message
real(ReKi) :: D_tgt !< target distance outside bounds
! Step 1: did a plane that was in the low res domain just cross out?
! If plane crossed boundary, set message and tracking of it
if (planeDomainExit == 0_IntKi) then
if (p_plane(1) < p%Grid_Low(1,1) ) then ! lower x boundary
ErrStat3 = ErrID_Warn
tmpStr12 = 'lower-most X'
planeDomainExit = -1
elseif ( p_plane(1) > p%Grid_Low(1,p%NumGrid_low) ) then ! upper x boundary
ErrStat3 = ErrID_Warn
tmpStr12 = 'upper-most X'
planeDomainExit = 1
elseif ( p_plane(2) < p%Grid_Low(2,1) ) then ! lower y boundary
ErrStat3 = ErrID_Warn
tmpStr12 = 'lower-most Y'
planeDomainExit = -2
elseif ( p_plane(2) > p%Grid_Low(2,p%NumGrid_low) ) then ! upper y boundary
ErrStat3 = ErrID_Warn
tmpStr12 = 'upper-most Y'
planeDomainExit = 2
elseif ( p_plane(3) < p%Grid_Low(3,1) ) then ! lower z boundary
ErrStat3 = ErrID_Warn
tmpStr12 = 'lower-most Z'
planeDomainExit = -3
elseif ( p_plane(3) > p%Grid_Low(3,p%NumGrid_low) ) then ! upper z boundary
ErrStat3 = ErrID_Warn
tmpStr12 = 'upper-most Z'
planeDomainExit = 3
endif
if (errStat3 == ErrID_Warn) then
ErrMsg3 = 'The center of wake plane #'//trim(num2lstr(np))//' for turbine #'//trim(num2lstr(nt))//' has passed the ' &
//tmpStr12//' boundary of the low-resolution domain. Further warnings are suppressed.'
endif
endif

! Step 2: for planes outside boundary (including one that just crossed outside) set velocity component to approach target offset.
! asymptotically approach a distance D_wake away from the boundary (quadratic approach)
! example: V at -Y boundary:
! Vy = (Y_target - Y_pos) / (2 * DT)
select case (planeDomainExit)
case (0_IntKi)
return
case (-1_IntKi) ! Crossed -X
D_tgt = p%Grid_Low(1,1) - D_wake
V_plane(1) = (D_tgt - p_plane(1)) / (2.0_ReKi * real(p%dt_low,ReKi)) ! push towards (-X_bound - D_wake)
case ( 1_IntKi) ! Crossed +X
D_tgt = p%Grid_Low(1,p%NumGrid_low) + D_wake
V_plane(1) = (D_tgt - p_plane(1)) / (2.0_ReKi * real(p%dt_low,ReKi)) ! push towards (+X_bound + D_wake)
case (-2_IntKi) ! Crossed -Y
D_tgt = p%Grid_Low(2,1) - D_wake
V_plane(2) = (D_tgt - p_plane(2)) / (2.0_ReKi * real(p%dt_low,ReKi)) ! push towards (-Y_bound - D_wake)
case ( 2_IntKi) ! Crossed +Y
D_tgt = p%Grid_Low(2,p%NumGrid_low) + D_wake
V_plane(2) = (D_tgt - p_plane(2)) / (2.0_ReKi * real(p%dt_low,ReKi)) ! push towards (-Y_bound - D_wake)
case (-3_IntKi) ! Crossed -Z
D_tgt = p%Grid_Low(3,1) - D_wake
V_plane(3) = (D_tgt - p_plane(3)) / (2.0_ReKi * real(p%dt_low,ReKi)) ! push towards (-Z_bound - D_wake)
case ( 3_IntKi) ! Crossed +Z
D_tgt = p%Grid_Low(3,p%NumGrid_low) + D_wake
V_plane(3) = (D_tgt - p_plane(3)) / (2.0_ReKi * real(p%dt_low,ReKi)) ! push towards (+Z_bound + D_wake)
end select

! Step 3: add background XYZ flow to keep plane drifting (will have already returned on any planes still in bounds)
V_plane(1:3) = V_plane(1:3) + xd%Ufarm(1:3)

end subroutine PlaneOutOfDomain
end subroutine LowResGridCalcOutput

!----------------------------------------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -1117,6 +1214,11 @@ subroutine AWAE_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitO
call AllocAry(m%V_amb_low_disk,3,p%NumTurbines,'m%V_amb_low_disk', ErrStat2, ErrMsg2); if(Failed()) return;
m%V_amb_low_disk=0.0_ReKi ! IMPORTANT ALLOCATION. This misc var is not set before a low res calcoutput

! track if a plan has left the domain (all planes start in domain).
! Value indicates edge number (+/-1: +/-X, +/-2: +/-Y, +/-3: +/-Z) the plane crossed
allocate(m%planeDomainExit(0:p%NumPlanes-1,1:p%NumTurbines), STAT=ErrStat2); if (Failed0('m%planeDomainExit.')) return;
m%planeDomainExit = 0_IntKi

! Read-in the ambient wind data for the initial calculate output
call AWAE_UpdateStates( 0.0_DbKi, -1, u, p, x, xd, z, OtherState, m, errStat2, errMsg2 ); if(Failed()) return;

Expand Down
1 change: 1 addition & 0 deletions modules/awae/src/AWAE_Registry.txt
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ typedef ^ MiscVarType InflowWind_OutputType y_IfW_High - - - "InflowWin

#wake added turbulence
typedef ^ MiscVarType ReKi V_amb_low_disk {:}{:} - - "Rotor averaged ambiend wind speed for each wind turbine (3 x nWT)" m/s
typedef ^ MiscVarType IntKi planeDomainExit {:}{:} 0 - "Value indicates edge number (0: still in domain, +/-1: +/-X, +/-2: +/-Y, +/-3: +/-Z) the plane crossed" -


# ..... Parameters ................................................................................................................
Expand Down
18 changes: 18 additions & 0 deletions modules/awae/src/AWAE_Types.f90
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ MODULE AWAE_Types
TYPE(InflowWind_OutputType) :: y_IfW_Low !< InflowWind module outputs for the low-resolution grid [-]
TYPE(InflowWind_OutputType) :: y_IfW_High !< InflowWind module outputs for the high-resolution grid [-]
REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: V_amb_low_disk !< Rotor averaged ambiend wind speed for each wind turbine (3 x nWT) [m/s]
INTEGER(IntKi) , DIMENSION(:,:), ALLOCATABLE :: planeDomainExit !< Value indicates edge number (0: still in domain, +/-1: +/-X, +/-2: +/-Y, +/-3: +/-Z) the plane crossed [-]
END TYPE AWAE_MiscVarType
! =======================
! ========= AWAE_ParameterType =======
Expand Down Expand Up @@ -1625,6 +1626,18 @@ subroutine AWAE_CopyMisc(SrcMiscData, DstMiscData, CtrlCode, ErrStat, ErrMsg)
end if
DstMiscData%V_amb_low_disk = SrcMiscData%V_amb_low_disk
end if
if (allocated(SrcMiscData%planeDomainExit)) then
LB(1:2) = lbound(SrcMiscData%planeDomainExit)
UB(1:2) = ubound(SrcMiscData%planeDomainExit)
if (.not. allocated(DstMiscData%planeDomainExit)) then
allocate(DstMiscData%planeDomainExit(LB(1):UB(1),LB(2):UB(2)), stat=ErrStat2)
if (ErrStat2 /= 0) then
call SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%planeDomainExit.', ErrStat, ErrMsg, RoutineName)
return
end if
end if
DstMiscData%planeDomainExit = SrcMiscData%planeDomainExit
end if
end subroutine

subroutine AWAE_DestroyMisc(MiscData, ErrStat, ErrMsg)
Expand Down Expand Up @@ -1709,6 +1722,9 @@ subroutine AWAE_DestroyMisc(MiscData, ErrStat, ErrMsg)
if (allocated(MiscData%V_amb_low_disk)) then
deallocate(MiscData%V_amb_low_disk)
end if
if (allocated(MiscData%planeDomainExit)) then
deallocate(MiscData%planeDomainExit)
end if
end subroutine

subroutine AWAE_PackMisc(RF, Indata)
Expand Down Expand Up @@ -1755,6 +1771,7 @@ subroutine AWAE_PackMisc(RF, Indata)
call InflowWind_PackOutput(RF, InData%y_IfW_Low)
call InflowWind_PackOutput(RF, InData%y_IfW_High)
call RegPackAlloc(RF, InData%V_amb_low_disk)
call RegPackAlloc(RF, InData%planeDomainExit)
if (RegCheckErr(RF, RoutineName)) return
end subroutine

Expand Down Expand Up @@ -1812,6 +1829,7 @@ subroutine AWAE_UnPackMisc(RF, OutData)
call InflowWind_UnpackOutput(RF, OutData%y_IfW_Low) ! y_IfW_Low
call InflowWind_UnpackOutput(RF, OutData%y_IfW_High) ! y_IfW_High
call RegUnpackAlloc(RF, OutData%V_amb_low_disk); if (RegCheckErr(RF, RoutineName)) return
call RegUnpackAlloc(RF, OutData%planeDomainExit); if (RegCheckErr(RF, RoutineName)) return
end subroutine

subroutine AWAE_CopyParam(SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg)
Expand Down