Gyselalib++
 
Loading...
Searching...
No Matches
matrix_batch_csr.hpp
1#pragma once
2
3#include <sll/matrix_batch.hpp>
4#include <sll/matrix_utils.hpp>
5
6#include <ginkgo/extensions/kokkos.hpp>
7#include <ginkgo/ginkgo.hpp>
8
9#include <Kokkos_Core.hpp>
10
18enum class MatrixBatchCsrSolver { CG, BICGSTAB, BATCH_CG, BATCH_BICGSTAB };
19
34template <class ExecSpace, MatrixBatchCsrSolver Solver = MatrixBatchCsrSolver::BICGSTAB>
35class MatrixBatchCsr : public MatrixBatch<ExecSpace>
36{
37public:
39 using MatrixBatch<ExecSpace>::size;
40 using MatrixBatch<ExecSpace>::batch_size;
41
42private:
43 using batch_sparse_type = gko::batch::matrix::Csr<double, int>;
44 using solver_type = std::conditional_t<
45 Solver == MatrixBatchCsrSolver::CG,
46 gko::solver::Cg<double>,
47 std::conditional_t<
48 Solver == MatrixBatchCsrSolver::BICGSTAB,
49 gko::solver::Bicgstab<double>,
50 std::conditional_t<
51 Solver == MatrixBatchCsrSolver::BATCH_CG,
52 gko::batch::solver::Cg<double>,
53 gko::batch::solver::Bicgstab<double>>>>;
54
55 std::shared_ptr<batch_sparse_type> m_batch_matrix_csr;
56 std::conditional_t<
57 Solver == MatrixBatchCsrSolver::CG || Solver == MatrixBatchCsrSolver::BICGSTAB,
58 std::vector<std::shared_ptr<solver_type>>,
59 std::shared_ptr<solver_type>>
60 m_solver;
61 int m_max_iter;
62 double m_tol;
63 bool m_with_logger;
64 unsigned int m_preconditionner_max_block_size; // Maximum size of Jacobi-block preconditionner
65
66public:
80 const int batch_size,
81 const int mat_size,
82 const int nnz_per_system,
83 std::optional<int> max_iter = std::nullopt,
84 std::optional<double> res_tol = std::nullopt,
85 std::optional<bool> logger = std::nullopt,
86 std::optional<int> preconditionner_max_block_size = 1u)
87 : MatrixBatch<ExecSpace>(batch_size, mat_size)
88 , m_max_iter(max_iter.value_or(1000))
89 , m_tol(res_tol.value_or(1e-15))
90 , m_with_logger(logger.value_or(false))
91 , m_preconditionner_max_block_size(preconditionner_max_block_size.value_or(
92 default_preconditionner_max_block_size<ExecSpace>()))
93 {
94 std::shared_ptr const gko_exec = gko::ext::kokkos::create_executor(ExecSpace());
95 m_batch_matrix_csr = gko::share(
96 batch_sparse_type::
97 create(gko_exec,
98 gko::batch_dim<2>(batch_size, gko::dim<2>(mat_size, mat_size)),
99 nnz_per_system));
100 }
101
120 Kokkos::View<double**, Kokkos::LayoutRight, ExecSpace> batch_values,
121 Kokkos::View<int*, Kokkos::LayoutRight, ExecSpace> cols_idx,
122 Kokkos::View<int*, Kokkos::LayoutRight, ExecSpace> nnz_per_row,
123 std::optional<int> max_iter = std::nullopt,
124 std::optional<double> res_tol = std::nullopt,
125 std::optional<bool> logger = std::nullopt,
126 std::optional<int> preconditionner_max_block_size = 1u)
127 : MatrixBatch<ExecSpace>(batch_values.extent(0), nnz_per_row.size() - 1)
128 , m_max_iter(max_iter.value_or(1000))
129 , m_tol(res_tol.value_or(1e-15))
130 , m_with_logger(logger.value_or(false))
131 , m_preconditionner_max_block_size(preconditionner_max_block_size.value_or(
132 default_preconditionner_max_block_size<ExecSpace>()))
133 {
134 std::shared_ptr const gko_exec = gko::ext::kokkos::create_executor(ExecSpace());
135 m_batch_matrix_csr = gko::share(
136 batch_sparse_type::
137 create(gko_exec,
138 gko::batch_dim<2>(batch_size(), gko::dim<2>(size(), size())),
139 std::move(gko::array<double>::
140 view(gko_exec,
141 batch_values.span(),
142 batch_values.data())),
143 std::move(gko::array<
144 int>::view(gko_exec, cols_idx.span(), cols_idx.data())),
145 std::move(gko::array<int>::
146 view(gko_exec,
147 nnz_per_row.span(),
148 nnz_per_row.data()))));
149 }
150
159 std::tuple<
160 Kokkos::View<double**, Kokkos::LayoutRight, ExecSpace>,
161 Kokkos::View<int*, Kokkos::LayoutRight, ExecSpace>,
162 Kokkos::View<int*, Kokkos::LayoutRight, ExecSpace>>
164 {
165 int* idx_buffer = m_batch_matrix_csr->get_col_idxs();
166 int* nnz_per_row_buffer = m_batch_matrix_csr->get_row_ptrs();
167 double* vals_buffer = m_batch_matrix_csr->get_values();
168
169 Kokkos::View<int*, Kokkos::LayoutRight, ExecSpace>
170 col_idx_view_buffer(idx_buffer, m_batch_matrix_csr->get_num_elements_per_item());
171 Kokkos::View<int*, Kokkos::LayoutRight, ExecSpace>
172 nnz_per_row_view_buffer(nnz_per_row_buffer, size() + 1);
173 Kokkos::View<double**, Kokkos::LayoutRight, ExecSpace> vals_view_buffer(
174 vals_buffer,
175 batch_size(),
176 m_batch_matrix_csr->get_num_elements_per_item());
177
178 return {vals_view_buffer, col_idx_view_buffer, nnz_per_row_view_buffer};
179 }
180
189 void setup_solver() final
190 {
191 std::shared_ptr const gko_exec = m_batch_matrix_csr->get_executor();
192 //Check if the indices array is sorted, and sort it if necessary.
193 //The values array corresponding to the indices is also reordered.
194 for (size_t i = 0; i < batch_size(); i++) {
195 std::unique_ptr<gko::matrix::Csr<double, int>> tmp_matrix
196 = m_batch_matrix_csr->create_view_for_item(i);
197 if (!tmp_matrix->is_sorted_by_column_index()) {
198 tmp_matrix->sort_by_column_index();
199 }
200 }
201 if constexpr (
202 Solver == MatrixBatchCsrSolver::CG || Solver == MatrixBatchCsrSolver::BICGSTAB) {
203 // Create the solver factory
204 std::shared_ptr const residual_criterion
205 = gko::stop::ResidualNorm<double>::build().with_reduction_factor(m_tol).on(
206 gko_exec);
207
208 std::shared_ptr const iterations_criterion
209 = gko::stop::Iteration::build().with_max_iters(m_max_iter).on(gko_exec);
210
211 std::shared_ptr const preconditioner
212 = gko::preconditioner::Jacobi<double>::build()
213 .with_max_block_size(m_preconditionner_max_block_size)
214 .on(gko_exec);
215
216 std::unique_ptr const solver_factory
217 = solver_type::build()
218 .with_preconditioner(preconditioner)
219 .with_criteria(residual_criterion, iterations_criterion)
220 .on(gko_exec);
221
222 // Create the solvers
223 for (size_t i = 0; i < batch_size(); i++) {
224 m_solver.emplace_back(solver_factory->generate(
225 m_batch_matrix_csr->create_const_view_for_item(i)));
226 }
227 } else {
228 // Create the solver factory
229 std::shared_ptr const preconditioner
230 = gko::batch::preconditioner::Jacobi<double, int>::build()
231 .with_max_block_size(m_preconditionner_max_block_size)
232 .on(gko_exec);
233
234 std::shared_ptr solver_factory = solver_type::build()
235 .with_max_iterations(m_max_iter)
236 .with_tolerance(m_tol)
237 .with_preconditioner(preconditioner)
238 .on(gko_exec);
239
240 // Create the solver
241 m_solver = solver_factory->generate(m_batch_matrix_csr);
242 }
243 gko_exec->synchronize();
244 }
245
251 void solve(BatchedRHS const b) const final
252 {
253 BatchedRHS x_view("x_view", batch_size(), size());
254 Kokkos::deep_copy(x_view, b);
255 solve(x_view, b);
256 Kokkos::deep_copy(b, x_view);
257 }
258
266 void solve(BatchedRHS const x, BatchedRHS const b) const
267 {
268 if constexpr (
269 Solver == MatrixBatchCsrSolver::CG || Solver == MatrixBatchCsrSolver::BICGSTAB) {
270 for (size_t i = 0; i < batch_size(); i++) {
271 std::shared_ptr const gko_exec = m_solver[i]->get_executor();
272
273 // Create a logger to obtain the iteration counts and "implicit" residual norms for every system after the solve.
274 std::shared_ptr const logger = gko::log::Convergence<double>::create();
275
276 // Solve & log
277 m_solver[i]->add_logger(logger);
278 m_solver[i]
279 ->apply(to_gko_multivector(gko_exec, b)->create_const_view_for_item(i),
280 to_gko_multivector(gko_exec, x)->create_view_for_item(i));
281 m_solver[i]->remove_logger(logger);
282 // save logger data
283 if (m_with_logger) {
284 std::fstream log_file("csr_log.txt", std::ios::out | std::ios::app);
285 save_logger(
286 log_file,
287 i,
288 m_batch_matrix_csr->create_const_view_for_item(i),
289 Kokkos::subview(x, i, Kokkos::ALL),
290 Kokkos::subview(b, i, Kokkos::ALL),
291 logger,
292 m_tol);
293 log_file.close();
294 }
295 // Check convergency
296 if (!logger->has_converged()) {
297 throw std::runtime_error("Ginkgo did not converge in MatrixBatchCsr");
298 }
299 }
300 } else {
301 std::shared_ptr const gko_exec = m_solver->get_executor();
302
303 // Create a logger to obtain the iteration counts and "implicit" residual norms for every system after the solve.
304 std::shared_ptr const logger = gko::batch::log::BatchConvergence<double>::create();
305
306 // Solve & log
307 m_solver->add_logger(logger);
308 m_solver->apply(to_gko_multivector(gko_exec, b), to_gko_multivector(gko_exec, x));
309 m_solver->remove_logger(logger);
310
311 // Save logger data
312 if (m_with_logger) {
313 std::fstream log_file("csr_log.txt", std::ios::out | std::ios::app);
314 save_logger(log_file, m_batch_matrix_csr, x, b, logger, m_tol);
315 log_file.close();
316 }
317 // Check convergence
318 check_conv(batch_size(), m_tol, gko_exec, logger);
319 }
320 }
321
327 double norm(int batch_idx) const
328 {
329 int const tmp_mat_size = size();
330 int const tmp_batch_size = batch_size();
331 double result = 0.;
332 double* vals_proxy = m_batch_matrix_csr->get_values();
333 int* row_ptr_proxy = m_batch_matrix_csr->get_row_ptrs();
334 Kokkos::View<double**, Kokkos::LayoutRight, typename ExecSpace::memory_space> vals_view(
335 vals_proxy,
336 tmp_batch_size,
337 m_batch_matrix_csr->get_num_elements_per_item());
338 Kokkos::View<int*, Kokkos::LayoutRight, typename ExecSpace::memory_space>
339 row_ptr_view(row_ptr_proxy, tmp_mat_size + 1);
340
341 Kokkos::parallel_reduce(
342 "L-infinity norm",
343 Kokkos::RangePolicy<ExecSpace>(0, tmp_mat_size),
344 KOKKOS_LAMBDA(int const i, double& res) {
345 double row_sum = 0.;
346 for (int k = row_ptr_view[i]; k < row_ptr_view[i + 1]; k++) {
347 row_sum += Kokkos::abs(vals_view(batch_idx, k));
348 }
349 if (row_sum > res) {
350 res = row_sum;
351 }
352 },
353 Kokkos::Max<double>(result));
354
355 return result;
356 }
357};
358
368template <MatrixBatchCsrSolver Solver = MatrixBatchCsrSolver::BICGSTAB>
369void convert_coo_to_csr(
371 Kokkos::View<double*, Kokkos::LayoutRight, Kokkos::DefaultHostExecutionSpace> vals_coo_host,
372 Kokkos::View<int*, Kokkos::LayoutRight, Kokkos::DefaultHostExecutionSpace> row_coo_host,
373 Kokkos::View<int*, Kokkos::LayoutRight, Kokkos::DefaultHostExecutionSpace> col_coo_host)
374{
375 int const mat_size = matrix->size();
376 int const batch_size = matrix->batch_size();
377 int const non_zero_per_system = vals_coo_host.extent(0) / batch_size;
378
379 Kokkos::View<double**, Kokkos::LayoutRight, Kokkos::DefaultHostExecutionSpace>
380 values_view_host("", batch_size, non_zero_per_system);
381 Kokkos::View<int*, Kokkos::LayoutRight, Kokkos::DefaultHostExecutionSpace>
382 idx_view_host("", non_zero_per_system);
383 Kokkos::View<int*, Kokkos::LayoutRight, Kokkos::DefaultHostExecutionSpace>
384 nnz_per_row_view_host("", mat_size + 1);
385 nnz_per_row_view_host(0) = 0;
386 nnz_per_row_view_host(mat_size) = non_zero_per_system;
387
388 for (int i = 0; i < mat_size; i++) {
389 int n_non_zero_in_row = 0;
390 for (int k = 0; k < non_zero_per_system; k++) {
391 if (row_coo_host(k) == i) {
392 int const idx = nnz_per_row_view_host(i) + n_non_zero_in_row;
393 idx_view_host(idx) = col_coo_host(k);
394 values_view_host(0, idx) = vals_coo_host(k);
395 n_non_zero_in_row++;
396 }
397 }
398 nnz_per_row_view_host(i + 1) = nnz_per_row_view_host(i) + n_non_zero_in_row;
399 }
400 for (int batch_idx = 1; batch_idx < batch_size; batch_idx++) {
401 for (int idx = 0; idx < non_zero_per_system; idx++) {
402 values_view_host(batch_idx, idx) = vals_coo_host(batch_idx * non_zero_per_system + idx);
403 }
404 }
405 auto [values, col_idx, nnz_per_row] = matrix->get_batch_csr();
406 Kokkos::deep_copy(values, values_view_host);
407 Kokkos::deep_copy(col_idx, idx_view_host);
408 Kokkos::deep_copy(nnz_per_row, nnz_per_row_view_host);
409}
Matrix class which is able to manage and solve a batch of sparse linear systems.
Definition matrix_batch_csr.hpp:36
std::tuple< Kokkos::View< double **, Kokkos::LayoutRight, ExecSpace >, Kokkos::View< int *, Kokkos::LayoutRight, ExecSpace >, Kokkos::View< int *, Kokkos::LayoutRight, ExecSpace > > get_batch_csr()
A function to update information about values,indices and the number of non-zero per row for the whol...
Definition matrix_batch_csr.hpp:163
MatrixBatchCsr(const int batch_size, const int mat_size, const int nnz_per_system, std::optional< int > max_iter=std::nullopt, std::optional< double > res_tol=std::nullopt, std::optional< bool > logger=std::nullopt, std::optional< int > preconditionner_max_block_size=1u)
The constructor for MatrixBatchCsr class.
Definition matrix_batch_csr.hpp:79
void solve(BatchedRHS const x, BatchedRHS const b) const
Solve the batched linear problem Ax=b.
Definition matrix_batch_csr.hpp:266
void solve(BatchedRHS const b) const final
Solve the batched linear problem Ax=b.
Definition matrix_batch_csr.hpp:251
double norm(int batch_idx) const
A function returning the norm of a matrix located at batch_idx.
Definition matrix_batch_csr.hpp:327
void setup_solver() final
Perform a pre-process operation on the solver.
Definition matrix_batch_csr.hpp:189
MatrixBatchCsr(Kokkos::View< double **, Kokkos::LayoutRight, ExecSpace > batch_values, Kokkos::View< int *, Kokkos::LayoutRight, ExecSpace > cols_idx, Kokkos::View< int *, Kokkos::LayoutRight, ExecSpace > nnz_per_row, std::optional< int > max_iter=std::nullopt, std::optional< double > res_tol=std::nullopt, std::optional< bool > logger=std::nullopt, std::optional< int > preconditionner_max_block_size=1u)
Constructor for MatrixBatchCsr class.
Definition matrix_batch_csr.hpp:119
MatrixBatch superclass for managing a collection of linear systems.
Definition matrix_batch.hpp:23
std::size_t batch_size() const
Get the batch size of the linear problem.
Definition matrix_batch.hpp:76
std::size_t size() const
Get the size of the square matrix corresponding to a single batch in one of its dimensions.
Definition matrix_batch.hpp:66
Kokkos::View< double **, Kokkos::LayoutRight, ExecSpace > BatchedRHS
The type of a Kokkos::View storing batched right-hand sides. Second dimenion is batch dimension.
Definition matrix_batch.hpp:26