dune-istl  2.11
umfpack.hh
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root
2 // SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception
3 // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
4 // vi: set et ts=4 sw=2 sts=2:
5 #ifndef DUNE_ISTL_UMFPACK_HH
6 #define DUNE_ISTL_UMFPACK_HH
7 
8 #if HAVE_SUITESPARSE_UMFPACK || defined DOXYGEN
9 
10 #include<complex>
11 #include<type_traits>
12 
13 #include<umfpack.h>
14 
15 #include<dune/common/exceptions.hh>
16 #include<dune/common/fmatrix.hh>
17 #include<dune/common/fvector.hh>
20 #include<dune/istl/matrix.hh>
21 #include<dune/istl/foreach.hh>
24 #include<dune/istl/solvers.hh>
27 
28 
29 
30 namespace Dune {
42  // FORWARD DECLARATIONS
43  template<class M, class T, class TM, class TD, class TA>
44  class SeqOverlappingSchwarz;
45 
46  template<class T, bool tag>
47  struct SeqOverlappingSchwarzAssemblerHelper;
48 
49  // wrapper class for C-Function Calls in the backend. Choose the right function namespace
50  // depending on the template parameter used.
51  template<typename T>
53  {
54  static constexpr bool valid = false ;
55  };
56 
57  template<>
58  struct UMFPackMethodChooser<double>
59  {
60  static constexpr bool valid = true ;
61 
62  template<typename... A>
63  static void defaults(A... args)
64  {
65  umfpack_dl_defaults(args...);
66  }
67  template<typename... A>
68  static void free_numeric(A... args)
69  {
70  umfpack_dl_free_numeric(args...);
71  }
72  template<typename... A>
73  static void free_symbolic(A... args)
74  {
75  umfpack_dl_free_symbolic(args...);
76  }
77  template<typename... A>
78  static int load_numeric(A... args)
79  {
80  return umfpack_dl_load_numeric(args...);
81  }
82  template<typename... A>
83  static void numeric(A... args)
84  {
85  umfpack_dl_numeric(args...);
86  }
87  template<typename... A>
88  static void report_info(A... args)
89  {
90  umfpack_dl_report_info(args...);
91  }
92  template<typename... A>
93  static void report_status(A... args)
94  {
95  umfpack_dl_report_status(args...);
96  }
97  template<typename... A>
98  static int save_numeric(A... args)
99  {
100  return umfpack_dl_save_numeric(args...);
101  }
102  template<typename... A>
103  static void solve(A... args)
104  {
105  umfpack_dl_solve(args...);
106  }
107  template<typename... A>
108  static void symbolic(A... args)
109  {
110  umfpack_dl_symbolic(args...);
111  }
112  };
113 
114  template<>
115  struct UMFPackMethodChooser<std::complex<double> >
116  {
117  static constexpr bool valid = true ;
118  using size_type = SuiteSparse_long;
119 
120  template<typename... A>
121  static void defaults(A... args)
122  {
123  umfpack_zl_defaults(args...);
124  }
125  template<typename... A>
126  static void free_numeric(A... args)
127  {
128  umfpack_zl_free_numeric(args...);
129  }
130  template<typename... A>
131  static void free_symbolic(A... args)
132  {
133  umfpack_zl_free_symbolic(args...);
134  }
135  template<typename... A>
136  static int load_numeric(A... args)
137  {
138  return umfpack_zl_load_numeric(args...);
139  }
140  template<typename... A>
141  static void numeric(const size_type* cs, const size_type* ri, const double* val, A... args)
142  {
143  umfpack_zl_numeric(cs,ri,val,NULL,args...);
144  }
145  template<typename... A>
146  static void report_info(A... args)
147  {
148  umfpack_zl_report_info(args...);
149  }
150  template<typename... A>
151  static void report_status(A... args)
152  {
153  umfpack_zl_report_status(args...);
154  }
155  template<typename... A>
156  static int save_numeric(A... args)
157  {
158  return umfpack_zl_save_numeric(args...);
159  }
160  template<typename... A>
161  static void solve(size_type m, const size_type* cs, const size_type* ri, std::complex<double>* val, double* x, const double* b,A... args)
162  {
163  const double* cval = reinterpret_cast<const double*>(val);
164  umfpack_zl_solve(m,cs,ri,cval,NULL,x,NULL,b,NULL,args...);
165  }
166  template<typename... A>
167  static void symbolic(size_type m, size_type n, const size_type* cs, const size_type* ri, const double* val, A... args)
168  {
169  umfpack_zl_symbolic(m,n,cs,ri,val,NULL,args...);
170  }
171  };
172 
173  namespace Impl
174  {
175  template<class M, class = void>
176  struct UMFPackVectorChooser;
177 
179  template<class M> using UMFPackDomainType = typename UMFPackVectorChooser<M>::domain_type;
180 
182  template<class M> using UMFPackRangeType = typename UMFPackVectorChooser<M>::range_type;
183 
184  template<class M>
185  struct UMFPackVectorChooser<M,
186  std::enable_if_t<(std::is_same<M,double>::value) || (std::is_same<M,std::complex<double> >::value)>>
187  {
188  using domain_type = M;
189  using range_type = M;
190  };
191 
192  template<typename T, int n, int m>
193  struct UMFPackVectorChooser<FieldMatrix<T,n,m>,
194  std::enable_if_t<(std::is_same<T,double>::value) || (std::is_same<T,std::complex<double> >::value)>>
195  {
197  using domain_type = FieldVector<T,m>;
199  using range_type = FieldVector<T,n>;
200  };
201 
202  template<typename T, typename A>
203  struct UMFPackVectorChooser<BCRSMatrix<T,A>,
204  std::void_t<UMFPackDomainType<T>, UMFPackRangeType<T>>>
205  {
206  // In case of recursive deduction (e.g., BCRSMatrix<FieldMatrix<...>, Allocator<FieldMatrix<...>>>)
207  // the allocator needs to be converted to the sub-block allocator type too (e.g., Allocator<FieldVector<...>>).
208  // Note that matrix allocator is assumed to be the same as the domain/range type of allocators
210  using domain_type = BlockVector<UMFPackDomainType<T>, typename std::allocator_traits<A>::template rebind_alloc<UMFPackDomainType<T>>>;
212  using range_type = BlockVector<UMFPackRangeType<T>, typename std::allocator_traits<A>::template rebind_alloc<UMFPackRangeType<T>>>;
213  };
214 
215  template<typename T, typename A>
216  struct UMFPackVectorChooser<Matrix<T,A>,
217  std::void_t<UMFPackDomainType<T>, UMFPackRangeType<T>>>
218  : public UMFPackVectorChooser<BCRSMatrix<T,A>, std::void_t<UMFPackDomainType<T>, UMFPackRangeType<T>>>
219  {};
220 
221  // to make the `UMFPackVectorChooser` work with `MultiTypeBlockMatrix`, we need to add an intermediate step for the rows, which are typically `MultiTypeBlockVector`
222  template<typename FirstBlock, typename... Blocks>
223  struct UMFPackVectorChooser<MultiTypeBlockVector<FirstBlock, Blocks...>,
224  std::void_t<UMFPackDomainType<FirstBlock>, UMFPackRangeType<FirstBlock>, UMFPackDomainType<Blocks>...>>
225  {
227  using domain_type = MultiTypeBlockVector<UMFPackDomainType<FirstBlock>, UMFPackDomainType<Blocks>...>;
229  using range_type = UMFPackRangeType<FirstBlock>;
230  };
231 
232  // specialization for `MultiTypeBlockMatrix` with `MultiTypeBlockVector` rows
233  template<typename FirstRow, typename... Rows>
234  struct UMFPackVectorChooser<MultiTypeBlockMatrix<FirstRow, Rows...>,
235  std::void_t<UMFPackDomainType<FirstRow>, UMFPackRangeType<FirstRow>, UMFPackRangeType<Rows>...>>
236  {
238  using domain_type = UMFPackDomainType<FirstRow>;
240  using range_type = MultiTypeBlockVector< UMFPackRangeType<FirstRow>, UMFPackRangeType<Rows>... >;
241  };
242 
243  // dummy class to represent no BitVector
244  struct NoBitVector
245  {};
246 
247 
248  }
249 
263  template<typename M>
264  class UMFPack : public InverseOperator<Impl::UMFPackDomainType<M>,Impl::UMFPackRangeType<M>>
265  {
266  using T = typename M::field_type;
267 
268  public:
269  using size_type = SuiteSparse_long;
270 
272  using Matrix = M;
273  using matrix_type = M;
275  using UMFPackMatrix = ISTL::Impl::BCCSMatrix<typename Matrix::field_type, size_type>;
277  using MatrixInitializer = ISTL::Impl::BCCSMatrixInitializer<M, size_type>;
279  using domain_type = Impl::UMFPackDomainType<M>;
281  using range_type = Impl::UMFPackRangeType<M>;
282 
285  {
286  return SolverCategory::Category::sequential;
287  }
288 
297  UMFPack(const Matrix& matrix, int verbose=0) : matrixIsLoaded_(false)
298  {
299  //check whether T is a supported type
300  static_assert((std::is_same<T,double>::value) || (std::is_same<T,std::complex<double> >::value),
301  "Unsupported Type in UMFPack (only double and std::complex<double> supported)");
302  Caller::defaults(UMF_Control);
303  setVerbosity(verbose);
304  setMatrix(matrix);
305  }
306 
315  UMFPack(const Matrix& matrix, int verbose, bool) : matrixIsLoaded_(false)
316  {
317  //check whether T is a supported type
318  static_assert((std::is_same<T,double>::value) || (std::is_same<T,std::complex<double> >::value),
319  "Unsupported Type in UMFPack (only double and std::complex<double> supported)");
320  Caller::defaults(UMF_Control);
321  setVerbosity(verbose);
322  setMatrix(matrix);
323  }
324 
334  UMFPack(const Matrix& mat_, const ParameterTree& config)
335  : UMFPack(mat_, config.get<int>("verbose", 0))
336  {}
337 
340  UMFPack() : matrixIsLoaded_(false), verbosity_(0)
341  {
342  //check whether T is a supported type
343  static_assert((std::is_same<T,double>::value) || (std::is_same<T,std::complex<double> >::value),
344  "Unsupported Type in UMFPack (only double and std::complex<double> supported)");
345  Caller::defaults(UMF_Control);
346  }
347 
358  UMFPack(const Matrix& mat_, const char* file, int verbose=0)
359  {
360  //check whether T is a supported type
361  static_assert((std::is_same<T,double>::value) || (std::is_same<T,std::complex<double> >::value),
362  "Unsupported Type in UMFPack (only double and std::complex<double> supported)");
363  Caller::defaults(UMF_Control);
364  setVerbosity(verbose);
365  int errcode = Caller::load_numeric(&UMF_Numeric, const_cast<char*>(file));
366  if ((errcode == UMFPACK_ERROR_out_of_memory) || (errcode == UMFPACK_ERROR_file_IO))
367  {
368  matrixIsLoaded_ = false;
369  setMatrix(mat_);
370  saveDecomposition(file);
371  }
372  else
373  {
374  matrixIsLoaded_ = true;
375  std::cout << "UMFPack decomposition successfully loaded from " << file << std::endl;
376  }
377  }
378 
385  UMFPack(const char* file, int verbose=0)
386  {
387  //check whether T is a supported type
388  static_assert((std::is_same<T,double>::value) || (std::is_same<T,std::complex<double> >::value),
389  "Unsupported Type in UMFPack (only double and std::complex<double> supported)");
390  Caller::defaults(UMF_Control);
391  int errcode = Caller::load_numeric(&UMF_Numeric, const_cast<char*>(file));
392  if (errcode == UMFPACK_ERROR_out_of_memory)
393  DUNE_THROW(Dune::Exception, "ran out of memory while loading UMFPack decomposition");
394  if (errcode == UMFPACK_ERROR_file_IO)
395  DUNE_THROW(Dune::Exception, "IO error while loading UMFPack decomposition");
396  matrixIsLoaded_ = true;
397  std::cout << "UMFPack decomposition successfully loaded from " << file << std::endl;
398  setVerbosity(verbose);
399  }
400 
401  virtual ~UMFPack()
402  {
403  if ((umfpackMatrix_.N() + umfpackMatrix_.M() > 0) || matrixIsLoaded_)
404  free();
405  }
406 
410  void apply(domain_type& x, range_type& b, InverseOperatorResult& res) override
411  {
412  if (umfpackMatrix_.N() != b.dim())
413  DUNE_THROW(Dune::ISTLError, "Size of right-hand-side vector b does not match the number of matrix rows!");
414  if (umfpackMatrix_.M() != x.dim())
415  DUNE_THROW(Dune::ISTLError, "Size of solution vector x does not match the number of matrix columns!");
416  if (b.size() == 0)
417  return;
418 
419  // we have to convert x and b into flat structures
420  // however, this is linear in time
421  std::vector<T> xFlat(x.dim()), bFlat(b.dim());
422 
423  flatVectorForEach(x, [&](auto&& entry, auto&& offset)
424  {
425  xFlat[ offset ] = entry;
426  });
427 
428  flatVectorForEach(b, [&](auto&& entry, auto&& offset)
429  {
430  bFlat[ offset ] = entry;
431  });
432 
433  double UMF_Apply_Info[UMFPACK_INFO];
434  Caller::solve(UMFPACK_A,
435  umfpackMatrix_.getColStart(),
436  umfpackMatrix_.getRowIndex(),
437  umfpackMatrix_.getValues(),
438  reinterpret_cast<double*>(&xFlat[0]),
439  reinterpret_cast<double*>(&bFlat[0]),
440  UMF_Numeric,
441  UMF_Control,
442  UMF_Apply_Info);
443 
444  // copy back to blocked vector
445  flatVectorForEach(x, [&](auto&& entry, auto offset)
446  {
447  entry = xFlat[offset];
448  });
449 
450  //this is a direct solver
451  res.iterations = 1;
452  res.converged = true;
453  res.elapsed = UMF_Apply_Info[UMFPACK_SOLVE_WALLTIME];
454 
455  printOnApply(UMF_Apply_Info);
456  }
457 
461  void apply (domain_type& x, range_type& b, [[maybe_unused]] double reduction, InverseOperatorResult& res) override
462  {
463  apply(x,b,res);
464  }
465 
473  void apply(T* x, T* b)
474  {
475  double UMF_Apply_Info[UMFPACK_INFO];
476  Caller::solve(UMFPACK_A,
477  umfpackMatrix_.getColStart(),
478  umfpackMatrix_.getRowIndex(),
479  umfpackMatrix_.getValues(),
480  x,
481  b,
482  UMF_Numeric,
483  UMF_Control,
484  UMF_Apply_Info);
485  printOnApply(UMF_Apply_Info);
486  }
487 
499  void setOption(unsigned int option, double value)
500  {
501  if (option >= UMFPACK_CONTROL)
502  DUNE_THROW(RangeError, "Requested non-existing UMFPack option");
503 
504  UMF_Control[option] = value;
505  }
506 
510  void saveDecomposition(const char* file)
511  {
512  int errcode = Caller::save_numeric(UMF_Numeric, const_cast<char*>(file));
513  if (errcode != UMFPACK_OK)
514  DUNE_THROW(Dune::Exception,"IO ERROR while trying to save UMFPack decomposition");
515  }
516 
526  template<class BitVector = Impl::NoBitVector>
527  void setMatrix(const Matrix& matrix, const BitVector& bitVector = {})
528  {
529  if ((umfpackMatrix_.N() + umfpackMatrix_.M() > 0) || matrixIsLoaded_)
530  free();
531  if (matrix.N() == 0 or matrix.M() == 0)
532  return;
533 
534  if (umfpackMatrix_.N() + umfpackMatrix_.M() + umfpackMatrix_.nonzeroes() != 0)
535  umfpackMatrix_.free();
536 
537  constexpr bool useBitVector = not std::is_same_v<BitVector,Impl::NoBitVector>;
538 
539  // use a dynamic flat vector for the bitset
540  std::vector<bool> flatBitVector;
541  // and a mapping from the compressed indices
542  std::vector<size_type> subIndices;
543 
544  [[maybe_unused]] int numberOfIgnoredDofs = 0;
545  int nonZeros = 0;
546 
547  if constexpr ( useBitVector )
548  {
549  auto flatSize = flatVectorForEach(bitVector, [](auto&&, auto&&){});
550  flatBitVector.resize(flatSize);
551 
552  flatVectorForEach(bitVector, [&](auto&& entry, auto&& offset)
553  {
554  flatBitVector[ offset ] = entry;
555  if ( entry )
556  {
557  numberOfIgnoredDofs++;
558  }
559  });
560  }
561 
562  // compute the flat dimension and the number of nonzeros of the matrix
563  auto [flatRows,flatCols] = flatMatrixForEach( matrix, [&](auto&& /*entry*/, auto&& row, auto&& col){
564  // do not count ignored entries
565  if constexpr ( useBitVector )
566  if ( flatBitVector[row] or flatBitVector[col] )
567  return;
568 
569  nonZeros++;
570  });
571 
572  if constexpr ( useBitVector )
573  {
574  // use the original flatRows!
575  subIndices.resize(flatRows,std::numeric_limits<std::size_t>::max());
576 
577  size_type subIndexCounter = 0;
578  for ( size_type i=0; i<size_type(flatRows); i++ )
579  if ( not flatBitVector[ i ] )
580  subIndices[ i ] = subIndexCounter++;
581 
582  // update the original matrix size
583  flatRows -= numberOfIgnoredDofs;
584  flatCols -= numberOfIgnoredDofs;
585  }
586 
587 
588  umfpackMatrix_.setSize(flatRows,flatCols);
589  umfpackMatrix_.Nnz_ = nonZeros;
590 
591  // prepare the arrays
592  umfpackMatrix_.colstart = new size_type[flatCols+1];
593  umfpackMatrix_.rowindex = new size_type[nonZeros];
594  umfpackMatrix_.values = new T[nonZeros];
595 
596  for ( size_type i=0; i<size_type(flatCols+1); i++ )
597  {
598  umfpackMatrix_.colstart[i] = 0;
599  }
600 
601  // at first, we need to compute the column start indices
602  // therefore, we count all entries in each column and in the end we accumulate everything
603  flatMatrixForEach(matrix, [&](auto&& /*entry*/, auto&& flatRowIndex, auto&& flatColIndex)
604  {
605  // do nothing if entry is excluded
606  if constexpr ( useBitVector )
607  if ( flatBitVector[flatRowIndex] or flatBitVector[flatColIndex] )
608  return;
609 
610  // pick compressed or uncompressed index
611  // compiler will hopefully do some constexpr optimization here
612  auto colIdx = useBitVector ? subIndices[flatColIndex] : flatColIndex;
613 
614  umfpackMatrix_.colstart[colIdx+1]++;
615  });
616 
617  // now accumulate
618  for ( size_type i=0; i<(size_type)flatCols; i++ )
619  {
620  umfpackMatrix_.colstart[i+1] += umfpackMatrix_.colstart[i];
621  }
622 
623  // we need a compressed position counter in each column
624  std::vector<size_type> colPosition(flatCols,0);
625 
626  // now we can set the entries: the procedure below works with both row- or column major index ordering
627  flatMatrixForEach(matrix, [&](auto&& entry, auto&& flatRowIndex, auto&& flatColIndex)
628  {
629  // do nothing if entry is excluded
630  if constexpr ( useBitVector )
631  if ( flatBitVector[flatRowIndex] or flatBitVector[flatColIndex] )
632  return;
633 
634  // pick compressed or uncompressed index
635  // compiler will hopefully do some constexpr optimization here
636  auto rowIdx = useBitVector ? subIndices[flatRowIndex] : flatRowIndex;
637  auto colIdx = useBitVector ? subIndices[flatColIndex] : flatColIndex;
638 
639  // the start index of each column is already fixed
640  auto colStart = umfpackMatrix_.colstart[colIdx];
641  // get the current number of picked elements in this column
642  auto colPos = colPosition[colIdx];
643  // assign the corresponding row index and the value of this element
644  umfpackMatrix_.rowindex[ colStart + colPos ] = rowIdx;
645  umfpackMatrix_.values[ colStart + colPos ] = entry;
646  // increase the number of picked elements in this column
647  colPosition[colIdx]++;
648  });
649 
650  decompose();
651  }
652 
653  // Keep legacy version using a set of scalar indices
654  // The new version using a bitVector type for marking the active matrix indices is
655  // directly given in `setMatrix` with an additional BitVector argument.
656  // The new version is more flexible and allows, e.g., marking single components of a matrix block.
657  void setSubMatrix(const Matrix& _mat, const std::set<typename Matrix::size_type>& rowIndexSet)
658  {
659  if ((umfpackMatrix_.N() + umfpackMatrix_.M() > 0) || matrixIsLoaded_)
660  free();
661 
662  if (umfpackMatrix_.N() + umfpackMatrix_.M() + umfpackMatrix_.nonzeroes() != 0)
663  umfpackMatrix_.free();
664 
665  umfpackMatrix_.setSize(rowIndexSet.size()*MatrixDimension<Matrix>::rowdim(_mat) / _mat.N(),
666  rowIndexSet.size()*MatrixDimension<Matrix>::coldim(_mat) / _mat.M());
667  ISTL::Impl::BCCSMatrixInitializer<Matrix, SuiteSparse_long> initializer(umfpackMatrix_);
668 
669  copyToBCCSMatrix(initializer, ISTL::Impl::MatrixRowSubset<Matrix,std::set<typename Matrix::size_type> >(_mat,rowIndexSet));
670 
671  decompose();
672  }
673 
681  void setVerbosity(int v)
682  {
683  verbosity_ = v;
684  // set the verbosity level in UMFPack
685  if (verbosity_ == 0)
686  UMF_Control[UMFPACK_PRL] = 1;
687  if (verbosity_ == 1)
688  UMF_Control[UMFPACK_PRL] = 2;
689  if (verbosity_ == 2)
690  UMF_Control[UMFPACK_PRL] = 4;
691  }
692 
698  {
699  return UMF_Numeric;
700  }
701 
707  {
708  return umfpackMatrix_;
709  }
710 
715  void free()
716  {
717  if (!matrixIsLoaded_)
718  {
719  Caller::free_symbolic(&UMF_Symbolic);
720  umfpackMatrix_.free();
721  }
722  Caller::free_numeric(&UMF_Numeric);
723  matrixIsLoaded_ = false;
724  }
725 
726  const char* name() { return "UMFPACK"; }
727 
728  private:
729  typedef typename Dune::UMFPackMethodChooser<T> Caller;
730 
731  template<class Mat,class X, class TM, class TD, class T1>
732  friend class SeqOverlappingSchwarz;
734 
736  void decompose()
737  {
738  double UMF_Decomposition_Info[UMFPACK_INFO];
739  Caller::symbolic(static_cast<SuiteSparse_long>(umfpackMatrix_.N()),
740  static_cast<SuiteSparse_long>(umfpackMatrix_.N()),
741  umfpackMatrix_.getColStart(),
742  umfpackMatrix_.getRowIndex(),
743  reinterpret_cast<double*>(umfpackMatrix_.getValues()),
744  &UMF_Symbolic,
745  UMF_Control,
746  UMF_Decomposition_Info);
747  Caller::numeric(umfpackMatrix_.getColStart(),
748  umfpackMatrix_.getRowIndex(),
749  reinterpret_cast<double*>(umfpackMatrix_.getValues()),
750  UMF_Symbolic,
751  &UMF_Numeric,
752  UMF_Control,
753  UMF_Decomposition_Info);
754  Caller::report_status(UMF_Control,UMF_Decomposition_Info[UMFPACK_STATUS]);
755  if (verbosity_ == 1)
756  {
757  std::cout << "[UMFPack Decomposition]" << std::endl;
758  std::cout << "Wallclock Time taken: " << UMF_Decomposition_Info[UMFPACK_NUMERIC_WALLTIME] << " (CPU Time: " << UMF_Decomposition_Info[UMFPACK_NUMERIC_TIME] << ")" << std::endl;
759  std::cout << "Flops taken: " << UMF_Decomposition_Info[UMFPACK_FLOPS] << std::endl;
760  std::cout << "Peak Memory Usage: " << UMF_Decomposition_Info[UMFPACK_PEAK_MEMORY]*UMF_Decomposition_Info[UMFPACK_SIZE_OF_UNIT] << " bytes" << std::endl;
761  std::cout << "Condition number estimate: " << 1./UMF_Decomposition_Info[UMFPACK_RCOND] << std::endl;
762  std::cout << "Numbers of non-zeroes in decomposition: L: " << UMF_Decomposition_Info[UMFPACK_LNZ] << " U: " << UMF_Decomposition_Info[UMFPACK_UNZ] << std::endl;
763  }
764  if (verbosity_ == 2)
765  {
766  Caller::report_info(UMF_Control,UMF_Decomposition_Info);
767  }
768  }
769 
770  void printOnApply(double* UMF_Info)
771  {
772  Caller::report_status(UMF_Control,UMF_Info[UMFPACK_STATUS]);
773  if (verbosity_ > 0)
774  {
775  std::cout << "[UMFPack Solve]" << std::endl;
776  std::cout << "Wallclock Time: " << UMF_Info[UMFPACK_SOLVE_WALLTIME] << " (CPU Time: " << UMF_Info[UMFPACK_SOLVE_TIME] << ")" << std::endl;
777  std::cout << "Flops Taken: " << UMF_Info[UMFPACK_SOLVE_FLOPS] << std::endl;
778  std::cout << "Iterative Refinement steps taken: " << UMF_Info[UMFPACK_IR_TAKEN] << std::endl;
779  std::cout << "Error Estimate: " << UMF_Info[UMFPACK_OMEGA1] << " resp. " << UMF_Info[UMFPACK_OMEGA2] << std::endl;
780  }
781  }
782 
783  UMFPackMatrix umfpackMatrix_;
784  bool matrixIsLoaded_;
785  int verbosity_;
786  void *UMF_Symbolic;
787  void *UMF_Numeric;
788  double UMF_Control[UMFPACK_CONTROL];
789  };
790 
791  template<typename M>
793  {
794  enum { value=true};
795  };
796 
797  template<typename T, typename A>
799  {
800  enum { value = true };
801  };
802 
803  namespace UMFPackImpl {
804  template<class OpTraits, class=void> struct isValidBlock : std::false_type{};
805  template<class OpTraits> struct isValidBlock<OpTraits,
806  std::enable_if_t<
807  std::is_same_v<Impl::UMFPackDomainType<typename OpTraits::matrix_type>, typename OpTraits::domain_type>
808  && std::is_same_v<Impl::UMFPackRangeType<typename OpTraits::matrix_type>, typename OpTraits::range_type>
809  && std::is_same_v<typename FieldTraits<typename OpTraits::domain_type::field_type>::real_type, double>
810  && std::is_same_v<typename FieldTraits<typename OpTraits::range_type::field_type>::real_type, double>
811  >> : std::true_type {};
812  }
813  DUNE_REGISTER_SOLVER("umfpack",
814  [](auto opTraits, const auto& op, const Dune::ParameterTree& config)
815  -> std::shared_ptr<typename decltype(opTraits)::solver_type>
816  {
817  using OpTraits = decltype(opTraits);
818  // works only for sequential operators
819  if constexpr (OpTraits::isParallel){
820  if(opTraits.getCommOrThrow(op).communicator().size() > 1)
821  DUNE_THROW(Dune::InvalidStateException, "UMFPack works only for sequential operators.");
822  }
823  if constexpr (OpTraits::isAssembled){
824  using M = typename OpTraits::matrix_type;
825  // check if UMFPack<M>* is convertible to
826  // InverseOperator*. This checks compatibility of the
827  // domain and range types
828  if constexpr (UMFPackImpl::isValidBlock<OpTraits>::value) {
829  const auto& A = opTraits.getAssembledOpOrThrow(op);
830  const M& mat = A->getmat();
831  int verbose = config.get("verbose", 0);
832  return std::make_shared<Dune::UMFPack<M>>(mat,verbose);
833  }
834  }
835  DUNE_THROW(UnsupportedType,
836  "Unsupported Type in UMFPack (only double and std::complex<double> supported)");
837  return nullptr;
838  });
839 } // end namespace Dune
840 
841 #endif // HAVE_SUITESPARSE_UMFPACK
842 
843 #endif //DUNE_ISTL_UMFPACK_HH
The UMFPack direct sparse solver.
Definition: umfpack.hh:264
void free()
free allocated space.
Definition: umfpack.hh:715
static void solve(A... args)
Definition: umfpack.hh:103
SuiteSparse_long size_type
Definition: umfpack.hh:118
Impl::UMFPackDomainType< M > domain_type
The type of the domain of the solver.
Definition: umfpack.hh:279
std::size_t flatVectorForEach(Vector &&vector, F &&f, std::size_t offset=0)
Traverse a blocked vector and call a functor at each scalar entry.
Definition: foreach.hh:95
const char * name()
Definition: umfpack.hh:726
derive error class from the base class in common
Definition: istlexception.hh:19
static void defaults(A... args)
Definition: umfpack.hh:63
static void free_symbolic(A... args)
Definition: umfpack.hh:131
static void free_numeric(A... args)
Definition: umfpack.hh:126
UMFPack(const Matrix &mat_, const char *file, int verbose=0)
Try loading a decomposition from file and do a decomposition if unsuccessful.
Definition: umfpack.hh:358
Matrix & mat
Definition: matrixmatrix.hh:347
A sparse block matrix with compressed row storage.
Definition: bcrsmatrix.hh:466
whether the solver internally uses column compressed storage
Definition: solvertype.hh:36
virtual ~UMFPack()
Definition: umfpack.hh:401
Sequential overlapping Schwarz preconditioner.
Definition: ldl.hh:43
static void report_info(A... args)
Definition: umfpack.hh:146
Statistics about the application of an inverse operator.
Definition: solver.hh:49
static void numeric(const size_type *cs, const size_type *ri, const double *val, A... args)
Definition: umfpack.hh:141
STL namespace.
Col col
Definition: matrixmatrix.hh:351
void saveDecomposition(const char *file)
saves a decomposition to a file
Definition: umfpack.hh:510
M Matrix
The matrix type.
Definition: umfpack.hh:272
static void report_info(A... args)
Definition: umfpack.hh:88
void apply(domain_type &x, range_type &b, InverseOperatorResult &res) override
Apply inverse operator,.
Definition: umfpack.hh:410
void apply(domain_type &x, range_type &b, [[maybe_unused]] double reduction, InverseOperatorResult &res) override
apply inverse operator, with given convergence criteria.
Definition: umfpack.hh:461
static auto coldim(const M &)
Definition: matrixutils.hh:219
M matrix_type
Definition: umfpack.hh:273
Definition: solvertype.hh:29
static void defaults(A... args)
Definition: umfpack.hh:121
ISTL::Impl::BCCSMatrix< typename Matrix::field_type, size_type > UMFPackMatrix
The corresponding (scalar) UMFPack matrix type.
Definition: umfpack.hh:275
SuiteSparse_long size_type
Definition: umfpack.hh:269
Implementations of the inverse operator interface.
static void solve(size_type m, const size_type *cs, const size_type *ri, std::complex< double > *val, double *x, const double *b, A... args)
Definition: umfpack.hh:161
Definition: umfpack.hh:52
Templates characterizing the type of a solver.
static void report_status(A... args)
Definition: umfpack.hh:151
static int load_numeric(A... args)
Definition: umfpack.hh:78
DUNE_REGISTER_SOLVER("cholmod", [](auto opTraits, const auto &op, const Dune::ParameterTree &config) -> std::shared_ptr< typename decltype(opTraits)::solver_type > { using OpTraits=decltype(opTraits);using M=typename OpTraits::matrix_type;using D=typename OpTraits::domain_type;if constexpr(OpTraits::isParallel){ if(opTraits.getCommOrThrow(op).communicator().size() > 1) DUNE_THROW(Dune::InvalidStateException, "CholMod works only for sequential operators.");} if constexpr(OpTraits::isAssembled &&(std::is_same_v< typename FieldTraits< D >::field_type, double >||std::is_same_v< typename FieldTraits< D >::field_type, float >)){ const auto &A=opTraits.getAssembledOpOrThrow(op);const M &mat=A->getmat();auto solver=std::make_shared< Dune::Cholmod< D >>();solver->setMatrix(mat);return solver;} DUNE_THROW(UnsupportedType, "Unsupported Type in Cholmod (only double and float supported)");})
static void free_numeric(A... args)
Definition: umfpack.hh:68
Implementation of the BCRSMatrix class.
int iterations
Number of iterations.
Definition: solver.hh:69
static int save_numeric(A... args)
Definition: umfpack.hh:156
void setVerbosity(int v)
sets the verbosity level for the UMFPack solver
Definition: umfpack.hh:681
static constexpr bool valid
Definition: umfpack.hh:54
void setSubMatrix(const Matrix &_mat, const std::set< typename Matrix::size_type > &rowIndexSet)
Definition: umfpack.hh:657
static void free_symbolic(A... args)
Definition: umfpack.hh:73
static auto rowdim(const M &)
Definition: matrixutils.hh:214
void * getFactorization()
Return the matrix factorization.
Definition: umfpack.hh:697
static void numeric(A... args)
Definition: umfpack.hh:83
UMFPack(const Matrix &mat_, const ParameterTree &config)
Construct a solver object from a matrix.
Definition: umfpack.hh:334
Impl::UMFPackRangeType< M > range_type
The type of the range of the solver.
Definition: umfpack.hh:281
bool converged
True if convergence criterion has been met.
Definition: solver.hh:75
UMFPack(const Matrix &matrix, int verbose=0)
Construct a solver object from a matrix.
Definition: umfpack.hh:297
void setOption(unsigned int option, double value)
Set UMFPack-specific options.
Definition: umfpack.hh:499
std::pair< std::size_t, std::size_t > flatMatrixForEach(Matrix &&matrix, F &&f, std::size_t rowOffset=0, std::size_t colOffset=0)
Traverse a blocked matrix and call a functor at each scalar entry.
Definition: foreach.hh:132
UMFPack(const char *file, int verbose=0)
try loading a decomposition from file
Definition: umfpack.hh:385
Whether this is a direct solver.
Definition: solvertype.hh:24
A dynamic dense block matrix class.
ISTL::Impl::BCCSMatrixInitializer< M, size_type > MatrixInitializer
Type of an associated initializer class.
Definition: umfpack.hh:277
Category
Definition: solvercategory.hh:23
Definition: umfpack.hh:804
static void symbolic(size_type m, size_type n, const size_type *cs, const size_type *ri, const double *val, A... args)
Definition: umfpack.hh:167
UMFPack()
default constructor
Definition: umfpack.hh:340
static int load_numeric(A... args)
Definition: umfpack.hh:136
Definition: allocator.hh:11
void apply(T *x, T *b)
additional apply method with c-arrays in analogy to superlu
Definition: umfpack.hh:473
static void symbolic(A... args)
Definition: umfpack.hh:108
double elapsed
Elapsed time in seconds.
Definition: solver.hh:84
Abstract base class for all solvers.
Definition: solver.hh:101
SolverCategory::Category category() const override
Category of the solver (see SolverCategory::Category)
Definition: umfpack.hh:284
Definition: solvertype.hh:15
void setMatrix(const Matrix &matrix, const BitVector &bitVector={})
Initialize data from given matrix.
Definition: umfpack.hh:527
UMFPackMatrix & getInternalMatrix()
Return the column compress matrix from UMFPack.
Definition: umfpack.hh:706
PropertyMapTypeSelector< Amg::VertexVisitedTag, Amg::PropertiesGraph< G, Amg::VertexProperties, EP, VM, EM > >::Type get([[maybe_unused]] const Amg::VertexVisitedTag &tag, Amg::PropertiesGraph< G, Amg::VertexProperties, EP, VM, EM > &graph)
Definition: dependency.hh:293
UMFPack(const Matrix &matrix, int verbose, bool)
Constructor for compatibility with SuperLU standard constructor.
Definition: umfpack.hh:315
static void report_status(A... args)
Definition: umfpack.hh:93
static int save_numeric(A... args)
Definition: umfpack.hh:98