2
/// This file is part of Rheolef.
4
/// Copyright (C) 2000-2009 Pierre Saramito <Pierre.Saramito@imag.fr>
6
/// Rheolef is free software; you can redistribute it and/or modify
7
/// it under the terms of the GNU General Public License as published by
8
/// the Free Software Foundation; either version 2 of the License, or
9
/// (at your option) any later version.
11
/// Rheolef is sequential in the hope that it will be useful,
12
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
13
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
/// GNU General Public License for more details.
16
/// You should have received a copy of the GNU General Public License
17
/// along with Rheolef; if not, write to the Free Software
18
/// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
/// =========================================================================
21
// c++ & boost::mpi adaptation of pastix "simple.c" sequential example
23
#include "rheolef/config.h"
24
#ifdef _RHEOLEF_HAVE_PASTIX
25
#include "solver_pastix.h"
26
#include "rheolef/pcg.h"
27
#include "rheolef/eye.h"
32
template<class T, class M>
34
solver_pastix_base_rep<T,M>::resize (pastix_int_t n, pastix_int_t nnz)
42
template<class T, class M>
44
solver_pastix_base_rep<T,M>::check () const
46
warning_macro ("check...");
49
* Pastix matrix needs :
50
* - to be in fortran numbering
51
* - to have only the lower triangular part in symmetric case
52
* - to have a graph with a symmetric structure in unsymmetric case
54
pastix_int_t symmetry = (is_symmetric() ? API_SYM_YES : API_SYM_NO);
55
pastix_int_t *ptr_begin = (pastix_int_t*) _ptr.begin().operator->();
56
pastix_int_t *idx_begin = (pastix_int_t*) _idx.begin().operator->();
57
T *val_begin = (T*) _val.begin().operator->();
58
pastix_int_t status = d_pastix_checkMatrix (0, _opt.verbose_level, symmetry, API_YES,
59
_n, &ptr_begin, &idx_begin, &val_begin, NULL, 1);
60
check_macro (status == 0, "pastix check returns error status = " << status);
61
warning_macro ("pastix matrix check: ok");
63
template<class T, class M>
65
solver_pastix_base_rep<T,M>::load_both_continued (const csr<T,M>& a)
67
size_t first_dis_i = a.row_ownership().first_index();
68
size_t first_dis_j = a.col_ownership().first_index();
69
typename csr<T,M>::const_iterator aptr = a.begin();
71
_ptr [0] = bp + _base;
72
for (size_t i = 0; i < a.nrow(); i++) {
73
size_t dis_i = first_dis_i + i;
74
for (typename csr<T,M>::const_data_iterator ap = aptr[i]; ap < aptr[i+1]; ap++) {
75
size_t j = (*ap).first;
76
const T& val = (*ap).second;
77
size_t dis_j = first_dis_j + j;
78
if (_is_sym && dis_i > dis_j) continue;
80
_idx [bp] = dis_j + _base;
83
_ptr [i+1] = bp + _base;
85
check_macro (bp == _nnz, "factorization: invalid nnz count");
87
template<class T, class M>
89
solver_pastix_base_rep<T,M>::load_unsymmetric (const csr<T,M>& a)
94
load_both_continued (a);
96
template<class T, class M>
98
solver_pastix_base_rep<T,M>::load_symmetric (const csr<T,M>& a)
100
check_macro ((a.nnz()-a.ncol()) % 2 == 0, "factorization: symmetric csr has unsymmetric structure");
101
// conserve only the lower part of the csc(pastix) = the upper past of the csr(rheolef)
103
size_t nnz = a.nnz() - (a.nnz() - a.nrow())/2; // TODO: bug when matrix has some zero on the diag: fix it !
105
load_both_continued (a);
107
template<class T, class M>
109
solver_pastix_base_rep<T,M>::symbolic_factorization ()
112
if (_have_pastix_bug_small_matrix) {
113
warning_macro ("sym_fact: bug, circumvent !");
116
warning_macro ("sym_fact [1]...");
117
const pastix_int_t nbthread = 1; // threads are not yet very well supported with openmpi & scotch
118
const pastix_int_t ordering = 0; // scotch
121
// 0. set params to default values
122
_iparm[IPARM_START_TASK] = API_TASK_INIT;
123
_iparm[IPARM_END_TASK] = API_TASK_INIT;
124
_iparm[IPARM_MODIFY_PARAMETER] = API_NO;
125
d_pastix (&_pastix_data,
128
_ptr.begin().operator->(),
129
_idx.begin().operator->(),
130
NULL, // _val.begin().operator->(),
138
// Customize some parameters
139
_iparm[IPARM_THREAD_NBR] = nbthread;
140
if (is_symmetric()) {
141
_iparm[IPARM_SYM] = API_SYM_YES;
142
_iparm[IPARM_FACTORIZATION] = API_FACT_LDLT;
144
_iparm[IPARM_SYM] = API_SYM_NO;
145
_iparm[IPARM_FACTORIZATION] = API_FACT_LU;
147
_iparm[IPARM_MATRIX_VERIFICATION] = API_NO;
148
_iparm[IPARM_VERBOSE] = _opt.verbose_level;
149
_iparm[IPARM_ORDERING] = ordering;
151
if (_opt.incomplete != solver_option_type::decide) {
152
do_incomplete = (_opt.incomplete != 0);
154
do_incomplete = (_pattern_dimension > 2); // 3d-pattern => iterative & IC(k) precond
156
warning_macro ("do_incomplete = " << do_incomplete);
157
_iparm[IPARM_INCOMPLETE] = (do_incomplete ? 1 : 0);
158
_iparm[IPARM_OOC_LIMIT] = _opt.ooc;
159
if (_opt.incomplete == 1) {
160
_dparm[DPARM_EPSILON_REFINEMENT] = _opt.tol;
162
_iparm[IPARM_LEVEL_OF_FILL] = _opt.level_of_fill;
163
_iparm[IPARM_AMALGAMATION_LEVEL] = _opt.amalgamation;
164
_iparm[IPARM_RHS_MAKING] = API_RHS_B;
165
// 1) get the i2new_dis_i array: its indexes are in the [0:dis_n[ range
166
// i2new_dis_i[i] = i2new_dis_i [i]
167
_i2new_dis_i.resize (_n);
169
warning_macro ("sym_fact [2] i2new_dis_i...");
170
warning_macro ("sym_fact [2] n="<<_n);
171
warning_macro ("sym_fact [2] _ptr.begin="<< _ptr.begin().operator->());
172
warning_macro ("sym_fact [2] _idx.begin="<< _idx.begin().operator->());
173
warning_macro ("sym_fact [2] _i2new_dis_i.begin="<< _i2new_dis_i.begin().operator->());
175
pastix_int_t itmp = 0; // pastix does not manage NULL pointers: when n=0, vector::begin() retuns a NULL...
176
T vtmp = 0; // pastix does not manage NULL pointers: when n=0, vector::begin() retuns a NULL...
180
// 2. symbolic factorization
181
// 3. tasks mapping and scheduling
182
_iparm[IPARM_START_TASK] = API_TASK_ORDERING;
183
_iparm[IPARM_END_TASK] = API_TASK_ANALYSE;
185
std::vector<pastix_int_t> new_i2i (_n);
186
std::vector<double> dummy_rhs (_n);
187
warning_macro ("sym_fact [3] call pastix... _n="<<_n);
188
warning_macro ("sym_fact [3] call pastix... _ptr="<<_ptr.begin().operator->());
189
warning_macro ("sym_fact [3] call pastix... _idx="<<_idx.begin().operator->());
190
warning_macro ("sym_fact [3] call pastix... _i2new_i="<<_i2new_dis_i.begin().operator->());
191
warning_macro ("sym_fact [3] call pastix... new_i2i="<<new_i2i.begin().operator->());
192
d_pastix (&_pastix_data,
195
_ptr.begin().operator->(),
196
(_idx.begin().operator->() != NULL) ? _idx.begin().operator->() : &itmp,
198
(_i2new_dis_i.begin().operator->() != NULL) ? _i2new_dis_i.begin().operator->() : &itmp,
199
(new_i2i.begin().operator->() != NULL) ? new_i2i.begin().operator->() : &itmp,
204
warning_macro ("sym_fact [3] call pastix done");
206
warning_macro ("sym_fact done");
208
template<class T, class M>
210
solver_pastix_base_rep<T,M>::numeric_factorization ()
213
if (_have_pastix_bug_small_matrix) {
214
warning_macro ("num_fact: bug, circumvent !");
218
// 4. numerical factorization
219
warning_macro ("num_fact [2] factorise...");
220
pastix_int_t itmp = 0; // pastix does not manage NULL pointers: when n=0, vector::begin() retuns a NULL...
221
T vtmp = 0; // pastix does not manage NULL rhs pointer: when new_n=0, but vector::begin() retuns a NULL...
222
_iparm[IPARM_START_TASK] = API_TASK_NUMFACT;
223
_iparm[IPARM_END_TASK] = API_TASK_NUMFACT;
224
d_pastix (&_pastix_data,
227
_ptr.begin().operator->(),
228
(_idx.begin().operator->() != NULL) ? _idx.begin().operator->() : &itmp,
229
(_val.begin().operator->() != NULL) ? _val.begin().operator->() : &vtmp,
230
(_i2new_dis_i.begin().operator->() != NULL) ? _i2new_dis_i.begin().operator->() : &itmp,
237
warning_macro ("num fact done");
239
template<class T, class M>
241
solver_pastix_base_rep<T,M>::load (const csr<T,M>& a, const solver_option_type& opt)
243
_is_sym = a.is_symmetric();
244
_pattern_dimension = a.pattern_dimension();
245
warning_macro ("is_sym = " << _is_sym);
246
warning_macro ("pattern_dim = " << _pattern_dimension);
247
_csr_row_ownership = a.row_ownership();
248
_csr_col_ownership = a.col_ownership();
251
check_macro (a.nrow() == a.ncol(), "factorization: only square matrix are supported");
261
symbolic_factorization ();
262
numeric_factorization();
264
template<class T, class M>
265
solver_pastix_base_rep<T,M>::solver_pastix_base_rep ()
272
_pattern_dimension(0),
276
_csr_row_ownership(),
277
_csr_col_ownership(),
282
_have_pastix_bug_small_matrix(false),
286
template<class T, class M>
287
solver_pastix_base_rep<T,M>::solver_pastix_base_rep (const csr<T,M>& a, const solver_option_type& opt)
294
_pattern_dimension(0),
298
_csr_row_ownership(),
299
_csr_col_ownership(),
304
_have_pastix_bug_small_matrix(false),
309
template<class T, class M>
311
solver_pastix_base_rep<T,M>::update_values (const csr<T,M>& a)
314
check_macro (size_t(_n) == a.nrow() && size_t(_n) == a.ncol(),
315
"update: local input matrix size distribution mismatch: ("<<a.nrow()<<","<<a.ncol()<<"), expect ("
316
<< _n << "," << _n << ")");
321
// conserve only the lower part of the csc(pastix) = the upper past of the csr(rheolef)
322
nnz_a = a.nnz() - (a.nnz() - a.nrow())/2; // TODO: fix when zero on diag
324
check_macro (size_t(_nnz) == nnz_a,
325
"update: local input matrix nnz distribution mismatch: nnz="<<nnz_a<<", expect nnz="<<_nnz);
327
size_t first_dis_i = a.row_ownership().first_index();
328
size_t first_dis_j = a.col_ownership().first_index();
330
typename csr<T,M>::const_iterator aptr = a.begin();
331
for (size_t i = 0; i < a.nrow(); i++) {
332
size_t dis_i = first_dis_i + i;
333
for (typename csr<T,M>::const_data_iterator ap = aptr[i]; ap < aptr[i+1]; ap++) {
334
size_t j = (*ap).first;
335
size_t dis_j = first_dis_j + j;
336
if (_is_sym && dis_i > dis_j) continue;
337
_val [bp] = (*ap).second;
341
numeric_factorization();
343
template<class T, class M>
345
solver_pastix_base_rep<T,M>::trans_solve (const vec<T,M>& rhs)
347
if (_n == 0) return rhs;
348
// ================================================================
350
// ================================================================
351
warning_macro ("trans_solve [1]... n="<<_n);
352
check_macro (rhs.size() == size_t(_n), "invalid rhs size="<<rhs.size()<<": expect size="<<_n);
354
_new_rhs.resize (_n);
355
for (pastix_int_t i = 0; i < _n; i++) {
356
_new_rhs [i] = rhs [i];
359
// 5. numerical solve
360
// 6. numerical refinement
362
warning_macro ("trans_solve [3] solve...new_rhs.ptr="<< _new_rhs.begin().operator->());
363
pastix_int_t itmp = 0; // pastix does not manage NULL pointers: when n=0, vector::begin() retuns a NULL...
364
T vtmp = 0; // pastix does not manage NULL rhs pointer: when new_n=0, but vector::begin() retuns a NULL...
365
_iparm[IPARM_START_TASK] = API_TASK_SOLVE;
366
_iparm[IPARM_END_TASK] = API_TASK_REFINE;
367
d_pastix (&_pastix_data,
370
_ptr.begin().operator->(),
371
(_idx.begin().operator->() != NULL) ? _idx.begin().operator->() : &itmp,
372
(_val.begin().operator->() != NULL) ? _val.begin().operator->() : &vtmp,
373
(_i2new_dis_i.begin().operator->() != NULL) ? _i2new_dis_i.begin().operator->() : &itmp,
375
(_n != 0) ? _new_rhs.begin().operator->() : &vtmp,
380
// new_i2dis_i_base [new_i] - base = new_i2dis_i [new_i]
381
warning_macro ("trans_solve [4] perm(x)...");
382
vec<T,M> x (_csr_row_ownership);
383
for (pastix_int_t i = 0; i < _n; i++) {
384
x [i] = _new_rhs [i];
386
warning_macro ("trans_solve done");
389
template<class T, class M>
391
solver_pastix_base_rep<T,M>::solve (const vec<T,M>& rhs)
393
warning_macro ("solve...");
394
// TODO: make a csc<T> wrapper arround csr<T> and use csc<T> in form & form_assembly
395
// => avoid the transposition
397
warning_macro ("solve: not yet supported for unsymmetric matrix; continue with trans_solve....");
399
return trans_solve (rhs);
401
template<class T, class M>
402
solver_pastix_base_rep<T,M>::~solver_pastix_base_rep()
404
warning_macro ("dstor...");
405
if (_pastix_data == 0) return;
408
_iparm[IPARM_START_TASK] = API_TASK_CLEAN;
409
_iparm[IPARM_END_TASK] = API_TASK_CLEAN;
410
d_pastix (&_pastix_data,
418
_new_rhs.begin().operator->(),
423
// was allocated by d_cscd_redispatch()
424
warning_macro ("dstor call free...");
426
warning_macro ("dstor done");
428
// ----------------------------------------------------------------------------
429
// instanciation in library
430
// ----------------------------------------------------------------------------
431
// TODO: code is only valid here for T=double (d_pastix etc)
433
template class solver_pastix_base_rep<double,sequential>;
435
#ifdef _RHEOLEF_HAVE_MPI
436
template class solver_pastix_base_rep<double,distributed>;
437
#endif // _RHEOLEF_HAVE_MPI
439
} // namespace rheolef
440
#endif // _RHEOLEF_HAVE_PASTIX