DDC 0.14.0
Loading...
Searching...
No Matches
examples/heat_equation_spectral.cpp
1// Copyright (C) The DDC development team, see COPYRIGHT.md file
2//
3// SPDX-License-Identifier: MIT
4
5#include <cmath>
6#include <cstddef>
7#include <iomanip>
8#include <iostream>
9#include <string>
10#include <utility>
11
12#include <ddc/ddc.hpp>
13#include <ddc/kernels/fft.hpp>
14
15#include <Kokkos_Core.hpp>
16
18struct X
19{
20};
21
23struct DDimX : ddc::UniformPointSampling<X>
24{
25};
26
27struct DDimFx : ddc::PeriodicSampling<ddc::Fourier<X>>
28{
29};
30
31// Our second continuous dimension
32struct Y
33{
34};
35// Its uniform discretization
36struct DDimY : ddc::UniformPointSampling<Y>
37{
38};
39
40struct DDimFy : ddc::PeriodicSampling<ddc::Fourier<Y>>
41{
42};
43
44// Our simulated time dimension
45struct T
46{
47};
48// Its uniform discretization
49struct DDimT : ddc::UniformPointSampling<T>
50{
51};
52
57template <class ChunkType>
58void display(double time, ChunkType temp)
59{
60 double const mean_temp
61 = ddc::host_transform_reduce(temp.domain(), 0., ddc::reducer::sum<double>(), temp)
62 / temp.domain().size();
63 std::cout << std::fixed << std::setprecision(3);
64 std::cout << "At t = " << time << ",\n";
65 std::cout << " * mean temperature = " << mean_temp << "\n";
66 // take a slice in the middle of the box
67 ddc::ChunkSpan const temp_slice
68 = temp[ddc::get_domain<DDimY>(temp).front() + ddc::get_domain<DDimY>(temp).size() / 2];
69 std::cout << " * temperature[y:" << ddc::get_domain<DDimY>(temp).size() / 2 << "] = {";
71 std::cout << std::setw(6) << temp_slice(ix);
72 });
73 std::cout << " }\n" << std::flush;
74}
75
76int main(int argc, char** argv)
77{
78 Kokkos::ScopeGuard const kokkos_scope(argc, argv);
79 ddc::ScopeGuard const ddc_scope(argc, argv);
80
81 // some parameters that would typically be read from some form of
82 // configuration file in a more realistic code
83
84 // Start of the domain of interest in the X dimension
85 double const x_start = -1.;
86 // End of the domain of interest in the X dimension
87 double const x_end = 1.;
88 // Number of discretization points in the X dimension
89 std::size_t const nb_x_points = 10;
90 // Thermal diffusion coefficient
91 double const kx = .01;
92 // Start of the domain of interest in the Y dimension
93 double const y_start = -1.;
94 // End of the domain of interest in the Y dimension
95 double const y_end = 1.;
96 // Number of discretization points in the Y dimension
97 std::size_t const nb_y_points = 100;
98 // Thermal diffusion coefficient
99 double const ky = .002;
100 // Simulated time at which to start simulation
101 double const start_time = 0.;
102 // Simulated time to reach as target of the simulation
103 double const end_time = 10.;
104 // Number of time-steps between outputs
105 std::ptrdiff_t const t_output_period = 10;
106
107 // Initialization of the global domain in X including periodic point to have correct step
108 auto const x_domain_with_periodic_point = ddc::init_discrete_space<DDimX>(DDimX::init<DDimX>(
109 ddc::Coordinate<X>(x_start),
110 ddc::Coordinate<X>(x_end),
111 ddc::DiscreteVector<DDimX>(nb_x_points)));
112 ddc::DiscreteDomain<DDimX> const x_domain
113 = x_domain_with_periodic_point.remove_last(ddc::DiscreteVector<DDimX>(1));
114
115 // Initialization of the global domain in Y including periodic point to have correct step
116 auto const y_domain_with_periodic_point = ddc::init_discrete_space<DDimY>(DDimY::init<DDimY>(
117 ddc::Coordinate<Y>(y_start),
118 ddc::Coordinate<Y>(y_end),
119 ddc::DiscreteVector<DDimY>(nb_y_points)));
120 ddc::DiscreteDomain<DDimY> const y_domain
121 = y_domain_with_periodic_point.remove_last(ddc::DiscreteVector<DDimY>(1));
122
123 double const max_rkx = Kokkos::numbers::pi / ddc::step<DDimX>();
124 double const max_rky = Kokkos::numbers::pi / ddc::step<DDimY>();
125 ddc::Coordinate<T> const dt(2. / (kx * max_rkx * max_rkx + ky * max_rky * max_rky));
126
127 // number of time intervals required to reach the end time
128 ddc::DiscreteVector<DDimT> const nb_time_steps(std::ceil((end_time - start_time) / dt) + .2);
129 // Initialization of the global domain in time:
130 // - the number of discrete time-points is equal to the number of
131 // steps + 1
132 ddc::DiscreteDomain<DDimT> const time_domain
133 = ddc::init_discrete_space<DDimT>(DDimT::init<DDimT>(
134 ddc::Coordinate<T>(start_time),
135 ddc::Coordinate<T>(end_time),
136 nb_time_steps + 1));
137
138 ddc::DiscreteDomain<DDimX, DDimY> const xy_domain(x_domain, y_domain);
139
140 // Maps temperature into the full domain (including ghosts) twice:
141 // - once for the last fully computed time-step
142 ddc::Chunk _last_temp("_last_temp", xy_domain, ddc::DeviceAllocator<double>());
143
144 // - once for time-step being computed
145 ddc::Chunk _next_temp("_next_temp", xy_domain, ddc::DeviceAllocator<double>());
146
147 ddc::ChunkSpan const initial_temp = _last_temp.span_view();
148 // Initialize the temperature on the main domain
150 xy_domain,
151 KOKKOS_LAMBDA(ddc::DiscreteElement<DDimX, DDimY> const ixy) {
152 double const x = ddc::coordinate(ddc::DiscreteElement<DDimX>(ixy));
153 double const y = ddc::coordinate(ddc::DiscreteElement<DDimY>(ixy));
154 initial_temp(ixy) = 9.999 * ((x * x + y * y) < 0.25);
155 });
156
157 ddc::Chunk _host_temp = ddc::create_mirror(_last_temp.span_cview());
158
159 // display the initial data
160 ddc::parallel_deepcopy(_host_temp, _last_temp);
161 display(ddc::coordinate(time_domain.front()), _host_temp.span_cview());
162 // time of the iteration where the last output happened
163 ddc::DiscreteElement<DDimT> last_output = time_domain.front();
164
167
169 = ddc::fourier_mesh<DDimFx, DDimFy>(xy_domain, false);
171 Ff_allocation("Ff_allocation", k_mesh, ddc::DeviceAllocator<Kokkos::complex<double>>());
172 ddc::ChunkSpan const Ff = Ff_allocation.span_view();
173
174 for (ddc::DiscreteElement<DDimT> const iter :
175 time_domain.remove_first(ddc::DiscreteVector<DDimT>(1))) {
176 // a span excluding ghosts of the temperature at the time-step we
177 // will build
178 ddc::ChunkSpan const next_temp = _next_temp.span_view();
179 // a read-only view of the temperature at the previous time-step
180 ddc::ChunkSpan const last_temp = _last_temp.span_view();
181
182 // Stencil computation on the main domain
184 Kokkos::DefaultExecutionSpace const execution_space;
185 ddc::fft(execution_space, Ff, last_temp, kwargs);
187 execution_space,
188 k_mesh,
189 KOKKOS_LAMBDA(ddc::DiscreteElement<DDimFx, DDimFy> const ikxky) {
190 ddc::DiscreteElement<DDimFx> const ikx(ikxky);
191 ddc::DiscreteElement<DDimFy> const iky(ikxky);
192 double const rkx = ddc::coordinate(ikx);
193 double const rky = ddc::coordinate(iky);
194 Ff(ikxky) *= 1 - (kx * rkx * rkx + ky * rky * rky) * dt;
195 });
196 ddc::ifft(execution_space, next_temp, Ff, kwargs);
197
198 if (iter - last_output >= t_output_period) {
199 last_output = iter;
200 ddc::parallel_deepcopy(_host_temp, _next_temp);
201 display(ddc::coordinate(iter), _host_temp.span_cview());
202 }
203
204 // Swap our two buffers
205 std::swap(_last_temp, _next_temp);
206 }
207
208 if (last_output < time_domain.back()) {
209 ddc::parallel_deepcopy(_host_temp, _last_temp);
210 display(ddc::coordinate(time_domain.back()), _host_temp.span_cview());
211 }
212}
KOKKOS_FUNCTION constexpr size_type size() const noexcept
KOKKOS_FUNCTION constexpr span_type span_view() const
KOKKOS_FUNCTION constexpr DiscreteDomain remove_last(discrete_vector_type n) 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.
PeriodicSampling models a periodic discretization of the provided continuous dimension.
UniformPointSampling models a uniform discretization of the provided continuous dimension.
The top-level namespace of DDC.
void ifft(ExecSpace const &exec_space, ddc::ChunkSpan< Tout, ddc::DiscreteDomain< DDimX... >, LayoutOut, MemorySpace > out, ddc::ChunkSpan< Tin, ddc::DiscreteDomain< DDimFx... >, LayoutIn, MemorySpace > in, ddc::kwArgs_fft kwargs={ddc::FFT_Normalization::OFF})
Perform an inverse Fast Fourier Transform.
Definition fft.hpp:406
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.
void fft(ExecSpace const &exec_space, ddc::ChunkSpan< Tout, ddc::DiscreteDomain< DDimFx... >, LayoutOut, MemorySpace > out, ddc::ChunkSpan< Tin, ddc::DiscreteDomain< DDimX... >, LayoutIn, MemorySpace > in, ddc::kwArgs_fft kwargs={ddc::FFT_Normalization::OFF})
Perform a direct Fast Fourier Transform.
Definition fft.hpp:353
@ BACKWARD
No normalization for forward FFT, multiply by 1/N for backward FFT.
KOKKOS_FUNCTION Coordinate< typename DDims::continuous_dimension_type... > coordinate(DiscreteElement< DDims... > const &c)
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.
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)
A structure embedding the configuration of the exposed FFT function with the type of normalization.
Definition fft.hpp:318