FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
umfpack.cpp
1// FEAT3: Finite Element Analysis Toolbox, Version 3
2// Copyright (C) 2010 by Stefan Turek & the FEAT group
3// FEAT3 is released under the GNU General Public License version 3,
4// see the file 'copyright.txt' in the top level directory for details.
5
7
8#ifdef FEAT_HAVE_UMFPACK
9#include <kernel/solver/umfpack.hpp>
10FEAT_DISABLE_WARNINGS
11#include <umfpack.h>
12FEAT_RESTORE_WARNINGS
13
14namespace FEAT
15{
16 namespace Solver
17 {
51 template<typename Idx_, int sidx_ = sizeof(Idx_), bool eq_ = (sizeof(int) == sizeof(SuiteSparse_long))>
52 struct UmfpackWrapper;
53
54 // specialization for Idx_ = 32-bit integer
55 template<typename Idx_, bool eq_>
56 struct UmfpackWrapper<Idx_, sizeof(int), eq_>
57 {
58 static void init_defaults(double* control)
59 {
60 ::umfpack_di_defaults(control);
61 }
62
63 static int init_symbolic(Idx_ nrows, Idx_ ncols, const Idx_* row_ptr, const Idx_* col_idx,
64 const double* data, void** symb, const double* ctrl, double* info)
65 {
66 static_assert(sizeof(Idx_) == sizeof(int), "invalid index size");
67 return int(::umfpack_di_symbolic(static_cast<int>(nrows), static_cast<int>(ncols),
68 reinterpret_cast<const int*>(row_ptr), reinterpret_cast<const int*>(col_idx),
69 data, symb, ctrl, info));
70 }
71
72 static int init_numeric(const Idx_* row_ptr, const Idx_* col_idx,
73 const double* data, void* symb, void** nume, const double* ctrl, double* info)
74 {
75 static_assert(sizeof(Idx_) == sizeof(int), "invalid index size");
76 return int(::umfpack_di_numeric(
77 reinterpret_cast<const int*>(row_ptr), reinterpret_cast<const int*>(col_idx),
78 data, symb, nume, ctrl, info));
79 }
80
81 static void free_symbolic(void** symb)
82 {
83 ::umfpack_di_free_symbolic(symb);
84 }
85
86 static void free_numeric(void** nume)
87 {
88 ::umfpack_di_free_numeric(nume);
89 }
90
91 static int solve(int sys, const Idx_* row_ptr, const Idx_* col_idx, const double* data,
92 double* x, const double* b, void* nume, const double* control, double* info)
93 {
94 static_assert(sizeof(Idx_) == sizeof(int), "invalid index size");
95 return int(::umfpack_di_solve(static_cast<int>(sys),
96 reinterpret_cast<const int*>(row_ptr), reinterpret_cast<const int*>(col_idx),
97 data, x, b, nume, control, info));
98 }
99 };
100
102 template<typename Idx_>
103 struct UmfpackWrapper<Idx_, sizeof(SuiteSparse_long), false>
104 {
105 static void init_defaults(double* control)
106 {
107 ::umfpack_dl_defaults(control);
108 }
109
110 static int init_symbolic(Idx_ nrows, Idx_ ncols, const Idx_* row_ptr, const Idx_* col_idx,
111 const double* data, void** symb, const double* ctrl, double* info)
112 {
113 static_assert(sizeof(Idx_) == sizeof(SuiteSparse_long), "invalid index size");
114 return int(::umfpack_dl_symbolic(static_cast<SuiteSparse_long>(nrows), static_cast<SuiteSparse_long>(ncols),
115 reinterpret_cast<const SuiteSparse_long*>(row_ptr), reinterpret_cast<const SuiteSparse_long*>(col_idx),
116 data, symb, ctrl, info));
117 }
118
119 static int init_numeric(const Idx_* row_ptr, const Idx_* col_idx,
120 const double* data, void* symb, void** nume, const double* ctrl, double* info)
121 {
122 static_assert(sizeof(Idx_) == sizeof(SuiteSparse_long), "invalid index size");
123 return int(::umfpack_dl_numeric(
124 reinterpret_cast<const SuiteSparse_long*>(row_ptr), reinterpret_cast<const SuiteSparse_long*>(col_idx),
125 data, symb, nume, ctrl, info));
126 }
127
128 static void free_symbolic(void** symb)
129 {
130 ::umfpack_dl_free_symbolic(symb);
131 }
132
133 static void free_numeric(void** nume)
134 {
135 ::umfpack_dl_free_numeric(nume);
136 }
137
138 static int solve(int sys, const Idx_* row_ptr, const Idx_* col_idx, const double* data,
139 double* x, const double* b, void* nume, const double* control, double* info)
140 {
141 static_assert(sizeof(Idx_) == sizeof(SuiteSparse_long), "invalid index size");
142 return int(::umfpack_dl_solve(sys, reinterpret_cast<const SuiteSparse_long*>(row_ptr),
143 reinterpret_cast<const SuiteSparse_long*>(col_idx), data, x, b, nume, control, info));
144 }
145 };
146
147 /* ***************************************************************************************** */
148 /* ***************************************************************************************** */
149 /* ***************************************************************************************** */
150
151 Umfpack::Umfpack(const Umfpack::MatrixType& system_matrix) :
152 _system_matrix(system_matrix),
153 _umf_control(new double[UMFPACK_CONTROL]),
154 _umf_symbolic(nullptr),
155 _umf_numeric(nullptr),
156 _sym_peak_size(0),
157 _sym_mem_size(0),
158 _num_mem_size(0),
159 _umf_peak_size(0)
160 {
161 // initialize default umfpack control values
162 UmfpackWrapper<Index>::init_defaults(_umf_control);
163 }
164
166 Umfpack::~Umfpack()
167 {
168 done();
169 if(_umf_control != nullptr)
170 delete [] _umf_control;
171 }
172
173 void Umfpack::init_symbolic()
174 {
175 BaseClass::init_symbolic();
176
177 // ensure that we don't have a system matrix assigned
178 if(_umf_symbolic != nullptr)
179 throw SolverException("UMFPACK: already have symbolic factorization");
180
181 // umfpack info array
182 double info[UMFPACK_INFO];
183
184 // try to perform symbolic factorization
185 int status = UmfpackWrapper<Index>::init_symbolic(
186 _system_matrix.rows(),
187 _system_matrix.columns(),
188 _system_matrix.row_ptr(),
189 _system_matrix.col_ind(),
190 nullptr,
191 &_umf_symbolic,
192 _umf_control,
193 info
194 );
195
196 // check status code
197 switch(status)
198 {
199 case UMFPACK_OK:
200 break;
201 case UMFPACK_ERROR_out_of_memory:
202 throw SolverException("UMFPACK: out of memory");
203 case UMFPACK_ERROR_invalid_matrix:
204 throw InvalidMatrixStructureException("UMFPACK: invalid matrix structure");
205 case UMFPACK_ERROR_internal_error:
206 throw SolverException("UMFPACK: internal error");
207 default:
208 throw SolverException("UMFPACK: unknown error");
209 }
210
211 // gather statistics
212 _sym_peak_size = std::size_t(info[UMFPACK_SIZE_OF_UNIT] * info[UMFPACK_SYMBOLIC_PEAK_MEMORY]);
213 _sym_mem_size = std::size_t(info[UMFPACK_SIZE_OF_UNIT] * info[UMFPACK_SYMBOLIC_SIZE]);
214 }
215
216 void Umfpack::done_symbolic()
217 {
218 if(_umf_symbolic == nullptr)
219 return;
220
221 UmfpackWrapper<Index>::free_symbolic(&_umf_symbolic);
222
223 _umf_symbolic = nullptr;
224
225 BaseClass::done_symbolic();
226 }
227
228 void Umfpack::init_numeric()
229 {
230 BaseClass::init_numeric();
231
232 if(_umf_symbolic == nullptr)
233 throw SolverException("UFMPACK: symbolic factorization missing");
234
235 // umfpack info array
236 double info[UMFPACK_INFO];
237
238 // try to perform symbolic factorization
239 int status = UmfpackWrapper<Index>::init_numeric(
240 _system_matrix.row_ptr(),
241 _system_matrix.col_ind(),
242 _system_matrix.val(),
243 _umf_symbolic,
244 &_umf_numeric,
245 _umf_control,
246 info
247 );
248
249 // check status code
250 switch(status)
251 {
252 case UMFPACK_OK:
253 break;
254 case UMFPACK_ERROR_out_of_memory:
255 throw SolverException("UMFPACK: out of memory");
256 case UMFPACK_ERROR_invalid_matrix:
257 throw InvalidMatrixStructureException("UMFPACK: invalid matrix structure");
258 case UMFPACK_WARNING_singular_matrix:
259 throw SingularMatrixException("UMFPACK: singular matrix");
260 case UMFPACK_ERROR_different_pattern:
261 throw SolverException("UMFPACK: different pattern");
262 case UMFPACK_ERROR_internal_error:
263 throw SolverException("UMFPACK: internal error");
264 default:
265 throw SolverException("UMFPACK: unknown error");
266 }
267
268 // gather statistics
269 _umf_peak_size = std::size_t(info[UMFPACK_SIZE_OF_UNIT] * info[UMFPACK_PEAK_MEMORY]);
270 _num_mem_size = std::size_t(info[UMFPACK_SIZE_OF_UNIT] * info[UMFPACK_NUMERIC_SIZE]);
271 }
272
273 void Umfpack::done_numeric()
274 {
275 if(_umf_numeric == nullptr)
276 return;
277
278 UmfpackWrapper<Index>::free_numeric(&_umf_numeric);
279
280 _umf_numeric = nullptr;
281 BaseClass::done_numeric();
282 }
283
284 Status Umfpack::apply(VectorType& x, const VectorType& b)
285 {
286 // umfpack info array
287 double info[UMFPACK_INFO];
288
289 // solve
290 int status = UmfpackWrapper<Index>::solve(
291 UMFPACK_At,
292 _system_matrix.row_ptr(),
293 _system_matrix.col_ind(),
294 _system_matrix.val(),
295 x.elements(),
296 b.elements(),
297 _umf_numeric,
298 _umf_control,
299 info);
300
301 // check status code
302 return (status == UMFPACK_OK) ? Status::success : Status::aborted;
303 }
304
305 /* ***************************************************************************************** */
306 /* ***************************************************************************************** */
307 /* ***************************************************************************************** */
308
309 UmfpackMean::UmfpackMean(const MatrixType& system_matrix, const VectorType& weight_vector) :
310 BaseClass(),
311 _system_matrix(system_matrix),
312 _weight_vector(weight_vector),
313 _umfpack(_solver_matrix)
314 {
315 }
316
317 void UmfpackMean::init_symbolic()
318 {
319 BaseClass::init_symbolic();
320
321 // get the number of rows/columns
322 const Index n = _weight_vector.size();
323 if((n != _system_matrix.rows()) || (n != _system_matrix.columns()))
324 throw InvalidMatrixStructureException("system matrix/weight vector dimension mismatch");
325
326 // get the number of non-zeroes
327 const Index nnze = _system_matrix.used_elements();
328
329 // allocate our solver matrix
330 _solver_matrix = MatrixType(n+1, n+1, nnze + 2*n);
331
332 // get our input matrix arrays
333 const Index* irow_ptr = _system_matrix.row_ptr();
334 const Index* icol_idx = _system_matrix.col_ind();
335
336 // get our output matrix arrays
337 Index* orow_ptr = _solver_matrix.row_ptr();
338 Index* ocol_idx = _solver_matrix.col_ind();
339
340 // assemble the solver matrix structure
341 orow_ptr[0] = Index(0);
342 for(Index i(0); i < n; ++i)
343 {
344 Index op = orow_ptr[i];
345 // copy input matrix row pattern
346 for(Index ip(irow_ptr[i]); ip < irow_ptr[i+1]; ++ip, ++op)
347 {
348 ocol_idx[op] = icol_idx[ip];
349 }
350 // append a single entry in the last column
351 ocol_idx[op] = n;
352 // set next row pointer
353 orow_ptr[i+1] = ++op;
354 }
355
356 // append an (almost) dense row (length n of n+1)
357 Index op(orow_ptr[n]);
358 for(Index j(0); j < n; ++j, ++op)
359 {
360 ocol_idx[op] = j;
361 }
362 // set last row pointer
363 orow_ptr[n+1] = op;
364
365 // Okay, solver matrix structure assembly complete
366
367 // create temporary vectors
368 _vec_x = _solver_matrix.create_vector_r();
369 _vec_b = _solver_matrix.create_vector_r();
370
371 // initialize umfpack
372 _umfpack.init_symbolic();
373 }
374
375 void UmfpackMean::done_symbolic()
376 {
377 _umfpack.done_symbolic();
378 _vec_b.clear();
379 _vec_x.clear();
380 _solver_matrix.clear();
381
382 BaseClass::done_symbolic();
383 }
384
385 void UmfpackMean::init_numeric()
386 {
387 BaseClass::init_numeric();
388
389 const Index n = _system_matrix.rows();
390
391 // get input matrix arrays
392 const Index* irow_ptr = _system_matrix.row_ptr();
393 const double* idata = _system_matrix.val();
394
395 // get input vector array
396 const double* weight = _weight_vector.elements();
397
398 // get output matrix arrays
399 const Index* orow_ptr = _solver_matrix.row_ptr();
400 double* odata = _solver_matrix.val();
401
402 // loop over all input matrix rows
403 for(Index i(0); i < n; ++i)
404 {
405 Index op(orow_ptr[i]);
406 // copy input matrix row data
407 for(Index ip(irow_ptr[i]); ip < irow_ptr[i+1]; ++ip, ++op)
408 {
409 odata[op] = idata[ip];
410 }
411 // copy weight vector entry as last column entry
412 odata[op] = weight[i];
413 }
414
415 // copy weight vector into last row
416 Index op(orow_ptr[n]);
417 for(Index j(0); j < n; ++j, ++op)
418 {
419 odata[op] = weight[j];
420 }
421
422 // okay, solver matrix data assembly completed
423
424 // initialize umfpack
425 _umfpack.init_numeric();
426 }
427
428 void UmfpackMean::done_numeric()
429 {
430 _umfpack.done_numeric();
431
432 BaseClass::done_numeric();
433 }
434
435 Status UmfpackMean::apply(VectorType& vec_sol, const VectorType& vec_rhs)
436 {
437 const Index n = vec_sol.size();
438
439 // copy RHS vector
440 const double* vr = vec_rhs.elements();
441 double* vb = _vec_b.elements();
442 for(Index i(0); i < n; ++i)
443 {
444 vb[i] = vr[i];
445 }
446 vb[n] = 0.0;
447
448 // solve system
449 Status status = _umfpack.apply(_vec_x, _vec_b);
450
451 // copy sol vector
452 const double* vx = _vec_x.elements();
453 double* vs = vec_sol.elements();
454 for(Index i(0); i < n; ++i)
455 {
456 vs[i] = vx[i];
457 }
458
459 // okay
460 return status;
461 }
462
463 } // namespace Solver
464} // namespace FEAT
465#else
466// insert dummy function to suppress linker warnings
467void dummy_function_umfpack() {}
468#endif // FEAT_HAVE_UMFPACK
FEAT Kernel base header.
LAFEM::SparseMatrixCSR< double, Index > MatrixType
compatible matrix type
Definition: umfpack.hpp:45
Umfpack(const MatrixType &system_matrix)
Constructor.
Status
Solver status return codes enumeration.
Definition: base.hpp:47
Status solve(SolverBase< Vector_ > &solver, Vector_ &vec_sol, const Vector_ &vec_rhs, const Matrix_ &matrix, const Filter_ &filter)
Solve linear system with initial solution guess.
Definition: base.hpp:347
FEAT namespace.
Definition: adjactor.hpp:12
std::uint64_t Index
Index data type.