b2api
B2000++ API Reference Manual, VERSION 4.6
 
Loading...
Searching...
No Matches
b2gmm_solver.H
1//------------------------------------------------------------------------
2// b2gmm_solver.H --
3//
4//
5// written by Mathias Doreille
6//
7// Copyright (c) 2004-2012 SMR Engineering & Development SA
8// 2502 Bienne, Switzerland
9//
10// All Rights Reserved. Proprietary source code. The contents of
11// this file may not be disclosed to third parties, copied or
12// duplicated in any form, in whole or in part, without the prior
13// written permission of SMR.
14//------------------------------------------------------------------------
15
16#ifndef __B2GMM_SOLVER_H__
17#define __B2GMM_SOLVER_H__
18
19// #pragma GCC diagnostic push
20// #pragma GCC diagnostic warning "-fpermissive"
21
22#include "gmm/gmm_dense_Householder.h"
23#include "gmm/gmm_interface.h"
24#include "gmm/gmm_precond_diagonal.h"
25#include "gmm/gmm_precond_ildlt.h"
26#include "gmm/gmm_precond_ildltt.h"
27#include "gmm/gmm_precond_ilu.h"
28#include "gmm/gmm_precond_ilut.h"
29#include "gmm/gmm_precond_ilutp.h"
30#include "gmm/gmm_precond_mr_approx_inverse.h"
31#include "gmm/gmm_solver_cg.h"
32#include "gmm/gmm_solver_gmres.h"
33
34// #pragma GCC diagnostic pop
35
36#include "b2ppconfig.h"
37#include "utils/b2exception.H"
38
39namespace b2000 { namespace b2linalg {
40
41template <typename T, template <typename MATRIX> class PRECOND>
42class gmm_cg_iterative_solver : public LDLt_sparse_solver<T> {
43public:
44 typedef gmm::csc_matrix<T> gmm_matrix_t;
45 typedef PRECOND<gmm_matrix_t> precond_type;
46
47 gmm_cg_iterative_solver(precond_type* precond_, const Dictionary& dictionary_)
48 : colind(0),
49 rowind(0),
50 value(0),
51 precond(precond_),
52 modified_value(true),
53 dictionary(dictionary_) {}
54
55 ~gmm_cg_iterative_solver() { delete precond; }
56
57 void init(
58 size_t s_, size_t nnz_, const size_t* colind_, const size_t* rowind_, const T* value_,
59 int connectivity, const Dictionary& dictionary_) {
60 gmm_matrix.nc = s_;
61 gmm_matrix.nr = s_;
62 colind = colind_;
63 rowind = rowind_;
64 value = value_;
65 size_t nnz = colind[gmm_matrix.nc];
66 nnz = nnz * 2 - gmm_matrix.nc;
67#if GMM_VERSION == 4
68 gmm_matrix.pr.resize(nnz);
69 gmm_matrix.ir.resize(nnz);
70 gmm_matrix.jc.resize(gmm_matrix.nc + 2);
71#else
72 gmm_matrix.pr = new T[nnz];
73 gmm_matrix.ir = new typename gmm_matrix_t::IND_TYPE[nnz];
74 gmm_matrix.jc = new typename gmm_matrix_t::IND_TYPE[gmm_matrix.nc + 2];
75#endif
76 update_value();
77 }
78
79 void update_value() { modified_value = true; }
80
81 void resolve(
82 size_t s, size_t nrhs, const T* b, size_t ldb, T* x, size_t ldx,
83 char left_or_right = ' ') {
84 if (modified_value) {
85 size_t nnz = colind[gmm_matrix.nc];
86 nnz = nnz * 2 - gmm_matrix.nc;
87 size_t size = gmm_matrix.nc;
88#if GMM_VERSION == 4
89 typename gmm_matrix_t::IND_TYPE* colptr1 = &gmm_matrix.jc[0];
90#else
91 typename gmm_matrix_t::IND_TYPE* colptr1 = gmm_matrix.jc;
92#endif
93 colptr1[0] = colptr1[1] = 0;
94 colptr1 += 2;
95 for (size_t j = 0; j != size; ++j) { colptr1[j] = colind[j + 1] - colind[j]; }
96 for (size_t j = 0; j != size; ++j) {
97 const size_t i_end = colind[j + 1];
98 for (size_t i = colind[j] + 1; i < i_end; ++i) { ++colptr1[rowind[i]]; }
99 }
100 --colptr1;
101 for (size_t j = 0; j != size; ++j) { colptr1[j + 1] += colptr1[j]; }
102#if GMM_VERSION == 4
103 typename gmm_matrix_t::IND_TYPE* rowind1 = &gmm_matrix.ir[0];
104 T* nzval1 = &gmm_matrix.pr[0];
105#else
106 typename gmm_matrix_t::IND_TYPE* rowind1 = gmm_matrix.ir;
107 T* nzval1 = gmm_matrix.pr;
108#endif
109 for (size_t j = 0; j != size; ++j) {
110 size_t i = colind[j];
111 const size_t i_end = colind[j + 1];
112 typename gmm_matrix_t::IND_TYPE ii = colptr1[j];
113 colptr1[j] += i_end - i;
114 std::copy(rowind + i, rowind + i_end, rowind1 + ii);
115 std::copy(value + i, value + i_end, nzval1 + ii);
116 for (++i; i < i_end; ++i) {
117 int ii = colptr1[rowind[i]]++;
118 rowind1[ii] = j;
119 nzval1[ii] = value[i];
120 }
121 }
122 precond->build_with(gmm_matrix);
123 modified_value = false;
124 }
125
126 if (left_or_right != ' ') { UnimplementedError() << THROW; }
127
128 gmm::iteration iter(
129 dictionary.get_double("SLS_TOL_RESIDUUM", 1.0E-8),
130 dictionary.get_int("SLS_VERBOSITY", 0), dictionary.get_int("SLS_MAX_ITER", -1));
131 T* tmp = 0;
132 if (b == x) { tmp = new T[s]; }
133 for (size_t i = 0; i != nrhs; ++i) {
134 if (b == x) { std::copy(b + ldb * i, b + ldb * (i + 1), tmp); }
135 gmm::array1D_reference<const T*> B(b == x ? tmp : b + ldb * i, s);
136 gmm::array1D_reference<T*> X(x + ldx * i, s);
137 gmm::cg(gmm_matrix, X, B, *precond, iter);
138 if (!iter.converged()) {
139 Exception() << "The iterative sparse linear solver did not converge" << THROW;
140 }
141 }
142 if (b == x) { delete[] tmp; }
143 }
144
145protected:
146 const size_t* colind;
147 const size_t* rowind;
148 const T* value;
149 gmm_matrix_t gmm_matrix;
150 precond_type* precond;
151 bool modified_value;
152 const Dictionary& dictionary;
153};
154
155template <typename T>
156LDLt_sparse_solver<T>* new_gmm_cg_iterative_solver(const Dictionary& dictionary) {
157 std::string precond_name = dictionary.get_string("SLS_PRECOND", "ILDLT");
158 if (precond_name == "ILDLT") {
159 typedef gmm_cg_iterative_solver<T, gmm::ildlt_precond> s_t;
160 return new s_t(new typename s_t::precond_type(), dictionary);
161 }
162 if (precond_name == "ILDLTT") {
163 typedef gmm_cg_iterative_solver<T, gmm::ildltt_precond> s_t;
164 return new s_t(new typename s_t::precond_type(), dictionary);
165 }
166 if (precond_name == "DIAGONAL") {
167 typedef gmm_cg_iterative_solver<T, gmm::diagonal_precond> s_t;
168 return new s_t(new typename s_t::precond_type(), dictionary);
169 }
170 // if (precond_name == "_mr_approx_inverse") {
171 // typedef gmm_cg_iterative_solver<T, gmm::mr_approx_inverse_precond> s_t;
172 // return new s_t(new typename s_t::precond_type(), dictionary);
173 //}
174 Exception() << "Unknown GMM++ cg preconditioner " << precond_name << "." << THROW;
175 return 0;
176}
177
178template <typename T, template <typename MATRIX> class PRECOND>
179class extension_gmm_cg_iterative_solver : public LDLt_extension_sparse_solver<T>,
180 public gmm_cg_iterative_solver<T, PRECOND> {
181public:
182 extension_gmm_cg_iterative_solver(
183 typename gmm_cg_iterative_solver<T, PRECOND>::precond_type* precond_,
184 const Dictionary& dictionary_)
185 : gmm_cg_iterative_solver<T, PRECOND>(precond_, dictionary_) {}
186
187 ~extension_gmm_cg_iterative_solver() {}
188
189 void init(
190 size_t size_, size_t nnz_, const size_t* colind_, const size_t* rowind_, const T* value_,
191 size_t size_ext_, const int connectivity, const Dictionary& dictionary) {
192 if (size_ext_ != 1) { UnimplementedError() << THROW; }
193
194 gmm_cg_iterative_solver<T, PRECOND>::init(
195 size_, nnz_, colind_, rowind_, value_, connectivity, dictionary);
196 m_a.resize(size_);
197 m_b.resize(size_);
198 }
199
200 void update_value() { gmm_cg_iterative_solver<T, PRECOND>::update_value(); }
201
202 void resolve(
203 size_t s, size_t nrhs, const T* b, size_t ldb, T* x, size_t ldx, const T* ma_ = 0,
204 const T* mb_ = 0, const T* mc_ = 0, char left_or_right = ' ') {
205 if (ma_ != 0 && mb_ != 0 && mc_ != 0) {
206 gmm_cg_iterative_solver<T, PRECOND>::resolve(s - 1, 1, ma_, s - 1, &m_a[0], s - 1);
207 gmm_cg_iterative_solver<T, PRECOND>::resolve(s - 1, 1, mb_, s - 1, &m_b[0], s - 1);
208 div = 1 / (*mc_ - blas::dot(s - 1, ma_, 1, &m_b[0], 1));
209 }
210
211 for (size_t i = 0; i != nrhs; ++i) {
212 const double x2 = x[ldx * i + s - 1] =
213 div * (b[ldb * i + s - 1] - blas::dot(s - 1, b + ldb * i, 1, &m_b[0], 1));
214 gmm_cg_iterative_solver<T, PRECOND>::resolve(
215 s - 1, 1, b + ldb * i, s - 1, x + ldx * i, s - 1);
216 blas::axpy(s - 1, -x2, &m_a[0], 1, x + ldx * i, 1);
217 }
218 }
219
220protected:
221 std::vector<T> m_a;
222 std::vector<T> m_b;
223 T div;
224};
225
226template <typename T>
227LDLt_extension_sparse_solver<T>* new_extension_gmm_cg_iterative_solver(
228 const Dictionary& dictionary) {
229 std::string precond_name = dictionary.get_string("SLS_PRECOND", "ILDLT");
230 if (precond_name == "ILDLT") {
231 typedef extension_gmm_cg_iterative_solver<T, gmm::ildlt_precond> s_t;
232 return new s_t(new typename s_t::precond_type(), dictionary);
233 }
234 if (precond_name == "ILDLTT") {
235 typedef extension_gmm_cg_iterative_solver<T, gmm::ildltt_precond> s_t;
236 return new s_t(new typename s_t::precond_type(), dictionary);
237 }
238 if (precond_name == "DIAGONAL") {
239 typedef extension_gmm_cg_iterative_solver<T, gmm::diagonal_precond> s_t;
240 return new s_t(new typename s_t::precond_type(), dictionary);
241 }
242 // if (precond_name == "_mr_approx_inverse") {
243 // typedef gmm_cg_iterative_solver<T, gmm::mr_approx_inverse_precond> s_t;
244 // return new s_t(new typename s_t::precond_type(), dictionary);
245 //}
246
247 Exception() << "Unknow GMM++ cg preconditioner " << precond_name << "." << THROW;
248 return 0;
249}
250
251template <typename T, template <typename MATRIX> class PRECOND>
252class gmm_gmres_iterative_solver : public LU_sparse_solver<T> {
253public:
254 typedef gmm::csc_matrix_ref<const T*, const size_t*, const size_t*> gmm_matrix_ref_t;
255 typedef PRECOND<gmm_matrix_ref_t> precond_type;
256
257 gmm_gmres_iterative_solver(precond_type* precond_, const Dictionary& dictionary_)
258 : precond(precond_), modified_value(true), dictionary(dictionary_) {}
259
260 ~gmm_gmres_iterative_solver() { delete precond; }
261
262 void init(
263 size_t s, size_t nnz, const size_t* colind, const size_t* rowind, const T* value,
264 int connectivity, const Dictionary& dictionary_) {
265 gmm_matrix_ref = gmm_matrix_ref_t(value, rowind, colind, s, s);
266 update_value();
267 }
268
269 void update_value() { modified_value = true; }
270
271 void resolve(
272 size_t s, size_t nrhs, const T* b, size_t ldb, T* x, size_t ldx,
273 char left_or_right = ' ') {
274 if (modified_value) {
275 precond->build_with(gmm_matrix_ref);
276 modified_value = false;
277 }
278 gmm::iteration iter(
279 dictionary.get_double("SLS_TOL_RESIDUUM", 1.0E-8),
280 dictionary.get_int("SLS_VERBOSITY", 0), dictionary.get_int("SLS_MAX_ITER", -1));
281 T* tmp = 0;
282 if (b == x) { tmp = new T[s]; }
283 size_t restart = dictionary.get_int("SLS_RESTART", 200);
284 for (size_t i = 0; i != nrhs; ++i) {
285 if (b == x) { std::copy(b + ldb * i, b + ldb * (i + 1), tmp); }
286 gmm::array1D_reference<const T*> B(b == x ? tmp : b + ldb * i, s);
287 gmm::array1D_reference<T*> X(x + ldx * i, s);
288 gmm::gmres(gmm_matrix_ref, X, B, *precond, restart, iter);
289 if (!iter.converged()) {
290 Exception() << "The iterative sparse linear solver did not converge" << THROW;
291 }
292 }
293 if (b == x) { delete[] tmp; }
294 }
295
296protected:
297 gmm_matrix_ref_t gmm_matrix_ref;
298 precond_type* precond;
299 bool modified_value;
300 const Dictionary& dictionary;
301};
302
303template <typename T>
304LU_sparse_solver<T>* new_gmm_gmres_iterative_solver(const Dictionary& dictionary) {
305 std::string precond_name = dictionary.get_string("SLS_PRECOND", "ILU");
306 if (precond_name == "ILU") {
307 typedef gmm_gmres_iterative_solver<T, gmm::ilu_precond> s_t;
308 return new s_t(new typename s_t::precond_type(), dictionary);
309 }
310 if (precond_name == "ILUT") {
311 typedef gmm_gmres_iterative_solver<T, gmm::ilut_precond> s_t;
312 return new s_t(new typename s_t::precond_type(), dictionary);
313 }
314 if (precond_name == "ILUTP") {
315 typedef gmm_gmres_iterative_solver<T, gmm::ilutp_precond> s_t;
316 return new s_t(new typename s_t::precond_type(), dictionary);
317 }
318 if (precond_name == "DIAGONAL") {
319 typedef gmm_gmres_iterative_solver<T, gmm::diagonal_precond> s_t;
320 return new s_t(new typename s_t::precond_type(), dictionary);
321 }
322 if (precond_name == "MR_APPROX_INVERSE") {
323 typedef gmm_gmres_iterative_solver<T, gmm::mr_approx_inverse_precond> s_t;
324 return new s_t(new typename s_t::precond_type(), dictionary);
325 }
326
327 Exception() << "Unknown GMM++ gmres preconditioner " << precond_name << "." << THROW;
328
329 return 0;
330}
331
332}} // namespace b2000::b2linalg
333
334#endif
#define THROW
Definition b2exception.H:198
Contains the base classes for implementing Finite Elements.
Definition b2boundary_condition.H:32
GenericException< UnimplementedError_name > UnimplementedError
Definition b2exception.H:314