miniWeather_openacc.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771
  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. #include <stdlib.h>
  8. #include <math.h>
  9. #include <stdio.h>
  10. #include <netcdf.h>
  11. #include <nvtx3/nvToolsExt.h>
  12. const double pi = 3.14159265358979323846264338327; //Pi
  13. const double grav = 9.8; //Gravitational acceleration (m / s^2)
  14. const double cp = 1004.; //Specific heat of dry air at constant pressure
  15. const double rd = 287.; //Dry air constant for equation of state (P=rho*rd*T)
  16. const double p0 = 1.e5; //Standard pressure at the surface in Pascals
  17. const double C0 = 27.5629410929725921310572974482; //Constant to translate potential temperature into pressure (P=C0*(rho*theta)**gamma)
  18. const double gamm = 1.40027894002789400278940027894; //gamma=cp/Rd , have to call this gamm because "gamma" is taken (I hate C so much)
  19. //Define domain and stability-related constants
  20. const double xlen = 2.e4; //Length of the domain in the x-direction (meters)
  21. const double zlen = 1.e4; //Length of the domain in the z-direction (meters)
  22. const double hv_beta = 0.25; //How strong to diffuse the solution: hv_beta \in [0:1]
  23. const double cfl = 1.50; //"Courant, Friedrichs, Lewy" number (for numerical stability)
  24. const double max_speed = 450; //Assumed maximum wave speed during the simulation (speed of sound + speed of wind) (meter / sec)
  25. const int hs = 2; //"Halo" size: number of cells needed for a full "stencil" of information for reconstruction
  26. const int sten_size = 4; //Size of the stencil used for interpolation
  27. //Parameters for indexing and flags
  28. const int NUM_VARS = 4; //Number of fluid state variables
  29. const int ID_DENS = 0; //index for density ("rho")
  30. const int ID_UMOM = 1; //index for momentum in the x-direction ("rho * u")
  31. const int ID_WMOM = 2; //index for momentum in the z-direction ("rho * w")
  32. const int ID_RHOT = 3; //index for density * potential temperature ("rho * theta")
  33. const int DIR_X = 1; //Integer constant to express that this operation is in the x-direction
  34. const int DIR_Z = 2; //Integer constant to express that this operation is in the z-direction
  35. const int nqpoints = 3;
  36. double qpoints[] = {0.112701665379258311482073460022E0, 0.500000000000000000000000000000E0, 0.887298334620741688517926539980E0};
  37. double qweights[] = {0.277777777777777777777777777779E0, 0.444444444444444444444444444444E0, 0.277777777777777777777777777779E0};
  38. ///////////////////////////////////////////////////////////////////////////////////////
  39. // Variables that are initialized but remain static over the course of the simulation
  40. ///////////////////////////////////////////////////////////////////////////////////////
  41. double sim_time; //total simulation time in seconds
  42. double output_freq; //frequency to perform output in seconds
  43. double dt; //Model time step (seconds)
  44. int nx, nz; //Number of local grid cells in the x- and z- dimensions
  45. double dx, dz; //Grid space length in x- and z-dimension (meters)
  46. int nx_glob, nz_glob; //Number of total grid cells in the x- and z- dimensions
  47. int i_beg, k_beg; //beginning index in the x- and z-directions
  48. int nranks, myrank; //my rank id
  49. int left_rank, right_rank; //Rank IDs that exist to my left and right in the global domain
  50. double *hy_dens_cell; //hydrostatic density (vert cell avgs). Dimensions: (1-hs:nz+hs)
  51. double *hy_dens_theta_cell; //hydrostatic rho*t (vert cell avgs). Dimensions: (1-hs:nz+hs)
  52. double *hy_dens_int; //hydrostatic density (vert cell interf). Dimensions: (1:nz+1)
  53. double *hy_dens_theta_int; //hydrostatic rho*t (vert cell interf). Dimensions: (1:nz+1)
  54. double *hy_pressure_int; //hydrostatic press (vert cell interf). Dimensions: (1:nz+1)
  55. ///////////////////////////////////////////////////////////////////////////////////////
  56. // Variables that are dynamics over the course of the simulation
  57. ///////////////////////////////////////////////////////////////////////////////////////
  58. double etime; //Elapsed model time
  59. double output_counter; //Helps determine when it's time to do output
  60. //Runtime variable arrays
  61. double *state; //Fluid state. Dimensions: (1-hs:nx+hs,1-hs:nz+hs,NUM_VARS)
  62. double *state_tmp; //Fluid state. Dimensions: (1-hs:nx+hs,1-hs:nz+hs,NUM_VARS)
  63. double *flux; //Cell interface fluxes. Dimensions: (nx+1,nz+1,NUM_VARS)
  64. double *tend; //Fluid state tendencies. Dimensions: (nx,nz,NUM_VARS)
  65. int num_out = 0; //The number of outputs performed so far
  66. int direction_switch = 1;
  67. //How is this not in the standard?!
  68. double dmin(double a, double b)
  69. {
  70. if (a < b)
  71. {
  72. return a;
  73. }
  74. else
  75. {
  76. return b;
  77. }
  78. };
  79. //Declaring the functions defined after "main"
  80. void init();
  81. void finalize();
  82. void injection(double x, double z, double &r, double &u, double &w, double &t, double &hr, double &ht);
  83. void hydro_const_theta(double z, double &r, double &t);
  84. void output(double *state, double etime);
  85. void ncwrap(int ierr, int line);
  86. void perform_timestep(double *state, double *state_tmp, double *flux, double *tend, double dt);
  87. void semi_discrete_step(double *state_init, double *state_forcing, double *state_out, double dt, int dir, double *flux, double *tend);
  88. void compute_tendencies_x(double *state, double *flux, double *tend);
  89. void compute_tendencies_z(double *state, double *flux, double *tend);
  90. void set_halo_values_x(double *state);
  91. void set_halo_values_z(double *state);
  92. ///////////////////////////////////////////////////////////////////////////////////////
  93. // THE MAIN PROGRAM STARTS HERE
  94. ///////////////////////////////////////////////////////////////////////////////////////
  95. int main(int argc, char **argv)
  96. {
  97. ///////////////////////////////////////////////////////////////////////////////////////
  98. // BEGIN USER-CONFIGURABLE PARAMETERS
  99. ///////////////////////////////////////////////////////////////////////////////////////
  100. //The x-direction length is twice as long as the z-direction length
  101. //So, you'll want to have nx_glob be twice as large as nz_glob
  102. nx_glob = 400; //Number of total cells in the x-dirction
  103. nz_glob = 200; //Number of total cells in the z-dirction
  104. sim_time = 1500; //How many seconds to run the simulation
  105. output_freq = 100; //How frequently to output data to file (in seconds)
  106. ///////////////////////////////////////////////////////////////////////////////////////
  107. // END USER-CONFIGURABLE PARAMETERS
  108. ///////////////////////////////////////////////////////////////////////////////////////
  109. if (argc == 4)
  110. {
  111. printf("The arguments supplied are %s %s %s\n", argv[1], argv[2], argv[3]);
  112. nx_glob = atoi(argv[1]);
  113. nz_glob = atoi(argv[2]);
  114. sim_time = atoi(argv[3]);
  115. }
  116. else
  117. {
  118. printf("Using default values ...\n");
  119. }
  120. nvtxRangePushA("Total");
  121. init();
  122. #pragma acc data copyin(state_tmp[(nz + 2 * hs) * (nx + 2 * hs) * NUM_VARS], hy_dens_cell[nz + 2 * hs], hy_dens_theta_cell[nz + 2 * hs], hy_dens_int[nz + 1], hy_dens_theta_int[nz + 1], hy_pressure_int[nz + 1]) \
  123. create(flux[(nz + 1) * (nx + 1) * NUM_VARS], tend[nz * nx * NUM_VARS]) \
  124. copy(state [0:(nz + 2 * hs) * (nx + 2 * hs) * NUM_VARS])
  125. {
  126. //Output the initial state
  127. output(state, etime);
  128. ////////////////////////////////////////////////////
  129. // MAIN TIME STEP LOOP
  130. ////////////////////////////////////////////////////
  131. nvtxRangePushA("while");
  132. while (etime < sim_time)
  133. {
  134. //If the time step leads to exceeding the simulation time, shorten it for the last step
  135. if (etime + dt > sim_time)
  136. {
  137. dt = sim_time - etime;
  138. }
  139. //Perform a single time step
  140. nvtxRangePushA("perform_timestep");
  141. perform_timestep(state, state_tmp, flux, tend, dt);
  142. nvtxRangePop();
  143. //Inform the user
  144. printf("Elapsed Time: %lf / %lf\n", etime, sim_time);
  145. //Update the elapsed time and output counter
  146. etime = etime + dt;
  147. output_counter = output_counter + dt;
  148. //If it's time for output, reset the counter, and do output
  149. if (output_counter >= output_freq)
  150. {
  151. output_counter = output_counter - output_freq;
  152. #pragma acc update host(state[(nz + 2 * hs) * (nx + 2 * hs) * NUM_VARS])
  153. output(state, etime);
  154. }
  155. }
  156. nvtxRangePop();
  157. }
  158. finalize();
  159. nvtxRangePop();
  160. }
  161. //Performs a single dimensionally split time step using a simple low-storate three-stage Runge-Kutta time integrator
  162. //The dimensional splitting is a second-order-accurate alternating Strang splitting in which the
  163. //order of directions is alternated each time step.
  164. //The Runge-Kutta method used here is defined as follows:
  165. // q* = q[n] + dt/3 * rhs(q[n])
  166. // q** = q[n] + dt/2 * rhs(q* )
  167. // q[n+1] = q[n] + dt/1 * rhs(q** )
  168. void perform_timestep(double *state, double *state_tmp, double *flux, double *tend, double dt)
  169. {
  170. if (direction_switch)
  171. {
  172. //x-direction first
  173. semi_discrete_step(state, state, state_tmp, dt / 3, DIR_X, flux, tend);
  174. semi_discrete_step(state, state_tmp, state_tmp, dt / 2, DIR_X, flux, tend);
  175. semi_discrete_step(state, state_tmp, state, dt / 1, DIR_X, flux, tend);
  176. //z-direction second
  177. semi_discrete_step(state, state, state_tmp, dt / 3, DIR_Z, flux, tend);
  178. semi_discrete_step(state, state_tmp, state_tmp, dt / 2, DIR_Z, flux, tend);
  179. semi_discrete_step(state, state_tmp, state, dt / 1, DIR_Z, flux, tend);
  180. }
  181. else
  182. {
  183. //z-direction second
  184. semi_discrete_step(state, state, state_tmp, dt / 3, DIR_Z, flux, tend);
  185. semi_discrete_step(state, state_tmp, state_tmp, dt / 2, DIR_Z, flux, tend);
  186. semi_discrete_step(state, state_tmp, state, dt / 1, DIR_Z, flux, tend);
  187. //x-direction first
  188. semi_discrete_step(state, state, state_tmp, dt / 3, DIR_X, flux, tend);
  189. semi_discrete_step(state, state_tmp, state_tmp, dt / 2, DIR_X, flux, tend);
  190. semi_discrete_step(state, state_tmp, state, dt / 1, DIR_X, flux, tend);
  191. }
  192. if (direction_switch)
  193. {
  194. direction_switch = 0;
  195. }
  196. else
  197. {
  198. direction_switch = 1;
  199. }
  200. }
  201. //Perform a single semi-discretized step in time with the form:
  202. //state_out = state_init + dt * rhs(state_forcing)
  203. //Meaning the step starts from state_init, computes the rhs using state_forcing, and stores the result in state_out
  204. void semi_discrete_step(double *state_init, double *state_forcing, double *state_out, double dt, int dir, double *flux, double *tend)
  205. {
  206. int i, k, ll, inds, indt;
  207. if (dir == DIR_X)
  208. {
  209. //Set the halo values in the x-direction
  210. set_halo_values_x(state_forcing);
  211. //Compute the time tendencies for the fluid state in the x-direction
  212. compute_tendencies_x(state_forcing, flux, tend);
  213. }
  214. else if (dir == DIR_Z)
  215. {
  216. //Set the halo values in the z-direction
  217. set_halo_values_z(state_forcing);
  218. //Compute the time tendencies for the fluid state in the z-direction
  219. compute_tendencies_z(state_forcing, flux, tend);
  220. }
  221. /////////////////////////////////////////////////
  222. // TODO: THREAD ME
  223. /////////////////////////////////////////////////
  224. //Apply the tendencies to the fluid state
  225. #pragma acc parallel loop collapse(3) private(inds, indt) default(present)
  226. for (ll = 0; ll < NUM_VARS; ll++)
  227. {
  228. for (k = 0; k < nz; k++)
  229. {
  230. for (i = 0; i < nx; i++)
  231. {
  232. inds = ll * (nz + 2 * hs) * (nx + 2 * hs) + (k + hs) * (nx + 2 * hs) + i + hs;
  233. indt = ll * nz * nx + k * nx + i;
  234. state_out[inds] = state_init[inds] + dt * tend[indt];
  235. }
  236. }
  237. }
  238. }
  239. //Compute the time tendencies of the fluid state using forcing in the x-direction
  240. //First, compute the flux vector at each cell interface in the x-direction (including hyperviscosity)
  241. //Then, compute the tendencies using those fluxes
  242. void compute_tendencies_x(double *state, double *flux, double *tend)
  243. {
  244. int i, k, ll, s, inds, indf1, indf2, indt;
  245. double r, u, w, t, p, stencil[4], d3_vals[NUM_VARS], vals[NUM_VARS], hv_coef;
  246. //Compute the hyperviscosity coeficient
  247. hv_coef = -hv_beta * dx / (16 * dt);
  248. /////////////////////////////////////////////////
  249. // TODO: THREAD ME
  250. /////////////////////////////////////////////////
  251. //Compute fluxes in the x-direction for each cell
  252. #pragma acc parallel loop collapse(2) private(ll, s, inds, stencil, vals, d3_vals, r, u, w, t, p) default(present)
  253. for (k = 0; k < nz; k++)
  254. {
  255. for (i = 0; i < nx + 1; i++)
  256. {
  257. //Use fourth-order interpolation from four cell averages to compute the value at the interface in question
  258. for (ll = 0; ll < NUM_VARS; ll++)
  259. {
  260. for (s = 0; s < sten_size; s++)
  261. {
  262. inds = ll * (nz + 2 * hs) * (nx + 2 * hs) + (k + hs) * (nx + 2 * hs) + i + s;
  263. stencil[s] = state[inds];
  264. }
  265. //Fourth-order-accurate interpolation of the state
  266. vals[ll] = -stencil[0] / 12 + 7 * stencil[1] / 12 + 7 * stencil[2] / 12 - stencil[3] / 12;
  267. //First-order-accurate interpolation of the third spatial derivative of the state (for artificial viscosity)
  268. d3_vals[ll] = -stencil[0] + 3 * stencil[1] - 3 * stencil[2] + stencil[3];
  269. }
  270. //Compute density, u-wind, w-wind, potential temperature, and pressure (r,u,w,t,p respectively)
  271. r = vals[ID_DENS] + hy_dens_cell[k + hs];
  272. u = vals[ID_UMOM] / r;
  273. w = vals[ID_WMOM] / r;
  274. t = (vals[ID_RHOT] + hy_dens_theta_cell[k + hs]) / r;
  275. p = C0 * pow((r * t), gamm);
  276. //Compute the flux vector
  277. flux[ID_DENS * (nz + 1) * (nx + 1) + k * (nx + 1) + i] = r * u - hv_coef * d3_vals[ID_DENS];
  278. flux[ID_UMOM * (nz + 1) * (nx + 1) + k * (nx + 1) + i] = r * u * u + p - hv_coef * d3_vals[ID_UMOM];
  279. flux[ID_WMOM * (nz + 1) * (nx + 1) + k * (nx + 1) + i] = r * u * w - hv_coef * d3_vals[ID_WMOM];
  280. flux[ID_RHOT * (nz + 1) * (nx + 1) + k * (nx + 1) + i] = r * u * t - hv_coef * d3_vals[ID_RHOT];
  281. }
  282. }
  283. /////////////////////////////////////////////////
  284. // TODO: THREAD ME
  285. /////////////////////////////////////////////////
  286. //Use the fluxes to compute tendencies for each cell
  287. #pragma acc parallel loop collapse(3) private(indt, indf1, indf2) default(present)
  288. for (ll = 0; ll < NUM_VARS; ll++)
  289. {
  290. for (k = 0; k < nz; k++)
  291. {
  292. for (i = 0; i < nx; i++)
  293. {
  294. indt = ll * nz * nx + k * nx + i;
  295. indf1 = ll * (nz + 1) * (nx + 1) + k * (nx + 1) + i;
  296. indf2 = ll * (nz + 1) * (nx + 1) + k * (nx + 1) + i + 1;
  297. tend[indt] = -(flux[indf2] - flux[indf1]) / dx;
  298. }
  299. }
  300. }
  301. }
  302. //Compute the time tendencies of the fluid state using forcing in the z-direction
  303. //First, compute the flux vector at each cell interface in the z-direction (including hyperviscosity)
  304. //Then, compute the tendencies using those fluxes
  305. void compute_tendencies_z(double *state, double *flux, double *tend)
  306. {
  307. int i, k, ll, s, inds, indf1, indf2, indt;
  308. double r, u, w, t, p, stencil[4], d3_vals[NUM_VARS], vals[NUM_VARS], hv_coef;
  309. //Compute the hyperviscosity coeficient
  310. hv_coef = -hv_beta * dx / (16 * dt);
  311. /////////////////////////////////////////////////
  312. // TODO: THREAD ME
  313. /////////////////////////////////////////////////
  314. //Compute fluxes in the x-direction for each cell
  315. #pragma acc parallel loop collapse(2) private(ll, s, inds, stencil, vals, d3_vals, r, u, w, t, p) default(present)
  316. for (k = 0; k < nz + 1; k++)
  317. {
  318. for (i = 0; i < nx; i++)
  319. {
  320. //Use fourth-order interpolation from four cell averages to compute the value at the interface in question
  321. for (ll = 0; ll < NUM_VARS; ll++)
  322. {
  323. for (s = 0; s < sten_size; s++)
  324. {
  325. inds = ll * (nz + 2 * hs) * (nx + 2 * hs) + (k + s) * (nx + 2 * hs) + i + hs;
  326. stencil[s] = state[inds];
  327. }
  328. //Fourth-order-accurate interpolation of the state
  329. vals[ll] = -stencil[0] / 12 + 7 * stencil[1] / 12 + 7 * stencil[2] / 12 - stencil[3] / 12;
  330. //First-order-accurate interpolation of the third spatial derivative of the state
  331. d3_vals[ll] = -stencil[0] + 3 * stencil[1] - 3 * stencil[2] + stencil[3];
  332. }
  333. //Compute density, u-wind, w-wind, potential temperature, and pressure (r,u,w,t,p respectively)
  334. r = vals[ID_DENS] + hy_dens_int[k];
  335. u = vals[ID_UMOM] / r;
  336. w = vals[ID_WMOM] / r;
  337. t = (vals[ID_RHOT] + hy_dens_theta_int[k]) / r;
  338. p = C0 * pow((r * t), gamm) - hy_pressure_int[k];
  339. //Compute the flux vector with hyperviscosity
  340. flux[ID_DENS * (nz + 1) * (nx + 1) + k * (nx + 1) + i] = r * w - hv_coef * d3_vals[ID_DENS];
  341. flux[ID_UMOM * (nz + 1) * (nx + 1) + k * (nx + 1) + i] = r * w * u - hv_coef * d3_vals[ID_UMOM];
  342. flux[ID_WMOM * (nz + 1) * (nx + 1) + k * (nx + 1) + i] = r * w * w + p - hv_coef * d3_vals[ID_WMOM];
  343. flux[ID_RHOT * (nz + 1) * (nx + 1) + k * (nx + 1) + i] = r * w * t - hv_coef * d3_vals[ID_RHOT];
  344. }
  345. }
  346. /////////////////////////////////////////////////
  347. // TODO: THREAD ME
  348. /////////////////////////////////////////////////
  349. //Use the fluxes to compute tendencies for each cell
  350. #pragma acc parallel loop collapse(3) private(indt, indf1, indf2) default(present)
  351. for (ll = 0; ll < NUM_VARS; ll++)
  352. {
  353. for (k = 0; k < nz; k++)
  354. {
  355. for (i = 0; i < nx; i++)
  356. {
  357. indt = ll * nz * nx + k * nx + i;
  358. indf1 = ll * (nz + 1) * (nx + 1) + (k) * (nx + 1) + i;
  359. indf2 = ll * (nz + 1) * (nx + 1) + (k + 1) * (nx + 1) + i;
  360. tend[indt] = -(flux[indf2] - flux[indf1]) / dz;
  361. if (ll == ID_WMOM)
  362. {
  363. inds = ID_DENS * (nz + 2 * hs) * (nx + 2 * hs) + (k + hs) * (nx + 2 * hs) + i + hs;
  364. tend[indt] = tend[indt] - state[inds] * grav;
  365. }
  366. }
  367. }
  368. }
  369. }
  370. void set_halo_values_x(double *state)
  371. {
  372. int k, ll, ind_r, ind_u, ind_t, i;
  373. double z;
  374. #pragma acc parallel loop collapse(2) default(present)
  375. for (ll = 0; ll < NUM_VARS; ll++)
  376. {
  377. for (k = 0; k < nz; k++)
  378. {
  379. state[ll * (nz + 2 * hs) * (nx + 2 * hs) + (k + hs) * (nx + 2 * hs) + 0] = state[ll * (nz + 2 * hs) * (nx + 2 * hs) + (k + hs) * (nx + 2 * hs) + nx + hs - 2];
  380. state[ll * (nz + 2 * hs) * (nx + 2 * hs) + (k + hs) * (nx + 2 * hs) + 1] = state[ll * (nz + 2 * hs) * (nx + 2 * hs) + (k + hs) * (nx + 2 * hs) + nx + hs - 1];
  381. state[ll * (nz + 2 * hs) * (nx + 2 * hs) + (k + hs) * (nx + 2 * hs) + nx + hs] = state[ll * (nz + 2 * hs) * (nx + 2 * hs) + (k + hs) * (nx + 2 * hs) + hs];
  382. state[ll * (nz + 2 * hs) * (nx + 2 * hs) + (k + hs) * (nx + 2 * hs) + nx + hs + 1] = state[ll * (nz + 2 * hs) * (nx + 2 * hs) + (k + hs) * (nx + 2 * hs) + hs + 1];
  383. }
  384. }
  385. ////////////////////////////////////////////////////
  386. if (myrank == 0)
  387. {
  388. for (k = 0; k < nz; k++)
  389. {
  390. for (i = 0; i < hs; i++)
  391. {
  392. z = (k_beg + k + 0.5) * dz;
  393. if (abs(z - 3 * zlen / 4) <= zlen / 16)
  394. {
  395. ind_r = ID_DENS * (nz + 2 * hs) * (nx + 2 * hs) + (k + hs) * (nx + 2 * hs) + i;
  396. ind_u = ID_UMOM * (nz + 2 * hs) * (nx + 2 * hs) + (k + hs) * (nx + 2 * hs) + i;
  397. ind_t = ID_RHOT * (nz + 2 * hs) * (nx + 2 * hs) + (k + hs) * (nx + 2 * hs) + i;
  398. state[ind_u] = (state[ind_r] + hy_dens_cell[k + hs]) * 50.;
  399. state[ind_t] = (state[ind_r] + hy_dens_cell[k + hs]) * 298. - hy_dens_theta_cell[k + hs];
  400. }
  401. }
  402. }
  403. }
  404. }
  405. //Set this task's halo values in the z-direction.
  406. //decomposition in the vertical direction.
  407. void set_halo_values_z(double *state)
  408. {
  409. int i, ll;
  410. const double mnt_width = xlen / 8;
  411. double x, xloc, mnt_deriv;
  412. /////////////////////////////////////////////////
  413. // TODO: THREAD ME
  414. /////////////////////////////////////////////////
  415. #pragma acc parallel loop private(x, xloc, mnt_deriv) default(present)
  416. for (ll = 0; ll < NUM_VARS; ll++)
  417. {
  418. for (i = 0; i < nx + 2 * hs; i++)
  419. {
  420. if (ll == ID_WMOM)
  421. {
  422. state[ll * (nz + 2 * hs) * (nx + 2 * hs) + (0) * (nx + 2 * hs) + i] = 0.;
  423. state[ll * (nz + 2 * hs) * (nx + 2 * hs) + (1) * (nx + 2 * hs) + i] = 0.;
  424. state[ll * (nz + 2 * hs) * (nx + 2 * hs) + (nz + hs) * (nx + 2 * hs) + i] = 0.;
  425. state[ll * (nz + 2 * hs) * (nx + 2 * hs) + (nz + hs + 1) * (nx + 2 * hs) + i] = 0.;
  426. }
  427. else
  428. {
  429. state[ll * (nz + 2 * hs) * (nx + 2 * hs) + (0) * (nx + 2 * hs) + i] = state[ll * (nz + 2 * hs) * (nx + 2 * hs) + (hs) * (nx + 2 * hs) + i];
  430. state[ll * (nz + 2 * hs) * (nx + 2 * hs) + (1) * (nx + 2 * hs) + i] = state[ll * (nz + 2 * hs) * (nx + 2 * hs) + (hs) * (nx + 2 * hs) + i];
  431. state[ll * (nz + 2 * hs) * (nx + 2 * hs) + (nz + hs) * (nx + 2 * hs) + i] = state[ll * (nz + 2 * hs) * (nx + 2 * hs) + (nz + hs - 1) * (nx + 2 * hs) + i];
  432. state[ll * (nz + 2 * hs) * (nx + 2 * hs) + (nz + hs + 1) * (nx + 2 * hs) + i] = state[ll * (nz + 2 * hs) * (nx + 2 * hs) + (nz + hs - 1) * (nx + 2 * hs) + i];
  433. }
  434. }
  435. }
  436. }
  437. void init()
  438. {
  439. int i, k, ii, kk, ll, inds, i_end;
  440. double x, z, r, u, w, t, hr, ht, nper;
  441. //Set the cell grid size
  442. dx = xlen / nx_glob;
  443. dz = zlen / nz_glob;
  444. nranks = 1;
  445. myrank = 0;
  446. // For simpler version, replace i_beg = 0, nx = nx_glob, left_rank = 0, right_rank = 0;
  447. nper = ((double)nx_glob) / nranks;
  448. i_beg = round(nper * (myrank));
  449. i_end = round(nper * ((myrank) + 1)) - 1;
  450. nx = i_end - i_beg + 1;
  451. left_rank = myrank - 1;
  452. if (left_rank == -1)
  453. left_rank = nranks - 1;
  454. right_rank = myrank + 1;
  455. if (right_rank == nranks)
  456. right_rank = 0;
  457. ////////////////////////////////////////////////////////////////////////////////
  458. ////////////////////////////////////////////////////////////////////////////////
  459. // YOU DON'T NEED TO ALTER ANYTHING BELOW THIS POINT IN THE CODE
  460. ////////////////////////////////////////////////////////////////////////////////
  461. ////////////////////////////////////////////////////////////////////////////////
  462. k_beg = 0;
  463. nz = nz_glob;
  464. //Allocate the model data
  465. state = (double *)malloc((nx + 2 * hs) * (nz + 2 * hs) * NUM_VARS * sizeof(double));
  466. state_tmp = (double *)malloc((nx + 2 * hs) * (nz + 2 * hs) * NUM_VARS * sizeof(double));
  467. flux = (double *)malloc((nx + 1) * (nz + 1) * NUM_VARS * sizeof(double));
  468. tend = (double *)malloc(nx * nz * NUM_VARS * sizeof(double));
  469. hy_dens_cell = (double *)malloc((nz + 2 * hs) * sizeof(double));
  470. hy_dens_theta_cell = (double *)malloc((nz + 2 * hs) * sizeof(double));
  471. hy_dens_int = (double *)malloc((nz + 1) * sizeof(double));
  472. hy_dens_theta_int = (double *)malloc((nz + 1) * sizeof(double));
  473. hy_pressure_int = (double *)malloc((nz + 1) * sizeof(double));
  474. //Define the maximum stable time step based on an assumed maximum wind speed
  475. dt = dmin(dx, dz) / max_speed * cfl;
  476. //Set initial elapsed model time and output_counter to zero
  477. etime = 0.;
  478. output_counter = 0.;
  479. // Display grid information
  480. printf("nx_glob, nz_glob: %d %d\n", nx_glob, nz_glob);
  481. printf("dx,dz: %lf %lf\n", dx, dz);
  482. printf("dt: %lf\n", dt);
  483. //////////////////////////////////////////////////////////////////////////
  484. // Initialize the cell-averaged fluid state via Gauss-Legendre quadrature
  485. //////////////////////////////////////////////////////////////////////////
  486. for (k = 0; k < nz + 2 * hs; k++)
  487. {
  488. for (i = 0; i < nx + 2 * hs; i++)
  489. {
  490. //Initialize the state to zero
  491. for (ll = 0; ll < NUM_VARS; ll++)
  492. {
  493. inds = ll * (nz + 2 * hs) * (nx + 2 * hs) + k * (nx + 2 * hs) + i;
  494. state[inds] = 0.;
  495. }
  496. //Use Gauss-Legendre quadrature to initialize a hydrostatic balance + temperature perturbation
  497. for (kk = 0; kk < nqpoints; kk++)
  498. {
  499. for (ii = 0; ii < nqpoints; ii++)
  500. {
  501. //Compute the x,z location within the global domain based on cell and quadrature index
  502. x = (i_beg + i - hs + 0.5) * dx + (qpoints[ii] - 0.5) * dx;
  503. z = (k_beg + k - hs + 0.5) * dz + (qpoints[kk] - 0.5) * dz;
  504. //Set the fluid state based on the user's specification (default is injection in this example)
  505. injection(x, z, r, u, w, t, hr, ht);
  506. //Store into the fluid state array
  507. inds = ID_DENS * (nz + 2 * hs) * (nx + 2 * hs) + k * (nx + 2 * hs) + i;
  508. state[inds] = state[inds] + r * qweights[ii] * qweights[kk];
  509. inds = ID_UMOM * (nz + 2 * hs) * (nx + 2 * hs) + k * (nx + 2 * hs) + i;
  510. state[inds] = state[inds] + (r + hr) * u * qweights[ii] * qweights[kk];
  511. inds = ID_WMOM * (nz + 2 * hs) * (nx + 2 * hs) + k * (nx + 2 * hs) + i;
  512. state[inds] = state[inds] + (r + hr) * w * qweights[ii] * qweights[kk];
  513. inds = ID_RHOT * (nz + 2 * hs) * (nx + 2 * hs) + k * (nx + 2 * hs) + i;
  514. state[inds] = state[inds] + ((r + hr) * (t + ht) - hr * ht) * qweights[ii] * qweights[kk];
  515. }
  516. }
  517. for (ll = 0; ll < NUM_VARS; ll++)
  518. {
  519. inds = ll * (nz + 2 * hs) * (nx + 2 * hs) + k * (nx + 2 * hs) + i;
  520. state_tmp[inds] = state[inds];
  521. }
  522. }
  523. }
  524. //Compute the hydrostatic background state over vertical cell averages
  525. for (k = 0; k < nz + 2 * hs; k++)
  526. {
  527. hy_dens_cell[k] = 0.;
  528. hy_dens_theta_cell[k] = 0.;
  529. for (kk = 0; kk < nqpoints; kk++)
  530. {
  531. z = (k_beg + k - hs + 0.5) * dz;
  532. //Set the fluid state based on the user's specification (default is injection in this example)
  533. injection(0., z, r, u, w, t, hr, ht);
  534. hy_dens_cell[k] = hy_dens_cell[k] + hr * qweights[kk];
  535. hy_dens_theta_cell[k] = hy_dens_theta_cell[k] + hr * ht * qweights[kk];
  536. }
  537. }
  538. //Compute the hydrostatic background state at vertical cell interfaces
  539. for (k = 0; k < nz + 1; k++)
  540. {
  541. z = (k_beg + k) * dz;
  542. //Set the fluid state based on the user's specification (default is injection in this example)
  543. injection(0., z, r, u, w, t, hr, ht);
  544. hy_dens_int[k] = hr;
  545. hy_dens_theta_int[k] = hr * ht;
  546. hy_pressure_int[k] = C0 * pow((hr * ht), gamm);
  547. }
  548. }
  549. //This test case is initially balanced but injects fast, cold air from the left boundary near the model top
  550. //x and z are input coordinates at which to sample
  551. //r,u,w,t are output density, u-wind, w-wind, and potential temperature at that location
  552. //hr and ht are output background hydrostatic density and potential temperature at that location
  553. void injection(double x, double z, double &r, double &u, double &w, double &t, double &hr, double &ht)
  554. {
  555. hydro_const_theta(z, hr, ht);
  556. r = 0.;
  557. t = 0.;
  558. u = 0.;
  559. w = 0.;
  560. }
  561. //Establish hydrstatic balance using constant potential temperature (thermally neutral atmosphere)
  562. //z is the input coordinate
  563. //r and t are the output background hydrostatic density and potential temperature
  564. void hydro_const_theta(double z, double &r, double &t)
  565. {
  566. const double theta0 = 300.; //Background potential temperature
  567. const double exner0 = 1.; //Surface-level Exner pressure
  568. double p, exner, rt;
  569. //Establish hydrostatic balance first using Exner pressure
  570. t = theta0; //Potential Temperature at z
  571. exner = exner0 - grav * z / (cp * theta0); //Exner pressure at z
  572. p = p0 * pow(exner, (cp / rd)); //Pressure at z
  573. rt = pow((p / C0), (1. / gamm)); //rho*theta at z
  574. r = rt / t; //Density at z
  575. }
  576. //Output the fluid state (state) to a NetCDF file at a given elapsed model time (etime)
  577. //The file I/O uses netcdf, the only external library required for this mini-app.
  578. //If it's too cumbersome, you can comment the I/O out, but you'll miss out on some potentially cool graphics
  579. void output(double *state, double etime)
  580. {
  581. int ncid, t_dimid, x_dimid, z_dimid, dens_varid, uwnd_varid, wwnd_varid, theta_varid, t_varid, dimids[3];
  582. int i, k, ind_r, ind_u, ind_w, ind_t;
  583. size_t st1[1], ct1[1], st3[3], ct3[3];
  584. //Temporary arrays to hold density, u-wind, w-wind, and potential temperature (theta)
  585. double *dens, *uwnd, *wwnd, *theta;
  586. double *etimearr;
  587. //Inform the user
  588. printf("*** OUTPUT ***\n");
  589. //Allocate some (big) temp arrays
  590. dens = (double *)malloc(nx * nz * sizeof(double));
  591. uwnd = (double *)malloc(nx * nz * sizeof(double));
  592. wwnd = (double *)malloc(nx * nz * sizeof(double));
  593. theta = (double *)malloc(nx * nz * sizeof(double));
  594. etimearr = (double *)malloc(1 * sizeof(double));
  595. //If the elapsed time is zero, create the file. Otherwise, open the file
  596. if (etime == 0)
  597. {
  598. //Create the file
  599. ncwrap(nc_create("new.nc", NC_CLOBBER, &ncid), __LINE__);
  600. //Create the dimensions
  601. ncwrap(nc_def_dim(ncid, "t", NC_UNLIMITED, &t_dimid), __LINE__);
  602. ncwrap(nc_def_dim(ncid, "x", nx_glob, &x_dimid), __LINE__);
  603. ncwrap(nc_def_dim(ncid, "z", nz_glob, &z_dimid), __LINE__);
  604. //Create the variables
  605. dimids[0] = t_dimid;
  606. ncwrap(nc_def_var(ncid, "t", NC_DOUBLE, 1, dimids, &t_varid), __LINE__);
  607. dimids[0] = t_dimid;
  608. dimids[1] = z_dimid;
  609. dimids[2] = x_dimid;
  610. ncwrap(nc_def_var(ncid, "dens", NC_DOUBLE, 3, dimids, &dens_varid), __LINE__);
  611. ncwrap(nc_def_var(ncid, "uwnd", NC_DOUBLE, 3, dimids, &uwnd_varid), __LINE__);
  612. ncwrap(nc_def_var(ncid, "wwnd", NC_DOUBLE, 3, dimids, &wwnd_varid), __LINE__);
  613. ncwrap(nc_def_var(ncid, "theta", NC_DOUBLE, 3, dimids, &theta_varid), __LINE__);
  614. //End "define" mode
  615. ncwrap(nc_enddef(ncid), __LINE__);
  616. }
  617. else
  618. {
  619. //Open the file
  620. ncwrap(nc_open("new.nc", NC_WRITE, &ncid), __LINE__);
  621. //Get the variable IDs
  622. ncwrap(nc_inq_varid(ncid, "dens", &dens_varid), __LINE__);
  623. ncwrap(nc_inq_varid(ncid, "uwnd", &uwnd_varid), __LINE__);
  624. ncwrap(nc_inq_varid(ncid, "wwnd", &wwnd_varid), __LINE__);
  625. ncwrap(nc_inq_varid(ncid, "theta", &theta_varid), __LINE__);
  626. ncwrap(nc_inq_varid(ncid, "t", &t_varid), __LINE__);
  627. }
  628. //Store perturbed values in the temp arrays for output
  629. for (k = 0; k < nz; k++)
  630. {
  631. for (i = 0; i < nx; i++)
  632. {
  633. ind_r = ID_DENS * (nz + 2 * hs) * (nx + 2 * hs) + (k + hs) * (nx + 2 * hs) + i + hs;
  634. ind_u = ID_UMOM * (nz + 2 * hs) * (nx + 2 * hs) + (k + hs) * (nx + 2 * hs) + i + hs;
  635. ind_w = ID_WMOM * (nz + 2 * hs) * (nx + 2 * hs) + (k + hs) * (nx + 2 * hs) + i + hs;
  636. ind_t = ID_RHOT * (nz + 2 * hs) * (nx + 2 * hs) + (k + hs) * (nx + 2 * hs) + i + hs;
  637. dens[k * nx + i] = state[ind_r];
  638. uwnd[k * nx + i] = state[ind_u] / (hy_dens_cell[k + hs] + state[ind_r]);
  639. wwnd[k * nx + i] = state[ind_w] / (hy_dens_cell[k + hs] + state[ind_r]);
  640. theta[k * nx + i] = (state[ind_t] + hy_dens_theta_cell[k + hs]) / (hy_dens_cell[k + hs] + state[ind_r]) - hy_dens_theta_cell[k + hs] / hy_dens_cell[k + hs];
  641. }
  642. }
  643. //Write the grid data to file with all the processes writing collectively
  644. st3[0] = num_out;
  645. st3[1] = k_beg;
  646. st3[2] = i_beg;
  647. ct3[0] = 1;
  648. ct3[1] = nz;
  649. ct3[2] = nx;
  650. ncwrap(nc_put_vara_double(ncid, dens_varid, st3, ct3, dens), __LINE__);
  651. ncwrap(nc_put_vara_double(ncid, uwnd_varid, st3, ct3, uwnd), __LINE__);
  652. ncwrap(nc_put_vara_double(ncid, wwnd_varid, st3, ct3, wwnd), __LINE__);
  653. ncwrap(nc_put_vara_double(ncid, theta_varid, st3, ct3, theta), __LINE__);
  654. //Only the master process needs to write the elapsed time
  655. //write elapsed time to file
  656. st1[0] = num_out;
  657. ct1[0] = 1;
  658. etimearr[0] = etime;
  659. ncwrap(nc_put_vara_double(ncid, t_varid, st1, ct1, etimearr), __LINE__);
  660. //Close the file
  661. ncwrap(nc_close(ncid), __LINE__);
  662. //Increment the number of outputs
  663. num_out = num_out + 1;
  664. //Deallocate the temp arrays
  665. free(dens);
  666. free(uwnd);
  667. free(wwnd);
  668. free(theta);
  669. free(etimearr);
  670. }
  671. //Error reporting routine for the NetCDF I/O
  672. void ncwrap(int ierr, int line)
  673. {
  674. if (ierr != NC_NOERR)
  675. {
  676. printf("NetCDF Error at line: %d\n", line);
  677. printf("%s\n", nc_strerror(ierr));
  678. exit(-1);
  679. }
  680. }
  681. void finalize()
  682. {
  683. free(state);
  684. free(state_tmp);
  685. free(flux);
  686. free(tend);
  687. free(hy_dens_cell);
  688. free(hy_dens_theta_cell);
  689. free(hy_dens_int);
  690. free(hy_dens_theta_int);
  691. free(hy_pressure_int);
  692. }