DDC 0.14.0
Loading...
Searching...
No Matches
examples/non_uniform_heat_equation.cpp
1// Copyright (C) The DDC development team, see COPYRIGHT.md file
2//
3// SPDX-License-Identifier: MIT
4
6#include <algorithm>
7#include <cassert>
8#include <cmath>
9#include <cstddef>
10#include <iomanip>
11#include <iostream>
12#include <iterator>
13#include <random>
14#include <string>
15#include <tuple>
16#include <utility>
17#include <vector>
18
19#include <ddc/ddc.hpp>
20
21#include <Kokkos_Core.hpp>
23
25std::vector<double> generate_random_vector(int n, double lower_bound, double higher_bound)
26{
27 assert(n > 1);
28 assert(lower_bound < higher_bound);
29
30 std::random_device rd;
31 std::mt19937 gen(rd());
32 // p represents the fraction of displacement
33 // it should be less than 0.5 to avoid reordering of nodes
34 double const p = 0.1;
35 std::uniform_real_distribution<double> dis(-p, +p);
36
37 double const dx = (higher_bound - lower_bound) / (n - 1);
38
39 std::vector<double> points(n);
40
41 // Generate a uniform mesh
42 for (int i = 0; i < n; ++i) {
43 points[i] = lower_bound + i * dx;
44 }
45 // Add a random perturbation
46 for (int i = 1; i < n - 1; ++i) {
47 points[i] += dis(gen) * dx;
48 }
49
50 assert(std::is_sorted(points.begin(), points.end()));
51
52 return points;
53}
55
56std::vector<double> periodic_extrapolation_left(int gw, std::vector<double> const& points)
57{
58 assert(gw >= 0);
59 assert(points.size() > gw);
60 assert(std::is_sorted(points.begin(), points.end()));
61
62 std::vector<double> ghost(gw);
63 if (gw > 0) {
64 double const period = points.back() - points.front();
65 auto const it = std::next(points.crbegin());
66 std::transform(it, std::next(it, gw), ghost.rbegin(), [period](double pos) {
67 return pos - period;
68 });
69 }
70
71 return ghost;
72}
73
74std::vector<double> periodic_extrapolation_right(int gw, std::vector<double> const& points)
75{
76 assert(gw >= 0);
77 assert(points.size() > gw);
78 assert(std::is_sorted(points.begin(), points.end()));
79
80 std::vector<double> ghost(gw);
81 if (gw > 0) {
82 double const period = points.back() - points.front();
83 auto const it = std::next(points.cbegin());
84 std::transform(it, std::next(it, gw), ghost.begin(), [period](double pos) {
85 return pos + period;
86 });
87 }
88
89 return ghost;
90}
91
93struct X
94{
95};
97
99struct DDimX : ddc::NonUniformPointSampling<X>
100{
101};
103
105struct Y
106{
107};
108struct DDimY : ddc::NonUniformPointSampling<Y>
109{
110};
112
114struct T
115{
116};
117struct DDimT : ddc::UniformPointSampling<T>
118{
119};
121
129template <class ChunkType>
130void display(double time, ChunkType temp)
131{
132 double const mean_temp
133 = ddc::host_transform_reduce(temp.domain(), 0., ddc::reducer::sum<double>(), temp)
134 / temp.domain().size();
135 std::cout << std::fixed << std::setprecision(3);
136 std::cout << "At t = " << time << ",\n";
137 std::cout << " * mean temperature = " << mean_temp << "\n";
138 ddc::ChunkSpan const temp_slice
139 = temp[ddc::get_domain<DDimY>(temp).front() + ddc::get_domain<DDimY>(temp).size() / 2];
140 std::cout << " * temperature[y:" << ddc::get_domain<DDimY>(temp).size() / 2 << "] = {";
142 std::cout << std::setw(6) << temp_slice(ix);
143 });
144 std::cout << " }\n" << std::flush;
145}
147
148int main(int argc, char** argv)
149{
150 Kokkos::ScopeGuard const kokkos_scope(argc, argv);
151 ddc::ScopeGuard const ddc_scope(argc, argv);
152
155 double const x_start = -1.;
156 double const x_end = 1.;
157 std::size_t const nb_x_points = 10;
158 double const kx = .01;
161 double const y_start = -1.;
162 double const y_end = 1.;
163 std::size_t const nb_y_points = 100;
164 double const ky = .002;
167 double const start_time = 0.;
168 double const end_time = 10.;
170 std::ptrdiff_t const t_output_period = 10;
172
174 std::vector<double> const x_domain_vect = generate_random_vector(nb_x_points, x_start, x_end);
176
178 std::vector<double> const x_pre_ghost_vect = periodic_extrapolation_left(1, x_domain_vect);
179 std::vector<double> const x_post_ghost_vect = periodic_extrapolation_right(1, x_domain_vect);
181
183 auto const [x_domain, ghosted_x_domain, x_pre_ghost, x_post_ghost]
185 DDimX::init_ghosted<DDimX>(x_domain_vect, x_pre_ghost_vect, x_post_ghost_vect));
187
189 x_post_mirror(x_post_ghost.front() - x_domain.extents(), x_post_ghost.extents());
191 x_pre_mirror(x_pre_ghost.front() + x_domain.extents(), x_pre_ghost.extents());
192
194 std::vector<double> const y_domain_vect = generate_random_vector(nb_y_points, y_start, y_end);
195
197 std::vector<double> const y_pre_ghost_vect = periodic_extrapolation_left(1, y_domain_vect);
198 std::vector<double> const y_post_ghost_vect = periodic_extrapolation_right(1, y_domain_vect);
201
203 auto const [y_domain, ghosted_y_domain, y_pre_ghost, y_post_ghost]
205 DDimY::init_ghosted<DDimY>(y_domain_vect, y_pre_ghost_vect, y_post_ghost_vect));
207
209 y_post_mirror(y_post_ghost.front() - y_domain.extents(), y_post_ghost.extents());
210
212 y_pre_mirror(y_pre_ghost.front() + y_domain.extents(), y_pre_ghost.extents());
213
215 double const invdx2_max = ddc::host_transform_reduce(
216 x_domain,
217 0.,
220 return 1. / (ddc::distance_at_left(ix) * ddc::distance_at_right(ix));
221 });
222
223 double const invdy2_max = ddc::host_transform_reduce(
224 y_domain,
225 0.,
228 return 1. / (ddc::distance_at_left(iy) * ddc::distance_at_right(iy));
229 });
230
231 ddc::Coordinate<T> const max_dt(.5 / (kx * invdx2_max + ky * invdy2_max));
233
235 ddc::DiscreteVector<DDimT> const nb_time_steps(
236 std::ceil((end_time - start_time) / max_dt) + .2);
237
238 ddc::DiscreteDomain<DDimT> const time_domain
239 = ddc::init_discrete_space<DDimT>(DDimT::init<DDimT>(
240 ddc::Coordinate<T>(start_time),
241 ddc::Coordinate<T>(end_time),
242 nb_time_steps + 1));
244
246 ddc::Chunk ghosted_last_temp(
247 "ghosted_last_temp",
248 ddc::DiscreteDomain<DDimX, DDimY>(ghosted_x_domain, ghosted_y_domain),
250
251 ddc::Chunk ghosted_next_temp(
252 "ghosted_next_temp",
253 ddc::DiscreteDomain<DDimX, DDimY>(ghosted_x_domain, ghosted_y_domain),
256
258 ddc::ChunkSpan const ghosted_initial_temp = ghosted_last_temp.span_view();
260
263 ddc::DiscreteDomain<DDimX, DDimY>(x_domain, y_domain),
264 KOKKOS_LAMBDA(ddc::DiscreteElement<DDimX, DDimY> const ixy) {
265 double const x = ddc::coordinate(ddc::DiscreteElement<DDimX>(ixy));
266 double const y = ddc::coordinate(ddc::DiscreteElement<DDimY>(ixy));
267 ghosted_initial_temp(ixy) = 9.999 * ((x * x + y * y) < 0.25);
268 });
270
272 ddc::Chunk ghosted_temp = ddc::create_mirror(ghosted_last_temp.span_cview());
274
276 ddc::parallel_deepcopy(ghosted_temp, ghosted_last_temp);
278
280 display(ddc::coordinate(time_domain.front()), ghosted_temp[x_domain][y_domain]);
282
284 ddc::DiscreteElement<DDimT> last_output_iter = time_domain.front();
286
288 for (ddc::DiscreteElement<DDimT> const iter :
289 time_domain.remove_first(ddc::DiscreteVector<DDimT>(1))) {
291
293 for (ddc::DiscreteVectorElement ix = 0; ix < x_pre_ghost.extents().value(); ++ix) {
295 ghosted_last_temp[x_pre_ghost[ix]][y_domain],
296 ghosted_last_temp[x_pre_mirror[ix]][y_domain]);
297 }
298 for (ddc::DiscreteVectorElement ix = 0; ix < x_post_ghost.extents().value(); ++ix) {
300 ghosted_last_temp[x_post_ghost[ix]][y_domain],
301 ghosted_last_temp[x_post_mirror[ix]][y_domain]);
302 }
303 for (ddc::DiscreteVectorElement iy = 0; iy < y_pre_ghost.extents().value(); ++iy) {
305 ghosted_last_temp[x_domain][y_pre_ghost[iy]],
306 ghosted_last_temp[x_domain][y_pre_mirror[iy]]);
307 }
308 for (ddc::DiscreteVectorElement iy = 0; iy < y_post_ghost.extents().value(); ++iy) {
310 ghosted_last_temp[x_domain][y_post_ghost[iy]],
311 ghosted_last_temp[x_domain][y_post_mirror[iy]]);
312 }
314
316 ddc::ChunkSpan const next_temp(
317 ghosted_next_temp[ddc::DiscreteDomain<DDimX, DDimY>(x_domain, y_domain)]);
318 ddc::ChunkSpan const last_temp(ghosted_last_temp.span_cview());
320
323 next_temp.domain(),
324 KOKKOS_LAMBDA(ddc::DiscreteElement<DDimX, DDimY> const ixy) {
325 ddc::DiscreteElement<DDimX> const ix(ixy);
326 ddc::DiscreteElement<DDimY> const iy(ixy);
327 double const dx_l = ddc::distance_at_left(ix);
328 double const dx_r = ddc::distance_at_right(ix);
329 double const dx_m = 0.5 * (dx_l + dx_r);
330 double const dy_l = ddc::distance_at_left(iy);
331 double const dy_r = ddc::distance_at_right(iy);
332 double const dy_m = 0.5 * (dy_l + dy_r);
333 next_temp(ix, iy) = last_temp(ix, iy);
334 next_temp(ix, iy)
335 += kx * ddc::step<DDimT>()
336 * (dx_l * last_temp(ix + 1, iy) - 2.0 * dx_m * last_temp(ix, iy)
337 + dx_r * last_temp(ix - 1, iy))
338 / (dx_l * dx_m * dx_r);
339 next_temp(ix, iy)
340 += ky * ddc::step<DDimT>()
341 * (dy_l * last_temp(ix, iy + 1) - 2.0 * dy_m * last_temp(ix, iy)
342 + dy_r * last_temp(ix, iy - 1))
343 / (dy_l * dy_m * dy_r);
344 });
346
348 if (iter - last_output_iter >= t_output_period) {
349 last_output_iter = iter;
350 ddc::parallel_deepcopy(ghosted_temp, ghosted_next_temp);
351 display(ddc::coordinate(iter),
352 ghosted_temp[ddc::DiscreteDomain<DDimX, DDimY>(x_domain, y_domain)]);
353 }
355
357 std::swap(ghosted_last_temp, ghosted_next_temp);
359 }
360
362 if (last_output_iter < time_domain.back()) {
363 ddc::parallel_deepcopy(ghosted_temp, ghosted_last_temp);
364 display(ddc::coordinate(time_domain.back()),
365 ghosted_temp[ddc::DiscreteDomain<DDimX, DDimY>(x_domain, y_domain)]);
366 }
368}
KOKKOS_FUNCTION constexpr size_type size() const noexcept
KOKKOS_FUNCTION constexpr span_type span_view() const
KOKKOS_FUNCTION constexpr discrete_element_type front() const noexcept
KOKKOS_FUNCTION constexpr discrete_element_type back() const noexcept
A DiscreteElement identifies an element of the discrete dimension.
A DiscreteVector is a vector in the discrete dimension.
NonUniformPointSampling models a non-uniform discretization of the CDim segment .
UniformPointSampling models a uniform discretization of the provided continuous dimension.
The top-level namespace of DDC.
KOKKOS_FUNCTION Coordinate< typename DDim::continuous_dimension_type > distance_at_left(DiscreteElement< DDim > i)
auto parallel_deepcopy(ChunkDst &&dst, ChunkSrc &&src)
Copy the content of a borrowed chunk into another.
T host_transform_reduce(Support const &domain, T neutral, BinaryReductionOp &&reduce, UnaryTransformOp &&transform) noexcept
A reduction over a nD domain in serial.
KOKKOS_FUNCTION Coordinate< typename DDims::continuous_dimension_type... > coordinate(DiscreteElement< DDims... > const &c)
KOKKOS_FUNCTION Coordinate< typename DDim::continuous_dimension_type > distance_at_right(DiscreteElement< DDim > i)
void init_discrete_space(Args &&... args)
Initialize (emplace) a global singleton discrete space.
void host_for_each(Support const &domain, Functor &&f) noexcept
iterates over a nD domain in serial
Definition for_each.hpp:73
detail::TaggedVector< CoordinateElement, CDims... > Coordinate
A Coordinate represents a coordinate in the continuous space.
std::ptrdiff_t DiscreteVectorElement
A DiscreteVectorElement is a scalar that represents the difference between two coordinates.
void parallel_for_each(std::string const &label, ExecSpace const &execution_space, Support const &domain, Functor &&f) noexcept
iterates over a nD domain using a given Kokkos execution space
auto create_mirror(Space const &space, ChunkSpan< ElementType, Support, Layout, MemorySpace > const &src)