Gyselalib++
 
Loading...
Searching...
No Matches
matrix_utils.hpp
1#pragma once
2#include <ginkgo/ginkgo.hpp>
3
4#include <Kokkos_Core.hpp>
5
13template <class KokkosViewType>
14auto to_gko_multivector(
15 std::shared_ptr<const gko::Executor> const& gko_exec,
16 KokkosViewType const& view)
17{
18 static_assert((Kokkos::is_view_v<KokkosViewType> && KokkosViewType::rank == 2));
19 using value_type = typename KokkosViewType::traits::value_type;
20
21 assert(view.stride_1() == 1);
22 return gko::share(
23 gko::batch::MultiVector<value_type>::
24 create(gko_exec,
25 gko::batch_dim<2>(view.extent(0), gko::dim<2>(view.extent(1), 1)),
26 gko::array<value_type>::view(gko_exec, view.span(), view.data())));
27}
28
38inline void check_conv(
39 int const batch_size,
40 double const tol,
41 std::shared_ptr<const gko::Executor> gko_exec,
42 std::shared_ptr<const gko::batch::log::BatchConvergence<double>> logger)
43{
44 auto logger_residual_host
45 = gko::make_temporary_clone(gko_exec->get_master(), &logger->get_residual_norm());
46 bool has_converged = false;
47 Kokkos::parallel_reduce(
48 "convergence",
49 Kokkos::RangePolicy<Kokkos::DefaultHostExecutionSpace>(0, batch_size),
50 [&](int batch_idx, bool& check_tol) {
51 check_tol = check_tol && (logger_residual_host->get_const_data()[batch_idx] <= tol);
52 },
53 Kokkos::LAnd<bool>(has_converged));
54 if (!has_converged) {
55 throw ::std::runtime_error("Ginkgo did not converge");
56 }
57}
58
70inline void write_log(
71 std::fstream& log_file,
72 int const batch_index,
73 int const num_iterations,
74 double const implicit_res_norm,
75 double const true_res_norm,
76 double const b_norm,
77 double const tol)
78{
79 log_file << " System no. " << batch_index << ":" << std::endl;
80 log_file << " Number of iterations = " << num_iterations << std::endl;
81 log_file << " Implicit residual norm = " << implicit_res_norm << std::endl;
82 log_file << " True (Ax-b) residual norm = " << true_res_norm << std::endl;
83 log_file << " Right-hand side (b) norm = " << b_norm << std::endl;
84 if (!(true_res_norm <= tol)) {
85 log_file << " --- System " << batch_index << " did not converge! ---" << std::endl;
86 }
87 log_file << "------------------------------------------------" << std::endl;
88}
89
99template <class sparse_type>
100void save_logger(
101 std::fstream& log_file,
102 int const batch_index,
103 std::unique_ptr<sparse_type> matrix,
104 Kokkos::View<double*, Kokkos::LayoutRight, Kokkos::DefaultExecutionSpace> const x_view,
105 Kokkos::View<double*, Kokkos::LayoutRight, Kokkos::DefaultExecutionSpace> const b_view,
106 std::shared_ptr<const gko::log::Convergence<double>> logger,
107 double const tol)
108{
109 std::shared_ptr const gko_exec = matrix->get_executor();
110
111 auto x = gko::matrix::Dense<double>::
112 create(gko_exec,
113 gko::dim<2>(x_view.extent(0), 1),
114 gko::array<double>::view(gko_exec, x_view.span(), x_view.data()),
115 x_view.stride_0());
116 auto b = gko::matrix::Dense<double>::
117 create(gko_exec,
118 gko::dim<2>(b_view.extent(0), 1),
119 gko::array<double>::view(gko_exec, b_view.span(), b_view.data()),
120 b_view.stride_0());
121
122 // allocate the residual
123 auto res = gko::matrix::Dense<double>::create(gko_exec, gko::dim<2>(b_view.extent(0), 1));
124 res->copy_from(b);
125
126 auto norm_dim = gko::dim<2>(1, 1);
127 // allocate rhs norm on host.
128 auto b_norm_host = gko::matrix::Dense<double>::create(gko_exec->get_master(), norm_dim);
129 b_norm_host->fill(0.0);
130 // allocate the residual norm on host.
131 auto res_norm_host = gko::matrix::Dense<double>::create(gko_exec->get_master(), norm_dim);
132 res_norm_host->fill(0.0);
133 // compute rhs norm.
134 b->compute_norm2(b_norm_host);
135 // we need constants on the device
136 auto one = gko::matrix::Dense<double>::create(gko_exec, norm_dim);
137 one->fill(1.0);
138 auto neg_one = gko::matrix::Dense<double>::create(gko_exec, norm_dim);
139 neg_one->fill(-1.0);
140 //to estimate the "true" residual, the apply function below computes Ax-res, and stores the result in res.
141 matrix->apply(one, x, neg_one, res);
142 //compute residual norm.
143 res->compute_norm2(res_norm_host);
144
145 int const log_iters_host = logger->get_num_iterations();
146 double const log_resid_host
147 = gko::make_temporary_clone(
148 gko_exec->get_master(),
149 gko::as<gko::matrix::Dense<double>>(logger->get_residual_norm()))
150 ->at(0, 0);
151
152 write_log(
153 log_file,
154 batch_index,
155 log_iters_host,
156 log_resid_host,
157 res_norm_host->at(0, 0),
158 b_norm_host->at(0, 0),
159 tol);
160}
161
171template <class batch_sparse_type>
172void save_logger(
173 std::fstream& log_file,
174 std::shared_ptr<batch_sparse_type> batch_matrix,
175 Kokkos::View<double**, Kokkos::LayoutRight, Kokkos::DefaultExecutionSpace> const x_view,
176 Kokkos::View<double**, Kokkos::LayoutRight, Kokkos::DefaultExecutionSpace> const b_view,
177 std::shared_ptr<const gko::batch::log::BatchConvergence<double>> logger,
178 double const tol)
179{
180 std::shared_ptr const gko_exec = batch_matrix->get_executor();
181 int const batch_size = x_view.extent(0);
182
183 auto x = to_gko_multivector(gko_exec, x_view);
184 auto b = to_gko_multivector(gko_exec, b_view);
185
186 // allocate the residual
187 auto res = gko::batch::MultiVector<double>::
188 create(gko_exec, gko::batch_dim<2>(batch_size, gko::dim<2>(b_view.extent(1), 1)));
189 res->copy_from(b);
190
191 auto norm_dim = gko::batch_dim<2>(batch_size, gko::dim<2>(1, 1));
192 // allocate rhs norm on host.
193 auto b_norm_host = gko::batch::MultiVector<double>::create(gko_exec->get_master(), norm_dim);
194 b_norm_host->fill(0.0);
195 // allocate the residual norm on host.
196 auto res_norm_host = gko::batch::MultiVector<double>::create(gko_exec->get_master(), norm_dim);
197 res_norm_host->fill(0.0);
198 // compute rhs norm.
199 b->compute_norm2(b_norm_host);
200 // we need constants on the device
201 auto one = gko::batch::MultiVector<double>::create(gko_exec, norm_dim);
202 one->fill(1.0);
203 auto neg_one = gko::batch::MultiVector<double>::create(gko_exec, norm_dim);
204 neg_one->fill(-1.0);
205 //to estimate the "true" residual, the apply function below computes Ax-res, and stores the result in res.
206 batch_matrix->apply(one, x, neg_one, res);
207 //compute residual norm.
208 res->compute_norm2(res_norm_host);
209
210 auto log_iters_host
211 = gko::make_temporary_clone(gko_exec->get_master(), &logger->get_num_iterations());
212 auto log_resid_host
213 = gko::make_temporary_clone(gko_exec->get_master(), &logger->get_residual_norm());
214
215 // "unbatch" converts a batch object into a vector
216 // of objects of the corresponding single type.
217 for (int i = 0; i < batch_size; ++i) {
218 write_log(
219 log_file,
220 i,
221 log_iters_host->get_const_data()[i],
222 log_resid_host->get_const_data()[i],
223 res_norm_host->create_const_view_for_item(i)->at(0, 0),
224 b_norm_host->create_const_view_for_item(i)->at(0, 0),
225 tol);
226 }
227}
228
229template <class ExecSpace>
230unsigned int default_preconditionner_max_block_size() noexcept
231{
232#ifdef KOKKOS_ENABLE_SERIAL
233 if (std::is_same_v<ExecSpace, Kokkos::Serial>) {
234 return 32u;
235 }
236#endif
237#ifdef KOKKOS_ENABLE_OPENMP
238 if (std::is_same_v<ExecSpace, Kokkos::OpenMP>) {
239 return 1u;
240 }
241#endif
242#ifdef KOKKOS_ENABLE_CUDA
243 if (std::is_same_v<ExecSpace, Kokkos::Cuda>) {
244 return 1u;
245 }
246#endif
247#ifdef KOKKOS_ENABLE_HIP
248 if (std::is_same_v<ExecSpace, Kokkos::HIP>) {
249 return 1u;
250 }
251#endif
252 return 1u;
253}