16#include <ginkgo/extensions/kokkos.hpp>
17#include <ginkgo/ginkgo.hpp>
19#include <Kokkos_Core.hpp>
24namespace ddc::detail {
29
30
31
32
33
34
35template <
class KokkosViewType>
36auto to_gko_dense(std::shared_ptr<gko::Executor
const>
const& gko_exec, KokkosViewType
const& view)
38 static_assert(Kokkos::is_view_v<KokkosViewType> && KokkosViewType::rank == 2);
39 using value_type = KokkosViewType::traits::value_type;
41 if (view.stride(1) != 1) {
42 throw std::runtime_error(
"The view needs to be contiguous in the second dimension");
45 return gko::matrix::Dense<value_type>::
47 gko::dim<2>(view.extent(0), view.extent(1)),
48 gko::array<value_type>::view(gko_exec, view.span(), view.data()),
53
54
55
56
57
58
59
60
61template <
class ExecSpace>
62std::size_t default_cols_per_chunk()
noexcept
64#if defined(KOKKOS_ENABLE_SERIAL
)
65 if (std::is_same_v<ExecSpace, Kokkos::Serial>) {
69#if defined(KOKKOS_ENABLE_OPENMP)
70 if (std::is_same_v<ExecSpace, Kokkos::OpenMP>) {
74#if defined(KOKKOS_ENABLE_CUDA)
75 if (std::is_same_v<ExecSpace, Kokkos::Cuda>) {
79#if defined(KOKKOS_ENABLE_HIP)
80 if (std::is_same_v<ExecSpace, Kokkos::HIP>) {
84#if defined(KOKKOS_ENABLE_SYCL)
85 if (std::is_same_v<ExecSpace, Kokkos::SYCL>) {
93
94
95
96
97
98
99
100
101template <
class ExecSpace>
102unsigned int default_preconditioner_max_block_size()
noexcept
104#if defined(KOKKOS_ENABLE_SERIAL
)
105 if (std::is_same_v<ExecSpace, Kokkos::Serial>) {
109#if defined(KOKKOS_ENABLE_OPENMP)
110 if (std::is_same_v<ExecSpace, Kokkos::OpenMP>) {
114#if defined(KOKKOS_ENABLE_CUDA)
115 if (std::is_same_v<ExecSpace, Kokkos::Cuda>) {
119#if defined(KOKKOS_ENABLE_HIP)
120 if (std::is_same_v<ExecSpace, Kokkos::HIP>) {
124#if defined(KOKKOS_ENABLE_SYCL)
125 if (std::is_same_v<ExecSpace, Kokkos::SYCL>) {
134template <
class ExecSpace>
135class SplinesLinearProblemSparse<ExecSpace>::Impl
138 using MultiRHS = SplinesLinearProblem<ExecSpace>::MultiRHS;
141 using matrix_sparse_type = gko::matrix::Csr<Real, gko::int32>;
142 using solver_type = gko::solver::Bicgstab<Real>;
145 std::size_t m_mat_size;
147 std::unique_ptr<gko::matrix::Dense<Real>> m_matrix_dense;
149 std::shared_ptr<matrix_sparse_type> m_matrix_sparse;
151 std::shared_ptr<solver_type> m_solver;
152 std::shared_ptr<gko::LinOp> m_solver_tr;
154 std::size_t m_cols_per_chunk;
156 unsigned int m_preconditioner_max_block_size;
160 std::size_t
const mat_size,
161 std::optional<std::size_t>
const cols_per_chunk = std::nullopt,
162 std::optional<
unsigned int>
const preconditioner_max_block_size = std::nullopt)
163 : m_mat_size(mat_size)
164 , m_cols_per_chunk(cols_per_chunk.value_or(default_cols_per_chunk<ExecSpace>()))
165 , m_preconditioner_max_block_size(preconditioner_max_block_size.value_or(
166 default_preconditioner_max_block_size<ExecSpace>()))
168 std::shared_ptr
const gko_exec = gko::ext::kokkos::create_executor(ExecSpace());
169 m_matrix_dense = gko::matrix::Dense<
170 Real>::create(gko_exec->get_master(), gko::dim<2>(mat_size, mat_size));
171 m_matrix_dense->fill(0);
172 m_matrix_sparse = matrix_sparse_type::create(gko_exec, gko::dim<2>(mat_size, mat_size));
175 Real get_element(std::size_t
const i, std::size_t
const j)
const
177 return m_matrix_dense->at(i, j);
180 void set_element(std::size_t
const i, std::size_t
const j, Real
const aij)
182 m_matrix_dense->at(i, j) = aij;
188 gko::matrix_data<Real> matrix_data(gko::dim<2>(m_mat_size, m_mat_size));
189 m_matrix_dense->write(matrix_data);
190 m_matrix_dense.reset();
191 matrix_data.remove_zeros();
192 m_matrix_sparse->read(matrix_data);
193 std::shared_ptr
const gko_exec = m_matrix_sparse->get_executor();
196 std::shared_ptr
const residual_criterion
197 = gko::stop::ResidualNorm<Real>::build()
198 .with_reduction_factor(10 * std::numeric_limits<Real>::epsilon())
201 std::shared_ptr
const iterations_criterion
202 = gko::stop::Iteration::build().with_max_iters(1000U).on(gko_exec);
204 std::shared_ptr
const preconditioner
205 = gko::preconditioner::Jacobi<Real>::build()
206 .with_max_block_size(m_preconditioner_max_block_size)
209 std::unique_ptr
const solver_factory
210 = solver_type::build()
211 .with_preconditioner(preconditioner)
212 .with_criteria(residual_criterion, iterations_criterion)
215 m_solver = solver_factory->generate(m_matrix_sparse);
216 m_solver_tr = m_solver->transpose();
217 gko_exec->synchronize();
221
222
223
224
225
226
227
228
229
230 void solve(MultiRHS
const b,
bool const transpose)
const
232 assert(b.extent(0) == m_mat_size);
234 std::shared_ptr
const gko_exec = m_solver->get_executor();
235 std::shared_ptr
const convergence_logger = gko::log::Convergence<Real>::create();
237 std::size_t
const main_chunk_size = std::min(m_cols_per_chunk, b.extent(1));
239 MultiRHS
const b_buffer(
"ddc_sparse_b_buffer", m_mat_size, main_chunk_size);
240 MultiRHS
const x(
"ddc_sparse_x", m_mat_size, main_chunk_size);
242 std::size_t
const iend = (b.extent(1) + main_chunk_size - 1) / main_chunk_size;
243 for (std::size_t i = 0; i < iend; ++i) {
244 std::size_t
const subview_begin = i * main_chunk_size;
245 std::size_t
const subview_end
246 = (i + 1 == iend) ? b.extent(1) : (subview_begin + main_chunk_size);
249 = Kokkos::subview(b, Kokkos::ALL, Kokkos::pair(subview_begin, subview_end));
250 auto const b_buffer_chunk = Kokkos::
253 Kokkos::pair(
static_cast<std::size_t>(0), subview_end - subview_begin));
254 auto const x_chunk = Kokkos::
257 Kokkos::pair(
static_cast<std::size_t>(0), subview_end - subview_begin));
259 Kokkos::deep_copy(b_buffer_chunk, b_chunk);
260 Kokkos::deep_copy(x_chunk, b_chunk);
263 m_solver->add_logger(convergence_logger);
265 ->apply(to_gko_dense(gko_exec, b_buffer_chunk),
266 to_gko_dense(gko_exec, x_chunk));
267 m_solver->remove_logger(convergence_logger);
269 m_solver_tr->add_logger(convergence_logger);
271 ->apply(to_gko_dense(gko_exec, b_buffer_chunk),
272 to_gko_dense(gko_exec, x_chunk));
273 m_solver_tr->remove_logger(convergence_logger);
276 if (!convergence_logger->has_converged()) {
277 throw std::runtime_error(
278 "Ginkgo did not converged in ddc::detail::SplinesLinearProblemSparse");
281 Kokkos::deep_copy(b_chunk, x_chunk);
286template <
class ExecSpace>
287SplinesLinearProblemSparse<ExecSpace>::SplinesLinearProblemSparse(
288 std::size_t
const mat_size,
289 std::optional<std::size_t> cols_per_chunk,
290 std::optional<
unsigned int> preconditioner_max_block_size)
291 : SplinesLinearProblem<ExecSpace>(mat_size)
292 , m_impl(std::make_unique<Impl>(mat_size, cols_per_chunk, preconditioner_max_block_size))
296template <
class ExecSpace>
297SplinesLinearProblemSparse<ExecSpace>::~SplinesLinearProblemSparse() =
default;
299template <
class ExecSpace>
300Real SplinesLinearProblemSparse<ExecSpace>::get_element(std::size_t i, std::size_t j)
const
302 return m_impl->get_element(i, j);
305template <
class ExecSpace>
306void SplinesLinearProblemSparse<ExecSpace>::set_element(std::size_t i, std::size_t j, Real aij)
308 m_impl->set_element(i, j, aij);
311template <
class ExecSpace>
312void SplinesLinearProblemSparse<ExecSpace>::setup_solver()
314 m_impl->setup_solver();
317template <
class ExecSpace>
318void SplinesLinearProblemSparse<ExecSpace>::solve(MultiRHS
const b,
bool const transpose)
const
320 m_impl->solve(b, transpose);
323#if defined(KOKKOS_ENABLE_SERIAL
)
324template class SplinesLinearProblemSparse<Kokkos::Serial>;
326#if defined(KOKKOS_ENABLE_OPENMP)
327template class SplinesLinearProblemSparse<Kokkos::OpenMP>;
329#if defined(KOKKOS_ENABLE_CUDA)
330template class SplinesLinearProblemSparse<Kokkos::Cuda>;
332#if defined(KOKKOS_ENABLE_HIP)
333template class SplinesLinearProblemSparse<Kokkos::HIP>;
335#if defined(KOKKOS_ENABLE_SYCL)
336template class SplinesLinearProblemSparse<Kokkos::SYCL>;
The top-level namespace of DDC.