1 | /* |
2 | * SparseMatrix_petsc.hpp |
3 | * |
4 | * Created on: Apr 26, 2016 |
5 | * Author: i-bird |
6 | */ |
7 | |
8 | #ifndef OPENFPM_NUMERICS_SRC_MATRIX_SPARSEMATRIX_PETSC_HPP_ |
9 | #define OPENFPM_NUMERICS_SRC_MATRIX_SPARSEMATRIX_PETSC_HPP_ |
10 | |
11 | #include "util/petsc_util.hpp" |
12 | #include "Vector/map_vector.hpp" |
13 | #include <boost/mpl/int.hpp> |
14 | #include <petscmat.h> |
15 | |
16 | #define PETSC_BASE 2 |
17 | |
18 | /*! \brief It store one non-zero element in the sparse matrix |
19 | * |
20 | * Given a row, and a column, store a value |
21 | * |
22 | * |
23 | */ |
24 | template<typename T> |
25 | class triplet<T,PETSC_BASE> |
26 | { |
27 | //! Row of the sparse matrix |
28 | PetscInt row_; |
29 | |
30 | //! Colum of the sparse matrix |
31 | PetscInt col_; |
32 | |
33 | //! Value of the Matrix |
34 | PetscScalar val_; |
35 | |
36 | public: |
37 | |
38 | /*! \brief Return the row of the triplet |
39 | * |
40 | * \return the row index |
41 | * |
42 | */ |
43 | PetscInt & row() |
44 | { |
45 | return row_; |
46 | } |
47 | |
48 | /*! \brief Return the colum of the triplet |
49 | * |
50 | * \return the colum index |
51 | * |
52 | */ |
53 | PetscInt & col() |
54 | { |
55 | return col_; |
56 | } |
57 | |
58 | /*! \brief Return the value of the triplet |
59 | * |
60 | * \return the value |
61 | * |
62 | */ |
63 | PetscScalar & value() |
64 | { |
65 | return val_; |
66 | } |
67 | |
68 | /*! \brief Constructor from row, colum and value |
69 | * |
70 | * \param i row |
71 | * \param j colum |
72 | * \param val value |
73 | * |
74 | */ |
75 | triplet(long int i, long int j, T val) |
76 | { |
77 | row_ = i; |
78 | col_ = j; |
79 | val_ = val; |
80 | } |
81 | |
82 | // Default constructor |
83 | triplet() |
84 | :row_(0),col_(0),val_(0) |
85 | {}; |
86 | }; |
87 | |
88 | /*! \brief Sparse Matrix implementation, that map over Eigen |
89 | * |
90 | * \tparam T Type of the sparse Matrix store on each row,colums |
91 | * \tparam id_t type of id |
92 | * \tparam impl implementation |
93 | * |
94 | */ |
95 | template<typename T, typename id_t> |
96 | class SparseMatrix<T,id_t, PETSC_BASE> |
97 | { |
98 | public: |
99 | |
100 | //! Triplet implementation id |
101 | typedef boost::mpl::int_<PETSC_BASE> triplet_impl; |
102 | |
103 | //! Triplet type |
104 | typedef triplet<T,PETSC_BASE> triplet_type; |
105 | |
106 | private: |
107 | |
108 | //! Number of matrix row (global) |
109 | size_t g_row; |
110 | //! Number of matrix colums (global) |
111 | size_t g_col; |
112 | |
113 | //! Number of matrix row (local) |
114 | size_t l_row; |
115 | //! Number of matrix colums (local) |
116 | size_t l_col; |
117 | |
118 | //! starting row for this processor |
119 | size_t start_row; |
120 | |
121 | //! indicate if the matrix has been created |
122 | bool m_created = false; |
123 | |
124 | //! PETSC Matrix |
125 | Mat mat; |
126 | |
127 | //! Triplets of the matrix |
128 | openfpm::vector<triplet_type> trpl; |
129 | |
130 | |
131 | //! temporary list of values |
132 | mutable openfpm::vector<PetscScalar> vals; |
133 | //! temporary list of colums |
134 | mutable openfpm::vector<PetscInt> cols; |
135 | //! PETSC d_nnz |
136 | mutable openfpm::vector<PetscInt> d_nnz; |
137 | //! PETSC o_nnz |
138 | mutable openfpm::vector<PetscInt> o_nnz; |
139 | |
140 | /*! \brief Fill the petsc Matrix |
141 | * |
142 | * |
143 | */ |
144 | void fill_petsc() |
145 | { |
146 | d_nnz.resize(l_row); |
147 | o_nnz.resize(l_row); |
148 | |
149 | d_nnz.fill(0); |
150 | o_nnz.fill(0); |
151 | |
152 | // Here we explore every row to count how many non zero we have in the diagonal matrix part, |
153 | // and the non diagonal matrix part, needed by MatMPIAIJSetPreallocation |
154 | |
155 | size_t i = 0; |
156 | |
157 | // Set the Matrix from triplet |
158 | while (i < trpl.size()) |
159 | { |
160 | PetscInt row = trpl.get(i).row(); |
161 | |
162 | while(i < trpl.size() && row == trpl.get(i).row()) |
163 | { |
164 | if ((size_t)trpl.get(i).col() >= start_row && (size_t)trpl.get(i).col() < start_row + l_row) |
165 | d_nnz.get(row - start_row)++; |
166 | else |
167 | o_nnz.get(row - start_row)++; |
168 | i++; |
169 | } |
170 | } |
171 | |
172 | PETSC_SAFE_CALL(MatMPIAIJSetPreallocation(mat,0,static_cast<const PetscInt*>(d_nnz.getPointer()),0, |
173 | static_cast<const PetscInt*>(o_nnz.getPointer()))); |
174 | |
175 | // Counter i is zero |
176 | i = 0; |
177 | |
178 | // Set the Matrix from triplet |
179 | while (i < trpl.size()) |
180 | { |
181 | vals.clear(); |
182 | cols.clear(); |
183 | |
184 | PetscInt row = trpl.get(i).row(); |
185 | |
186 | while(i < trpl.size() && row == trpl.get(i).row()) |
187 | { |
188 | vals.add(trpl.get(i).value()); |
189 | cols.add(trpl.get(i).col()); |
190 | i++; |
191 | } |
192 | PETSC_SAFE_CALL(MatSetValues(mat,1,&row,cols.size(),static_cast<const PetscInt*>(cols.getPointer()), |
193 | static_cast<const PetscScalar *>(vals.getPointer()), |
194 | INSERT_VALUES)); |
195 | } |
196 | |
197 | PETSC_SAFE_CALL(MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY)); |
198 | PETSC_SAFE_CALL(MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY)); |
199 | |
200 | m_created = true; |
201 | } |
202 | |
203 | |
204 | public: |
205 | |
206 | /*! \brief Create an empty Matrix |
207 | * |
208 | * \param N1 number of row |
209 | * \param N2 number of colums |
210 | * \param N1_loc number of local row |
211 | * |
212 | */ |
213 | SparseMatrix(size_t N1, size_t N2, size_t n_row_local) |
214 | :g_row(N1),g_col(N2),l_row(n_row_local),l_col(n_row_local) |
215 | { |
216 | PETSC_SAFE_CALL(MatCreate(PETSC_COMM_WORLD,&mat)); |
217 | PETSC_SAFE_CALL(MatSetType(mat,MATMPIAIJ)); |
218 | PETSC_SAFE_CALL(MatSetSizes(mat,n_row_local,n_row_local,N1,N2)); |
219 | |
220 | Vcluster<> & v_cl = create_vcluster(); |
221 | |
222 | openfpm::vector<size_t> vn_row_local; |
223 | v_cl.allGather(l_row,vn_row_local); |
224 | v_cl.execute(); |
225 | |
226 | // Calculate the starting row for this processor |
227 | |
228 | start_row = 0; |
229 | for (size_t i = 0 ; i < v_cl.getProcessUnitID() ; i++) |
230 | start_row += vn_row_local.get(i); |
231 | } |
232 | |
233 | /*! \brief Create an empty Matrix |
234 | * |
235 | */ |
236 | SparseMatrix() |
237 | :g_row(0),g_col(0),l_row(0l),l_col(0),start_row(0) |
238 | { |
239 | PETSC_SAFE_CALL(MatCreate(PETSC_COMM_WORLD,&mat)); |
240 | PETSC_SAFE_CALL(MatSetType(mat,MATMPIAIJ)); |
241 | } |
242 | |
243 | ~SparseMatrix() |
244 | { |
245 | // Destroy the matrix |
246 | if (is_openfpm_init() == true) |
247 | {PETSC_SAFE_CALL(MatDestroy(&mat));} |
248 | } |
249 | |
250 | /*! \brief Get the Matrix triplets buffer |
251 | * |
252 | * It return a buffer that can be filled with triplets |
253 | * |
254 | * \return Petsc Matrix |
255 | * |
256 | */ |
257 | openfpm::vector<triplet_type> & getMatrixTriplets() |
258 | { |
259 | m_created = false; |
260 | |
261 | return this->trpl; |
262 | } |
263 | |
264 | /*! \brief Get the Patsc Matrix object |
265 | * |
266 | * \return the Eigen Matrix |
267 | * |
268 | */ |
269 | const Mat & getMat() const |
270 | { |
271 | if (m_created == false) |
272 | {fill_petsc();} |
273 | |
274 | return mat; |
275 | } |
276 | |
277 | /*! \brief Get the Petsc Matrix object |
278 | * |
279 | * \return the Petsc Matrix |
280 | * |
281 | */ |
282 | Mat & getMat() |
283 | { |
284 | if (m_created == false) |
285 | {fill_petsc();} |
286 | |
287 | return mat; |
288 | } |
289 | |
290 | /*! \brief Resize the Sparse Matrix |
291 | * |
292 | * \param row number for row |
293 | * \param col number of colums |
294 | * \param local number of row |
295 | * \param local number of colums |
296 | * |
297 | */ |
298 | void resize(size_t row, size_t col, size_t l_row, size_t l_col) |
299 | { |
300 | this->g_row = row; |
301 | this->g_col = col; |
302 | |
303 | this->l_row = l_row; |
304 | this->l_col = l_col; |
305 | |
306 | PETSC_SAFE_CALL(MatSetSizes(mat,l_row,l_col,g_row,g_col)); |
307 | |
308 | Vcluster<> & v_cl = create_vcluster(); |
309 | |
310 | openfpm::vector<size_t> vn_row_local; |
311 | v_cl.allGather(l_row,vn_row_local); |
312 | v_cl.execute(); |
313 | |
314 | // Calculate the starting row for this processor |
315 | |
316 | start_row = 0; |
317 | for (size_t i = 0 ; i < v_cl.getProcessUnitID() ; i++) |
318 | start_row += vn_row_local.get(i); |
319 | } |
320 | |
321 | /*! \brief Get the row i and the colum j of the Matrix |
322 | * |
323 | * \warning it is slow, consider to get blocks of the matrix |
324 | * |
325 | * \return the value of the matrix at row i colum j |
326 | * |
327 | */ |
328 | T operator()(id_t i, id_t j) |
329 | { |
330 | T v; |
331 | |
332 | MatGetValues(mat,1,&i,1,&j,&v); |
333 | |
334 | return v; |
335 | } |
336 | |
337 | /*! \brief Get the value from triplet |
338 | * |
339 | * \warning It is extremly slow because it do a full search across the triplets elements |
340 | * |
341 | * \param r row |
342 | * \param c colum |
343 | * |
344 | */ |
345 | T getValue(size_t r, size_t c) |
346 | { |
347 | for (size_t i = 0 ; i < trpl.size() ; i++) |
348 | { |
349 | if (r == (size_t)trpl.get(i).row() && c == (size_t)trpl.get(i).col()) |
350 | return trpl.get(i).value(); |
351 | } |
352 | |
353 | return 0; |
354 | } |
355 | }; |
356 | |
357 | |
358 | #endif /* OPENFPM_NUMERICS_SRC_MATRIX_SPARSEMATRIX_PETSC_HPP_ */ |
359 | |