miniWeather_openacc.f90 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  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 = 1000 !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. !$acc wait
  114. call system_clock(t2,rate)
  115. write(*,*) "CPU Time: ",dble(t2-t1)/dble(rate)
  116. !$acc end data
  117. !Deallocate
  118. call finalize()
  119. call nvtxEndRange
  120. contains
  121. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  122. !! HELPER SUBROUTINES AND FUNCTIONS GO HERE
  123. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  124. !Performs a single dimensionally split time step using a simple low-storate three-stage Runge-Kutta time integrator
  125. !The dimensional splitting is a second-order-accurate alternating Strang splitting in which the
  126. !order of directions is alternated each time step.
  127. !The Runge-Kutta method used here is defined as follows:
  128. ! q* = q[n] + dt/3 * rhs(q[n])
  129. ! q** = q[n] + dt/2 * rhs(q* )
  130. ! q[n+1] = q[n] + dt/1 * rhs(q** )
  131. subroutine perform_timestep(state,state_tmp,flux,tend,dt)
  132. implicit none
  133. real(rp), intent(inout) :: state (1-hs:nx+hs,1-hs:nz+hs,NUM_VARS)
  134. real(rp), intent( out) :: state_tmp(1-hs:nx+hs,1-hs:nz+hs,NUM_VARS)
  135. real(rp), intent( out) :: flux (nx+1,nz+1,NUM_VARS)
  136. real(rp), intent( out) :: tend (nx,nz,NUM_VARS)
  137. real(rp), intent(in ) :: dt
  138. logical, save :: direction_switch = .true.
  139. if (direction_switch) then
  140. !x-direction first
  141. call semi_discrete_step( state , state , state_tmp , dt / 3 , DIR_X , flux , tend )
  142. call semi_discrete_step( state , state_tmp , state_tmp , dt / 2 , DIR_X , flux , tend )
  143. call semi_discrete_step( state , state_tmp , state , dt / 1 , DIR_X , flux , tend )
  144. !z-direction second
  145. call semi_discrete_step( state , state , state_tmp , dt / 3 , DIR_Z , flux , tend )
  146. call semi_discrete_step( state , state_tmp , state_tmp , dt / 2 , DIR_Z , flux , tend )
  147. call semi_discrete_step( state , state_tmp , state , dt / 1 , DIR_Z , flux , tend )
  148. else
  149. !z-direction second
  150. call semi_discrete_step( state , state , state_tmp , dt / 3 , DIR_Z , flux , tend )
  151. call semi_discrete_step( state , state_tmp , state_tmp , dt / 2 , DIR_Z , flux , tend )
  152. call semi_discrete_step( state , state_tmp , state , dt / 1 , DIR_Z , flux , tend )
  153. !x-direction first
  154. call semi_discrete_step( state , state , state_tmp , dt / 3 , DIR_X , flux , tend )
  155. call semi_discrete_step( state , state_tmp , state_tmp , dt / 2 , DIR_X , flux , tend )
  156. call semi_discrete_step( state , state_tmp , state , dt / 1 , DIR_X , flux , tend )
  157. endif
  158. direction_switch = .not. direction_switch
  159. end subroutine perform_timestep
  160. !Perform a single semi-discretized step in time with the form:
  161. !state_out = state_init + dt * rhs(state_forcing)
  162. !Meaning the step starts from state_init, computes the rhs using state_forcing, and stores the result in state_out
  163. subroutine semi_discrete_step( state_init , state_forcing , state_out , dt , dir , flux , tend )
  164. implicit none
  165. real(rp), intent(in ) :: state_init (1-hs:nx+hs,1-hs:nz+hs,NUM_VARS)
  166. real(rp), intent(inout) :: state_forcing(1-hs:nx+hs,1-hs:nz+hs,NUM_VARS)
  167. real(rp), intent( out) :: state_out (1-hs:nx+hs,1-hs:nz+hs,NUM_VARS)
  168. real(rp), intent( out) :: flux (nx+1,nz+1,NUM_VARS)
  169. real(rp), intent( out) :: tend (nx,nz,NUM_VARS)
  170. real(rp), intent(in ) :: dt
  171. integer , intent(in ) :: dir
  172. integer :: i,k,ll
  173. if (dir == DIR_X) then
  174. !Set the halo values in the x-direction
  175. call set_halo_values_x(state_forcing)
  176. !Compute the time tendencies for the fluid state in the x-direction
  177. call compute_tendencies_x(state_forcing,flux,tend)
  178. elseif (dir == DIR_Z) then
  179. !Set the halo values in the z-direction
  180. call set_halo_values_z(state_forcing)
  181. !Compute the time tendencies for the fluid state in the z-direction
  182. call compute_tendencies_z(state_forcing,flux,tend)
  183. endif
  184. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  185. !! TODO: THREAD ME
  186. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  187. !Apply the tendencies to the fluid state
  188. !$acc parallel loop collapse(3)
  189. do ll = 1 , NUM_VARS
  190. do k = 1 , nz
  191. do i = 1 , nx
  192. state_out(i,k,ll) = state_init(i,k,ll) + dt * tend(i,k,ll)
  193. enddo
  194. enddo
  195. enddo
  196. end subroutine semi_discrete_step
  197. !Compute the time tendencies of the fluid state using forcing in the x-direction
  198. !First, compute the flux vector at each cell interface in the x-direction (including hyperviscosity)
  199. !Then, compute the tendencies using those fluxes
  200. subroutine compute_tendencies_x(state,flux,tend)
  201. implicit none
  202. real(rp), intent(in ) :: state(1-hs:nx+hs,1-hs:nz+hs,NUM_VARS)
  203. real(rp), intent( out) :: flux (nx+1,nz+1,NUM_VARS)
  204. real(rp), intent( out) :: tend (nx,nz,NUM_VARS)
  205. integer :: i,k,ll,s
  206. real(rp) :: r,u,w,t,p, stencil(4), d3_vals(NUM_VARS), vals(NUM_VARS), hv_coef
  207. !Compute the hyperviscosity coeficient
  208. hv_coef = -hv_beta * dx / (16*dt)
  209. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  210. !! TODO: THREAD ME
  211. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  212. !Compute fluxes in the x-direction for each cell
  213. !$acc parallel loop gang
  214. do k = 1 , nz
  215. !$acc loop vector private(stencil,vals,d3_vals)
  216. do i = 1 , nx+1
  217. !Use fourth-order interpolation from four cell averages to compute the value at the interface in question
  218. do ll = 1 , NUM_VARS
  219. do s = 1 , sten_size
  220. stencil(s) = state(i-hs-1+s,k,ll)
  221. enddo
  222. !Fourth-order-accurate interpolation of the state
  223. vals(ll) = -stencil(1)/12 + 7*stencil(2)/12 + 7*stencil(3)/12 - stencil(4)/12
  224. !First-order-accurate interpolation of the third spatial derivative of the state (for artificial viscosity)
  225. d3_vals(ll) = -stencil(1) + 3*stencil(2) - 3*stencil(3) + stencil(4)
  226. enddo
  227. !Compute density, u-wind, w-wind, potential temperature, and pressure (r,u,w,t,p respectively)
  228. r = vals(ID_DENS) + hy_dens_cell(k)
  229. u = vals(ID_UMOM) / r
  230. w = vals(ID_WMOM) / r
  231. t = ( vals(ID_RHOT) + hy_dens_theta_cell(k) ) / r
  232. p = C0*(r*t)**gamma
  233. !Compute the flux vector
  234. flux(i,k,ID_DENS) = r*u - hv_coef*d3_vals(ID_DENS)
  235. flux(i,k,ID_UMOM) = r*u*u+p - hv_coef*d3_vals(ID_UMOM)
  236. flux(i,k,ID_WMOM) = r*u*w - hv_coef*d3_vals(ID_WMOM)
  237. flux(i,k,ID_RHOT) = r*u*t - hv_coef*d3_vals(ID_RHOT)
  238. enddo
  239. enddo
  240. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  241. !! TODO: THREAD ME
  242. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  243. !Use the fluxes to compute tendencies for each cell
  244. !$acc parallel loop collapse(3)
  245. do ll = 1 , NUM_VARS
  246. do k = 1 , nz
  247. do i = 1 , nx
  248. tend(i,k,ll) = -( flux(i+1,k,ll) - flux(i,k,ll) ) / dx
  249. enddo
  250. enddo
  251. enddo
  252. end subroutine compute_tendencies_x
  253. !Compute the time tendencies of the fluid state using forcing in the z-direction
  254. !First, compute the flux vector at each cell interface in the z-direction (including hyperviscosity)
  255. !Then, compute the tendencies using those fluxes
  256. subroutine compute_tendencies_z(state,flux,tend)
  257. implicit none
  258. real(rp), intent(in ) :: state(1-hs:nx+hs,1-hs:nz+hs,NUM_VARS)
  259. real(rp), intent( out) :: flux (nx+1,nz+1,NUM_VARS)
  260. real(rp), intent( out) :: tend (nx,nz,NUM_VARS)
  261. integer :: i,k,ll,s
  262. real(rp) :: r,u,w,t,p, stencil(4), d3_vals(NUM_VARS), vals(NUM_VARS), hv_coef
  263. !Compute the hyperviscosity coeficient
  264. hv_coef = -hv_beta * dz / (16*dt)
  265. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  266. !! TODO: THREAD ME
  267. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  268. !Compute fluxes in the x-direction for each cell
  269. !$acc parallel loop gang
  270. do k = 1 , nz+1
  271. !$acc loop vector private(stencil,vals,d3_vals)
  272. do i = 1 , nx
  273. !Use fourth-order interpolation from four cell averages to compute the value at the interface in question
  274. do ll = 1 , NUM_VARS
  275. do s = 1 , sten_size
  276. stencil(s) = state(i,k-hs-1+s,ll)
  277. enddo
  278. !Fourth-order-accurate interpolation of the state
  279. vals(ll) = -stencil(1)/12 + 7*stencil(2)/12 + 7*stencil(3)/12 - stencil(4)/12
  280. !First-order-accurate interpolation of the third spatial derivative of the state
  281. d3_vals(ll) = -stencil(1) + 3*stencil(2) - 3*stencil(3) + stencil(4)
  282. enddo
  283. !Compute density, u-wind, w-wind, potential temperature, and pressure (r,u,w,t,p respectively)
  284. r = vals(ID_DENS) + hy_dens_int(k)
  285. u = vals(ID_UMOM) / r
  286. w = vals(ID_WMOM) / r
  287. t = ( vals(ID_RHOT) + hy_dens_theta_int(k) ) / r
  288. p = C0*(r*t)**gamma - hy_pressure_int(k)
  289. !Enforce vertical boundary condition and exact mass conservation
  290. if (k == 1 .or. k == nz+1) then
  291. w = 0
  292. d3_vals(ID_DENS) = 0
  293. endif
  294. !Compute the flux vector with hyperviscosity
  295. flux(i,k,ID_DENS) = r*w - hv_coef*d3_vals(ID_DENS)
  296. flux(i,k,ID_UMOM) = r*w*u - hv_coef*d3_vals(ID_UMOM)
  297. flux(i,k,ID_WMOM) = r*w*w+p - hv_coef*d3_vals(ID_WMOM)
  298. flux(i,k,ID_RHOT) = r*w*t - hv_coef*d3_vals(ID_RHOT)
  299. enddo
  300. enddo
  301. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  302. !! TODO: THREAD ME
  303. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  304. !Use the fluxes to compute tendencies for each cell
  305. !$acc parallel loop collapse(3)
  306. do ll = 1 , NUM_VARS
  307. do k = 1 , nz
  308. do i = 1 , nx
  309. tend(i,k,ll) = -( flux(i,k+1,ll) - flux(i,k,ll) ) / dz
  310. if (ll == ID_WMOM) then
  311. tend(i,k,ID_WMOM) = tend(i,k,ID_WMOM) - state(i,k,ID_DENS)*grav
  312. endif
  313. enddo
  314. enddo
  315. enddo
  316. end subroutine compute_tendencies_z
  317. !Set halo values in the x-direction.
  318. subroutine set_halo_values_x(state)
  319. implicit none
  320. real(rp), intent(inout) :: state(1-hs:nx+hs,1-hs:nz+hs,NUM_VARS)
  321. integer :: k, ll
  322. real(rp) :: z
  323. !$acc parallel loop collapse(2)
  324. do ll = 1 , NUM_VARS
  325. do k = 1 , nz
  326. state(-1 ,k,ll) = state(nx-1,k,ll)
  327. state(0 ,k,ll) = state(nx ,k,ll)
  328. state(nx+1,k,ll) = state(1 ,k,ll)
  329. state(nx+2,k,ll) = state(2 ,k,ll)
  330. enddo
  331. enddo
  332. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  333. if (myrank == 0) then
  334. !$acc parallel loop
  335. do k = 1 , nz
  336. z = (k_beg-1 + k-0.5_rp)*dz
  337. if (abs(z-3*zlen/4) <= zlen/16) then
  338. state(-1:0,k,ID_UMOM) = (state(-1:0,k,ID_DENS)+hy_dens_cell(k)) * 50._rp
  339. state(-1:0,k,ID_RHOT) = (state(-1:0,k,ID_DENS)+hy_dens_cell(k)) * 298._rp - hy_dens_theta_cell(k)
  340. endif
  341. enddo
  342. endif
  343. end subroutine set_halo_values_x
  344. !Set halo values in the z-direction.
  345. !decomposition in the vertical direction
  346. subroutine set_halo_values_z(state)
  347. implicit none
  348. real(rp), intent(inout) :: state(1-hs:nx+hs,1-hs:nz+hs,NUM_VARS)
  349. integer :: i, ll
  350. real(rp), parameter :: mnt_width = xlen/8
  351. real(rp) :: x, xloc, mnt_deriv
  352. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  353. !! TODO: THREAD ME
  354. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  355. !$acc parallel loop collapse(2) private(xloc,mnt_deriv,x)
  356. do ll = 1 , NUM_VARS
  357. do i = 1-hs,nx+hs
  358. if (ll == ID_WMOM) then
  359. state(i,-1 ,ll) = 0
  360. state(i,0 ,ll) = 0
  361. state(i,nz+1,ll) = 0
  362. state(i,nz+2,ll) = 0
  363. else
  364. state(i,-1 ,ll) = state(i,1 ,ll)
  365. state(i,0 ,ll) = state(i,1 ,ll)
  366. state(i,nz+1,ll) = state(i,nz,ll)
  367. state(i,nz+2,ll) = state(i,nz,ll)
  368. endif
  369. enddo
  370. enddo
  371. end subroutine set_halo_values_z
  372. !Initialize some grid settings, allocate data, and initialize the full grid and data
  373. subroutine init()
  374. implicit none
  375. integer :: i, k, ii, kk, ll, ierr
  376. real(rp) :: x, z, r, u, w, t, hr, ht
  377. !Set the cell grid size
  378. dx = xlen / nx_glob
  379. dz = zlen / nz_glob
  380. nranks = 1
  381. myrank = 0
  382. i_beg = 1
  383. nx = nx_glob
  384. left_rank = 0
  385. right_rank = 0
  386. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  387. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  388. !! YOU DON'T NEED TO ALTER ANYTHING BELOW THIS POINT IN THE CODE
  389. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  390. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  391. k_beg = 1
  392. nz = nz_glob
  393. !Allocate the model data
  394. allocate(state (1-hs:nx+hs,1-hs:nz+hs,NUM_VARS))
  395. allocate(state_tmp (1-hs:nx+hs,1-hs:nz+hs,NUM_VARS))
  396. allocate(flux (nx+1,nz+1,NUM_VARS))
  397. allocate(tend (nx,nz,NUM_VARS))
  398. allocate(hy_dens_cell (1-hs:nz+hs))
  399. allocate(hy_dens_theta_cell(1-hs:nz+hs))
  400. allocate(hy_dens_int (nz+1))
  401. allocate(hy_dens_theta_int (nz+1))
  402. allocate(hy_pressure_int (nz+1))
  403. !Define the maximum stable time step based on an assumed maximum wind speed
  404. dt = min(dx,dz) / max_speed * cfl
  405. !Set initial elapsed model time and output_counter to zero
  406. etime = 0
  407. output_counter = 0
  408. !Display some grid information
  409. write(*,*) 'nx_glob, nz_glob:', nx_glob, nz_glob
  410. write(*,*) 'dx,dz: ',dx,dz
  411. write(*,*) 'dt: ',dt
  412. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  413. !! Initialize the cell-averaged fluid state via Gauss-Legendre quadrature
  414. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  415. state = 0
  416. do k = 1-hs , nz+hs
  417. do i = 1-hs , nx+hs
  418. !Initialize the state to zero
  419. !Use Gauss-Legendre quadrature to initialize a hydrostatic balance + temperature perturbation
  420. do kk = 1 , nqpoints
  421. do ii = 1 , nqpoints
  422. !Compute the x,z location within the global domain based on cell and quadrature index
  423. x = (i_beg-1 + i-0.5_rp) * dx + (qpoints(ii)-0.5_rp)*dx
  424. z = (k_beg-1 + k-0.5_rp) * dz + (qpoints(kk)-0.5_rp)*dz
  425. !Set the fluid state based on the user's specification
  426. call injection (x,z,r,u,w,t,hr,ht)
  427. !Store into the fluid state array
  428. state(i,k,ID_DENS) = state(i,k,ID_DENS) + r * qweights(ii)*qweights(kk)
  429. state(i,k,ID_UMOM) = state(i,k,ID_UMOM) + (r+hr)*u * qweights(ii)*qweights(kk)
  430. state(i,k,ID_WMOM) = state(i,k,ID_WMOM) + (r+hr)*w * qweights(ii)*qweights(kk)
  431. state(i,k,ID_RHOT) = state(i,k,ID_RHOT) + ( (r+hr)*(t+ht) - hr*ht ) * qweights(ii)*qweights(kk)
  432. enddo
  433. enddo
  434. do ll = 1 , NUM_VARS
  435. state_tmp(i,k,ll) = state(i,k,ll)
  436. enddo
  437. enddo
  438. enddo
  439. !Compute the hydrostatic background state over vertical cell averages
  440. hy_dens_cell = 0
  441. hy_dens_theta_cell = 0
  442. do k = 1-hs , nz+hs
  443. do kk = 1 , nqpoints
  444. z = (k_beg-1 + k-0.5_rp) * dz + (qpoints(kk)-0.5_rp)*dz
  445. !Set the fluid state based on the user's specification
  446. call injection (0._rp,z,r,u,w,t,hr,ht)
  447. hy_dens_cell(k) = hy_dens_cell(k) + hr * qweights(kk)
  448. hy_dens_theta_cell(k) = hy_dens_theta_cell(k) + hr*ht * qweights(kk)
  449. enddo
  450. enddo
  451. !Compute the hydrostatic background state at vertical cell interfaces
  452. do k = 1 , nz+1
  453. z = (k_beg-1 + k-1) * dz
  454. call injection (0._rp,z,r,u,w,t,hr,ht)
  455. hy_dens_int (k) = hr
  456. hy_dens_theta_int(k) = hr*ht
  457. hy_pressure_int (k) = C0*(hr*ht)**gamma
  458. enddo
  459. end subroutine init
  460. !This test case is initially balanced but injects fast, cold air from the left boundary near the model top
  461. subroutine injection(x,z,r,u,w,t,hr,ht)
  462. implicit none
  463. real(rp), intent(in ) :: x, z !x- and z- location of the point being sampled
  464. real(rp), intent( out) :: r, u, w, t !Density, uwind, wwind, and potential temperature
  465. real(rp), intent( out) :: hr, ht !Hydrostatic density and potential temperature
  466. call hydro_const_theta(z,hr,ht)
  467. r = 0
  468. t = 0
  469. u = 0
  470. w = 0
  471. end subroutine injection
  472. !Establish hydrstatic balance using constant potential temperature (thermally neutral atmosphere)
  473. subroutine hydro_const_theta(z,r,t)
  474. implicit none
  475. real(rp), intent(in ) :: z !x- and z- location of the point being sampled
  476. real(rp), intent( out) :: r, t !Density and potential temperature at this point
  477. real(rp), parameter :: theta0 = 300._rp !Background potential temperature
  478. real(rp), parameter :: exner0 = 1._rp !Surface-level Exner pressure
  479. real(rp) :: p,exner,rt
  480. !Establish hydrostatic balance first using Exner pressure
  481. t = theta0 !Potential Temperature at z
  482. exner = exner0 - grav * z / (cp * theta0) !Exner pressure at z
  483. p = p0 * exner**(cp/rd) !Pressure at z
  484. rt = (p / c0)**(1._rp / gamma) !rho*theta at z
  485. r = rt / t !Density at z
  486. end subroutine hydro_const_theta
  487. !Deallocate and call Finalize
  488. subroutine finalize()
  489. implicit none
  490. integer :: ierr
  491. deallocate(state )
  492. deallocate(state_tmp )
  493. deallocate(flux )
  494. deallocate(tend )
  495. deallocate(hy_dens_cell )
  496. deallocate(hy_dens_theta_cell)
  497. deallocate(hy_dens_int )
  498. deallocate(hy_dens_theta_int )
  499. deallocate(hy_pressure_int )
  500. end subroutine finalize
  501. end program miniweather