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