Skip to content

Commit 58bb3bc

Browse files
authored
Merge pull request #362 from mwarusz/lauritzen_et_al_2012
Lauritzen et al 2012 test (do not merge yet)
2 parents 02e9199 + 9334018 commit 58bb3bc

File tree

10 files changed

+496
-0
lines changed

10 files changed

+496
-0
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
if(APPLE)
2+
# needed for the XCode clang to be identified as AppleClang and not Clang
3+
cmake_minimum_required(VERSION 3.0)
4+
else()
5+
# needed for the OpenMP test to work in C++-only project
6+
# (see http://public.kitware.com/Bug/view.php?id=11910)
7+
cmake_minimum_required(VERSION 2.8.8)
8+
endif()
9+
10+
project(libmpdata++-tests-lauritzen_et_al_2012 CXX)
11+
12+
include(${CMAKE_SOURCE_DIR}/../../libmpdata++-config.cmake)
13+
if(NOT libmpdataxx_FOUND)
14+
message(FATAL_ERROR "local libmpdata++-config.cmake not found!")
15+
endif()
16+
17+
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
18+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${libmpdataxx_CXX_FLAGS_RELEASE}")
19+
set(CMAKE_CXX_FLAGS_RELEASE "")
20+
else()
21+
set(CMAKE_CXX_FLAGS_DEBUG ${libmpdataxx_CXX_FLAGS_DEBUG})
22+
endif()
23+
24+
# to make <libmpdata++/...> work
25+
set(CMAKE_CXX_FLAGS "-I${CMAKE_CURRENT_SOURCE_DIR}/../.. ${CMAKE_CXX_FLAGS}")
26+
27+
# macro to be used in the subdirectories
28+
function(libmpdataxx_add_test test)
29+
add_executable(${test} ${test}.cpp)
30+
target_link_libraries(${test} ${libmpdataxx_LIBRARIES})
31+
target_include_directories(${test} PUBLIC ${libmpdataxx_INCLUDE_DIRS})
32+
add_test(${test} ${test})
33+
endfunction()
34+
35+
enable_testing()
36+
37+
libmpdataxx_add_test(gmd_2012)
38+
39+
add_test(gmd_2012_stats_and_plots bash -c "
40+
for i in nug_i2_120 nug_i2_240 nug_iga_fct_i2_120 nug_iga_fct_i2_240; do
41+
python ${CMAKE_CURRENT_SOURCE_DIR}/stats_and_plots.py $i;
42+
done
43+
")
44+
45+
add_test(gmd_2012_stats_diff bash -c "
46+
for i in nug_i2_120 nug_i2_240 nug_iga_fct_i2_120 nug_iga_fct_i2_240; do
47+
echo ${CMAKE_CURRENT_SOURCE_DIR}/stats_$i.txt.gz;
48+
echo ${CMAKE_CURRENT_BINARY_DIR}/stats_$i.txt;
49+
zdiff ${CMAKE_CURRENT_SOURCE_DIR}/refdata/stats_$i.txt.gz ${CMAKE_CURRENT_BINARY_DIR}/stats_$i.txt || exit 1;
50+
done
51+
")
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import numpy as np
2+
import matplotlib
3+
matplotlib.use('Pdf')
4+
import matplotlib.pyplot as plt
5+
6+
def calc_filament_diags(g, field_data):
7+
taus = np.linspace(0.10, 1.0, 19)
8+
lfs = []
9+
eps = 1e-12
10+
for tau in taus:
11+
area_0 = np.sum(g[field_data['cb']['initial'] >= tau - eps])
12+
area_h = np.sum(g[field_data['cb']['halfway'] >= tau - eps])
13+
if area_0 < eps:
14+
lf = 0
15+
else:
16+
lf = 100 * area_h / area_0
17+
lfs.append(lf)
18+
return list(zip(taus, lfs))
19+
20+
def plot_filament_diags(dirname, filament_diags, deg):
21+
plt.clf()
22+
taus, lfs = zip(*filament_diags)
23+
plt.plot(taus, lfs, 'ks-', lw = 2, ms = 8)
24+
fs = 22
25+
plt.xlabel(r'$\tau$', fontsize = fs)
26+
plt.ylabel(r'$l_f(\tau, T / 2)$', fontsize = fs)
27+
plt.ylim([0, 140])
28+
plt.title('filament preservation diagnostics at ${}\\degree$'.format(deg), fontsize = fs)
29+
plt.grid()
30+
plt.savefig('filaments_' + dirname + '.pdf')
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
/*
2+
* @file
3+
* @copyright University of Warsaw
4+
* @section LICENSE
5+
* GPLv3+ (see the COPYING file or http://www.gnu.org/licenses/)
6+
*/
7+
8+
#include <cmath>
9+
#include <boost/math/constants/constants.hpp>
10+
11+
#include <libmpdata++/solvers/mpdata.hpp>
12+
#include <libmpdata++/concurr/threads.hpp>
13+
#include <libmpdata++/output/hdf5_xdmf.hpp>
14+
15+
#include "gmd_2012.hpp"
16+
17+
using namespace libmpdataxx;
18+
19+
struct ct_test_params_t
20+
{
21+
// choosing non-dimensional sphere radius and evolution period
22+
static constexpr ::T
23+
R = 1,
24+
T = 5;
25+
};
26+
// to make refering to compile time test params easier
27+
using tp = ct_test_params_t;
28+
29+
// gaussian hills initial condition
30+
struct gauss_t
31+
{
32+
T x0, y0;
33+
static constexpr T b = 5, hmax = 0.95;
34+
T xc(const T x, const T y) const { return tp::R * std::cos(y) * std::cos(x); }
35+
T yc(const T x, const T y) const { return tp::R * std::cos(y) * std::sin(x); }
36+
T zc(const T x, const T y) const { return tp::R * std::sin(y); }
37+
38+
T operator()(const T x, const T y) const
39+
{
40+
return hmax * std::exp(-b * ( std::pow(xc(x, y) - xc(x0, y0), 2)
41+
+ std::pow(yc(x, y) - yc(x0, y0), 2)
42+
+ std::pow(zc(x, y) - zc(x0, y0), 2)));
43+
}
44+
BZ_DECLARE_FUNCTOR2(gauss_t);
45+
};
46+
47+
// cosine bells initial condition
48+
struct bells_t
49+
{
50+
T x0, y0;
51+
static constexpr T r = tp::R / 2, hmax = 1.0, c = 0.9;
52+
T operator()(const T x, const T y) const
53+
{
54+
T ri = tp::R * std::acos(std::sin(y0) * std::sin(y) + std::cos(y0) * std::cos(y) * std::cos(x - x0));
55+
return ri < r ? c * hmax / 2 * (1 + std::cos(pi * ri / r)) : 0;
56+
}
57+
BZ_DECLARE_FUNCTOR2(bells_t);
58+
};
59+
60+
// slotted cylinders initial condition
61+
struct scyls_t
62+
{
63+
T x0, y0;
64+
bool flip;
65+
static constexpr T r = tp::R / 2, c = 1.0;
66+
T operator()(const T x, const T y) const
67+
{
68+
T ri = tp::R * std::acos(std::sin(y0) * std::sin(y) + std::cos(y0) * std::cos(y) * std::cos(x - x0));
69+
bool cond1 = ri < r && std::abs(x - x0) >= r / (6 * tp::R);
70+
bool cond2 = flip ? (y - y0) < -5. / 12 * r / tp::R : (y - y0) > 5. / 12 * r / tp::R;
71+
bool cond3 = ri < r && (std::abs(x - x0) < r / (6 * tp::R) && cond2);
72+
73+
return cond1 || cond3 ? c : 0;
74+
}
75+
BZ_DECLARE_FUNCTOR2(scyls_t);
76+
};
77+
78+
template <bool var_dt_arg, int opts_arg, int opts_iters>
79+
void test(const std::string &base_name, const int ny, const T max_cfl)
80+
{
81+
auto dir_name = base_name + "_" + std::to_string(ny);
82+
std::cout << "Calculating: " << dir_name << std::endl;
83+
84+
struct ct_params_t : ct_params_default_t
85+
{
86+
using real_t = double;
87+
enum { var_dt = var_dt_arg };
88+
enum { n_dims = 2 };
89+
enum { n_eqns = 4 };
90+
enum { opts = opts_arg };
91+
};
92+
93+
94+
const int nx = 2 * ny + 1;
95+
const T dx = 2 * pi / (nx - 1), dy = pi / ny;
96+
const T time = tp::T;
97+
const T dt = dx / (48 * 2 * pi);
98+
const int nt = time / dt;
99+
100+
using slv_out_t =
101+
output::hdf5_xdmf<
102+
gmd_2012<ct_params_t, ct_test_params_t>
103+
>;
104+
typename slv_out_t::rt_params_t p;
105+
106+
p.n_iters = opts_iters;
107+
p.grid_size = {nx, ny};
108+
p.dt = dt;
109+
p.di = dx;
110+
p.dj = dy;
111+
p.max_courant = max_cfl;
112+
113+
p.outfreq = var_dt_arg ? tp::T / 2 : nt / 2;
114+
p.outvars[0].name = "gh";
115+
p.outvars[1].name = "cb";
116+
p.outvars[2].name = "sc";
117+
p.outvars[3].name = "ccb";
118+
p.outdir = dir_name;
119+
120+
concurr::threads<
121+
slv_out_t,
122+
bcond::cyclic, bcond::cyclic,
123+
bcond::polar, bcond::polar
124+
> run(p);
125+
126+
blitz::firstIndex i;
127+
blitz::secondIndex j;
128+
129+
// coordinates
130+
decltype(run.advectee()) X(run.advectee().extent()), Y(run.advectee().extent());
131+
X = i * dx;
132+
Y = (j + 0.5) * dy - pi / 2;
133+
134+
std::array<T, 2> x0s = {5 * pi / 6, 7 * pi / 6};
135+
std::array<T, 2> y0s = {0, 0};
136+
137+
// initial conditions
138+
const T b = 0.1;
139+
run.advectee(0) = 0;
140+
run.advectee(1) = b;
141+
run.advectee(2) = b;
142+
143+
for (int m = 0; m < 2; ++m)
144+
{
145+
run.advectee(0) += gauss_t{x0s[m], y0s[m]}(X, Y);
146+
run.advectee(1) += bells_t{x0s[m], y0s[m]}(X, Y);
147+
run.advectee(2) += scyls_t{x0s[m], y0s[m], m > 0}(X, Y);
148+
}
149+
run.advectee(3) = -0.8 * blitz::pow(run.advectee(1), 2) + 0.9;
150+
run.g_factor() = tp::R * blitz::cos(Y) * dx * dy;
151+
152+
// to avoid divergence check
153+
run.advector(0) = 0;
154+
run.advector(1) = 0;
155+
156+
// integration
157+
run.advance(var_dt_arg ? time : nt);
158+
}
159+
160+
int main()
161+
{
162+
const bool var_dt = true;
163+
const T max_cfl = 0.90;
164+
165+
std::vector<int> nys = {120, 240};
166+
{
167+
enum { opts = opts::nug};
168+
const int opts_iters = 2;
169+
for (const auto ny : nys) test<var_dt, opts, opts_iters>("nug_i2", ny, max_cfl);
170+
}
171+
172+
{
173+
enum { opts = opts::nug | opts::iga | opts::fct};
174+
const int opts_iters = 2;
175+
for (const auto ny : nys) test<var_dt, opts, opts_iters>("nug_iga_fct_i2", ny, max_cfl);
176+
}
177+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/**
2+
* @file
3+
* @copyright University of Warsaw
4+
* @section LICENSE
5+
* GPLv3+ (see the COPYING file or http://www.gnu.org/licenses/)
6+
*/
7+
8+
#pragma once
9+
#include <libmpdata++/solvers/mpdata.hpp>
10+
11+
using T = double;
12+
constexpr T pi = boost::math::constants::pi<T>();
13+
14+
template <class ct_params_t, class ct_test_params_t>
15+
class gmd_2012 : public libmpdataxx::solvers::mpdata<ct_params_t>
16+
{
17+
using parent_t = libmpdataxx::solvers::mpdata<ct_params_t>;
18+
using parent_t::parent_t;
19+
20+
public:
21+
22+
using real_t = typename ct_params_t::real_t;
23+
24+
protected:
25+
26+
using tp = ct_test_params_t;
27+
28+
libmpdataxx::arrvec_t<typename parent_t::arr_t> &gc_node;
29+
30+
std::pair<real_t, real_t> gc_exact(const real_t t, const real_t x, const real_t y)
31+
{
32+
const auto xp = x - 2 * pi * t / tp::T;
33+
34+
return {
35+
( 10 * tp::R / tp::T * std::pow(std::sin(xp), 2) * std::sin(2 * y) * std::cos(pi * t / tp::T)
36+
+ 2 * pi * tp::R / tp::T * std::cos(y)
37+
) * this->dj * this->dt
38+
,
39+
( 10 * tp::R / tp::T * std::sin(2 * xp) * std::pow(std::cos(y), 2) * std::cos(pi * t / tp::T)
40+
) * this->di * this->dt
41+
};
42+
}
43+
44+
bool calc_gc() final
45+
{
46+
using namespace libmpdataxx::arakawa_c;
47+
const auto t = this->time + 0.5 * this->dt;
48+
49+
// calculate exact advectors at grid points
50+
for (int i = this->i.first(); i <= this->i.last(); ++i)
51+
{
52+
for (int j = this->j.first(); j <= this->j.last(); ++j)
53+
{
54+
const auto x = i * this->di;
55+
const auto y = (j+ 0.5) * this->dj - pi / 2;
56+
57+
auto gc_ij = gc_exact(t, x, y);
58+
59+
gc_node[0](i, j) = gc_ij.first;
60+
gc_node[1](i, j) = gc_ij.second;
61+
}
62+
}
63+
64+
this->xchng_sclr(gc_node[0], this->i, this->j);
65+
this->xchng_sclr(gc_node[1], this->i, this->j);
66+
67+
// calculate staggered advectors
68+
for (int i = this->i.first()-1; i <= this->i.last(); ++i)
69+
{
70+
for (int j = this->j.first()-1; j <= this->j.last(); ++j)
71+
{
72+
this->mem->GC[0](i+h, j) = 0.5 * (gc_node[0](i, j) + gc_node[0](i+1, j));
73+
this->mem->GC[1](i, j+h) = 0.5 * (gc_node[1](i, j) + gc_node[1](i, j+1));
74+
}
75+
}
76+
77+
auto ex = this->halo - 1;
78+
this->xchng_vctr_nrml(this->mem->GC, this->i^ex, this->j^ex);
79+
80+
return true;
81+
}
82+
83+
public:
84+
85+
// ctor
86+
gmd_2012(
87+
typename parent_t::ctor_args_t args,
88+
const typename parent_t::rt_params_t &p
89+
) :
90+
parent_t(args, p),
91+
gc_node(args.mem->tmp[__FILE__][0])
92+
{}
93+
94+
static void alloc(
95+
typename parent_t::mem_t *mem,
96+
const int &n_iters
97+
) {
98+
parent_t::alloc(mem, n_iters);
99+
parent_t::alloc_tmp_sclr(mem, __FILE__, 2); // gc_node
100+
}
101+
};

0 commit comments

Comments
 (0)