20
20
#include " mdspan/mdspan.hpp"
21
21
#include " unique_mdarray.hpp"
22
22
23
+ #if defined(MINIWEATHER_KOKKOS)
24
+ # include " Kokkos_Core.hpp"
25
+ # define MINIWEATHER_INLINE_FUNCTION KOKKOS_INLINE_FUNCTION
26
+ #else
27
+ # define MINIWEATHER_INLINE_FUNCTION inline
28
+ #endif
29
+
23
30
constexpr double pi = 3.14159265358979323846264338327 ; // Pi
24
31
constexpr double grav = 9.8 ; // Gravitational acceleration (m / s^2)
25
32
constexpr double cp = 1004 .; // Specific heat of dry air at constant pressure
@@ -251,6 +258,64 @@ struct init_result {
251
258
global_arrays<MemorySpace> arrays;
252
259
};
253
260
261
+ struct r_t_pair {
262
+ double r;
263
+ double t;
264
+ };
265
+
266
+ // Establish hydrostatic balance using constant potential temperature
267
+ // (thermally neutral atmosphere)
268
+ // z is the input coordinate
269
+ // r and t are the output background hydrostatic density and potential temperature
270
+ MINIWEATHER_INLINE_FUNCTION
271
+ r_t_pair hydro_const_theta (double z) {
272
+ const double theta0 = 300 .; // Background potential temperature
273
+ const double exner0 = 1 .; // Surface-level Exner pressure
274
+ double p,exner,rt;
275
+ // Establish hydrostatic balance first using Exner pressure
276
+ double t = theta0; // Potential Temperature at z
277
+ exner = exner0 - grav * z / (cp * theta0); // Exner pressure at z
278
+ p = p0 * pow (exner,(cp/rd)); // Pressure at z
279
+ rt = pow ((p / C0),(1 . / gamm)); // rho*theta at z
280
+ double r = rt / t; // Density at z
281
+
282
+ return {r, t};
283
+ }
284
+
285
+ // Establish hydrostatic balance using constant Brunt-Vaisala frequency
286
+ // z is the input coordinate
287
+ // bv_freq0 is the constant Brunt-Vaisala frequency
288
+ // r and t are the output background hydrostatic density and potential temperature
289
+ MINIWEATHER_INLINE_FUNCTION
290
+ r_t_pair hydro_const_bvfreq (double z, double bv_freq0) {
291
+ const double theta0 = 300 .; // Background potential temperature
292
+ const double exner0 = 1 .; // Surface-level Exner pressure
293
+ double p, exner, rt;
294
+ double t = theta0 * exp ( bv_freq0*bv_freq0 / grav * z ); // Pot temp at z
295
+ exner = exner0 - grav*grav / (cp * bv_freq0*bv_freq0) * (t - theta0) / (t * theta0); // Exner pressure at z
296
+ p = p0 * pow (exner,(cp/rd)); // Pressure at z
297
+ rt = pow ((p / C0), (1 . / gamm)); // rho*theta at z
298
+ double r = rt / t; // Density at z
299
+
300
+ return {r, t};
301
+ }
302
+
303
+ // Sample from an ellipse of a specified center, radius, and amplitude at a specified location
304
+ // x and z are input coordinates
305
+ // amp,x0,z0,xrad,zrad are input amplitude, center, and radius of the ellipse
306
+ MINIWEATHER_INLINE_FUNCTION
307
+ double sample_ellipse_cosine ( double x , double z , double amp , double x0 , double z0 , double xrad , double zrad ) {
308
+ double dist;
309
+ // Compute distance from bubble center
310
+ dist = sqrt ( ((x-x0)/xrad)*((x-x0)/xrad) + ((z-z0)/zrad)*((z-z0)/zrad) ) * pi / 2.0 ;
311
+ // If the distance from bubble center is less than the radius, create a cos**2 profile
312
+ if (dist <= pi / 2.0 ) {
313
+ return amp * pow (cos (dist), 2.0 );
314
+ } else {
315
+ return 0 .;
316
+ }
317
+ }
318
+
254
319
struct test_case {
255
320
double r;
256
321
double u;
@@ -265,43 +330,71 @@ struct test_case {
265
330
// hr and ht are output background hydrostatic density and potential temperature at that location.
266
331
267
332
// This test case is initially balanced but injects fast, cold air from the left boundary near the model top
268
- test_case injection (double x, double z);
333
+ MINIWEATHER_INLINE_FUNCTION
334
+ test_case injection (double x , double z) {
335
+ auto [hr, ht] = hydro_const_theta (z);
336
+ double r = 0.0 ;
337
+ double t = 0.0 ;
338
+ double u = 0.0 ;
339
+ double w = 0.0 ;
340
+ return {r, u, w, t, hr, ht};
341
+ }
269
342
270
343
// Initialize a density current (falling cold thermal that propagates along the model bottom)
271
- test_case density_current (double x, double z);
272
-
273
- test_case gravity_waves (double x, double z);
344
+ MINIWEATHER_INLINE_FUNCTION
345
+ test_case density_current (double x , double z) {
346
+ auto [hr, ht] = hydro_const_theta (z);
347
+ double r = 0.0 ;
348
+ double t = sample_ellipse_cosine (x, z, -20.0 , xlen/2 , 5000.0 , 4000.0 , 2000.0 );
349
+ double u = 0.0 ;
350
+ double w = 0.0 ;
351
+ return {r, u, w, t, hr, ht};
352
+ }
353
+
354
+ MINIWEATHER_INLINE_FUNCTION
355
+ test_case gravity_waves (double x, double z) {
356
+ auto [hr, ht] = hydro_const_bvfreq (z, 0.02 );
357
+ double r = 0.0 ;
358
+ double t = 0.0 ;
359
+ double u = 15.0 ;
360
+ double w = 0.0 ;
361
+ return {r, u, w, t, hr, ht};
362
+ }
274
363
275
364
// Rising thermal
276
- test_case thermal (double x, double z);
365
+ MINIWEATHER_INLINE_FUNCTION
366
+ test_case thermal (double x, double z) {
367
+ auto [hr, ht] = hydro_const_theta (z);
368
+ double r = 0.0 ;
369
+ double t = sample_ellipse_cosine (x, z, 3.0 , xlen/2 ,2000.0 , 2000.0 , 2000.0 );
370
+ double u = 0.0 ;
371
+ double w = 0.0 ;
372
+ return {r, u, w, t, hr, ht};
373
+ }
277
374
278
375
// Colliding thermals
279
- test_case collision (double x, double z);
280
-
281
- test_case get_test_case (int data_spec, double x_, double z_);
282
-
283
- struct r_t_pair {
284
- double r;
285
- double t;
286
- };
287
-
288
- // Establish hydrostatic balance using constant potential temperature
289
- // (thermally neutral atmosphere)
290
- // z is the input coordinate
291
- // r and t are the output background hydrostatic density and potential temperature
292
- r_t_pair hydro_const_theta (double z);
293
-
294
- // Establish hydrostatic balance using constant Brunt-Vaisala frequency
295
- // z is the input coordinate
296
- // bv_freq0 is the constant Brunt-Vaisala frequency
297
- // r and t are the output background hydrostatic density and potential temperature
298
- r_t_pair hydro_const_bvfreq (double z, double bv_freq0);
299
-
300
- // Sample from an ellipse of a specified center, radius, and amplitude at a specified location
301
- // x and z are input coordinates
302
- // amp,x0,z0,xrad,zrad are input amplitude, center, and radius of the ellipse
303
- double sample_ellipse_cosine (double x, double z, double amp, double x0, double z0,
304
- double xrad, double zrad);
376
+ MINIWEATHER_INLINE_FUNCTION
377
+ test_case collision (double x , double z) {
378
+ auto [hr, ht] = hydro_const_theta (z);
379
+ double r = 0.0 ;
380
+ double t = 0.0 ;
381
+ double u = 0.0 ;
382
+ double w = 0.0 ;
383
+ t = t + sample_ellipse_cosine (x, z, 20.0 , xlen/2 ,2000.0 , 2000.0 , 2000.0 );
384
+ t = t + sample_ellipse_cosine (x, z, -20.0 , xlen/2 ,8000.0 , 2000.0 , 2000.0 );
385
+ return {r, u, w, t, hr, ht};
386
+ }
387
+
388
+ MINIWEATHER_INLINE_FUNCTION
389
+ test_case get_test_case (int data_spec, double x, double z) {
390
+ if (data_spec == DATA_SPEC_COLLISION ) { return collision (x, z); }
391
+ if (data_spec == DATA_SPEC_THERMAL ) { return thermal (x, z); }
392
+ if (data_spec == DATA_SPEC_GRAVITY_WAVES ) { return gravity_waves (x, z); }
393
+ if (data_spec == DATA_SPEC_DENSITY_CURRENT) { return density_current (x, z); }
394
+ if (data_spec == DATA_SPEC_INJECTION ) { return injection (x, z); }
395
+ assert (false );
396
+ return test_case{};
397
+ }
305
398
306
399
struct reduction_result {
307
400
double mass;
0 commit comments