KASKADE 7 development version
mumps_solve.hh
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the library KASKADE 7 */
4/* https://www.zib.de/research/projects/kaskade7-finite-element-toolbox */
5/* */
6/* Copyright (C) 2002-2024 Zuse Institute Berlin */
7/* */
8/* KASKADE 7 is distributed under the terms of the ZIB Academic License. */
9/* see $KASKADE/academic.txt */
10/* */
11/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12
13#ifndef MUMPS_SOLVE_HH
14#define MUMPS_SOLVE_HH
15
16#include <iostream>
17#include <memory>
18#include <string>
19#include <vector>
20
21#include "dmumps_c.h"
22#include "smumps_c.h"
23#define ICNTL(I) icntl[(I)-1]
24#define JOB_INIT -1
25#define JOB_END -2
26#define USE_COMM_WORLD -987654
27
30
31namespace Kaskade
32{
33
39template <class Scalar>
40class MUMPSFactorization: public Factorization<Scalar>
41{
42private:
44
45 void printMatrixInfo()
46 {
47 if (this->options.verbosity>=2)
48 {
49 const char *s = "UNKNOWN";
50 if (this->options.matrixProperty==MatrixProperties::GENERAL) s = "GENERAL";
51 else if (this->options.matrixProperty==MatrixProperties::SYMMETRIC) s = "MatrixProperties::SYMMETRIC";
52 else if (this->options.matrixProperty==MatrixProperties::SYMMETRICSTRUCTURE) s = "SYMMETRICSTRUCTURE";
53 else if (this->options.matrixProperty==MatrixProperties::POSITIVEDEFINITE) s = "MatrixProperties::POSITIVEDEFINITE";
54 std::cout << "MUMPS" << " solver, n=" << n << ", nnz=" << N << ", matrix is " << s << std::endl;
55 }
56 }
57
58public:
59
69 MUMPSFactorization(MUMPS_INT n_,
70 std::vector<MUMPS_INT>& ridx,
71 std::vector<MUMPS_INT>& cidx,
72 std::vector<Scalar>& values,
73 typename Base::Options options)
74 : Base(options), N(ridx.size()), n(n_)
75 {
76 assert(cidx.size()==N && values.size()==N);
77
78 printMatrixInfo();
79
80 // MUMPS expects symmetric matrices to be given as only one triangular half-matrix. If both a_ij and a_ji are
81 // given, they are summed up (which may not be what we want). Thus, if we tell MUMPS that the matrix is symmetric,
82 // we set the upper right half to zero.
84 || this->options.matrixProperty==MatrixProperties::POSITIVEDEFINITE)
85 for (MUMPS_INT i=0; i<N; ++i)
86 if (cidx[i] > ridx[i]) // found a super-diagonal entry
87 values[i] = 0; // ... that we don't wont to fool MUMPS
88
89 init();
90 analyze(&ridx[0], &cidx[0]);
91 factorize(&values[0]);
92 }
93
95 {
96 mumps_par.job = JOB_END;
97 mumps_par.ICNTL(3) = 0;
98 callMumps(&mumps_par);
99 }
100
101 void init()
102 {
103 mumps_par.job = JOB_INIT;
104 mumps_par.par = 1;
105
106 // Tell MUMPS the structure of the matrix to be factorized. MUMPS distinguishes between
107 // unsymmetric(0), general symmetric(2), and positive definite(1) matrices. For the latter,
108 // no pivoting is performed.
109 switch (this->options.matrixProperty)
110 {
112 mumps_par.sym = 0;
113 break;
115 mumps_par.sym = 0;
116 break;
118 mumps_par.sym = 2;
119 break;
121 mumps_par.sym = 1;
122 break;
123 }
124 mumps_par.comm_fortran = USE_COMM_WORLD;
125 callMumps(&mumps_par);
126 if (this->options.verbosity < 1) // If no verbose reporting is asked for
127 mumps_par.ICNTL(3) = 0; // reset the output stream
128 mumps_par.ICNTL(14) += 5; // 5% additonal workspace
129 }
130
131 void analyze(MUMPS_INT* irn, MUMPS_INT* jcn)
132 {
133 mumps_par.job = 1;
134 mumps_par.n = n;
135 mumps_par.nz = N;
136
137 // Convert to 1-based indexing
138 for (int k=0; k<N; k++)
139 {
140 irn[k]++;
141 jcn[k]++;
142 }
143 mumps_par.irn = irn;
144 mumps_par.jcn = jcn;
146 && this->options.mumps.inertia)
147 {
148 mumps_par.ICNTL(24) = 1;
149 mumps_par.cntl[2] = this->options.mumps.zeroPivotThreshold;
150 }
151 callMumps(&mumps_par);
152 if (mumps_par.info[0] < 0)
153 throw DirectSolverException("MUMPS analyze failed with error " + std::to_string(mumps_par.info[0]),
154 __FILE__,__LINE__);
155 }
156
157 void factorize(Scalar* a)
158 {
159 mumps_par.job = 2;
160 mumps_par.a = a;
161 callMumps(&mumps_par);
162 if (mumps_par.info[0] < 0)
163 {
164 std::string errmsg;
165 switch(mumps_par.info[0])
166 {
167 case -13:
168 {
169 size_t entries = mumps_par.info[1]<0? -1000000*mumps_par.info[1]: mumps_par.info[1];
170 errmsg = "\nAllocation of " + std::to_string(entries) + " scalar entries (" + std::to_string(entries*sizeof(Scalar)/1024/1024) + "MB) failed.";
171 break;
172 }
173 default:
174 break;
175 }
176 throw DirectSolverException("MUMPS factorization failed with error " + std::to_string(mumps_par.info[0])+errmsg,__FILE__,__LINE__);
177 }
178
180 && this->options.mumps.inertia) {
181 this->info_.mumps.negativePivots = mumps_par.infog[11];
182 this->info_.mumps.zeroPivots = mumps_par.infog[27];
183 }
184 }
185
191 void solve(std::vector<Scalar> const& b, std::vector<Scalar>& x, bool transpose=false) const
192 {
193 assert(b.size()>=n);
194 assert(&x != &b);
195 x = b;
196 solve(x);
197 }
198
199 void solve(Scalar const* b, Scalar* x, bool transpose=false) const
200 {
201 std::copy(b,b+n,x);
202 solve(x);
203 }
204
205
206
211 void solve(std::vector<Scalar>& b) const
212 {
213 assert(b.size()>=n);
214 solve(&b[0]);
215 }
216
217 void solve(Scalar* b) const
218 {
219 mumps_par.job = 3;
220 mumps_par.rhs = b;
221 callMumps(&mumps_par);
222 if (mumps_par.info[0] < 0)
223 throw DirectSolverException("MUMPS solve failed with error "+ std::to_string(mumps_par.info[0]),
224 __FILE__,__LINE__);
225 }
226
227 size_t size() const
228 {
229 return n;
230 }
231
232
233
234private:
235 void callMumps(SMUMPS_STRUC_C* mumpsPar) const
236 {
237 smumps_c(mumpsPar);
238 }
239
240 void callMumps(DMUMPS_STRUC_C* mumpsPar) const
241 {
242 dmumps_c(mumpsPar);
243 }
244
245 size_t N; // number of nonzero entries
246 size_t n; // matrix dimension
247 using MumpsStruct = std::conditional_t<std::is_same<Scalar, float>::value, SMUMPS_STRUC_C, DMUMPS_STRUC_C>;
248 mutable MumpsStruct mumps_par;
249};
250
251} // namespace Kaskade
252#endif
To be raised if a direct solver fails.
Abstract base class for matrix factorizations.
Factorization of sparse linear systems with mumps.
Definition: mumps_solve.hh:41
void solve(std::vector< Scalar > const &b, std::vector< Scalar > &x, bool transpose=false) const
Solves the system for the given right hand side.
Definition: mumps_solve.hh:191
void solve(Scalar const *b, Scalar *x, bool transpose=false) const
Solves the system for the given right hand side .
Definition: mumps_solve.hh:199
void solve(std::vector< Scalar > &b) const
Solves the system for the given right hand side.
Definition: mumps_solve.hh:211
size_t size() const
reports the dimension of the system
Definition: mumps_solve.hh:227
MUMPSFactorization(MUMPS_INT n_, std::vector< MUMPS_INT > &ridx, std::vector< MUMPS_INT > &cidx, std::vector< Scalar > &values, typename Base::Options options)
Constructor taking input data in triplet format (aka coordinate format).
Definition: mumps_solve.hh:69
void solve(Scalar *b) const
Solves the system for the given right hand side .
Definition: mumps_solve.hh:217
void analyze(MUMPS_INT *irn, MUMPS_INT *jcn)
Definition: mumps_solve.hh:131
#define JOB_END
Definition: mumps_solve.hh:25
#define JOB_INIT
Definition: mumps_solve.hh:24
#define USE_COMM_WORLD
Definition: mumps_solve.hh:26
T transpose(T x)
int zeroPivots
number of zero eigenvalues (if inertia detection for symmetric matrix was enabled)
int negativePivots
number of negative eigenvalues (if inertia detection for symmetric matrix was enabled)
struct Kaskade::Factorization::Info::Mumps mumps
double zeroPivotThreshold
Threshold that defines which pivots will be considered as zero. See CNTL(3) in MUMPS documentation.
The Options struct allows to specify several options of factorization.
MatrixProperties matrixProperty
We can specify the properties of the matrix, which might be taken into account for selecing an orderi...
struct Kaskade::FactorizationOptions::Mumps mumps
int verbosity
How detailed information should be reported.