DDC 0.10.0
Loading...
Searching...
No Matches
splines_linear_problem_3x3_blocks.hpp
1// Copyright (C) The DDC development team, see COPYRIGHT.md file
2//
3// SPDX-License-Identifier: MIT
4
5#pragma once
6
7#include <cassert>
8#include <cstddef>
9#include <memory>
10#include <utility>
11
12#include <Kokkos_Core.hpp>
13
14#include "splines_linear_problem.hpp"
15#include "splines_linear_problem_2x2_blocks.hpp"
16
17namespace ddc::detail {
18
19/**
20 * @brief A 3x3-blocks linear problem dedicated to the computation of a spline approximation,
21 * with all blocks except center one being stored in dense format.
22 *
23 * A = | a | b | c |
24 * | d | Q | e |
25 * | f | g | h |
26 *
27 * The storage format is dense for all blocks except center one, whose storage format is determined by its type.
28 *
29 * The matrix itself and blocks a, Q and h are square (which fully determines the dimensions of the others).
30 *
31 * This class implements row & columns interchanges of the matrix and of multiple right-hand sides to restructure the
32 * 3x3-blocks linear problem into a 2x2-blocks linear problem, relying then on the operations implemented in SplinesLinearProblem2x2Blocks.
33 *
34 * @tparam ExecSpace The Kokkos::ExecutionSpace on which operations related to the matrix are supposed to be performed.
35 */
36template <class ExecSpace>
37class SplinesLinearProblem3x3Blocks : public SplinesLinearProblem2x2Blocks<ExecSpace>
38{
39public:
40 using typename SplinesLinearProblem2x2Blocks<ExecSpace>::MultiRHS;
41 using SplinesLinearProblem2x2Blocks<ExecSpace>::size;
42 using SplinesLinearProblem2x2Blocks<ExecSpace>::solve;
43 using SplinesLinearProblem2x2Blocks<ExecSpace>::m_top_left_block;
44
45protected:
46 std::size_t m_top_size;
47
48public:
49 /**
50 * @brief SplinesLinearProblem3x3Blocks constructor.
51 *
52 * @param mat_size The size of one of the dimensions of the square matrix.
53 * @param top_size The size of one of the dimensions of the top-left square block.
54 * @param center_block A pointer toward the center SplinesLinearProblem. `setup_solver` must not have been called on it.
55 */
56 explicit SplinesLinearProblem3x3Blocks(
57 std::size_t const mat_size,
58 std::size_t const top_size,
59 std::unique_ptr<SplinesLinearProblem<ExecSpace>> center_block)
60 : SplinesLinearProblem2x2Blocks<ExecSpace>(mat_size, std::move(center_block))
61 , m_top_size(top_size)
62 {
63 }
64
65private:
66 /// @brief Adjust indices, governs the row & columns interchanges to restructure the 3x3-blocks matrix into a 2x2-blocks matrix.
67 void adjust_indices(std::size_t& i, std::size_t& j) const
68 {
69 std::size_t const nq = m_top_left_block->size(); // size of the center block
70
71 if (i < m_top_size) {
72 i += nq;
73 } else if (i < m_top_size + nq) {
74 i -= m_top_size;
75 }
76
77 if (j < m_top_size) {
78 j += nq;
79 } else if (j < m_top_size + nq) {
80 j -= m_top_size;
81 }
82 }
83
84public:
85 double get_element(std::size_t i, std::size_t j) const override
86 {
87 adjust_indices(i, j);
88 return SplinesLinearProblem2x2Blocks<ExecSpace>::get_element(i, j);
89 }
90
91 void set_element(std::size_t i, std::size_t j, double const aij) override
92 {
93 adjust_indices(i, j);
94 return SplinesLinearProblem2x2Blocks<ExecSpace>::set_element(i, j, aij);
95 }
96
97private:
98 /**
99 * @brief Perform row interchanges on multiple right-hand sides to get a 2-blocks structure (matching the requirements
100 * of the SplinesLinearProblem2x2Blocks solver).
101 *
102 * | b_top | | - |
103 * | b_center | -> | b_center |
104 * | b_bottom | | b_top | -- Considered as a
105 * | - | | b_bottom | -- single bottom block
106 *
107 * @param b The multiple right-hand sides.
108 */
109 void interchange_rows_from_3_to_2_blocks_rhs(MultiRHS const b) const
110 {
111 std::size_t const nq = m_top_left_block->size(); // size of the center block
112
113 MultiRHS const b_top = Kokkos::
114 subview(b, std::pair<std::size_t, std::size_t> {0, m_top_size}, Kokkos::ALL);
115 MultiRHS const b_bottom = Kokkos::
116 subview(b,
117 std::pair<std::size_t, std::size_t> {m_top_size + nq, size()},
118 Kokkos::ALL);
119
120 MultiRHS const b_top_dst = Kokkos::
121 subview(b,
122 std::pair<std::size_t, std::size_t> {m_top_size + nq, 2 * m_top_size + nq},
123 Kokkos::ALL);
124 MultiRHS const b_bottom_dst = Kokkos::
125 subview(b,
126 std::pair<
127 std::size_t,
128 std::size_t> {2 * m_top_size + nq, m_top_size + size()},
129 Kokkos::ALL);
130
131 if (b_bottom.extent(0) > b_top.extent(0)) {
132 // Need a buffer to prevent overlapping
133 MultiRHS const buffer = Kokkos::create_mirror(ExecSpace(), b_bottom);
134
135 Kokkos::deep_copy(buffer, b_bottom);
136 Kokkos::deep_copy(b_bottom_dst, buffer);
137 } else {
138 Kokkos::deep_copy(b_bottom_dst, b_bottom);
139 }
140 Kokkos::deep_copy(b_top_dst, b_top);
141 }
142
143 /**
144 * @brief Perform row interchanges on multiple right-hand sides to restore its 3-blocks structure.
145 *
146 * | - | | b_top |
147 * | b_center | -> | b_center |
148 * | b_top | | b_bottom |
149 * | b_bottom | | - |
150 *
151 * @param b The multiple right-hand sides.
152 */
153 void interchange_rows_from_2_to_3_blocks_rhs(MultiRHS const b) const
154 {
155 std::size_t const nq = m_top_left_block->size(); // size of the center block
156
157 MultiRHS const b_top = Kokkos::
158 subview(b, std::pair<std::size_t, std::size_t> {0, m_top_size}, Kokkos::ALL);
159 MultiRHS const b_bottom = Kokkos::
160 subview(b,
161 std::pair<std::size_t, std::size_t> {m_top_size + nq, size()},
162 Kokkos::ALL);
163
164 MultiRHS const b_top_src = Kokkos::
165 subview(b,
166 std::pair<std::size_t, std::size_t> {m_top_size + nq, 2 * m_top_size + nq},
167 Kokkos::ALL);
168 MultiRHS const b_bottom_src = Kokkos::
169 subview(b,
170 std::pair<
171 std::size_t,
172 std::size_t> {2 * m_top_size + nq, m_top_size + size()},
173 Kokkos::ALL);
174
175 Kokkos::deep_copy(b_top, b_top_src);
176 if (b_bottom.extent(0) > b_top.extent(0)) {
177 // Need a buffer to prevent overlapping
178 MultiRHS const buffer = Kokkos::create_mirror(ExecSpace(), b_bottom);
179
180 Kokkos::deep_copy(buffer, b_bottom_src);
181 Kokkos::deep_copy(b_bottom, buffer);
182 } else {
183 Kokkos::deep_copy(b_bottom, b_bottom_src);
184 }
185 }
186
187public:
188 /**
189 * @brief Solve the multiple right-hand sides linear problem Ax=b or its transposed version A^tx=b inplace.
190 *
191 * Perform row interchanges on multiple right-hand sides to obtain a 2x2-blocks linear problem and call the SplinesLinearProblem2x2Blocks solver.
192 *
193 * This class requires an additional allocation corresponding to top_size rows for internal operation.
194 *
195 * @param[in, out] b A 2D Kokkos::View storing the multiple right-hand sides (+ additional garbage allocation) of the problem and receiving the corresponding solution.
196 * @param transpose Choose between the direct or transposed version of the linear problem.
197 */
198 void solve(MultiRHS const b, bool const transpose) const override
199 {
200 assert(b.extent(0) == size() + m_top_size);
201
202 interchange_rows_from_3_to_2_blocks_rhs(b);
203 SplinesLinearProblem2x2Blocks<ExecSpace>::
204 solve(Kokkos::
205 subview(b,
206 std::pair<
207 std::size_t,
208 std::size_t> {m_top_size, m_top_size + size()},
209 Kokkos::ALL),
210 transpose);
211 interchange_rows_from_2_to_3_blocks_rhs(b);
212 }
213
214private:
215 std::size_t impl_required_number_of_rhs_rows() const override
216 {
217 return size() + m_top_size;
218 }
219};
220
221} // namespace ddc::detail
The top-level namespace of DDC.