!WRF:MODEL_LAYER:PHYSICS
MODULE module_wind_fitch 2
! Represents kinetic energy extracted by wind turbines and turbulence
! (TKE) they produce at model levels within the rotor area. The thrust and
! power coefficient curves included to calculate momentum sink and source of TKE are
! generic and an approximation to a real turbine. These coefficients should be
! obtained from the turbine manufacturer for the turbines of interest and incorporated
! into the code in subroutine dragcof (we could not include real curves since they
! are proprietary).
!
! References:
! Fitch, A. C. et al. 2012: Local and Mesoscale Impacts of Wind Farms as Parameterized in a
! Mesoscale NWP Model. Monthly Weather Review, doi:10.1175/MWR-D-11-00352.1
! Fitch, A. C. et al. 2012: Mesoscale Influences of Wind Farms Throughout a Diurnal Cycle.
! Monthly Weather Review, submitted.
!
! Output:
! du, dv: horizontal velocity tendencies
! qke: TKE
! Input:
! u, v: horizontal velocities
! dz = dz between full levels (m)
! !not yet: z_at_w = height above sea level at layer interfaces (m)
! !not yet: ht = terrain height
! phb = geopotential height
! %hubheight = hub height (m)
! %diameter = turbine diameter (m)
! %stdthrcoef = standing thrust coeff. (thrust coeff of turbine when not operating)
! %power = turbine power (MW)
! %cutinspeed = cut-in speed (m/s)
! %cutoutspeed = cut-out speed (m/s)
! ewfx = x-extent of rectangular wind farm in grid cells
! ewfy = y-extent of rectangular wind farm in grid cells
! pwfx = x-coord of grid cell in SW corner of farm
! pwfy = y-coord of grid cell in SW corner of farm
! turbpercell = no. of turbines per grid cell
USE module_wind_generic
USE module_driver_constants
, ONLY : max_domains
USE module_model_constants
, ONLY : piconst
USE module_model_constants
, ONLY : g
IMPLICIT NONE
LOGICAL, DIMENSION(max_domains) :: inited
PUBLIC turbine_drag
PRIVATE dragcof, turbine_area, inited
CONTAINS
SUBROUTINE turbine_drag( & 1
& id &
&,phb,u,v,xlat_u,xlong_u &
&,xlat_v,xlong_v &
&,dx,dz,dt,qke &
&,qke_adv,bl_mynn_tkeadvect &
&,du,dv &
&,ids,ide,jds,jde,kds,kde &
&,ims,ime,jms,jme,kms,kme &
&,its,ite,jts,jte,kts,kte &
&)
INTEGER, INTENT(IN) :: id ! grid id
INTEGER, INTENT(IN) :: its,ite,jts,jte,kts,kte
INTEGER, INTENT(IN) :: ims,ime,jms,jme,kms,kme
INTEGER, INTENT(IN) :: ids,ide,jds,jde,kds,kde
LOGICAL, INTENT(IN) :: bl_mynn_tkeadvect
REAL, INTENT(IN) :: dx,dt
REAL, DIMENSION(ims:ime,kms:kme,jms:jme), INTENT(IN) :: dz,u,v,phb
REAL, DIMENSION(ims:ime,jms:jme), INTENT(IN) :: xlat_u, xlong_u
REAL, DIMENSION(ims:ime,jms:jme), INTENT(IN) :: xlat_v, xlong_v
REAL, DIMENSION(ims:ime,kms:kme,jms:jme), INTENT(INOUT) :: du,dv,qke,qke_adv
! Local
TYPE(windturbine_specs), POINTER :: p
INTEGER turbgridid
REAL hubheight,diameter,power,cutinspeed,cutoutspeed,stdthrcoef,turbpercell
INTEGER ewfx,ewfy,pwfx,pwfy
REAL blade_l_point,blade_u_point,zheightl,zheightu,z1,z2,tarea
REAL speed,tkecof,powcof,thrcof,wfdensity
INTEGER itf,jtf,ktf
INTEGER i,j,k,swfindx,ewfindx,swfindy,ewfindy,n,n1,n2,iturbine
INTEGER k_turbine_bot, k_turbine_top
LOGICAL :: kfound
INTEGER :: allzero
itf=MIN0(ite,ide-1)
jtf=MIN0(jte,jde-1)
ktf=MIN0(kte,kde-1)
!QKE should already == QKE_ADV coming out of PBL scheme
!ACF copy qke_adv into qke if using advection
! IF (BL_MYNN_TKEADVECT) THEN
! qke=qke_adv
! ENDIF
!ACF-end
CALL nl_get_td_turbpercell(1,turbpercell)
CALL nl_get_td_turbgridid(1,turbgridid)
IF ( .NOT. inited(id) ) THEN
IF ( windspec .EQ. WIND_TURBINES_FROMLIST ) THEN
! first check and see if xlat and xlong are all zero, if so, then use i,j directly
! (just check the u variables)
allzero=1
DO j=jts,jtf
DO i=its,itf
IF (xlat_u(i,j).NE.0. .OR. xlong_u(i,j).NE.0.)allzero=0
ENDDO
ENDDO
CALL wrf_dm_bcast_integer
(allzero,1)
IF ( allzero .NE. 1 ) THEN
! if there are actual lats and lons available, find i and j based on lat and lon
! otherwise, it is an idealized case and the user has specified i and j in the
! turbines file read in by read_windturbines_in in module_wind_generic
DO iturbine = 1,nwindturbines ! nwindturbines defined in module_wind_generic
p => windturbines(iturbine)
IF ( id .EQ. p%id ) THEN
DO j=jts,jtf
DO i=its,itf
IF (xlat_v(i,j) .LE. p%lat .AND. p%lat .LT. xlat_v(i,j+1) .AND. &
xlong_u(i,j).LE. p%lon .AND. p%lon .LT. xlong_u(i+1,j)) THEN
p%i=i
p%j=j
ENDIF
ENDDO
ENDDO
ENDIF
ENDDO
ENDIF
ELSE IF ( windspec .EQ. WIND_TURBINES_IDEAL .AND. id .EQ. turbgridid ) THEN
CALL nl_get_td_ewfx(1,ewfx)
CALL nl_get_td_ewfy(1,ewfy)
CALL nl_get_td_pwfx(1,pwfx)
CALL nl_get_td_pwfy(1,pwfy)
CALL nl_get_td_hubheight(1,hubheight)
CALL nl_get_td_diameter(1,diameter)
CALL nl_get_td_power(1,power)
CALL nl_get_td_cutinspeed(1,cutinspeed)
CALL nl_get_td_cutoutspeed(1,cutoutspeed)
CALL nl_get_td_stdthrcoef(1,stdthrcoef)
! count the turbines
n = 0
DO j = jts,jtf
IF ( pwfy .LE. j .AND. j .LE. (pwfy+ewfy-1) ) THEN
DO i = its,itf
IF ( pwfx .LE. i .AND. i .LE. (pwfx+ewfx-1) ) THEN
n = n + 1
ENDIF
ENDDO
ENDIF
ENDDO
nwindturbines = n
ALLOCATE(windturbines(nwindturbines))
! set the turbines
n = 0
DO j = jts,jtf
IF ( pwfy .LE. j .AND. j .LE. (pwfy+ewfy-1) ) THEN
DO i = its,itf
IF ( pwfx .LE. i .AND. i .LE. (pwfx+ewfx-1) ) THEN
n = n + 1
IF ( n .GT. nwindturbines ) THEN
CALL wrf_error_fatal
('would overrun windturbines array')
ENDIF
windturbines(n)%id = id
windturbines(n)%lat = 0.0
windturbines(n)%lon = 0.0
windturbines(n)%i = i
windturbines(n)%j = j
windturbines(n)%hubheight = hubheight
windturbines(n)%diameter = diameter
windturbines(n)%stdthrcoef = stdthrcoef
windturbines(n)%power = power
windturbines(n)%cutinspeed = cutinspeed
windturbines(n)%cutoutspeed = cutoutspeed
ENDIF
ENDDO
ENDIF
ENDDO
ENDIF
inited(id) = .TRUE.
ENDIF
IF ( windspec .EQ. WIND_TURBINES_FROMLIST ) THEN
wfdensity = 1.0/(dx*dx) ! per turbine, so numerator is 1
ELSE
wfdensity = turbpercell/(dx*dx)
ENDIF
IF (inited(id) .AND. &
((windspec .EQ. WIND_TURBINES_FROMLIST) .OR. &
(windspec .EQ. WIND_TURBINES_IDEAL .AND. id .EQ. turbgridid ))) THEN
DO iturbine = 1,nwindturbines ! nwindturbines defined in module_wind_generic
p => windturbines(iturbine)
IF ( id .EQ. p%id ) THEN
! vertical layers cut by turbine blades
k_turbine_bot=0 !bottom level
k_turbine_top=-1 !top level
i = p%i
j = p%j
IF (( its .LE. i .AND. i .LE. itf ) .AND. &
( jts .LE. j .AND. j .LE. jtf ) ) THEN
blade_l_point=p%hubheight-p%diameter/2. ! height of lower blade tip above ground (m)
blade_u_point=p%hubheight+p%diameter/2. ! height of upper blade tip above ground (m)
kfound = .false.
zheightl=0.0
! find vertical levels cut by turbine blades
DO k=kts,ktf
IF(.NOT. kfound) THEN
zheightu = zheightl + dz(i,k,j) ! increment height
IF(blade_l_point .GE. zheightl .AND. blade_l_point .LE. zheightu) THEN
k_turbine_bot=k ! lower blade tip cuts this level
ENDIF
IF(blade_u_point .GE. zheightl .AND. blade_u_point .LE. zheightu) THEN
k_turbine_top=k ! upper blade tip cuts this level
kfound = .TRUE.
ENDIF
zheightl = zheightu
ENDIF
ENDDO
IF ( kfound ) THEN
DO k=k_turbine_bot,k_turbine_top ! loop over turbine blade levels
z1=phb(i,k,j)/g-blade_l_point-phb(i,1,j)/g ! distance between k level and lower blade tip
z2=phb(i,k+1,j)/g-blade_l_point-phb(i,1,j)/g ! distance between k+1 level and lower blade tip
IF(z1 .LT. 0.) z1=0.0 ! k level lower than lower blade tip
IF(z2 .GT. p%diameter) z2=p%diameter ! k+1 level higher than turbine upper blade tip
! horizontal wind speed
speed=sqrt(u(i,k,j)**2.+v(i,k,j)**2.)
! calculate TKE, power and thrust coeffs
CALL dragcof
(tkecof,powcof,thrcof, &
speed,p%cutinspeed,p%cutoutspeed, &
p%power,p%diameter,p%stdthrcoef)
CALL turbine_area
(z1,z2,p%diameter,wfdensity,tarea)
! output TKE
qke(i,k,j) = qke(i,k,j)+speed**3.*tarea*tkecof*dt/dz(i,k,j)
! output u tendency
du(i,k,j) = du(i,k,j)-.5*u(i,k,j)*thrcof*speed*tarea/dz(i,k,j)
! output v tendency
dv(i,k,j) = dv(i,k,j)-.5*v(i,k,j)*thrcof*speed*tarea/dz(i,k,j)
ENDDO
ENDIF
ENDIF
ENDIF
ENDDO
ENDIF
!ACF copy qke into qke_adv if using advection
IF (BL_MYNN_TKEADVECT) THEN
qke_adv=qke
ENDIF
!ACF-end
END SUBROUTINE turbine_drag
! calculates area of turbine between two vertical levels
! Input variables :
! z1 = distance between k level and lower blade tip
! z2 = distance between k+1 level and lower blade tip
! wfdensity = wind farm density in m^-2
! tdiameter = turbine diameter
! Output variable :
! tarea = area of turbine between two levels * wfdensity
SUBROUTINE turbine_area(z1,z2,tdiameter,wfdensity,tarea) 1
REAL, INTENT(IN) ::tdiameter,wfdensity
REAL, INTENT(INOUT) ::z1,z2
REAL, INTENT(OUT):: tarea
REAL r,zc1,zc2
r=tdiameter/2. !r = turbine radius
z1=r-z1 !distance of kth level from turbine center
z2=r-z2 !distance of k+1 th level from turbine center
zc1=abs(z1)
zc2=abs(z2)
!turbine area between z1 and z2
IF(z1 .GT. 0. .AND. z2 .GT. 0.) THEN
tarea=zc1*sqrt(r*r-zc1*zc1)+r*r*asin(zc1/r)- &
(zc2*sqrt(r*r-zc2*zc2)+r*r*asin(zc2/r))
ELSE IF(z1 .LT. 0. .AND. z2 .LT. 0.) THEN
tarea=zc2*sqrt(r*r-zc2*zc2)+r*r*asin(zc2/r)- &
(zc1*sqrt(r*r-zc1*zc1)+r*r*asin(zc1/r))
ELSE
tarea=zc2*sqrt(r*r-zc2*zc2)+r*r*asin(zc2/r)+ &
zc1*sqrt(r*r-zc1*zc1)+r*r*asin(zc1/r)
ENDIF
tarea=tarea*wfdensity !turbine area * wind farm density
END SUBROUTINE turbine_area
! Caculates tke, power and thrust coefficients as function of horiz wind speed
! from fit to turbine power curve - needs to be changed for particular turbine used
! tkecof = tke coefficient
! powcof = power coefficient
! thrcof = thrust coefficient
! cispeed = cut-in speed in m/s
! cospeed = cut-out speed in m/s
! tpower = turbine power in MW
! speed = horiz wind speed in m/s
! tdiameter = turbine diameter in m
! stdthrcoef = standing thrust coefficient
SUBROUTINE dragcof(tkecof,powcof,thrcof,speed,cispeed,cospeed, & 1
tpower,tdiameter,stdthrcoef)
! DISCLAIMER: The following power curve, power coefficients, and thrust
! coefficients are meant for testing purposes only, and were formulated as
! an approximation to a real curve. The user is strongly encouraged to
! incorporate their own curves for the particular turbine of interest
! to them.
REAL, INTENT(IN):: speed, cispeed, cospeed, tpower,tdiameter,stdthrcoef
REAL, INTENT(OUT):: tkecof,powcof,thrcof
REAL :: power,area,mspeed,hspeed
area=piconst/4.*tdiameter**2. ! area swept by turbine blades
! GENERIC POWER CURVE - USE AT YOUR OWN RISK
mspeed=0.5*(cospeed+cispeed) !average of cispeed & cospeed
hspeed=0.5*(cospeed-mspeed) !this regulates the transition to full power
power =tpower*(.5*tanh((speed - (mspeed-hspeed))/(hspeed*0.60)) + .5)*.8
! GENERIC power coefficient calculation - USE AT YOUR OWN RISK
IF(speed .LE. cispeed .OR. speed .GE. cospeed) THEN
power=0.
powcof=0.
ELSE
powcof = power * 2.e+6 / (speed**3.*area)
IF (speed .LT. cispeed*2.) THEN ! dampen artificial max near cispeed
powcof = powcof * exp(-((speed-cispeed*2.)**2./(cispeed*2.)))
end if
powcof = MIN(powcof,.55)
ENDIF
! GENERIC Thrust coefficient calculation - USE AT YOUR OWN RISK
IF (speed .LE. cispeed .OR. speed .GE. cospeed) THEN
thrcof = stdthrcoef
ELSE
!thrcof= stdthrcoef+2.3/speed**.8
thrcof = powcof + powcof*0.75
thrcof = MIN(thrcof,.9)
thrcof = MAX(thrcof,stdthrcoef)
ENDIF
! tke coefficient calculation
tkecof=thrcof-powcof
IF(tkecof .LT. 0.) tkecof=0.
END SUBROUTINE dragcof
SUBROUTINE init_module_wind_fitch 1
inited = .FALSE.
END SUBROUTINE init_module_wind_fitch
END MODULE module_wind_fitch