GetFEM  5.4.3
gmm_MUMPS_interface.h
Go to the documentation of this file.
1 /* -*- c++ -*- (enables emacs c++ mode) */
2 /*===========================================================================
3 
4  Copyright (C) 2003-2020 Yves Renard, Julien Pommier
5 
6  This file is a part of GetFEM
7 
8  GetFEM is free software; you can redistribute it and/or modify it
9  under the terms of the GNU Lesser General Public License as published
10  by the Free Software Foundation; either version 3 of the License, or
11  (at your option) any later version along with the GCC Runtime Library
12  Exception either version 3.1 or (at your option) any later version.
13  This program is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16  License and GCC Runtime Library Exception for more details.
17  You should have received a copy of the GNU Lesser General Public License
18  along with this program; if not, write to the Free Software Foundation,
19  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
20 
21  As a special exception, you may use this file as it is a part of a free
22  software library without restriction. Specifically, if other files
23  instantiate templates or use macros or inline functions from this file,
24  or you compile this file and link it with other files to produce an
25  executable, this file does not by itself cause the resulting executable
26  to be covered by the GNU Lesser General Public License. This exception
27  does not however invalidate any other reasons why the executable file
28  might be covered by the GNU Lesser General Public License.
29 
30 ===========================================================================*/
31 
32 /**@file gmm_MUMPS_interface.h
33  @author Yves Renard <[email protected]>,
34  @author Julien Pommier <[email protected]>
35  @date December 8, 2005.
36  @brief Interface with MUMPS (LU direct solver for sparse matrices).
37 */
38 #if defined(GMM_USES_MUMPS)
39 
40 #ifndef GMM_MUMPS_INTERFACE_H
41 #define GMM_MUMPS_INTERFACE_H
42 
43 #include "gmm_kernel.h"
44 
45 
46 extern "C" {
47 
48 #include <smumps_c.h>
49 #undef F_INT
50 #undef F_DOUBLE
51 #undef F_DOUBLE2
52 #include <dmumps_c.h>
53 #undef F_INT
54 #undef F_DOUBLE
55 #undef F_DOUBLE2
56 #include <cmumps_c.h>
57 #undef F_INT
58 #undef F_DOUBLE
59 #undef F_DOUBLE2
60 #include <zmumps_c.h>
61 #undef F_INT
62 #undef F_DOUBLE
63 #undef F_DOUBLE2
64 
65 }
66 
67 namespace gmm {
68 
69 #define ICNTL(I) icntl[(I)-1]
70 #define INFO(I) info[(I)-1]
71 #define INFOG(I) infog[(I)-1]
72 #define RINFOG(I) rinfog[(I)-1]
73 
74  template <typename T> struct ij_sparse_matrix {
75  std::vector<int> irn;
76  std::vector<int> jcn;
77  std::vector<T> a;
78  bool sym;
79 
80  template <typename L> void store(const L& l, size_type i) {
81  typename linalg_traits<L>::const_iterator it = vect_const_begin(l),
82  ite = vect_const_end(l);
83  for (; it != ite; ++it) {
84  int ir = (int)i + 1, jc = (int)it.index() + 1;
85  if (*it != T(0) && (!sym || ir >= jc))
86  { irn.push_back(ir); jcn.push_back(jc); a.push_back(*it); }
87  }
88  }
89 
90  template <typename L> void build_from(const L& l, row_major) {
91  for (size_type i = 0; i < mat_nrows(l); ++i)
92  store(mat_const_row(l, i), i);
93  }
94 
95  template <typename L> void build_from(const L& l, col_major) {
96  for (size_type i = 0; i < mat_ncols(l); ++i)
97  store(mat_const_col(l, i), i);
98  irn.swap(jcn);
99  }
100 
101  template <typename L> ij_sparse_matrix(const L& A, bool sym_) {
102  size_type nz = nnz(A);
103  sym = sym_;
104  irn.reserve(nz); jcn.reserve(nz); a.reserve(nz);
105  build_from(A, typename principal_orientation_type<typename
106  linalg_traits<L>::sub_orientation>::potype());
107  }
108  };
109 
110  /* ********************************************************************* */
111  /* MUMPS solve interface */
112  /* ********************************************************************* */
113 
114  template <typename T> struct mumps_interf {};
115 
116  template <> struct mumps_interf<float> {
117  typedef SMUMPS_STRUC_C MUMPS_STRUC_C;
118  typedef float value_type;
119 
120  static void mumps_c(MUMPS_STRUC_C &id) { smumps_c(&id); }
121  };
122 
123  template <> struct mumps_interf<double> {
124  typedef DMUMPS_STRUC_C MUMPS_STRUC_C;
125  typedef double value_type;
126  static void mumps_c(MUMPS_STRUC_C &id) { dmumps_c(&id); }
127  };
128 
129  template <> struct mumps_interf<std::complex<float> > {
130  typedef CMUMPS_STRUC_C MUMPS_STRUC_C;
131  typedef mumps_complex value_type;
132  static void mumps_c(MUMPS_STRUC_C &id) { cmumps_c(&id); }
133  };
134 
135  template <> struct mumps_interf<std::complex<double> > {
136  typedef ZMUMPS_STRUC_C MUMPS_STRUC_C;
137  typedef mumps_double_complex value_type;
138  static void mumps_c(MUMPS_STRUC_C &id) { zmumps_c(&id); }
139  };
140 
141 
142  template <typename MUMPS_STRUCT>
143  static inline bool mumps_error_check(MUMPS_STRUCT &id) {
144  if (id.INFO(1) < 0) {
145  switch (id.INFO(1)) {
146  case -2:
147  GMM_ASSERT1(false, "Solve with MUMPS failed: NZ = " << id.INFO(2)
148  << " is out of range");
149  break;
150  case -6 : case -10 :
151  GMM_WARNING1("Solve with MUMPS failed: matrix is singular");
152  return false;
153  case -9:
154  GMM_ASSERT1(false, "Solve with MUMPS failed: error "
155  << id.INFO(1) << ", increase ICNTL(14)");
156  break;
157  case -13 :
158  GMM_ASSERT1(false, "Solve with MUMPS failed: not enough memory");
159  break;
160  default :
161  GMM_ASSERT1(false, "Solve with MUMPS failed with error "
162  << id.INFO(1));
163  break;
164  }
165  }
166  return true;
167  }
168 
169 
170  /** MUMPS solve interface
171  * Works only with sparse or skyline matrices
172  */
173  template <typename MAT, typename VECTX, typename VECTB>
174  bool MUMPS_solve(const MAT &A, const VECTX &X_, const VECTB &B,
175  bool sym = false, bool distributed = false) {
176  VECTX &X = const_cast<VECTX &>(X_);
177 
178  typedef typename linalg_traits<MAT>::value_type T;
179  typedef typename mumps_interf<T>::value_type MUMPS_T;
180  GMM_ASSERT2(gmm::mat_nrows(A) == gmm::mat_ncols(A), "Non-square matrix");
181 
182  std::vector<T> rhs(gmm::vect_size(B)); gmm::copy(B, rhs);
183 
184  ij_sparse_matrix<T> AA(A, sym);
185 
186  const int JOB_INIT = -1;
187  const int JOB_END = -2;
188  const int USE_COMM_WORLD = -987654;
189 
190  typename mumps_interf<T>::MUMPS_STRUC_C id;
191 
192  int rank(0);
193 #ifdef GMM_USES_MPI
194  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
195 #endif
196 
197  id.job = JOB_INIT;
198  id.par = 1;
199  id.sym = sym ? 2 : 0;
200  id.comm_fortran = USE_COMM_WORLD;
201  mumps_interf<T>::mumps_c(id);
202 
203  if (rank == 0 || distributed) {
204  id.n = int(gmm::mat_nrows(A));
205  if (distributed) {
206  id.nz_loc = int(AA.irn.size());
207  id.irn_loc = &(AA.irn[0]);
208  id.jcn_loc = &(AA.jcn[0]);
209  id.a_loc = (MUMPS_T*)(&(AA.a[0]));
210  } else {
211  id.nz = int(AA.irn.size());
212  id.irn = &(AA.irn[0]);
213  id.jcn = &(AA.jcn[0]);
214  id.a = (MUMPS_T*)(&(AA.a[0]));
215  }
216  if (rank == 0)
217  id.rhs = (MUMPS_T*)(&(rhs[0]));
218  }
219 
220  id.ICNTL(1) = -1; // output stream for error messages
221  id.ICNTL(2) = -1; // output stream for other messages
222  id.ICNTL(3) = -1; // output stream for global information
223  id.ICNTL(4) = 0; // verbosity level
224 
225  if (distributed)
226  id.ICNTL(5) = 0; // assembled input matrix (default)
227 
228  id.ICNTL(14) += 80; /* small boost to the workspace size as we have encountered some problem
229  who did not fit in the default settings of mumps..
230  by default, ICNTL(14) = 15 or 20
231  */
232  //cout << "ICNTL(14): " << id.ICNTL(14) << "\n";
233 
234  if (distributed)
235  id.ICNTL(18) = 3; // strategy for distributed input matrix
236 
237  // id.ICNTL(22) = 1; /* enables out-of-core support */
238 
239  id.job = 6;
240  mumps_interf<T>::mumps_c(id);
241  bool ok = mumps_error_check(id);
242 
243  id.job = JOB_END;
244  mumps_interf<T>::mumps_c(id);
245 
246 #ifdef GMM_USES_MPI
247  MPI_Bcast(&(rhs[0]),id.n,gmm::mpi_type(T()),0,MPI_COMM_WORLD);
248 #endif
249 
250  gmm::copy(rhs, X);
251 
252  return ok;
253 
254  }
255 
256 
257 
258  /** MUMPS solve interface for distributed matrices
259  * Works only with sparse or skyline matrices
260  */
261  template <typename MAT, typename VECTX, typename VECTB>
262  bool MUMPS_distributed_matrix_solve(const MAT &A, const VECTX &X_,
263  const VECTB &B, bool sym = false) {
264  return MUMPS_solve(A, X_, B, sym, true);
265  }
266 
267 
268 
269  template<typename T>
270  inline T real_or_complex(std::complex<T> a) { return a.real(); }
271  template<typename T>
272  inline T real_or_complex(T &a) { return a; }
273 
274 
275  /** Evaluate matrix determinant with MUMPS
276  * Works only with sparse or skyline matrices
277  */
278  template <typename MAT, typename T = typename linalg_traits<MAT>::value_type>
279  T MUMPS_determinant(const MAT &A, int &exponent,
280  bool sym = false, bool distributed = false) {
281  exponent = 0;
282  typedef typename mumps_interf<T>::value_type MUMPS_T;
283  typedef typename number_traits<T>::magnitude_type R;
284  GMM_ASSERT2(gmm::mat_nrows(A) == gmm::mat_ncols(A), "Non-square matrix");
285 
286  ij_sparse_matrix<T> AA(A, sym);
287 
288  const int JOB_INIT = -1;
289  const int JOB_END = -2;
290  const int USE_COMM_WORLD = -987654;
291 
292  typename mumps_interf<T>::MUMPS_STRUC_C id;
293 
294  int rank(0);
295 #ifdef GMM_USES_MPI
296  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
297 #endif
298 
299  id.job = JOB_INIT;
300  id.par = 1;
301  id.sym = sym ? 2 : 0;
302  id.comm_fortran = USE_COMM_WORLD;
303  mumps_interf<T>::mumps_c(id);
304 
305  if (rank == 0 || distributed) {
306  id.n = int(gmm::mat_nrows(A));
307  if (distributed) {
308  id.nz_loc = int(AA.irn.size());
309  id.irn_loc = &(AA.irn[0]);
310  id.jcn_loc = &(AA.jcn[0]);
311  id.a_loc = (MUMPS_T*)(&(AA.a[0]));
312  } else {
313  id.nz = int(AA.irn.size());
314  id.irn = &(AA.irn[0]);
315  id.jcn = &(AA.jcn[0]);
316  id.a = (MUMPS_T*)(&(AA.a[0]));
317  }
318  }
319 
320  id.ICNTL(1) = -1; // output stream for error messages
321  id.ICNTL(2) = -1; // output stream for other messages
322  id.ICNTL(3) = -1; // output stream for global information
323  id.ICNTL(4) = 0; // verbosity level
324 
325  if (distributed)
326  id.ICNTL(5) = 0; // assembled input matrix (default)
327 
328 // id.ICNTL(14) += 80; // small boost to the workspace size
329 
330  if (distributed)
331  id.ICNTL(18) = 3; // strategy for distributed input matrix
332 
333  id.ICNTL(31) = 1; // only factorization, no solution to follow
334  id.ICNTL(33) = 1; // request determinant calculation
335 
336  id.job = 4; // abalysis (job=1) + factorization (job=2)
337  mumps_interf<T>::mumps_c(id);
338  mumps_error_check(id);
339 
340  T det = real_or_complex(std::complex<R>(id.RINFOG(12),id.RINFOG(13)));
341  exponent = id.INFOG(34);
342 
343  id.job = JOB_END;
344  mumps_interf<T>::mumps_c(id);
345 
346  return det;
347  }
348 
349 #undef ICNTL
350 #undef INFO
351 #undef INFOG
352 #undef RINFOG
353 
354 }
355 
356 
357 #endif // GMM_MUMPS_INTERFACE_H
358 
359 #endif // GMM_USES_MUMPS
size_type nnz(const L &l)
count the number of non-zero entries of a vector or matrix.
Definition: gmm_blas.h:69
void copy(const L1 &l1, L2 &l2)
*‍/
Definition: gmm_blas.h:978
Include the base gmm files.
size_t size_type
used as the common size type in the library
Definition: bgeot_poly.h:49