Skip to content

Commit 2582627

Browse files
committed
Adds the matsuno-gill heating pattern as an idealized forcing namelist option.
It is enabled in standalone HOMME by using the namelist option `test_case = "matsuno_gill"`. This test case is described in, e.g., (this paper)[https://iopscience.iop.org/article/10.1016/j.fluiddyn.2004.03.003/pdf). Add the vertical coordinate files for the Matsuno-Gill heating test. The hybrid coefficients are analytically calculated to give constant ∆z between model levels for this test case, with a model top at 10km. Update CMakeLists.txt for theta-l_kokkos to include the new file for the matsuno gill heating profile.
1 parent bc491d0 commit 2582627

File tree

7 files changed

+336
-1
lines changed

7 files changed

+336
-1
lines changed

components/homme/src/preqx_kokkos/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ MACRO(PREQX_KOKKOS_SETUP)
127127
${TEST_SRC_DIR}/dcmip2016-terminator.F90
128128
${TEST_SRC_DIR}/dcmip2016-tropical-cyclone.F90
129129
${TEST_SRC_DIR}/held_suarez_mod.F90
130+
${TEST_SRC_DIR}/matsuno_gill_mod.F90
130131
${TEST_SRC_DIR}/dry_planar.F90
131132
${TEST_SRC_DIR}/moist_planar.F90
132133
${TEST_SRC_DIR}/mtests.F90

components/homme/src/share/namelist_mod.F90

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,7 @@ subroutine readnl(par)
555555
#ifdef _PRIM
556556
write(iulog,*) "reading physics namelist..."
557557
if (test_case == "held_suarez0" .or. &
558+
test_case == "matsuno_gill" .or. &
558559
test_case(1:10)== "baroclinic" .or. &
559560
test_case(1:13)== "jw_baroclinic" .or. &
560561
test_case(1:5) == "dcmip" .or. &

components/homme/src/test_mod.F90

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ module test_mod
2626
dcmip2016_test1_forcing, dcmip2016_test2_forcing, dcmip2016_test3_forcing, &
2727
dcmip2016_pg_init, dcmip2016_test1_pg, dcmip2016_test1_pg_forcing, dcmip2016_init
2828
use held_suarez_mod, only: hs0_init_state
29+
use matsuno_gill_mod, only: mg_init_state
2930

3031
use dry_planar_tests, only: planar_hydro_gravity_wave_init, planar_nonhydro_gravity_wave_init
3132
use dry_planar_tests, only: planar_hydro_mountain_wave_init, planar_nonhydro_mountain_wave_init, planar_schar_mountain_wave_init
@@ -84,6 +85,7 @@ subroutine set_test_initial_conditions(elem, deriv, hybrid, hvcoord, tl, nets, n
8485
case('mtest1'); test_with_forcing = .true. ;
8586
case('mtest2'); test_with_forcing = .true. ;
8687
case('mtest3'); test_with_forcing = .true. ;
88+
case('matsuno_gill'); test_with_forcing = .true. ;
8789
case('held_suarez0'); test_with_forcing = .true. ;
8890
case('jw_baroclinic');
8991
case('planar_hydro_gravity_wave');
@@ -139,6 +141,7 @@ subroutine set_test_initial_conditions(elem, deriv, hybrid, hvcoord, tl, nets, n
139141
case('mtest2'); call mtest_init (elem,hybrid,hvcoord,nets,nete,2)
140142
case('mtest3'); call mtest_init (elem,hybrid,hvcoord,nets,nete,3)
141143
case('held_suarez0'); call hs0_init_state (elem,hybrid,hvcoord,nets,nete,300.0_rl)
144+
case('matsuno_gill'); call mg_init_state (elem,hybrid,hvcoord,nets,nete)
142145
case('jw_baroclinic'); call jw_baroclinic (elem,hybrid,hvcoord,nets,nete)
143146
case('planar_hydro_gravity_wave'); call planar_hydro_gravity_wave_init(elem,hybrid,hvcoord,nets,nete)
144147
case('planar_nonhydro_gravity_wave'); call planar_nonhydro_gravity_wave_init(elem,hybrid,hvcoord,nets,nete)
@@ -160,7 +163,6 @@ subroutine set_test_initial_conditions(elem, deriv, hybrid, hvcoord, tl, nets, n
160163

161164
endselect
162165
! endif
163-
164166
if (midpoint_eta_dot_dpdn) then
165167
do ie = nets,nete
166168
elem(ie)%derived%eta_dot_dpdn = 0
@@ -211,6 +213,7 @@ subroutine compute_test_forcing(elem,hybrid,hvcoord,nt,ntQ,dt,nets,nete,tl)
211213

212214
use dcmip12_wrapper, only: dcmip2012_test2_x_forcing
213215
use held_suarez_mod, only: hs_forcing
216+
use matsuno_gill_mod, only: mg_forcing
214217
use control_mod, only: ftype
215218
implicit none
216219
type(element_t), intent(inout) :: elem(:) ! element array
@@ -261,6 +264,11 @@ subroutine compute_test_forcing(elem,hybrid,hvcoord,nt,ntQ,dt,nets,nete,tl)
261264
do ie=nets,nete
262265
call hs_forcing(elem(ie),hvcoord,nt,ntQ,dt)
263266
enddo
267+
case('matsuno_gill');
268+
do ie=nets,nete
269+
call mg_forcing(elem(ie),hvcoord,nt,ntQ,dt)
270+
enddo
271+
264272

265273
endselect
266274

Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
#ifdef HAVE_CONFIG_H
2+
#include "config.h"
3+
#endif
4+
5+
module matsuno_gill_mod
6+
7+
8+
use coordinate_systems_mod, only: spherical_polar_t
9+
use dimensions_mod, only: nlev,np,qsize,nlevp
10+
use element_mod, only: element_t
11+
use element_state, only: timelevels
12+
use element_ops, only: set_thermostate, get_temperature
13+
use hybrid_mod, only: hybrid_t
14+
use hybvcoord_mod, only: hvcoord_t
15+
use kinds, only: real_kind, iulog
16+
use physical_constants, only: p0, kappa,g, dd_pi, Rgas,Cp
17+
use physics_mod, only: prim_condense
18+
use time_mod, only: secpday
19+
#ifndef HOMME_WITHOUT_PIOLIBRARY
20+
use common_io_mod, only: infilenames
21+
#endif
22+
23+
implicit none
24+
private
25+
26+
real (kind=real_kind), public, parameter :: sigma_b = 0.70D0
27+
real (kind=real_kind), public, parameter :: k_Tv = 1.0D0/(40.0D0*secpday)
28+
real (kind=real_kind), public, parameter :: bv_sq = 1.0D-4
29+
real (kind=real_kind), public, parameter :: T0 = 300
30+
real (kind=real_kind), public, parameter :: q0 = 5d0 /secpday
31+
real (kind=real_kind), public, parameter :: dlam = 1.0D0 * 30D0 * dd_pi/180D0
32+
real (kind=real_kind), public, parameter :: dphi = 1.0D0 * 10D0 * dd_pi/180D0
33+
34+
public :: mg_v_forcing
35+
public :: mg_T_forcing
36+
public :: mg_init_state
37+
public :: mg_forcing
38+
39+
contains
40+
41+
subroutine mg_forcing(elemin,hvcoord,nm1,nm1_Q,dt)
42+
43+
type (element_t) :: elemin
44+
type (hvcoord_t) :: hvcoord
45+
integer :: nm1,nm1_Q ! timelevel to use
46+
real (kind=real_kind) :: dt
47+
48+
! local
49+
real (kind=real_kind) :: pmid,r0,r1,dtf_q,dp,rdp,FQ
50+
real (kind=real_kind), dimension(np,np) :: psfrc
51+
real (kind=real_kind) :: temperature(np,np,nlev)
52+
real (kind=real_kind) :: v(np,np,3,nlev)
53+
real (kind=real_kind) :: fv(np,np,3,nlev)
54+
integer :: i,j,k,q
55+
56+
dtf_q = dt
57+
call get_temperature(elemin,temperature,hvcoord,nm1)
58+
59+
do j=1,np
60+
do i=1,np
61+
psfrc(i,j) = (elemin%state%ps_v(i,j,nm1))
62+
end do
63+
end do
64+
65+
elemin%derived%FT(:,:,:) = elemin%derived%FT(:,:,:) + &
66+
mg_T_forcing(hvcoord,psfrc(1,1), &
67+
temperature,elemin%spherep,np, nlev)
68+
69+
v(:,:,1:2,:) = elemin%state%v(:,:,1:2,:,nm1)
70+
#if ( defined MODEL_THETA_L )
71+
v(:,:,3,:) = elemin%state%w_i(:,:,1:nlev,nm1) ! dont apply at surface
72+
#else
73+
v(:,:,3,:) = 0
74+
#endif
75+
76+
fv = mg_v_forcing(hvcoord,psfrc(1,1),v,np,nlev)
77+
78+
#if ( defined MODEL_THETA_L )
79+
elemin%derived%FM(:,:,1:3,:) = elemin%derived%FM(:,:,1:3,:) + fv(:,:,1:3,:)
80+
#else
81+
elemin%derived%FM(:,:,1:2,:) = elemin%derived%FM(:,:,1:2,:) + fv(:,:,1:2,:)
82+
#endif
83+
84+
if (qsize>=1) then
85+
! HS with tracer (Galewsky type forcing, with flux of 2.3e-5 kg/m^2/s
86+
! MASS in kg/m^2 = < Q dp_in_Pa / g >
87+
! flux in kg/m^2/s = < FQ dp_in_Pa / g >
88+
! We want < FQ dp_in_Pa / g > = 2.3e-5 so: FQ = 2.3e-5*g/dp_in_Pa
89+
90+
! lowest layer thickness, in Pa
91+
dp = ( hvcoord%hyai(nlev+1) - hvcoord%hyai(nlev) ) + &
92+
( hvcoord%hybi(nlev+1) - hvcoord%hybi(nlev) )*1000*100
93+
rdp = 1./ dp
94+
q=1
95+
do j=1,np
96+
do i=1,np
97+
FQ = rdp * g * 2.3E-5 * COS(elemin%spherep(i,j)%lat)**2
98+
elemin%derived%FQ(i,j,nlev,q) =elemin%derived%FQ(i,j,nlev,q)+FQ
99+
enddo
100+
enddo
101+
102+
do j=1,np
103+
do i=1,np
104+
do k=1,nlev
105+
pmid = hvcoord%hyam(k)*hvcoord%ps0 + hvcoord%hybm(k)*(elemin%state%ps_v(i,j,nm1))
106+
r0=elemin%state%Q(i,j,k,q)
107+
r1=r0
108+
call Prim_Condense(r1,temperature(i,j,k),pmid)
109+
elemin%derived%FQ(i,j,k,q) = elemin%derived%FQ(i,j,k,q) + &
110+
(r1-r0)/(dtf_q)
111+
enddo
112+
enddo
113+
enddo
114+
endif
115+
116+
end subroutine mg_forcing
117+
function z_given_p(p) result(z)
118+
real (kind=real_kind), intent(in) :: p
119+
real (kind=real_kind):: z
120+
z = (-g/bv_sq)*log( (T0/(g**2/(bv_sq*Cp)))*( (p/p0)**(Rgas/Cp) - 1.0 ) + 1.0 )
121+
!z = (-g/Nsq)*np.log( (T0/bigG)*( (p/p0)**(Rd/Cp) - 1.0 ) + 1.0 )
122+
end function
123+
function T_given_p(p) result(T)
124+
real (kind=real_kind), intent(in) :: p
125+
real (kind=real_kind) :: T
126+
T = T0 * (p/p0)**kappa * exp(bv_sq/g * z_given_p(p))
127+
end function
128+
129+
function mg_v_forcing(hvcoord,ps,v,npts,nlevels) result(mg_v_frc)
130+
131+
integer, intent(in) :: npts
132+
integer, intent(in) :: nlevels
133+
type (hvcoord_t), intent(in) :: hvcoord
134+
real (kind=real_kind), intent(in) :: ps(npts,npts)
135+
136+
real (kind=real_kind), intent(in) :: v(npts,npts,3,nlevels)
137+
real (kind=real_kind) :: mg_v_frc(npts,npts,3,nlevels)
138+
139+
! Local variables
140+
141+
integer i,j,k
142+
real (kind=real_kind) :: k_v
143+
real (kind=real_kind) :: p,etam
144+
145+
do k=1,nlevels
146+
do j=1,npts
147+
do i=1,npts
148+
p = hvcoord%hyam(k)*hvcoord%ps0 + hvcoord%hybm(k)*ps(i,j)
149+
mg_v_frc(i,j,1,k) = -k_Tv*v(i,j,1,k)
150+
mg_v_frc(i,j,2,k) = -k_Tv*v(i,j,2,k)
151+
152+
mg_v_frc(i,j,3,k) = -k_Tv*v(i,j,3,k)
153+
end do
154+
end do
155+
end do
156+
157+
end function mg_v_forcing
158+
159+
function mg_T_forcing(hvcoord,ps,T,sphere,npts,nlevels) result(mg_T_frc)
160+
161+
integer, intent(in) :: npts
162+
integer, intent(in) :: nlevels
163+
164+
type (hvcoord_t), intent(in) :: hvcoord
165+
real (kind=real_kind), intent(in) :: ps(npts,npts)
166+
real (kind=real_kind), intent(in) :: T(npts,npts,nlevels)
167+
type (spherical_polar_t), intent(in) :: sphere(npts,npts)
168+
169+
real (kind=real_kind) :: mg_T_frc(npts,npts,nlevels)
170+
171+
! Local variables
172+
173+
real (kind=real_kind) :: p,logprat,pratk,Teq,T_forcing
174+
real (kind=real_kind) :: logps0,etam
175+
real (kind=real_kind) :: lat,snlat
176+
177+
real (kind=real_kind) :: k_t(npts,npts)
178+
real (kind=real_kind) :: snlatsq(npts,npts)
179+
real (kind=real_kind) :: latlon_comp(npts,npts), z_top(npts,npts)
180+
real (kind=real_kind) :: cslatsq(npts,npts)
181+
182+
real (kind=real_kind) :: rec_one_minus_sigma_b
183+
184+
integer i,j,k
185+
186+
logps0 = LOG(hvcoord%ps0 )
187+
188+
do j=1,npts
189+
do i=1,npts
190+
snlat = SIN(sphere(i,j)%lat)
191+
if (abs(sphere(i,j)%lon-dd_pi/2) < dlam .and. abs(sphere(i,j)%lat) < dphi ) then
192+
latlon_comp(i,j) = cos((sphere(i,j)%lon-dd_pi/2)/(2 * dlam))**2 * cos(sphere(i,j)%lat/(2*dphi))**2
193+
else
194+
latlon_comp(i,j) = 0
195+
end if
196+
z_top(i,j) = z_given_p(hvcoord%hyai(1)*hvcoord%ps0 + hvcoord%hybi(1)*ps(i,j))
197+
end do
198+
end do
199+
200+
rec_one_minus_sigma_b = 1.0D0/(1.0D0 - sigma_b)
201+
202+
do k=1,nlevels
203+
do j=1,npts
204+
do i=1,npts
205+
p = hvcoord%hyam(k)*hvcoord%ps0 + hvcoord%hybm(k)*ps(i,j)
206+
207+
T_forcing = q0 * latlon_comp(i,j) * sin(dd_pi * z_given_p(p)/z_top(i,j))
208+
#if 0
209+
! ======================================
210+
! This is a smooth forcing
211+
! for debugging purposes only...
212+
! ======================================
213+
214+
#endif
215+
mg_T_frc(i,j,k)= -k_Tv*(T(i,j,k)-T_given_p(p)) + T_forcing
216+
end do
217+
end do
218+
end do
219+
220+
end function mg_T_forcing
221+
222+
subroutine mg_init_state(elem, hybrid, hvcoord,nets,nete)
223+
224+
type(element_t), intent(inout) :: elem(:)
225+
type(hybrid_t), intent(in) :: hybrid ! hybrid parallel structure
226+
type (hvcoord_t), intent(in) :: hvcoord
227+
integer, intent(in) :: nets
228+
integer, intent(in) :: nete
229+
230+
! Local variables
231+
232+
integer ie,i,j,k,q,tl
233+
integer :: nm1
234+
integer :: n0
235+
integer :: np1
236+
real (kind=real_kind) :: lat_mtn,lon_mtn,r_mtn,h_mtn,rsq,lat,lon,p_tmp
237+
real (kind=real_kind) :: temperature(np,np,nlev),p(np,np),exner(np,np),ps(np,np)
238+
239+
if (hybrid%masterthread) write(iulog,*) 'initializing Held-Suarez primitive equations test'
240+
241+
nm1= 1
242+
n0 = 2
243+
np1= 3
244+
245+
do ie=nets,nete
246+
247+
elem(ie)%state%ps_v(:,:,n0) =p0
248+
elem(ie)%state%ps_v(:,:,nm1)=p0
249+
elem(ie)%state%ps_v(:,:,np1)=p0
250+
251+
elem(ie)%state%v(:,:,:,:,n0) =0.0D0
252+
elem(ie)%state%v(:,:,:,:,nm1)=elem(ie)%state%v(:,:,:,:,n0)
253+
elem(ie)%state%v(:,:,:,:,np1)=elem(ie)%state%v(:,:,:,:,n0)
254+
255+
#ifdef MODEL_THETA_L
256+
elem(ie)%state%w_i = 0.0
257+
#endif
258+
259+
260+
! if topo file was given in the namelist, PHIS was initilized in prim_main
261+
! otherwise assume 0
262+
#ifndef HOMME_WITHOUT_PIOLIBRARY
263+
if (infilenames(1)=='') then
264+
elem(ie)%state%phis(:,:)=0.0D0
265+
endif
266+
#endif
267+
268+
do k=1,nlev
269+
p_tmp = hvcoord%hyam(k)*hvcoord%ps0 + hvcoord%hybm(k)*elem(ie)%state%ps_v(1,1,n0)
270+
temperature(1, 1, k) = T_given_p(p_tmp)
271+
end do
272+
do i=1,np
273+
do j=1,np
274+
temperature(i,j, :) = temperature(1,1, :)
275+
end do
276+
end do
277+
278+
279+
280+
281+
!if (qsize>=1) then
282+
!q=1
283+
!elem(ie)%state%Q(:,:,:,q) =0 ! moist HS tracer IC=0
284+
!do q=2,qsize
285+
! elem(ie)%state%Q(:,:,:,q) =temperature(:,:,:)/400
286+
!enddo
287+
!endif
288+
ps=elem(ie)%state%ps_v(:,:,n0)
289+
call set_thermostate(elem(ie),ps,temperature,hvcoord) ! sets z based on hydrostatic presumption
290+
end do
291+
292+
293+
end subroutine mg_init_state
294+
295+
296+
end module matsuno_gill_mod
297+

components/homme/src/theta-l_kokkos/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ MACRO(THETAL_KOKKOS_SETUP)
129129
${TEST_SRC_DIR}/dcmip2016-terminator.F90
130130
${TEST_SRC_DIR}/dcmip2016-tropical-cyclone.F90
131131
${TEST_SRC_DIR}/held_suarez_mod.F90
132+
${TEST_SRC_DIR}/matsuno_gill_mod.F90
132133
${TEST_SRC_DIR}/dry_planar.F90
133134
${TEST_SRC_DIR}/moist_planar.F90
134135
${TEST_SRC_DIR}/mtests.F90
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
21 !hyai
2+
0.27381905404907 0.26590539035976 0.25752394878279
3+
0.24865429808716 0.23927536347865 0.22936541085572 0.21890203071294
4+
0.20786212168493 0.19622187372385 0.18395675090318 0.17104147384052
5+
0.15745000173179 0.14315551398919 0.12813039147516 0.11234619732416
6+
0.095773657344247 0.078382639990006 0.060142135898353
7+
0.041020236978492 0.020984115047143 0
8+
21 ! hybi
9+
0 0.028901070149364 0.059510487036309 0.091902866472543
10+
0.1261551745929 0.16234678535331 0.20055953931639 0.24087780374962
11+
0.28338853406205 0.32818133660555 0.37534853286773 0.42498522508382
12+
0.4771893632956 0.53206181388604 0.58970642961892 0.65023012121324
13+
0.71374293048299 0.78035810507338 0.85019217482527 0.92336502980036 1

0 commit comments

Comments
 (0)