miniWeather_openacc.f90 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  1. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  2. !! miniWeather
  3. !! Author: Matt Norman <normanmr@ornl.gov> , Oak Ridge National Laboratory
  4. !! This code simulates dry, stratified, compressible, non-hydrostatic fluid flows
  5. !! For documentation, please see the attached documentation in the "documentation" folder
  6. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  7. program miniweather
  8. use nvtx
  9. !implicit none
  10. !Declare the precision for the real constants (at least 15 digits of accuracy = double precision)
  11. integer , parameter :: rp = selected_real_kind(15)
  12. !Define some physical constants to use throughout the simulation
  13. real(rp), parameter :: pi = 3.14159265358979323846264338327_rp !Pi
  14. real(rp), parameter :: grav = 9.8_rp !Gravitational acceleration (m / s^2)
  15. real(rp), parameter :: cp = 1004._rp !Specific heat of dry air at constant pressure
  16. real(rp), parameter :: rd = 287._rp !Dry air constant for equation of state (P=rho*rd*T)
  17. real(rp), parameter :: p0 = 1.e5_rp !Standard pressure at the surface in Pascals
  18. real(rp), parameter :: C0 = 27.5629410929725921310572974482_rp !Constant to translate potential temperature into pressure (P=C0*(rho*theta)**gamma)
  19. real(rp), parameter :: gamma = 1.40027894002789400278940027894_rp !gamma=cp/Rd
  20. !Define domain and stability-related constants
  21. real(rp), parameter :: xlen = 2.e4_rp !Length of the domain in the x-direction (meters)
  22. real(rp), parameter :: zlen = 1.e4_rp !Length of the domain in the z-direction (meters)
  23. real(rp), parameter :: hv_beta = 0.25_rp !How strong to diffuse the solution: hv_beta \in [0:1]
  24. real(rp), parameter :: cfl = 1.50_rp !"Courant, Friedrichs, Lewy" number (for numerical stability)
  25. real(rp), parameter :: max_speed = 450 !Assumed maximum wave speed during the simulation (speed of sound + speed of wind) (meter / sec)
  26. integer , parameter :: hs = 2 !"Halo" size: number of cells needed for a full "stencil" of information for reconstruction
  27. integer , parameter :: sten_size = 4 !Size of the stencil used for interpolation
  28. !Parameters for indexing and flags
  29. integer , parameter :: NUM_VARS = 4 !Number of fluid state variables
  30. integer , parameter :: ID_DENS = 1 !index for density ("rho")
  31. integer , parameter :: ID_UMOM = 2 !index for momentum in the x-direction ("rho * u")
  32. integer , parameter :: ID_WMOM = 3 !index for momentum in the z-direction ("rho * w")
  33. integer , parameter :: ID_RHOT = 4 !index for density * potential temperature ("rho * theta")
  34. integer , parameter :: DIR_X = 1 !Integer constant to express that this operation is in the x-direction
  35. integer , parameter :: DIR_Z = 2 !Integer constant to express that this operation is in the z-direction
  36. !Gauss-Legendre quadrature points and weights on the domain [0:1]
  37. integer , parameter :: nqpoints = 3
  38. real(rp) :: qpoints (nqpoints) = (/ 0.112701665379258311482073460022E0_rp , 0.500000000000000000000000000000E0_rp , 0.887298334620741688517926539980E0_rp /)
  39. real(rp) :: qweights(nqpoints) = (/ 0.277777777777777777777777777779E0_rp , 0.444444444444444444444444444444E0_rp , 0.277777777777777777777777777779E0_rp /)
  40. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  41. !! Variables that are initialized but remain static over the course of the simulation
  42. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  43. real(rp) :: sim_time !total simulation time in seconds
  44. real(rp) :: output_freq !frequency to perform output in seconds
  45. real(rp) :: dt !Model time step (seconds)
  46. integer :: nx, nz !Number of local grid cells in the x- and z- dimensions
  47. real(rp) :: dx, dz !Grid space length in x- and z-dimension (meters)
  48. integer :: nx_glob, nz_glob !Number of total grid cells in the x- and z- dimensions
  49. integer :: i_beg, k_beg !beginning index in the x- and z-directions
  50. integer :: nranks, myrank !my rank id
  51. integer :: left_rank, right_rank
  52. real(rp), allocatable :: hy_dens_cell (:) !hydrostatic density (vert cell avgs). Dimensions: (1-hs:nz+hs)
  53. real(rp), allocatable :: hy_dens_theta_cell(:) !hydrostatic rho*t (vert cell avgs). Dimensions: (1-hs:nz+hs)
  54. real(rp), allocatable :: hy_dens_int (:) !hydrostatic density (vert cell interf). Dimensions: (1:nz+1)
  55. real(rp), allocatable :: hy_dens_theta_int (:) !hydrostatic rho*t (vert cell interf). Dimensions: (1:nz+1)
  56. real(rp), allocatable :: hy_pressure_int (:) !hydrostatic press (vert cell interf). Dimensions: (1:nz+1)
  57. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  58. !! Variables that are dynamics over the course of the simulation
  59. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  60. real(rp) :: etime !Elapsed model time
  61. real(rp) :: output_counter !Helps determine when it's time to do output
  62. !Runtime variable arrays
  63. real(rp), allocatable :: state (:,:,:) !Fluid state. Dimensions: (1-hs:nx+hs,1-hs:nz+hs,NUM_VARS)
  64. real(rp), allocatable :: state_tmp (:,:,:) !Fluid state. Dimensions: (1-hs:nx+hs,1-hs:nz+hs,NUM_VARS)
  65. real(rp), allocatable :: flux (:,:,:) !Cell interface fluxes. Dimensions: (nx+1,nz+1,NUM_VARS)
  66. real(rp), allocatable :: tend (:,:,:) !Fluid state tendencies. Dimensions: (nx,nz,NUM_VARS)
  67. integer(8) :: t1, t2, rate !For CPU Timings
  68. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  69. !! THE MAIN PROGRAM STARTS HERE
  70. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  71. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  72. !! BEGIN USER-CONFIGURABLE PARAMETERS
  73. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  74. !The x-direction length is twice as long as the z-direction length
  75. !So, you'll want to have nx_glob be twice as large as nz_glob
  76. nx_glob = 40 !Number of total cells in the x-dirction
  77. nz_glob = 20 !Number of total cells in the z-dirction
  78. sim_time = 10 !How many seconds to run the simulation
  79. output_freq = 100 !How frequently to output data to file (in seconds)
  80. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  81. !! END USER-CONFIGURABLE PARAMETERS
  82. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  83. !Allocate arrays, initialize the grid and the data
  84. call nvtxStartRange("Total")
  85. call init()
  86. !$acc data copyin(state_tmp,hy_dens_cell,hy_dens_theta_cell,hy_dens_int,hy_dens_theta_int,hy_pressure_int) create(flux,tend) copy(state)
  87. !Output the initial state
  88. !call output(state,etime)
  89. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  90. !! MAIN TIME STEP LOOP
  91. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  92. call system_clock(t1)
  93. call nvtxStartRange("while")
  94. do while (etime < sim_time)
  95. !If the time step leads to exceeding the simulation time, shorten it for the last step
  96. if (etime + dt > sim_time) dt = sim_time - etime
  97. !Perform a single time step
  98. call nvtxStartRange("perform_timestep")
  99. call perform_timestep(state,state_tmp,flux,tend,dt)
  100. call nvtxEndRange
  101. !Inform the user
  102. write(*,*) 'Elapsed Time: ', etime , ' / ' , sim_time
  103. !Update the elapsed time and output counter
  104. etime = etime + dt
  105. output_counter = output_counter + dt
  106. !If it's time for output, reset the counter, and do output
  107. if (output_counter >= output_freq) then
  108. output_counter = output_counter - output_freq
  109. !call output(state,etime)
  110. endif
  111. enddo
  112. call nvtxEndRange
  113. call system_clock(t2,rate)
  114. write(*,*) "CPU Time: ",dble(t2-t1)/dble(rate)
  115. !$acc end data
  116. !Deallocate
  117. call finalize()
  118. call nvtxEndRange
  119. contains
  120. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  121. !! HELPER SUBROUTINES AND FUNCTIONS GO HERE
  122. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  123. !Performs a single dimensionally split time step using a simple low-storate three-stage Runge-Kutta time integrator
  124. !The dimensional splitting is a second-order-accurate alternating Strang splitting in which the
  125. !order of directions is alternated each time step.
  126. !The Runge-Kutta method used here is defined as follows:
  127. ! q* = q[n] + dt/3 * rhs(q[n])
  128. ! q** = q[n] + dt/2 * rhs(q* )
  129. ! q[n+1] = q[n] + dt/1 * rhs(q** )
  130. subroutine perform_timestep(state,state_tmp,flux,tend,dt)
  131. implicit none
  132. real(rp), intent(inout) :: state (1-hs:nx+hs,1-hs:nz+hs,NUM_VARS)
  133. real(rp), intent( out) :: state_tmp(1-hs:nx+hs,1-hs:nz+hs,NUM_VARS)
  134. real(rp), intent( out) :: flux (nx+1,nz+1,NUM_VARS)
  135. real(rp), intent( out) :: tend (nx,nz,NUM_VARS)
  136. real(rp), intent(in ) :: dt
  137. logical, save :: direction_switch = .true.
  138. if (direction_switch) then
  139. !x-direction first
  140. call semi_discrete_step( state , state , state_tmp , dt / 3 , DIR_X , flux , tend )
  141. call semi_discrete_step( state , state_tmp , state_tmp , dt / 2 , DIR_X , flux , tend )
  142. call semi_discrete_step( state , state_tmp , state , dt / 1 , DIR_X , flux , tend )
  143. !z-direction second
  144. call semi_discrete_step( state , state , state_tmp , dt / 3 , DIR_Z , flux , tend )
  145. call semi_discrete_step( state , state_tmp , state_tmp , dt / 2 , DIR_Z , flux , tend )
  146. call semi_discrete_step( state , state_tmp , state , dt / 1 , DIR_Z , flux , tend )
  147. else
  148. !z-direction second
  149. call semi_discrete_step( state , state , state_tmp , dt / 3 , DIR_Z , flux , tend )
  150. call semi_discrete_step( state , state_tmp , state_tmp , dt / 2 , DIR_Z , flux , tend )
  151. call semi_discrete_step( state , state_tmp , state , dt / 1 , DIR_Z , flux , tend )
  152. !x-direction first
  153. call semi_discrete_step( state , state , state_tmp , dt / 3 , DIR_X , flux , tend )
  154. call semi_discrete_step( state , state_tmp , state_tmp , dt / 2 , DIR_X , flux , tend )
  155. call semi_discrete_step( state , state_tmp , state , dt / 1 , DIR_X , flux , tend )
  156. endif
  157. direction_switch = .not. direction_switch
  158. end subroutine perform_timestep
  159. !Perform a single semi-discretized step in time with the form:
  160. !state_out = state_init + dt * rhs(state_forcing)
  161. !Meaning the step starts from state_init, computes the rhs using state_forcing, and stores the result in state_out
  162. subroutine semi_discrete_step( state_init , state_forcing , state_out , dt , dir , flux , tend )
  163. implicit none
  164. real(rp), intent(in ) :: state_init (1-hs:nx+hs,1-hs:nz+hs,NUM_VARS)
  165. real(rp), intent(inout) :: state_forcing(1-hs:nx+hs,1-hs:nz+hs,NUM_VARS)
  166. real(rp), intent( out) :: state_out (1-hs:nx+hs,1-hs:nz+hs,NUM_VARS)
  167. real(rp), intent( out) :: flux (nx+1,nz+1,NUM_VARS)
  168. real(rp), intent( out) :: tend (nx,nz,NUM_VARS)
  169. real(rp), intent(in ) :: dt
  170. integer , intent(in ) :: dir
  171. integer :: i,k,ll
  172. if (dir == DIR_X) then
  173. !Set the halo values in the x-direction
  174. call set_halo_values_x(state_forcing)
  175. !Compute the time tendencies for the fluid state in the x-direction
  176. call compute_tendencies_x(state_forcing,flux,tend)
  177. elseif (dir == DIR_Z) then
  178. !Set the halo values in the z-direction
  179. call set_halo_values_z(state_forcing)
  180. !Compute the time tendencies for the fluid state in the z-direction
  181. call compute_tendencies_z(state_forcing,flux,tend)
  182. endif
  183. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  184. !! TODO: THREAD ME
  185. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  186. !Apply the tendencies to the fluid state
  187. !$acc parallel loop collapse(3)
  188. do ll = 1 , NUM_VARS
  189. do k = 1 , nz
  190. do i = 1 , nx
  191. state_out(i,k,ll) = state_init(i,k,ll) + dt * tend(i,k,ll)
  192. enddo
  193. enddo
  194. enddo
  195. end subroutine semi_discrete_step
  196. !Compute the time tendencies of the fluid state using forcing in the x-direction
  197. !First, compute the flux vector at each cell interface in the x-direction (including hyperviscosity)
  198. !Then, compute the tendencies using those fluxes
  199. subroutine compute_tendencies_x(state,flux,tend)
  200. implicit none
  201. real(rp), intent(in ) :: state(1-hs:nx+hs,1-hs:nz+hs,NUM_VARS)
  202. real(rp), intent( out) :: flux (nx+1,nz+1,NUM_VARS)
  203. real(rp), intent( out) :: tend (nx,nz,NUM_VARS)
  204. integer :: i,k,ll,s
  205. real(rp) :: r,u,w,t,p, stencil(4), d3_vals(NUM_VARS), vals(NUM_VARS), hv_coef
  206. !Compute the hyperviscosity coeficient
  207. hv_coef = -hv_beta * dx / (16*dt)
  208. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  209. !! TODO: THREAD ME
  210. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  211. !Compute fluxes in the x-direction for each cell
  212. !$acc parallel loop
  213. do k = 1 , nz
  214. !$acc loop private(stencil,vals,d3_vals)
  215. do i = 1 , nx+1
  216. !Use fourth-order interpolation from four cell averages to compute the value at the interface in question
  217. do ll = 1 , NUM_VARS
  218. do s = 1 , sten_size
  219. stencil(s) = state(i-hs-1+s,k,ll)
  220. enddo
  221. !Fourth-order-accurate interpolation of the state
  222. vals(ll) = -stencil(1)/12 + 7*stencil(2)/12 + 7*stencil(3)/12 - stencil(4)/12
  223. !First-order-accurate interpolation of the third spatial derivative of the state (for artificial viscosity)
  224. d3_vals(ll) = -stencil(1) + 3*stencil(2) - 3*stencil(3) + stencil(4)
  225. enddo
  226. !Compute density, u-wind, w-wind, potential temperature, and pressure (r,u,w,t,p respectively)
  227. r = vals(ID_DENS) + hy_dens_cell(k)
  228. u = vals(ID_UMOM) / r
  229. w = vals(ID_WMOM) / r
  230. t = ( vals(ID_RHOT) + hy_dens_theta_cell(k) ) / r
  231. p = C0*(r*t)**gamma
  232. !Compute the flux vector
  233. flux(i,k,ID_DENS) = r*u - hv_coef*d3_vals(ID_DENS)
  234. flux(i,k,ID_UMOM) = r*u*u+p - hv_coef*d3_vals(ID_UMOM)
  235. flux(i,k,ID_WMOM) = r*u*w - hv_coef*d3_vals(ID_WMOM)
  236. flux(i,k,ID_RHOT) = r*u*t - hv_coef*d3_vals(ID_RHOT)
  237. enddo
  238. enddo
  239. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  240. !! TODO: THREAD ME
  241. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  242. !Use the fluxes to compute tendencies for each cell
  243. !$acc parallel loop collapse(3)
  244. do ll = 1 , NUM_VARS
  245. do k = 1 , nz
  246. do i = 1 , nx
  247. tend(i,k,ll) = -( flux(i+1,k,ll) - flux(i,k,ll) ) / dx
  248. enddo
  249. enddo
  250. enddo
  251. end subroutine compute_tendencies_x
  252. !Compute the time tendencies of the fluid state using forcing in the z-direction
  253. !First, compute the flux vector at each cell interface in the z-direction (including hyperviscosity)
  254. !Then, compute the tendencies using those fluxes
  255. subroutine compute_tendencies_z(state,flux,tend)
  256. implicit none
  257. real(rp), intent(in ) :: state(1-hs:nx+hs,1-hs:nz+hs,NUM_VARS)
  258. real(rp), intent( out) :: flux (nx+1,nz+1,NUM_VARS)
  259. real(rp), intent( out) :: tend (nx,nz,NUM_VARS)
  260. integer :: i,k,ll,s
  261. real(rp) :: r,u,w,t,p, stencil(4), d3_vals(NUM_VARS), vals(NUM_VARS), hv_coef
  262. !Compute the hyperviscosity coeficient
  263. hv_coef = -hv_beta * dz / (16*dt)
  264. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  265. !! TODO: THREAD ME
  266. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  267. !Compute fluxes in the x-direction for each cell
  268. !$acc parallel loop
  269. do k = 1 , nz+1
  270. !$acc loop private(stencil,vals,d3_vals)
  271. do i = 1 , nx
  272. !Use fourth-order interpolation from four cell averages to compute the value at the interface in question
  273. do ll = 1 , NUM_VARS
  274. do s = 1 , sten_size
  275. stencil(s) = state(i,k-hs-1+s,ll)
  276. enddo
  277. !Fourth-order-accurate interpolation of the state
  278. vals(ll) = -stencil(1)/12 + 7*stencil(2)/12 + 7*stencil(3)/12 - stencil(4)/12
  279. !First-order-accurate interpolation of the third spatial derivative of the state
  280. d3_vals(ll) = -stencil(1) + 3*stencil(2) - 3*stencil(3) + stencil(4)
  281. enddo
  282. !Compute density, u-wind, w-wind, potential temperature, and pressure (r,u,w,t,p respectively)
  283. r = vals(ID_DENS) + hy_dens_int(k)
  284. u = vals(ID_UMOM) / r
  285. w = vals(ID_WMOM) / r
  286. t = ( vals(ID_RHOT) + hy_dens_theta_int(k) ) / r
  287. p = C0*(r*t)**gamma - hy_pressure_int(k)
  288. !Enforce vertical boundary condition and exact mass conservation
  289. if (k == 1 .or. k == nz+1) then
  290. w = 0
  291. d3_vals(ID_DENS) = 0
  292. endif
  293. !Compute the flux vector with hyperviscosity
  294. flux(i,k,ID_DENS) = r*w - hv_coef*d3_vals(ID_DENS)
  295. flux(i,k,ID_UMOM) = r*w*u - hv_coef*d3_vals(ID_UMOM)
  296. flux(i,k,ID_WMOM) = r*w*w+p - hv_coef*d3_vals(ID_WMOM)
  297. flux(i,k,ID_RHOT) = r*w*t - hv_coef*d3_vals(ID_RHOT)
  298. enddo
  299. enddo
  300. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  301. !! TODO: THREAD ME
  302. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  303. !Use the fluxes to compute tendencies for each cell
  304. !$acc parallel loop collapse(3)
  305. do ll = 1 , NUM_VARS
  306. do k = 1 , nz
  307. do i = 1 , nx
  308. tend(i,k,ll) = -( flux(i,k+1,ll) - flux(i,k,ll) ) / dz
  309. if (ll == ID_WMOM) then
  310. tend(i,k,ID_WMOM) = tend(i,k,ID_WMOM) - state(i,k,ID_DENS)*grav
  311. endif
  312. enddo
  313. enddo
  314. enddo
  315. end subroutine compute_tendencies_z
  316. !Set halo values in the x-direction.
  317. subroutine set_halo_values_x(state)
  318. implicit none
  319. real(rp), intent(inout) :: state(1-hs:nx+hs,1-hs:nz+hs,NUM_VARS)
  320. integer :: k, ll
  321. real(rp) :: z
  322. !$acc parallel loop collapse(2)
  323. do ll = 1 , NUM_VARS
  324. do k = 1 , nz
  325. state(-1 ,k,ll) = state(nx-1,k,ll)
  326. state(0 ,k,ll) = state(nx ,k,ll)
  327. state(nx+1,k,ll) = state(1 ,k,ll)
  328. state(nx+2,k,ll) = state(2 ,k,ll)
  329. enddo
  330. enddo
  331. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  332. if (myrank == 0) then
  333. !$acc parallel loop
  334. do k = 1 , nz
  335. z = (k_beg-1 + k-0.5_rp)*dz
  336. if (abs(z-3*zlen/4) <= zlen/16) then
  337. state(-1:0,k,ID_UMOM) = (state(-1:0,k,ID_DENS)+hy_dens_cell(k)) * 50._rp
  338. state(-1:0,k,ID_RHOT) = (state(-1:0,k,ID_DENS)+hy_dens_cell(k)) * 298._rp - hy_dens_theta_cell(k)
  339. endif
  340. enddo
  341. endif
  342. end subroutine set_halo_values_x
  343. !Set halo values in the z-direction.
  344. !decomposition in the vertical direction
  345. subroutine set_halo_values_z(state)
  346. implicit none
  347. real(rp), intent(inout) :: state(1-hs:nx+hs,1-hs:nz+hs,NUM_VARS)
  348. integer :: i, ll
  349. real(rp), parameter :: mnt_width = xlen/8
  350. real(rp) :: x, xloc, mnt_deriv
  351. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  352. !! TODO: THREAD ME
  353. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  354. !$acc parallel loop collapse(2) private(xloc,mnt_deriv,x)
  355. do ll = 1 , NUM_VARS
  356. do i = 1-hs,nx+hs
  357. if (ll == ID_WMOM) then
  358. state(i,-1 ,ll) = 0
  359. state(i,0 ,ll) = 0
  360. state(i,nz+1,ll) = 0
  361. state(i,nz+2,ll) = 0
  362. else
  363. state(i,-1 ,ll) = state(i,1 ,ll)
  364. state(i,0 ,ll) = state(i,1 ,ll)
  365. state(i,nz+1,ll) = state(i,nz,ll)
  366. state(i,nz+2,ll) = state(i,nz,ll)
  367. endif
  368. enddo
  369. enddo
  370. end subroutine set_halo_values_z
  371. !Initialize some grid settings, allocate data, and initialize the full grid and data
  372. subroutine init()
  373. implicit none
  374. integer :: i, k, ii, kk, ll, ierr
  375. real(rp) :: x, z, r, u, w, t, hr, ht
  376. !Set the cell grid size
  377. dx = xlen / nx_glob
  378. dz = zlen / nz_glob
  379. nranks = 1
  380. myrank = 0
  381. i_beg = 1
  382. nx = nx_glob
  383. left_rank = 0
  384. right_rank = 0
  385. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  386. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  387. !! YOU DON'T NEED TO ALTER ANYTHING BELOW THIS POINT IN THE CODE
  388. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  389. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  390. k_beg = 1
  391. nz = nz_glob
  392. !Allocate the model data
  393. allocate(state (1-hs:nx+hs,1-hs:nz+hs,NUM_VARS))
  394. allocate(state_tmp (1-hs:nx+hs,1-hs:nz+hs,NUM_VARS))
  395. allocate(flux (nx+1,nz+1,NUM_VARS))
  396. allocate(tend (nx,nz,NUM_VARS))
  397. allocate(hy_dens_cell (1-hs:nz+hs))
  398. allocate(hy_dens_theta_cell(1-hs:nz+hs))
  399. allocate(hy_dens_int (nz+1))
  400. allocate(hy_dens_theta_int (nz+1))
  401. allocate(hy_pressure_int (nz+1))
  402. !Define the maximum stable time step based on an assumed maximum wind speed
  403. dt = min(dx,dz) / max_speed * cfl
  404. !Set initial elapsed model time and output_counter to zero
  405. etime = 0
  406. output_counter = 0
  407. !Display some grid information
  408. write(*,*) 'nx_glob, nz_glob:', nx_glob, nz_glob
  409. write(*,*) 'dx,dz: ',dx,dz
  410. write(*,*) 'dt: ',dt
  411. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  412. !! Initialize the cell-averaged fluid state via Gauss-Legendre quadrature
  413. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  414. state = 0
  415. do k = 1-hs , nz+hs
  416. do i = 1-hs , nx+hs
  417. !Initialize the state to zero
  418. !Use Gauss-Legendre quadrature to initialize a hydrostatic balance + temperature perturbation
  419. do kk = 1 , nqpoints
  420. do ii = 1 , nqpoints
  421. !Compute the x,z location within the global domain based on cell and quadrature index
  422. x = (i_beg-1 + i-0.5_rp) * dx + (qpoints(ii)-0.5_rp)*dx
  423. z = (k_beg-1 + k-0.5_rp) * dz + (qpoints(kk)-0.5_rp)*dz
  424. !Set the fluid state based on the user's specification
  425. call injection (x,z,r,u,w,t,hr,ht)
  426. !Store into the fluid state array
  427. state(i,k,ID_DENS) = state(i,k,ID_DENS) + r * qweights(ii)*qweights(kk)
  428. state(i,k,ID_UMOM) = state(i,k,ID_UMOM) + (r+hr)*u * qweights(ii)*qweights(kk)
  429. state(i,k,ID_WMOM) = state(i,k,ID_WMOM) + (r+hr)*w * qweights(ii)*qweights(kk)
  430. state(i,k,ID_RHOT) = state(i,k,ID_RHOT) + ( (r+hr)*(t+ht) - hr*ht ) * qweights(ii)*qweights(kk)
  431. enddo
  432. enddo
  433. do ll = 1 , NUM_VARS
  434. state_tmp(i,k,ll) = state(i,k,ll)
  435. enddo
  436. enddo
  437. enddo
  438. !Compute the hydrostatic background state over vertical cell averages
  439. hy_dens_cell = 0
  440. hy_dens_theta_cell = 0
  441. do k = 1-hs , nz+hs
  442. do kk = 1 , nqpoints
  443. z = (k_beg-1 + k-0.5_rp) * dz + (qpoints(kk)-0.5_rp)*dz
  444. !Set the fluid state based on the user's specification
  445. call injection (0._rp,z,r,u,w,t,hr,ht)
  446. hy_dens_cell(k) = hy_dens_cell(k) + hr * qweights(kk)
  447. hy_dens_theta_cell(k) = hy_dens_theta_cell(k) + hr*ht * qweights(kk)
  448. enddo
  449. enddo
  450. !Compute the hydrostatic background state at vertical cell interfaces
  451. do k = 1 , nz+1
  452. z = (k_beg-1 + k-1) * dz
  453. call injection (0._rp,z,r,u,w,t,hr,ht)
  454. hy_dens_int (k) = hr
  455. hy_dens_theta_int(k) = hr*ht
  456. hy_pressure_int (k) = C0*(hr*ht)**gamma
  457. enddo
  458. end subroutine init
  459. !This test case is initially balanced but injects fast, cold air from the left boundary near the model top
  460. subroutine injection(x,z,r,u,w,t,hr,ht)
  461. implicit none
  462. real(rp), intent(in ) :: x, z !x- and z- location of the point being sampled
  463. real(rp), intent( out) :: r, u, w, t !Density, uwind, wwind, and potential temperature
  464. real(rp), intent( out) :: hr, ht !Hydrostatic density and potential temperature
  465. call hydro_const_theta(z,hr,ht)
  466. r = 0
  467. t = 0
  468. u = 0
  469. w = 0
  470. end subroutine injection
  471. !Establish hydrstatic balance using constant potential temperature (thermally neutral atmosphere)
  472. subroutine hydro_const_theta(z,r,t)
  473. implicit none
  474. real(rp), intent(in ) :: z !x- and z- location of the point being sampled
  475. real(rp), intent( out) :: r, t !Density and potential temperature at this point
  476. real(rp), parameter :: theta0 = 300._rp !Background potential temperature
  477. real(rp), parameter :: exner0 = 1._rp !Surface-level Exner pressure
  478. real(rp) :: p,exner,rt
  479. !Establish hydrostatic balance first using Exner pressure
  480. t = theta0 !Potential Temperature at z
  481. exner = exner0 - grav * z / (cp * theta0) !Exner pressure at z
  482. p = p0 * exner**(cp/rd) !Pressure at z
  483. rt = (p / c0)**(1._rp / gamma) !rho*theta at z
  484. r = rt / t !Density at z
  485. end subroutine hydro_const_theta
  486. !Deallocate and call Finalize
  487. subroutine finalize()
  488. implicit none
  489. integer :: ierr
  490. deallocate(state )
  491. deallocate(state_tmp )
  492. deallocate(flux )
  493. deallocate(tend )
  494. deallocate(hy_dens_cell )
  495. deallocate(hy_dens_theta_cell)
  496. deallocate(hy_dens_int )
  497. deallocate(hy_dens_theta_int )
  498. deallocate(hy_pressure_int )
  499. end subroutine finalize
  500. end program miniweather