-
Notifications
You must be signed in to change notification settings - Fork 364
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
Update gw_convect #6749
base: master
Are you sure you want to change the base?
Update gw_convect #6749
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,10 +4,9 @@ module gw_convect | |
! This module handles gravity waves from convection, and was extracted from | ||
! gw_drag in May 2013. | ||
! | ||
|
||
use gw_utils, only: r8 | ||
|
||
use gw_common, only: pver, pgwv | ||
use cam_logfile, only: iulog | ||
use gw_utils, only: r8 | ||
use gw_common, only: pver, pgwv | ||
|
||
implicit none | ||
private | ||
|
@@ -21,8 +20,8 @@ module gw_convect | |
! Dimension for mean wind in heating. | ||
integer :: maxuh | ||
|
||
! Index for level at 700 mb. | ||
integer :: k700 | ||
! Index for level for storm/steering flow (usually 700 mb) | ||
integer :: k_src_wind | ||
|
||
! Table of source spectra. | ||
real(r8), allocatable :: mfcc(:,:,:) | ||
|
@@ -31,19 +30,20 @@ module gw_convect | |
|
||
!========================================================================== | ||
|
||
subroutine gw_convect_init(k700_in, mfcc_in, errstring) | ||
! Index at 700 mb. | ||
integer, intent(in) :: k700_in | ||
! Source spectra to keep as table. | ||
real(r8), intent(in) :: mfcc_in(:,:,:) | ||
! Report any errors from this routine. | ||
character(len=*), intent(out) :: errstring | ||
|
||
subroutine gw_convect_init( plev_src_wind, mfcc_in, errstring) | ||
use ref_pres, only: pref_edge | ||
real(r8), intent(in) :: plev_src_wind ! previously hardcoded to 70000._r8 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd add here in the comments that plev_src_wind should be in units Pa to match pref_edge. Maybe also want to mention that actual steering flow pressure level can differ from what the user requests wherever the reference pressure values differ from the actual pressure values (i.e. over mountainous terrain). |
||
real(r8), intent(in) :: mfcc_in(:,:,:) ! Source spectra to keep as table | ||
character(len=*), intent(out) :: errstring ! Report any errors from this routine | ||
integer :: ierr | ||
|
||
errstring = "" | ||
|
||
k700 = k700_in | ||
do k = 0, pver | ||
if ( pref_edge(k+1) < plev_src_wind ) k_src_wind = k+1 | ||
end do | ||
|
||
if (masterproc) write (iulog,*) 'gw_convect: steering flow level = ',k_src_wind | ||
|
||
! First dimension is maxh. | ||
maxh = size(mfcc_in,1) | ||
|
@@ -60,7 +60,9 @@ end subroutine gw_convect_init | |
|
||
subroutine gw_beres_src(ncol, ngwv, lat, u, v, netdt, & | ||
zm, src_level, tend_level, tau, ubm, ubi, xv, yv, c, & | ||
hdepth, maxq0, CF, hdepth_scaling_factor) | ||
hdepth, maxq0_out, maxq0_conversion_factor, hdepth_scaling_factor, & | ||
hdepth_min, storm_speed_min, & | ||
use_gw_convect_old) | ||
!----------------------------------------------------------------------- | ||
! Driver for multiple gravity wave drag parameterization. | ||
! | ||
|
@@ -90,11 +92,20 @@ subroutine gw_beres_src(ncol, ngwv, lat, u, v, netdt, & | |
real(r8), intent(in) :: zm(ncol,pver) | ||
|
||
! Heating conversion factor | ||
real(r8), intent(in) :: CF | ||
real(r8), intent(in) :: maxq0_conversion_factor | ||
|
||
! Scaling factor for the heating depth | ||
real(r8), intent(in) :: hdepth_scaling_factor | ||
|
||
! minimum hdepth for for spectrum lookup table | ||
real(r8), intent(in) :: hdepth_min | ||
|
||
! minimum convective storm speed | ||
real(r8), intent(in) :: storm_speed_min | ||
|
||
! switch for restoring legacy method | ||
logical, intent(in) :: use_gw_convect_old | ||
|
||
! Indices of top gravity wave source level and lowest level where wind | ||
! tendencies are allowed. | ||
integer, intent(out) :: src_level(ncol) | ||
|
@@ -110,19 +121,19 @@ subroutine gw_beres_src(ncol, ngwv, lat, u, v, netdt, & | |
real(r8), intent(out) :: c(ncol,-pgwv:pgwv) | ||
|
||
! Heating depth and maximum heating in each column. | ||
real(r8), intent(out) :: hdepth(ncol), maxq0(ncol) | ||
real(r8), intent(out) :: hdepth(ncol), maxq0_out(ncol) | ||
|
||
!---------------------------Local Storage------------------------------- | ||
! Column and level indices. | ||
integer :: i, k | ||
|
||
! Zonal/meridional wind at 700mb. | ||
real(r8) :: u700(ncol), v700(ncol) | ||
! Zonal/meridional source wind | ||
real(r8) :: u_src(ncol), v_src(ncol) | ||
! 3.14... | ||
real(r8), parameter :: pi = 4._r8*atan(1._r8) | ||
|
||
! Maximum heating rate. | ||
real(r8) :: q0(ncol) | ||
real(r8) :: maxq0(ncol) | ||
|
||
! Bottom/top heating range index. | ||
integer :: mini(ncol), maxi(ncol) | ||
|
@@ -135,36 +146,36 @@ subroutine gw_beres_src(ncol, ngwv, lat, u, v, netdt, & | |
! Source level tau for a column. | ||
real(r8) :: tau0(-PGWV:PGWV) | ||
! Speed of convective cells relative to storm. | ||
integer :: CS(ncol) | ||
integer :: storm_speed(ncol) | ||
! Index to shift spectra relative to ground. | ||
integer :: shift | ||
|
||
! Heating rate conversion factor. Change to take the value from caller and controllable by namelist (to tune QBO) | ||
! real(r8), parameter :: CF = 20._r8 | ||
! Averaging length. | ||
real(r8), parameter :: AL = 1.0e5_r8 | ||
! fixed parameters (we may want to expose these in the namelist for tuning) | ||
real(r8), parameter :: tau_avg_length = 1.0e5_r8 ! spectrum averaging length | ||
real(r8), parameter :: heating_altitude_max = 20e3 ! max altitude to check heating (probably don't need this) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add units to heating_altitude_max description. Also, 20000._r8? |
||
|
||
integer :: ndepth_pos | ||
integer :: ndepth_tot | ||
|
||
!---------------------------------------------------------------------- | ||
! Initialize tau array | ||
!---------------------------------------------------------------------- | ||
|
||
tau = 0.0_r8 | ||
tau = 0.0_r8 | ||
hdepth = 0.0_r8 | ||
q0 = 0.0_r8 | ||
tau0 = 0.0_r8 | ||
maxq0 = 0.0_r8 | ||
tau0 = 0.0_r8 | ||
|
||
!------------------------------------------------------------------------ | ||
! Determine 700 mb layer wind and unit vectors, then project winds. | ||
! Determine source layer wind and unit vectors, then project winds. | ||
!------------------------------------------------------------------------ | ||
|
||
! Just use the 700 mb interface values for the source wind speed and | ||
! direction (unit vector). | ||
|
||
u700 = u(:,k700) | ||
v700 = v(:,k700) | ||
! source wind speed and direction | ||
u_src = u(:,k_src_wind) | ||
v_src = v(:,k_src_wind) | ||
|
||
! Get the unit vector components and magnitude at the surface. | ||
call get_unit_vector(u700, v700, xv, yv, ubi(:,k700)) | ||
call get_unit_vector(u_src, v_src, xv, yv, ubi(:,k_src_wind)) | ||
|
||
! Project the local wind at midpoints onto the source wind. | ||
do k = 1, pver | ||
|
@@ -184,33 +195,62 @@ subroutine gw_beres_src(ncol, ngwv, lat, u, v, netdt, & | |
! which heating rate is continuously positive. | ||
!----------------------------------------------------------------------- | ||
|
||
! First find the indices for the top and bottom of the heating range. | ||
! Find indices for the top and bottom of the heating range. | ||
mini = 0 | ||
maxi = 0 | ||
do k = pver, 1, -1 | ||
do i = 1, ncol | ||
|
||
if (use_gw_convect_old) then | ||
!--------------------------------------------------------------------- | ||
! original version used in CAM4/5/6 and EAMv1/2/3 | ||
do k = pver, 1, -1 | ||
do i = 1, ncol | ||
if (mini(i) == 0) then | ||
! Detect if we are outside the maximum range (where z = 20 km). | ||
if (zm(i,k) >= 20000._r8) then | ||
mini(i) = k | ||
maxi(i) = k | ||
else | ||
! First spot where heating rate is positive. | ||
if (netdt(i,k) > 0.0_r8) mini(i) = k | ||
end if | ||
! Detect if we are outside the maximum range (where z = 20 km). | ||
if (zm(i,k) >= heating_altitude_max) then | ||
mini(i) = k | ||
maxi(i) = k | ||
else | ||
! First spot where heating rate is positive. | ||
if (netdt(i,k) > 0.0_r8) mini(i) = k | ||
end if | ||
else if (maxi(i) == 0) then | ||
! Detect if we are outside the maximum range (z = 20 km). | ||
if (zm(i,k) >= 20000._r8) then | ||
maxi(i) = k | ||
else | ||
! First spot where heating rate is no longer positive. | ||
if (.not. (netdt(i,k) > 0.0_r8)) maxi(i) = k | ||
end if | ||
! Detect if we are outside the maximum range (z = 20 km). | ||
if (zm(i,k) >= heating_altitude_max) then | ||
maxi(i) = k | ||
else | ||
! First spot where heating rate is no longer positive. | ||
if (.not. (netdt(i,k) > 0.0_r8)) maxi(i) = k | ||
end if | ||
end if | ||
end do | ||
! When all done, exit | ||
if (all(maxi /= 0)) exit | ||
end do | ||
end do | ||
! When all done, exit | ||
if (all(maxi /= 0)) exit | ||
end do | ||
!--------------------------------------------------------------------- | ||
else | ||
!--------------------------------------------------------------------- | ||
! cleaner version that addresses bug in original where heating max and | ||
! depth were too low whenever heating <=0 occurred in the middle of | ||
! the heating profile (ex. at the melting level) | ||
do i = 1, ncol | ||
do k = pver, 1, -1 | ||
if ( zm(i,k) < heating_altitude_max ) then | ||
if ( netdt(i,k) > 0.0_r8 ) then | ||
! Set mini as first spot where heating rate is positive | ||
if ( mini(i)==0 ) mini(i) = k | ||
! Set maxi to current level | ||
maxi(i) = k | ||
end if | ||
else | ||
! above the max check if indices were found | ||
if ( mini(i)==0 ) mini(i) = k | ||
if ( maxi(i)==0 ) maxi(i) = k | ||
end if | ||
end do | ||
end do | ||
!--------------------------------------------------------------------- | ||
end if | ||
|
||
|
||
! Heating depth in km. | ||
hdepth = [ ( (zm(i,maxi(i))-zm(i,mini(i)))/1000._r8, i = 1, ncol ) ] | ||
|
@@ -223,19 +263,19 @@ subroutine gw_beres_src(ncol, ngwv, lat, u, v, netdt, & | |
! Maximum heating rate. | ||
do k = minval(maxi), maxval(mini) | ||
where (k >= maxi .and. k <= mini) | ||
q0 = max(q0, netdt(:ncol,k)) | ||
maxq0 = max(maxq0, netdt(:ncol,k)) | ||
end where | ||
end do | ||
|
||
!output max heating rate in K/day | ||
maxq0 = q0*24._r8*3600._r8 | ||
maxq0_out = maxq0*24._r8*3600._r8 | ||
|
||
! Multipy by conversion factor | ||
q0 = q0 * CF | ||
maxq0 = maxq0 * maxq0_conversion_factor | ||
|
||
! Taking ubm at 700 mb to be the storm speed, find the cell speed where | ||
! the storm speed is > 10 m/s. | ||
CS = int(sign(max(abs(ubm(:,k700))-10._r8, 0._r8), ubm(:,k700))) | ||
! Taking ubm at assumed source level to be the storm speed, | ||
! find the cell speed where the storm speed is > storm_speed_min | ||
storm_speed = int(sign(max(abs(ubm(:,k_src_wind))-storm_speed_min, 0._r8), ubm(:,k_src_wind))) | ||
|
||
uh = 0._r8 | ||
do k = minval(maxi), maxval(mini) | ||
|
@@ -244,7 +284,7 @@ subroutine gw_beres_src(ncol, ngwv, lat, u, v, netdt, & | |
end where | ||
end do | ||
|
||
uh = uh - real(CS, r8) | ||
uh = uh - real(storm_speed, r8) | ||
|
||
! Limit uh to table range. | ||
uh = min(uh, real(maxuh, r8)) | ||
|
@@ -270,8 +310,19 @@ subroutine gw_beres_src(ncol, ngwv, lat, u, v, netdt, & | |
!--------------------------------------------------------------------- | ||
! Look up spectrum only if depth >= 2.5 km, else set tau0 = 0. | ||
!--------------------------------------------------------------------- | ||
|
||
if ((hdepth(i) >= 2.5_r8) .and. (abs(lat(i)) < (pi/2._r8))) then | ||
if ((hdepth(i) >= hdepth_min)) then | ||
ndepth_pos = 0 | ||
ndepth_tot = 0 | ||
do k = 1,pver | ||
if ( k>=maxi(i).and.k<=mini(i) ) then | ||
ndepth_tot = ndepth_tot + 1 | ||
if ( netdt(i,k)>0 ) ndepth_pos = ndepth_pos + 1 | ||
end if | ||
end do | ||
! write (iulog,*) 'WHDEBUG - i: ',i,' Hd: ',hdepth(i),' Hn: ',ndepth_pos,' N: ',ndepth_tot | ||
end if | ||
|
||
if ((hdepth(i) >= hdepth_min) .and. (abs(lat(i)) < (pi/2._r8))) then | ||
|
||
!------------------------------------------------------------------ | ||
! Look up the spectrum using depth and uh. | ||
|
@@ -280,11 +331,11 @@ subroutine gw_beres_src(ncol, ngwv, lat, u, v, netdt, & | |
tau0 = mfcc(NINT(hdepth(i)),NINT(uh(i)),:) | ||
|
||
! Shift spectrum so that it is relative to the ground. | ||
shift = -nint(real(CS(i), r8)/dc) | ||
shift = -nint(storm_speed(i)/dc) | ||
tau0 = cshift(tau0,shift) | ||
|
||
! Adjust magnitude. | ||
tau0 = tau0*q0(i)*q0(i)/AL | ||
tau0 = tau0*maxq0(i)*maxq0(i)/tau_avg_length | ||
|
||
! Adjust for critical level filtering. | ||
Umini = max(nint(Umin(i)/dc),-PGWV) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add units: km (presumably)