37#include <Kokkos_Core.hpp>
57const char* geomName(
int g) {
58 return g == 0 ?
"periodic" :
"wallz";
62void writeMatrix(
const std::string& path,
const std::vector<double>& a,
long n) {
63 FILE*
f = std::fopen(
path.c_str(),
"wb");
65 std::fprintf(stderr,
"mg_dense_precond: cannot open %s for writing\n",
path.c_str());
68 const std::int64_t
hdr[3] = {0x50434D47444E5331LL,
n,
n};
69 std::fwrite(hdr,
sizeof(std::int64_t), 3, f);
70 std::fwrite(
a.data(),
sizeof(
double), (
size_t)n * (
size_t)n, f);
75void run(
const Config& cfg,
const std::string& outdir) {
76 const int nx = cfg.n,
ny = cfg.n, nz = cfg.n;
77 const int G = CutcellMG::G;
78 const C3 ext{nx + 2 *
G,
ny + 2 *
G, nz + 2 *
G};
79 const long sy = ext.x, sz = (long)ext.x * ext.y;
80 const long next = (long)ext.x * ext.y * ext.z;
81 const long n = (long)nx * ny * nz;
84 mg.init(nx, ny, nz, cfg.levels);
85 int bc[6] = {0, 0, 0, 0, 0, 0};
90 mg.setBoundaryConditions(bc);
95 std::vector<double>
rho((
size_t)next, 1.0);
96 for (
int z = 0;
z < ext.z; ++
z) {
98 int zi = ((
z -
G) % nz + nz) % nz;
99 const double r = (zi >= nz / 2) ? cfg.ratio : 1.0;
100 for (
int y = 0;
y < ext.y; ++
y)
101 for (
int x = 0;
x < ext.x; ++
x)
102 rho[(
size_t)(
x + (long)y * sy + (
long)
z * sz)] = r;
104 std::vector<double> hcx((
size_t)next, 0.0), hcy((
size_t)next, 0.0), hcz((
size_t)next, 0.0);
105 for (
int z =
G;
z < ext.z -
G; ++
z)
106 for (
int y =
G;
y < ext.y -
G; ++
y)
107 for (
int x =
G;
x < ext.x -
G; ++
x) {
108 const long i =
x + (long)y * sy + (
long)
z * sz;
109 hcx[(size_t)i] = 1.0 / (0.5 * (rho[(
size_t)
i] +
rho[(size_t)(i - 1)]));
110 hcy[(size_t)i] = 1.0 / (0.5 * (rho[(
size_t)i] + rho[(
size_t)(i - sy)]));
111 hcz[(size_t)i] = 1.0 / (0.5 * (rho[(
size_t)
i] +
rho[(size_t)(i - sz)]));
113 CCField cx(
"cx", next), cy(
"cy", next), cz(
"cz", next);
114 auto hx = Kokkos::create_mirror_view(cx), hy = Kokkos::create_mirror_view(cy),
115 hz = Kokkos::create_mirror_view(cz);
116 for (
long i = 0;
i < next; ++
i) {
117 hx(i) = hcx[(size_t)i];
118 hy(i) = hcy[(size_t)i];
119 hz(i) = hcz[(size_t)i];
121 Kokkos::deep_copy(cx, hx);
122 Kokkos::deep_copy(cy, hy);
123 Kokkos::deep_copy(cz, hz);
126 CutcellMG::Level& l0 = mg.level(0);
132 CCField s0(
"s0", next),
s1(
"s1", next),
s2(
"s2", next),
s3(
"s3", next),
s4(
"s4", next);
133 mg.solvePCG(s0, s1, s2, s3, s4, y, 0, 1e-8, 2, 2, 12);
135 auto hv = Kokkos::create_mirror_view(v), hy2 = Kokkos::create_mirror_view(y);
137 std::vector<long> idx((
size_t)n);
138 for (
int k = 0;
k < nz; ++
k)
139 for (
int j = 0;
j <
ny; ++
j)
140 for (
int i = 0;
i < nx; ++
i)
141 idx[(
size_t)(
i + (long)j * nx + (
long)
k * nx *
ny)] =
142 (i +
G) + (long)(j +
G) * sy + (long)(k +
G) * sz;
144 std::vector<double>
A((
size_t)n * (
size_t)n, 0.0),
M((
size_t)n * (
size_t)n, 0.0);
147 for (
long c = 0;
c <
n; ++
c) {
148 Kokkos::deep_copy(hv, 0.0);
149 hv(idx[(
size_t)c]) = 1.0;
150 Kokkos::deep_copy(v, hv);
151 mg.matvecOverlap(l0, y, v);
152 Kokkos::deep_copy(hy2, y);
153 for (
long r = 0;
r <
n; ++
r)
154 A[(
size_t)
r * (size_t)n + (
size_t)
c] = hy2(idx[(
size_t)r]);
160 for (
long c = 0;
c <
n; ++
c) {
161 Kokkos::deep_copy(hv, 0.0);
162 hv(idx[(
size_t)c]) = 1.0;
163 Kokkos::deep_copy(v, hv);
164 mg.removeMean(l0, v);
165 Kokkos::deep_copy(l0.rhs, v);
166 Kokkos::deep_copy(l0.x, 0.0);
168 Kokkos::deep_copy(hy2, l0.x);
169 for (
long r = 0;
r <
n; ++
r)
170 M[(
size_t)
r * (size_t)n + (
size_t)
c] = hy2(idx[(
size_t)r]);
178 double rowsumAbs = 0, rowsumRelMax = 0, rowsumRelMin = 0;
179 for (
long r = 0;
r <
n; ++
r) {
180 double s = 0,
mx = 0, mn = 1e300;
181 for (
long c = 0;
c <
n; ++
c) {
182 const double a =
A[(size_t)r * (
size_t)
n + (size_t)c];
184 if (c != r && a != 0.0) {
185 mx = std::fmax(mx, std::fabs(a));
186 mn = std::fmin(mn, std::fabs(a));
191 rowsumAbs = std::fmax(rowsumAbs, std::fabs(s));
192 rowsumRelMax = std::fmax(rowsumRelMax, std::fabs(s) / mx);
193 rowsumRelMin = std::fmax(rowsumRelMin, std::fabs(s) / mn);
197 double fs = 0, fa = 0;
198 for (
long r = 0;
r <
n; ++
r)
199 for (
long c = 0;
c <
n; ++
c) {
200 const double m =
M[(size_t)r * (
size_t)
n + (size_t)c],
201 t = M[(
size_t)
c * (size_t)n + (
size_t)
r];
203 fs += (
m -
t) * (m - t);
205 const double skew = std::sqrt(fs) / std::sqrt(fa + 1e-300);
207#ifdef PECLET_FLOW_OPERATOR_DOUBLE
208 const char* prec =
"double";
210 const char* prec =
"float";
213 "%-8s %-8s ratio %-9.3g skew %.4e A*1 defect: abs %.3e /max|a| %.3e /min|a| %.3e\n",
214 prec, geomName(cfg.geom), cfg.ratio, skew, rowsumAbs, rowsumRelMax, rowsumRelMin);
217 if (!outdir.empty()) {
219 std::snprintf(tag,
sizeof(tag),
"%s/M_%s_%s_n%d_L%d_r%.0e.bin", outdir.c_str(), prec,
220 geomName(cfg.geom), cfg.n, cfg.levels, cfg.ratio);
221 writeMatrix(tag, M, n);
222 std::snprintf(tag,
sizeof(tag),
"%s/A_%s_%s_n%d_L%d_r%.0e.bin", outdir.c_str(), prec,
223 geomName(cfg.geom), cfg.n, cfg.levels, cfg.ratio);
224 writeMatrix(tag, A, n);
230int main(
int argc,
char** argv) {
234 for (
int i = 1; i < argc; ++i) {
235 const std::string a = argv[i];
236 auto next = [&]() {
return (i + 1 < argc) ? argv[++i] : (
char*)
"0"; };
238 cfg.n = std::atoi(next());
239 else if (a ==
"--levels")
240 cfg.levels = std::atoi(next());
241 else if (a ==
"--geom")
242 cfg.geom = std::strcmp(next(),
"periodic") == 0 ? 0 : 1;
243 else if (a ==
"--ratio")
244 cfg.
ratio = std::atof(next());
245 else if (a ==
"--outdir")
247 else if (a ==
"--sweep")
250 Kokkos::initialize(argc, argv);
253 const double ratios[] = {1.0, 1e2, 1e3, 1e4, 1e5, 1e6};
254 for (
int g = 0; g < 2; ++g)
255 for (
double r : ratios) {
flow — portable (Kokkos) geometric multigrid for the cut-cell (variable-openness) pressure Poisson.
Kokkos::View< double *, CCMem > CCField
Kokkos::View< const double *, CCMem > CCConst