MFEM  v4.1.0
Finite element discretization library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
hypre.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
2 // at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3 // LICENSE and NOTICE for details. LLNL-CODE-806117.
4 //
5 // This file is part of the MFEM library. For more information and source code
6 // availability visit https://mfem.org.
7 //
8 // MFEM is free software; you can redistribute it and/or modify it under the
9 // terms of the BSD-3 license. We welcome feedback and contributions, see file
10 // CONTRIBUTING.md for details.
11 
12 #include "../config/config.hpp"
13 
14 #ifdef MFEM_USE_MPI
15 
16 #include "linalg.hpp"
17 #include "../fem/fem.hpp"
18 
19 #include <fstream>
20 #include <iomanip>
21 #include <cmath>
22 #include <cstdlib>
23 
24 // Define macro wrappers for hypre_TAlloc, hypre_CTAlloc and hypre_TFree:
25 // mfem_hypre_TAlloc, mfem_hypre_CTAlloc, and mfem_hypre_TFree, respectively.
26 // Note: the same macros are defined in hypre_parcsr.cpp.
27 #if MFEM_HYPRE_VERSION < 21400
28 
29 #define mfem_hypre_TAlloc(type, size) hypre_TAlloc(type, size)
30 #define mfem_hypre_CTAlloc(type, size) hypre_CTAlloc(type, size)
31 #define mfem_hypre_TFree(ptr) hypre_TFree(ptr)
32 
33 #else // MFEM_HYPRE_VERSION >= 21400
34 
35 #define mfem_hypre_TAlloc(type, size) \
36  hypre_TAlloc(type, size, HYPRE_MEMORY_HOST)
37 #define mfem_hypre_CTAlloc(type, size) \
38  hypre_CTAlloc(type, size, HYPRE_MEMORY_HOST)
39 #define mfem_hypre_TFree(ptr) hypre_TFree(ptr, HYPRE_MEMORY_HOST)
40 
41 // Notes regarding allocation and deallocation of hypre objects in 2.14.0
42 //-----------------------------------------------------------------------
43 //
44 // 1. hypre_CSRMatrix: i, j, data, and rownnz use HYPRE_MEMORY_SHARED while the
45 // hypre_CSRMatrix structure uses HYPRE_MEMORY_HOST.
46 //
47 // Note: the function HYPRE_CSRMatrixCreate creates the i array using
48 // HYPRE_MEMORY_HOST!
49 // Note: the functions hypre_CSRMatrixAdd and hypre_CSRMatrixMultiply create
50 // C_i using HYPRE_MEMORY_HOST!
51 //
52 // 2. hypre_Vector: data uses HYPRE_MEMORY_SHARED while the hypre_Vector
53 // structure uses HYPRE_MEMORY_HOST.
54 //
55 // 3. hypre_ParVector: the structure hypre_ParVector uses HYPRE_MEMORY_HOST;
56 // partitioning uses HYPRE_MEMORY_HOST.
57 //
58 // 4. hypre_ParCSRMatrix: the structure hypre_ParCSRMatrix uses
59 // HYPRE_MEMORY_HOST; col_map_offd, row_starts, col_starts, rowindices,
60 // rowvalues also use HYPRE_MEMORY_HOST.
61 //
62 // Note: the function hypre_ParCSRMatrixToCSRMatrixAll allocates matrix_i
63 // using HYPRE_MEMORY_HOST!
64 //
65 // 5. The goal for the MFEM wrappers of hypre objects is to support only the
66 // standard hypre build case, i.e. when hypre is build without device support
67 // and all memory types correspond to host memory. In this case memory
68 // allocated with operator new can be used by hypre but (as usual) it must
69 // not be owned by hypre.
70 
71 #endif // #if MFEM_HYPRE_VERSION < 21400
72 
73 using namespace std;
74 
75 namespace mfem
76 {
77 
78 template<typename TargetT, typename SourceT>
79 static TargetT *DuplicateAs(const SourceT *array, int size,
80  bool cplusplus = true)
81 {
82  TargetT *target_array = cplusplus ? (TargetT*) Memory<TargetT>(size)
83  /* */ : mfem_hypre_TAlloc(TargetT, size);
84  for (int i = 0; i < size; i++)
85  {
86  target_array[i] = array[i];
87  }
88  return target_array;
89 }
90 
91 inline void HypreParVector::_SetDataAndSize_()
92 {
93  SetDataAndSize(hypre_VectorData(hypre_ParVectorLocalVector(x)),
95  hypre_VectorSize(hypre_ParVectorLocalVector(x))));
96 }
97 
98 HypreParVector::HypreParVector(MPI_Comm comm, HYPRE_Int glob_size,
99  HYPRE_Int *col) : Vector()
100 {
101  x = hypre_ParVectorCreate(comm,glob_size,col);
102  hypre_ParVectorInitialize(x);
103  hypre_ParVectorSetPartitioningOwner(x,0);
104  // The data will be destroyed by hypre (this is the default)
105  hypre_ParVectorSetDataOwner(x,1);
106  hypre_SeqVectorSetDataOwner(hypre_ParVectorLocalVector(x),1);
107  _SetDataAndSize_();
108  own_ParVector = 1;
109 }
110 
111 HypreParVector::HypreParVector(MPI_Comm comm, HYPRE_Int glob_size,
112  double *_data, HYPRE_Int *col) : Vector()
113 {
114  x = hypre_ParVectorCreate(comm,glob_size,col);
115  hypre_ParVectorSetDataOwner(x,1); // owns the seq vector
116  hypre_SeqVectorSetDataOwner(hypre_ParVectorLocalVector(x),0);
117  hypre_ParVectorSetPartitioningOwner(x,0);
118  double tmp = 0.0;
119  hypre_VectorData(hypre_ParVectorLocalVector(x)) = &tmp;
120  // If hypre_ParVectorLocalVector(x) and &tmp are non-NULL,
121  // hypre_ParVectorInitialize(x) does not allocate memory!
122  hypre_ParVectorInitialize(x);
123  // Set the internal data array to the one passed in
124  hypre_VectorData(hypre_ParVectorLocalVector(x)) = _data;
125  _SetDataAndSize_();
126  own_ParVector = 1;
127 }
128 
130 {
131  x = hypre_ParVectorCreate(y.x -> comm, y.x -> global_size,
132  y.x -> partitioning);
133  hypre_ParVectorInitialize(x);
134  hypre_ParVectorSetPartitioningOwner(x,0);
135  hypre_ParVectorSetDataOwner(x,1);
136  hypre_SeqVectorSetDataOwner(hypre_ParVectorLocalVector(x),1);
137  _SetDataAndSize_();
138  own_ParVector = 1;
139 }
140 
142  int transpose) : Vector()
143 {
144  if (!transpose)
145  {
146  x = hypre_ParVectorInDomainOf(const_cast<HypreParMatrix&>(A));
147  }
148  else
149  {
150  x = hypre_ParVectorInRangeOf(const_cast<HypreParMatrix&>(A));
151  }
152  _SetDataAndSize_();
153  own_ParVector = 1;
154 }
155 
157 {
158  x = (hypre_ParVector *) y;
159  _SetDataAndSize_();
160  own_ParVector = 0;
161 }
162 
164 {
165  x = hypre_ParVectorCreate(pfes->GetComm(), pfes->GlobalTrueVSize(),
166  pfes->GetTrueDofOffsets());
167  hypre_ParVectorInitialize(x);
168  hypre_ParVectorSetPartitioningOwner(x,0);
169  // The data will be destroyed by hypre (this is the default)
170  hypre_ParVectorSetDataOwner(x,1);
171  hypre_SeqVectorSetDataOwner(hypre_ParVectorLocalVector(x),1);
172  _SetDataAndSize_();
173  own_ParVector = 1;
174 }
175 
177 {
178  hypre_Vector *hv = hypre_ParVectorToVectorAll(*this);
179  Vector *v = new Vector(hv->data, internal::to_int(hv->size));
180  v->MakeDataOwner();
181  hypre_SeqVectorSetDataOwner(hv,0);
182  hypre_SeqVectorDestroy(hv);
183  return v;
184 }
185 
187 {
189  return *this;
190 }
191 
193 {
194 #ifdef MFEM_DEBUG
195  if (size != y.Size())
196  {
197  mfem_error("HypreParVector::operator=");
198  }
199 #endif
200 
202  return *this;
203 }
204 
205 void HypreParVector::SetData(double *_data)
206 {
207  hypre_VectorData(hypre_ParVectorLocalVector(x)) = _data;
208  Vector::SetData(_data);
209 }
210 
211 HYPRE_Int HypreParVector::Randomize(HYPRE_Int seed)
212 {
213  return hypre_ParVectorSetRandomValues(x,seed);
214 }
215 
216 void HypreParVector::Print(const char *fname) const
217 {
218  hypre_ParVectorPrint(x,fname);
219 }
220 
222 {
223  if (own_ParVector)
224  {
225  hypre_ParVectorDestroy(x);
226  }
227 }
228 
229 #ifdef MFEM_USE_SUNDIALS
230 
231 void HypreParVector::ToNVector(N_Vector &nv)
232 {
233  MFEM_ASSERT(nv && N_VGetVectorID(nv) == SUNDIALS_NVEC_PARHYP,
234  "invalid N_Vector");
235  N_VectorContent_ParHyp nv_c = (N_VectorContent_ParHyp)(nv->content);
236  MFEM_ASSERT(nv_c->own_parvector == SUNFALSE, "invalid N_Vector");
237  nv_c->local_length = x->local_vector->size;
238  nv_c->global_length = x->global_size;
239  nv_c->comm = x->comm;
240  nv_c->x = x;
241 }
242 
243 #endif // MFEM_USE_SUNDIALS
244 
245 
247 {
248  return hypre_ParVectorInnerProd(*x, *y);
249 }
250 
252 {
253  return hypre_ParVectorInnerProd(x, y);
254 }
255 
256 
257 double ParNormlp(const Vector &vec, double p, MPI_Comm comm)
258 {
259  double norm = 0.0;
260  if (p == 1.0)
261  {
262  double loc_norm = vec.Norml1();
263  MPI_Allreduce(&loc_norm, &norm, 1, MPI_DOUBLE, MPI_SUM, comm);
264  }
265  if (p == 2.0)
266  {
267  double loc_norm = vec*vec;
268  MPI_Allreduce(&loc_norm, &norm, 1, MPI_DOUBLE, MPI_SUM, comm);
269  norm = sqrt(norm);
270  }
271  if (p < infinity())
272  {
273  double sum = 0.0;
274  for (int i = 0; i < vec.Size(); i++)
275  {
276  sum += pow(fabs(vec(i)), p);
277  }
278  MPI_Allreduce(&sum, &norm, 1, MPI_DOUBLE, MPI_SUM, comm);
279  norm = pow(norm, 1.0/p);
280  }
281  else
282  {
283  double loc_norm = vec.Normlinf();
284  MPI_Allreduce(&loc_norm, &norm, 1, MPI_DOUBLE, MPI_MAX, comm);
285  }
286  return norm;
287 }
288 
289 
290 void HypreParMatrix::Init()
291 {
292  A = NULL;
293  X = Y = NULL;
294  diagOwner = offdOwner = colMapOwner = -1;
295  ParCSROwner = 1;
296 }
297 
299 {
300  Init();
301  height = width = 0;
302 }
303 
304 char HypreParMatrix::CopyCSR(SparseMatrix *csr, hypre_CSRMatrix *hypre_csr)
305 {
306  hypre_CSRMatrixData(hypre_csr) = csr->GetData();
307 #ifndef HYPRE_BIGINT
308  hypre_CSRMatrixI(hypre_csr) = csr->GetI();
309  hypre_CSRMatrixJ(hypre_csr) = csr->GetJ();
310  // Prevent hypre from destroying hypre_csr->{i,j,data}
311  return 0;
312 #else
313  hypre_CSRMatrixI(hypre_csr) =
314  DuplicateAs<HYPRE_Int>(csr->GetI(), csr->Height()+1);
315  hypre_CSRMatrixJ(hypre_csr) =
316  DuplicateAs<HYPRE_Int>(csr->GetJ(), csr->NumNonZeroElems());
317  // Prevent hypre from destroying hypre_csr->{i,j,data}, own {i,j}
318  return 1;
319 #endif
320 }
321 
322 char HypreParMatrix::CopyBoolCSR(Table *bool_csr, hypre_CSRMatrix *hypre_csr)
323 {
324  int nnz = bool_csr->Size_of_connections();
325  double *data = new double[nnz];
326  for (int i = 0; i < nnz; i++)
327  {
328  data[i] = 1.0;
329  }
330  hypre_CSRMatrixData(hypre_csr) = data;
331 #ifndef HYPRE_BIGINT
332  hypre_CSRMatrixI(hypre_csr) = bool_csr->GetI();
333  hypre_CSRMatrixJ(hypre_csr) = bool_csr->GetJ();
334  // Prevent hypre from destroying hypre_csr->{i,j,data}, own {data}
335  return 2;
336 #else
337  hypre_CSRMatrixI(hypre_csr) =
338  DuplicateAs<HYPRE_Int>(bool_csr->GetI(), bool_csr->Size()+1);
339  hypre_CSRMatrixJ(hypre_csr) =
340  DuplicateAs<HYPRE_Int>(bool_csr->GetJ(), nnz);
341  // Prevent hypre from destroying hypre_csr->{i,j,data}, own {i,j,data}
342  return 3;
343 #endif
344 }
345 
346 void HypreParMatrix::CopyCSR_J(hypre_CSRMatrix *hypre_csr, int *J)
347 {
348  HYPRE_Int nnz = hypre_CSRMatrixNumNonzeros(hypre_csr);
349  for (HYPRE_Int j = 0; j < nnz; j++)
350  {
351  J[j] = int(hypre_CSRMatrixJ(hypre_csr)[j]);
352  }
353 }
354 
355 // Square block-diagonal constructor (4 arguments, v1)
356 HypreParMatrix::HypreParMatrix(MPI_Comm comm, HYPRE_Int glob_size,
357  HYPRE_Int *row_starts, SparseMatrix *diag)
358  : Operator(diag->Height(), diag->Width())
359 {
360  Init();
361  A = hypre_ParCSRMatrixCreate(comm, glob_size, glob_size, row_starts,
362  row_starts, 0, diag->NumNonZeroElems(), 0);
363  hypre_ParCSRMatrixSetDataOwner(A,1);
364  hypre_ParCSRMatrixSetRowStartsOwner(A,0);
365  hypre_ParCSRMatrixSetColStartsOwner(A,0);
366 
367  hypre_CSRMatrixSetDataOwner(A->diag,0);
368  diagOwner = CopyCSR(diag, A->diag);
369  hypre_CSRMatrixSetRownnz(A->diag);
370 
371  hypre_CSRMatrixSetDataOwner(A->offd,1);
372  hypre_CSRMatrixI(A->offd) = mfem_hypre_CTAlloc(HYPRE_Int, diag->Height()+1);
373 
374  /* Don't need to call these, since they allocate memory only
375  if it was not already allocated */
376  // hypre_CSRMatrixInitialize(A->diag);
377  // hypre_ParCSRMatrixInitialize(A);
378 
379  hypre_ParCSRMatrixSetNumNonzeros(A);
380 
381  /* Make sure that the first entry in each row is the diagonal one. */
382  hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
383 #ifdef HYPRE_BIGINT
384  CopyCSR_J(A->diag, diag->GetJ());
385 #endif
386 
387  hypre_MatvecCommPkgCreate(A);
388 }
389 
390 // Rectangular block-diagonal constructor (6 arguments, v1)
392  HYPRE_Int global_num_rows,
393  HYPRE_Int global_num_cols,
394  HYPRE_Int *row_starts, HYPRE_Int *col_starts,
395  SparseMatrix *diag)
396  : Operator(diag->Height(), diag->Width())
397 {
398  Init();
399  A = hypre_ParCSRMatrixCreate(comm, global_num_rows, global_num_cols,
400  row_starts, col_starts,
401  0, diag->NumNonZeroElems(), 0);
402  hypre_ParCSRMatrixSetDataOwner(A,1);
403  hypre_ParCSRMatrixSetRowStartsOwner(A,0);
404  hypre_ParCSRMatrixSetColStartsOwner(A,0);
405 
406  hypre_CSRMatrixSetDataOwner(A->diag,0);
407  diagOwner = CopyCSR(diag, A->diag);
408  hypre_CSRMatrixSetRownnz(A->diag);
409 
410  hypre_CSRMatrixSetDataOwner(A->offd,1);
411  hypre_CSRMatrixI(A->offd) = mfem_hypre_CTAlloc(HYPRE_Int, diag->Height()+1);
412 
413  hypre_ParCSRMatrixSetNumNonzeros(A);
414 
415  /* Make sure that the first entry in each row is the diagonal one. */
416  if (row_starts == col_starts)
417  {
418  hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
419 #ifdef HYPRE_BIGINT
420  CopyCSR_J(A->diag, diag->GetJ());
421 #endif
422  }
423 
424  hypre_MatvecCommPkgCreate(A);
425 }
426 
427 // General rectangular constructor with diagonal and off-diagonal (8 arguments)
429  HYPRE_Int global_num_rows,
430  HYPRE_Int global_num_cols,
431  HYPRE_Int *row_starts, HYPRE_Int *col_starts,
432  SparseMatrix *diag, SparseMatrix *offd,
433  HYPRE_Int *cmap)
434  : Operator(diag->Height(), diag->Width())
435 {
436  Init();
437  A = hypre_ParCSRMatrixCreate(comm, global_num_rows, global_num_cols,
438  row_starts, col_starts,
439  offd->Width(), diag->NumNonZeroElems(),
440  offd->NumNonZeroElems());
441  hypre_ParCSRMatrixSetDataOwner(A,1);
442  hypre_ParCSRMatrixSetRowStartsOwner(A,0);
443  hypre_ParCSRMatrixSetColStartsOwner(A,0);
444 
445  hypre_CSRMatrixSetDataOwner(A->diag,0);
446  diagOwner = CopyCSR(diag, A->diag);
447  hypre_CSRMatrixSetRownnz(A->diag);
448 
449  hypre_CSRMatrixSetDataOwner(A->offd,0);
450  offdOwner = CopyCSR(offd, A->offd);
451  hypre_CSRMatrixSetRownnz(A->offd);
452 
453  hypre_ParCSRMatrixColMapOffd(A) = cmap;
454  // Prevent hypre from destroying A->col_map_offd
455  colMapOwner = 0;
456 
457  hypre_ParCSRMatrixSetNumNonzeros(A);
458 
459  /* Make sure that the first entry in each row is the diagonal one. */
460  if (row_starts == col_starts)
461  {
462  hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
463 #ifdef HYPRE_BIGINT
464  CopyCSR_J(A->diag, diag->GetJ());
465 #endif
466  }
467 
468  hypre_MatvecCommPkgCreate(A);
469 }
470 
471 // General rectangular constructor with diagonal and off-diagonal (13 arguments)
473  MPI_Comm comm,
474  HYPRE_Int global_num_rows, HYPRE_Int global_num_cols,
475  HYPRE_Int *row_starts, HYPRE_Int *col_starts,
476  HYPRE_Int *diag_i, HYPRE_Int *diag_j, double *diag_data,
477  HYPRE_Int *offd_i, HYPRE_Int *offd_j, double *offd_data,
478  HYPRE_Int offd_num_cols, HYPRE_Int *offd_col_map)
479 {
480  Init();
481  A = hypre_ParCSRMatrixCreate(comm, global_num_rows, global_num_cols,
482  row_starts, col_starts, offd_num_cols, 0, 0);
483  hypre_ParCSRMatrixSetDataOwner(A,1);
484  hypre_ParCSRMatrixSetRowStartsOwner(A,0);
485  hypre_ParCSRMatrixSetColStartsOwner(A,0);
486 
487  HYPRE_Int local_num_rows = hypre_CSRMatrixNumRows(A->diag);
488 
489  hypre_CSRMatrixSetDataOwner(A->diag,0);
490  hypre_CSRMatrixI(A->diag) = diag_i;
491  hypre_CSRMatrixJ(A->diag) = diag_j;
492  hypre_CSRMatrixData(A->diag) = diag_data;
493  hypre_CSRMatrixNumNonzeros(A->diag) = diag_i[local_num_rows];
494  hypre_CSRMatrixSetRownnz(A->diag);
495  // Prevent hypre from destroying A->diag->{i,j,data}, own A->diag->{i,j,data}
496  diagOwner = 3;
497 
498  hypre_CSRMatrixSetDataOwner(A->offd,0);
499  hypre_CSRMatrixI(A->offd) = offd_i;
500  hypre_CSRMatrixJ(A->offd) = offd_j;
501  hypre_CSRMatrixData(A->offd) = offd_data;
502  hypre_CSRMatrixNumNonzeros(A->offd) = offd_i[local_num_rows];
503  hypre_CSRMatrixSetRownnz(A->offd);
504  // Prevent hypre from destroying A->offd->{i,j,data}, own A->offd->{i,j,data}
505  offdOwner = 3;
506 
507  hypre_ParCSRMatrixColMapOffd(A) = offd_col_map;
508  // Prevent hypre from destroying A->col_map_offd, own A->col_map_offd
509  colMapOwner = 1;
510 
511  hypre_ParCSRMatrixSetNumNonzeros(A);
512 
513  /* Make sure that the first entry in each row is the diagonal one. */
514  if (row_starts == col_starts)
515  {
516  hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
517  }
518 
519  hypre_MatvecCommPkgCreate(A);
520 
521  height = GetNumRows();
522  width = GetNumCols();
523 }
524 
525 // Constructor from a CSR matrix on rank 0 (4 arguments, v2)
527  HYPRE_Int *row_starts, HYPRE_Int *col_starts,
528  SparseMatrix *sm_a)
529 {
530  MFEM_ASSERT(sm_a != NULL, "invalid input");
531  MFEM_VERIFY(!HYPRE_AssumedPartitionCheck(),
532  "this method can not be used with assumed partition");
533 
534  Init();
535 
536  hypre_CSRMatrix *csr_a;
537  csr_a = hypre_CSRMatrixCreate(sm_a -> Height(), sm_a -> Width(),
538  sm_a -> NumNonZeroElems());
539 
540  hypre_CSRMatrixSetDataOwner(csr_a,0);
541  CopyCSR(sm_a, csr_a);
542  hypre_CSRMatrixSetRownnz(csr_a);
543 
544  A = hypre_CSRMatrixToParCSRMatrix(comm, csr_a, row_starts, col_starts);
545 
546 #ifdef HYPRE_BIGINT
547  delete [] hypre_CSRMatrixI(csr_a);
548  delete [] hypre_CSRMatrixJ(csr_a);
549 #endif
550  hypre_CSRMatrixI(csr_a) = NULL;
551  hypre_CSRMatrixDestroy(csr_a);
552 
553  height = GetNumRows();
554  width = GetNumCols();
555 
556  /* Make sure that the first entry in each row is the diagonal one. */
557  if (row_starts == col_starts)
558  {
559  hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
560  }
561 
562  hypre_MatvecCommPkgCreate(A);
563 }
564 
565 // Boolean, rectangular, block-diagonal constructor (6 arguments, v2)
567  HYPRE_Int global_num_rows,
568  HYPRE_Int global_num_cols,
569  HYPRE_Int *row_starts, HYPRE_Int *col_starts,
570  Table *diag)
571 {
572  Init();
573  int nnz = diag->Size_of_connections();
574  A = hypre_ParCSRMatrixCreate(comm, global_num_rows, global_num_cols,
575  row_starts, col_starts, 0, nnz, 0);
576  hypre_ParCSRMatrixSetDataOwner(A,1);
577  hypre_ParCSRMatrixSetRowStartsOwner(A,0);
578  hypre_ParCSRMatrixSetColStartsOwner(A,0);
579 
580  hypre_CSRMatrixSetDataOwner(A->diag,0);
581  diagOwner = CopyBoolCSR(diag, A->diag);
582  hypre_CSRMatrixSetRownnz(A->diag);
583 
584  hypre_CSRMatrixSetDataOwner(A->offd,1);
585  hypre_CSRMatrixI(A->offd) = mfem_hypre_CTAlloc(HYPRE_Int, diag->Size()+1);
586 
587  hypre_ParCSRMatrixSetNumNonzeros(A);
588 
589  /* Make sure that the first entry in each row is the diagonal one. */
590  if (row_starts == col_starts)
591  {
592  hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
593 #ifdef HYPRE_BIGINT
594  CopyCSR_J(A->diag, diag->GetJ());
595 #endif
596  }
597 
598  hypre_MatvecCommPkgCreate(A);
599 
600  height = GetNumRows();
601  width = GetNumCols();
602 }
603 
604 // Boolean, general rectangular constructor with diagonal and off-diagonal
605 // (11 arguments)
606 HypreParMatrix::HypreParMatrix(MPI_Comm comm, int id, int np,
607  HYPRE_Int *row, HYPRE_Int *col,
608  HYPRE_Int *i_diag, HYPRE_Int *j_diag,
609  HYPRE_Int *i_offd, HYPRE_Int *j_offd,
610  HYPRE_Int *cmap, HYPRE_Int cmap_size)
611 {
612  HYPRE_Int diag_nnz, offd_nnz;
613 
614  Init();
615  if (HYPRE_AssumedPartitionCheck())
616  {
617  diag_nnz = i_diag[row[1]-row[0]];
618  offd_nnz = i_offd[row[1]-row[0]];
619 
620  A = hypre_ParCSRMatrixCreate(comm, row[2], col[2], row, col,
621  cmap_size, diag_nnz, offd_nnz);
622  }
623  else
624  {
625  diag_nnz = i_diag[row[id+1]-row[id]];
626  offd_nnz = i_offd[row[id+1]-row[id]];
627 
628  A = hypre_ParCSRMatrixCreate(comm, row[np], col[np], row, col,
629  cmap_size, diag_nnz, offd_nnz);
630  }
631 
632  hypre_ParCSRMatrixSetDataOwner(A,1);
633  hypre_ParCSRMatrixSetRowStartsOwner(A,0);
634  hypre_ParCSRMatrixSetColStartsOwner(A,0);
635 
636  HYPRE_Int i;
637 
638  double *a_diag = Memory<double>(diag_nnz);
639  for (i = 0; i < diag_nnz; i++)
640  {
641  a_diag[i] = 1.0;
642  }
643 
644  double *a_offd = Memory<double>(offd_nnz);
645  for (i = 0; i < offd_nnz; i++)
646  {
647  a_offd[i] = 1.0;
648  }
649 
650  hypre_CSRMatrixSetDataOwner(A->diag,0);
651  hypre_CSRMatrixI(A->diag) = i_diag;
652  hypre_CSRMatrixJ(A->diag) = j_diag;
653  hypre_CSRMatrixData(A->diag) = a_diag;
654  hypre_CSRMatrixSetRownnz(A->diag);
655  // Prevent hypre from destroying A->diag->{i,j,data}, own A->diag->{i,j,data}
656  diagOwner = 3;
657 
658  hypre_CSRMatrixSetDataOwner(A->offd,0);
659  hypre_CSRMatrixI(A->offd) = i_offd;
660  hypre_CSRMatrixJ(A->offd) = j_offd;
661  hypre_CSRMatrixData(A->offd) = a_offd;
662  hypre_CSRMatrixSetRownnz(A->offd);
663  // Prevent hypre from destroying A->offd->{i,j,data}, own A->offd->{i,j,data}
664  offdOwner = 3;
665 
666  hypre_ParCSRMatrixColMapOffd(A) = cmap;
667  // Prevent hypre from destroying A->col_map_offd, own A->col_map_offd
668  colMapOwner = 1;
669 
670  hypre_ParCSRMatrixSetNumNonzeros(A);
671 
672  /* Make sure that the first entry in each row is the diagonal one. */
673  if (row == col)
674  {
675  hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
676  }
677 
678  hypre_MatvecCommPkgCreate(A);
679 
680  height = GetNumRows();
681  width = GetNumCols();
682 }
683 
684 // General rectangular constructor with diagonal and off-diagonal constructed
685 // from a CSR matrix that contains both diagonal and off-diagonal blocks
686 // (9 arguments)
687 HypreParMatrix::HypreParMatrix(MPI_Comm comm, int nrows, HYPRE_Int glob_nrows,
688  HYPRE_Int glob_ncols, int *I, HYPRE_Int *J,
689  double *data, HYPRE_Int *rows, HYPRE_Int *cols)
690 {
691  Init();
692 
693  // Determine partitioning size, and my column start and end
694  int part_size;
695  HYPRE_Int my_col_start, my_col_end; // my range: [my_col_start, my_col_end)
696  if (HYPRE_AssumedPartitionCheck())
697  {
698  part_size = 2;
699  my_col_start = cols[0];
700  my_col_end = cols[1];
701  }
702  else
703  {
704  int myid;
705  MPI_Comm_rank(comm, &myid);
706  MPI_Comm_size(comm, &part_size);
707  part_size++;
708  my_col_start = cols[myid];
709  my_col_end = cols[myid+1];
710  }
711 
712  // Copy in the row and column partitionings
713  HYPRE_Int *row_starts, *col_starts;
714  if (rows == cols)
715  {
716  row_starts = col_starts = mfem_hypre_TAlloc(HYPRE_Int, part_size);
717  for (int i = 0; i < part_size; i++)
718  {
719  row_starts[i] = rows[i];
720  }
721  }
722  else
723  {
724  row_starts = mfem_hypre_TAlloc(HYPRE_Int, part_size);
725  col_starts = mfem_hypre_TAlloc(HYPRE_Int, part_size);
726  for (int i = 0; i < part_size; i++)
727  {
728  row_starts[i] = rows[i];
729  col_starts[i] = cols[i];
730  }
731  }
732 
733  // Create a map for the off-diagonal indices - global to local. Count the
734  // number of diagonal and off-diagonal entries.
735  HYPRE_Int diag_nnz = 0, offd_nnz = 0, offd_num_cols = 0;
736  map<HYPRE_Int, HYPRE_Int> offd_map;
737  for (HYPRE_Int j = 0, loc_nnz = I[nrows]; j < loc_nnz; j++)
738  {
739  HYPRE_Int glob_col = J[j];
740  if (my_col_start <= glob_col && glob_col < my_col_end)
741  {
742  diag_nnz++;
743  }
744  else
745  {
746  offd_map.insert(pair<const HYPRE_Int, HYPRE_Int>(glob_col, -1));
747  offd_nnz++;
748  }
749  }
750  // count the number of columns in the off-diagonal and set the local indices
751  for (map<HYPRE_Int, HYPRE_Int>::iterator it = offd_map.begin();
752  it != offd_map.end(); ++it)
753  {
754  it->second = offd_num_cols++;
755  }
756 
757  // construct the global ParCSR matrix
758  A = hypre_ParCSRMatrixCreate(comm, glob_nrows, glob_ncols,
759  row_starts, col_starts, offd_num_cols,
760  diag_nnz, offd_nnz);
761  hypre_ParCSRMatrixInitialize(A);
762 
763  HYPRE_Int *diag_i, *diag_j, *offd_i, *offd_j, *offd_col_map;
764  double *diag_data, *offd_data;
765  diag_i = A->diag->i;
766  diag_j = A->diag->j;
767  diag_data = A->diag->data;
768  offd_i = A->offd->i;
769  offd_j = A->offd->j;
770  offd_data = A->offd->data;
771  offd_col_map = A->col_map_offd;
772 
773  diag_nnz = offd_nnz = 0;
774  for (HYPRE_Int i = 0, j = 0; i < nrows; i++)
775  {
776  diag_i[i] = diag_nnz;
777  offd_i[i] = offd_nnz;
778  for (HYPRE_Int j_end = I[i+1]; j < j_end; j++)
779  {
780  HYPRE_Int glob_col = J[j];
781  if (my_col_start <= glob_col && glob_col < my_col_end)
782  {
783  diag_j[diag_nnz] = glob_col - my_col_start;
784  diag_data[diag_nnz] = data[j];
785  diag_nnz++;
786  }
787  else
788  {
789  offd_j[offd_nnz] = offd_map[glob_col];
790  offd_data[offd_nnz] = data[j];
791  offd_nnz++;
792  }
793  }
794  }
795  diag_i[nrows] = diag_nnz;
796  offd_i[nrows] = offd_nnz;
797  for (map<HYPRE_Int, HYPRE_Int>::iterator it = offd_map.begin();
798  it != offd_map.end(); ++it)
799  {
800  offd_col_map[it->second] = it->first;
801  }
802 
803  hypre_ParCSRMatrixSetNumNonzeros(A);
804  /* Make sure that the first entry in each row is the diagonal one. */
805  if (row_starts == col_starts)
806  {
807  hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
808  }
809  hypre_MatvecCommPkgCreate(A);
810 
811  height = GetNumRows();
812  width = GetNumCols();
813 }
814 
816 {
817  hypre_ParCSRMatrix *Ph = static_cast<hypre_ParCSRMatrix *>(P);
818 
819  Init();
820 
821  // Clone the structure
822  A = hypre_ParCSRMatrixCompleteClone(Ph);
823  // Make a deep copy of the data from the source
824  hypre_ParCSRMatrixCopy(Ph, A, 1);
825 
826  height = GetNumRows();
827  width = GetNumCols();
828 
829  CopyRowStarts();
830  CopyColStarts();
831 
832  hypre_ParCSRMatrixSetNumNonzeros(A);
833 
834  hypre_MatvecCommPkgCreate(A);
835 }
836 
838 {
839  Destroy();
840  Init();
841  A = master.A;
842  ParCSROwner = 0;
843  height = master.GetNumRows();
844  width = master.GetNumCols();
845 }
846 
847 hypre_ParCSRMatrix* HypreParMatrix::StealData()
848 {
849  // Only safe when (diagOwner == -1 && offdOwner == -1 && colMapOwner == -1)
850  // Otherwise, there may be memory leaks or hypre may destroy arrays allocated
851  // with operator new.
852  MFEM_ASSERT(diagOwner == -1 && offdOwner == -1 && colMapOwner == -1, "");
853  MFEM_ASSERT(ParCSROwner, "");
854  hypre_ParCSRMatrix *R = A;
855  A = NULL;
856  Destroy();
857  Init();
858  return R;
859 }
860 
862 {
863  if (!A || hypre_ParCSRMatrixOwnsRowStarts(A) ||
864  (hypre_ParCSRMatrixRowStarts(A) == hypre_ParCSRMatrixColStarts(A) &&
865  hypre_ParCSRMatrixOwnsColStarts(A)))
866  {
867  return;
868  }
869 
870  int row_starts_size;
871  if (HYPRE_AssumedPartitionCheck())
872  {
873  row_starts_size = 2;
874  }
875  else
876  {
877  MPI_Comm_size(hypre_ParCSRMatrixComm(A), &row_starts_size);
878  row_starts_size++; // num_proc + 1
879  }
880 
881  HYPRE_Int *old_row_starts = hypre_ParCSRMatrixRowStarts(A);
882  HYPRE_Int *new_row_starts = mfem_hypre_CTAlloc(HYPRE_Int, row_starts_size);
883  for (int i = 0; i < row_starts_size; i++)
884  {
885  new_row_starts[i] = old_row_starts[i];
886  }
887 
888  hypre_ParCSRMatrixRowStarts(A) = new_row_starts;
889  hypre_ParCSRMatrixOwnsRowStarts(A) = 1;
890 
891  if (hypre_ParCSRMatrixColStarts(A) == old_row_starts)
892  {
893  hypre_ParCSRMatrixColStarts(A) = new_row_starts;
894  hypre_ParCSRMatrixOwnsColStarts(A) = 0;
895  }
896 }
897 
899 {
900  if (!A || hypre_ParCSRMatrixOwnsColStarts(A) ||
901  (hypre_ParCSRMatrixRowStarts(A) == hypre_ParCSRMatrixColStarts(A) &&
902  hypre_ParCSRMatrixOwnsRowStarts(A)))
903  {
904  return;
905  }
906 
907  int col_starts_size;
908  if (HYPRE_AssumedPartitionCheck())
909  {
910  col_starts_size = 2;
911  }
912  else
913  {
914  MPI_Comm_size(hypre_ParCSRMatrixComm(A), &col_starts_size);
915  col_starts_size++; // num_proc + 1
916  }
917 
918  HYPRE_Int *old_col_starts = hypre_ParCSRMatrixColStarts(A);
919  HYPRE_Int *new_col_starts = mfem_hypre_CTAlloc(HYPRE_Int, col_starts_size);
920  for (int i = 0; i < col_starts_size; i++)
921  {
922  new_col_starts[i] = old_col_starts[i];
923  }
924 
925  hypre_ParCSRMatrixColStarts(A) = new_col_starts;
926 
927  if (hypre_ParCSRMatrixRowStarts(A) == old_col_starts)
928  {
929  hypre_ParCSRMatrixRowStarts(A) = new_col_starts;
930  hypre_ParCSRMatrixOwnsRowStarts(A) = 1;
931  hypre_ParCSRMatrixOwnsColStarts(A) = 0;
932  }
933  else
934  {
935  hypre_ParCSRMatrixOwnsColStarts(A) = 1;
936  }
937 }
938 
940 {
941  int size = Height();
942  diag.SetSize(size);
943  for (int j = 0; j < size; j++)
944  {
945  diag(j) = A->diag->data[A->diag->i[j]];
946  MFEM_ASSERT(A->diag->j[A->diag->i[j]] == j,
947  "the first entry in each row must be the diagonal one");
948  }
949 }
950 
951 static void MakeWrapper(const hypre_CSRMatrix *mat, SparseMatrix &wrapper)
952 {
953  HYPRE_Int nr = hypre_CSRMatrixNumRows(mat);
954  HYPRE_Int nc = hypre_CSRMatrixNumCols(mat);
955 #ifndef HYPRE_BIGINT
956  SparseMatrix tmp(hypre_CSRMatrixI(mat),
957  hypre_CSRMatrixJ(mat),
958  hypre_CSRMatrixData(mat),
959  nr, nc, false, false, false);
960 #else
961  HYPRE_Int nnz = hypre_CSRMatrixNumNonzeros(mat);
962  SparseMatrix tmp(DuplicateAs<int>(hypre_CSRMatrixI(mat), nr+1),
963  DuplicateAs<int>(hypre_CSRMatrixJ(mat), nnz),
964  hypre_CSRMatrixData(mat),
965  nr, nc, true, false, false);
966 #endif
967  wrapper.Swap(tmp);
968 }
969 
971 {
972  MakeWrapper(A->diag, diag);
973 }
974 
975 void HypreParMatrix::GetOffd(SparseMatrix &offd, HYPRE_Int* &cmap) const
976 {
977  MakeWrapper(A->offd, offd);
978  cmap = A->col_map_offd;
979 }
980 
982  bool interleaved_rows,
983  bool interleaved_cols) const
984 {
985  int nr = blocks.NumRows();
986  int nc = blocks.NumCols();
987 
988  hypre_ParCSRMatrix **hypre_blocks = new hypre_ParCSRMatrix*[nr * nc];
989  internal::hypre_ParCSRMatrixSplit(A, nr, nc, hypre_blocks,
990  interleaved_rows, interleaved_cols);
991 
992  for (int i = 0; i < nr; i++)
993  {
994  for (int j = 0; j < nc; j++)
995  {
996  blocks[i][j] = new HypreParMatrix(hypre_blocks[i*nc + j]);
997  }
998  }
999 
1000  delete [] hypre_blocks;
1001 }
1002 
1004 {
1005  hypre_ParCSRMatrix * At;
1006  hypre_ParCSRMatrixTranspose(A, &At, 1);
1007  hypre_ParCSRMatrixSetNumNonzeros(At);
1008 
1009  hypre_MatvecCommPkgCreate(At);
1010 
1011  if ( M() == N() )
1012  {
1013  /* If the matrix is square, make sure that the first entry in each
1014  row is the diagonal one. */
1015  hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(At));
1016  }
1017 
1018  return new HypreParMatrix(At);
1019 }
1020 
1022  double a, double b)
1023 {
1024  x.HostRead();
1025  (b == 0.0) ? y.HostWrite() : y.HostReadWrite();
1026  return hypre_ParCSRMatrixMatvec(a, A, x, b, y);
1027 }
1028 
1029 void HypreParMatrix::Mult(double a, const Vector &x, double b, Vector &y) const
1030 {
1031  MFEM_ASSERT(x.Size() == Width(), "invalid x.Size() = " << x.Size()
1032  << ", expected size = " << Width());
1033  MFEM_ASSERT(y.Size() == Height(), "invalid y.Size() = " << y.Size()
1034  << ", expected size = " << Height());
1035 
1036  auto x_data = x.HostRead();
1037  auto y_data = (b == 0.0) ? y.HostWrite() : y.HostReadWrite();
1038  if (X == NULL)
1039  {
1040  X = new HypreParVector(A->comm,
1041  GetGlobalNumCols(),
1042  const_cast<double*>(x_data),
1043  GetColStarts());
1044  Y = new HypreParVector(A->comm,
1045  GetGlobalNumRows(),
1046  y_data,
1047  GetRowStarts());
1048  }
1049  else
1050  {
1051  X->SetData(const_cast<double*>(x_data));
1052  Y->SetData(y_data);
1053  }
1054 
1055  hypre_ParCSRMatrixMatvec(a, A, *X, b, *Y);
1056 }
1057 
1059  double b, Vector &y) const
1060 {
1061  MFEM_ASSERT(x.Size() == Height(), "invalid x.Size() = " << x.Size()
1062  << ", expected size = " << Height());
1063  MFEM_ASSERT(y.Size() == Width(), "invalid y.Size() = " << y.Size()
1064  << ", expected size = " << Width());
1065 
1066  // Note: x has the dimensions of Y (height), and
1067  // y has the dimensions of X (width)
1068  auto x_data = x.HostRead();
1069  auto y_data = (b == 0.0) ? y.HostWrite() : y.HostReadWrite();
1070  if (X == NULL)
1071  {
1072  X = new HypreParVector(A->comm,
1073  GetGlobalNumCols(),
1074  y_data,
1075  GetColStarts());
1076  Y = new HypreParVector(A->comm,
1077  GetGlobalNumRows(),
1078  const_cast<double*>(x_data),
1079  GetRowStarts());
1080  }
1081  else
1082  {
1083  X->SetData(y_data);
1084  Y->SetData(const_cast<double*>(x_data));
1085  }
1086 
1087  hypre_ParCSRMatrixMatvecT(a, A, *Y, b, *X);
1088 }
1089 
1090 HYPRE_Int HypreParMatrix::Mult(HYPRE_ParVector x, HYPRE_ParVector y,
1091  double a, double b)
1092 {
1093  return hypre_ParCSRMatrixMatvec(a, A, (hypre_ParVector *) x, b,
1094  (hypre_ParVector *) y);
1095 }
1096 
1098  double a, double b)
1099 {
1100  return hypre_ParCSRMatrixMatvecT(a, A, x, b, y);
1101 }
1102 
1104  HYPRE_Int* row_starts) const
1105 {
1106  const bool assumed_partition = HYPRE_AssumedPartitionCheck();
1107  const bool row_starts_given = (row_starts != NULL);
1108  if (!row_starts_given)
1109  {
1110  row_starts = hypre_ParCSRMatrixRowStarts(A);
1111  MFEM_VERIFY(D.Height() == hypre_CSRMatrixNumRows(A->diag),
1112  "the matrix D is NOT compatible with the row starts of"
1113  " this HypreParMatrix, row_starts must be given.");
1114  }
1115  else
1116  {
1117  int offset;
1118  if (assumed_partition)
1119  {
1120  offset = 0;
1121  }
1122  else
1123  {
1124  MPI_Comm_rank(GetComm(), &offset);
1125  }
1126  int local_num_rows = row_starts[offset+1]-row_starts[offset];
1127  MFEM_VERIFY(local_num_rows == D.Height(), "the number of rows in D is "
1128  " not compatible with the given row_starts");
1129  }
1130  // D.Width() will be checked for compatibility by the SparseMatrix
1131  // multiplication function, mfem::Mult(), called below.
1132 
1133  int part_size;
1134  HYPRE_Int global_num_rows;
1135  if (assumed_partition)
1136  {
1137  part_size = 2;
1138  if (row_starts_given)
1139  {
1140  global_num_rows = row_starts[2];
1141  // Here, we use row_starts[2], so row_starts must come from the
1142  // methods GetDofOffsets/GetTrueDofOffsets of ParFiniteElementSpace
1143  // (HYPRE's partitions have only 2 entries).
1144  }
1145  else
1146  {
1147  global_num_rows = hypre_ParCSRMatrixGlobalNumRows(A);
1148  }
1149  }
1150  else
1151  {
1152  MPI_Comm_size(GetComm(), &part_size);
1153  global_num_rows = row_starts[part_size];
1154  part_size++;
1155  }
1156 
1157  HYPRE_Int *col_starts = hypre_ParCSRMatrixColStarts(A);
1158  HYPRE_Int *col_map_offd;
1159 
1160  // get the diag and offd blocks as SparseMatrix wrappers
1161  SparseMatrix A_diag, A_offd;
1162  GetDiag(A_diag);
1163  GetOffd(A_offd, col_map_offd);
1164 
1165  // multiply the blocks with D and create a new HypreParMatrix
1166  SparseMatrix* DA_diag = mfem::Mult(D, A_diag);
1167  SparseMatrix* DA_offd = mfem::Mult(D, A_offd);
1168 
1169  HypreParMatrix* DA =
1170  new HypreParMatrix(GetComm(),
1171  global_num_rows, hypre_ParCSRMatrixGlobalNumCols(A),
1172  DuplicateAs<HYPRE_Int>(row_starts, part_size, false),
1173  DuplicateAs<HYPRE_Int>(col_starts, part_size, false),
1174  DA_diag, DA_offd,
1175  DuplicateAs<HYPRE_Int>(col_map_offd, A_offd.Width()));
1176 
1177  // When HYPRE_BIGINT is defined, we want DA_{diag,offd} to delete their I and
1178  // J arrays but not their data arrays; when HYPRE_BIGINT is not defined, we
1179  // don't want DA_{diag,offd} to delete anything.
1180 #ifndef HYPRE_BIGINT
1181  DA_diag->LoseData();
1182  DA_offd->LoseData();
1183 #else
1184  DA_diag->SetDataOwner(false);
1185  DA_offd->SetDataOwner(false);
1186 #endif
1187 
1188  delete DA_diag;
1189  delete DA_offd;
1190 
1191  hypre_ParCSRMatrixSetRowStartsOwner(DA->A, 1);
1192  hypre_ParCSRMatrixSetColStartsOwner(DA->A, 1);
1193 
1194  DA->diagOwner = DA->offdOwner = 3;
1195  DA->colMapOwner = 1;
1196 
1197  return DA;
1198 }
1199 
1201 {
1202  if (hypre_CSRMatrixNumRows(A->diag) != hypre_CSRMatrixNumRows(A->offd))
1203  {
1204  mfem_error("Row does not match");
1205  }
1206 
1207  if (hypre_CSRMatrixNumRows(A->diag) != diag.Size())
1208  {
1209  mfem_error("Note the Vector diag is not of compatible dimensions with A\n");
1210  }
1211 
1212  int size = Height();
1213  double *Adiag_data = hypre_CSRMatrixData(A->diag);
1214  HYPRE_Int *Adiag_i = hypre_CSRMatrixI(A->diag);
1215 
1216 
1217  double *Aoffd_data = hypre_CSRMatrixData(A->offd);
1218  HYPRE_Int *Aoffd_i = hypre_CSRMatrixI(A->offd);
1219  double val;
1220  HYPRE_Int jj;
1221  for (int i(0); i < size; ++i)
1222  {
1223  val = diag[i];
1224  for (jj = Adiag_i[i]; jj < Adiag_i[i+1]; ++jj)
1225  {
1226  Adiag_data[jj] *= val;
1227  }
1228  for (jj = Aoffd_i[i]; jj < Aoffd_i[i+1]; ++jj)
1229  {
1230  Aoffd_data[jj] *= val;
1231  }
1232  }
1233 }
1234 
1236 {
1237  if (hypre_CSRMatrixNumRows(A->diag) != hypre_CSRMatrixNumRows(A->offd))
1238  {
1239  mfem_error("Row does not match");
1240  }
1241 
1242  if (hypre_CSRMatrixNumRows(A->diag) != diag.Size())
1243  {
1244  mfem_error("Note the Vector diag is not of compatible dimensions with A\n");
1245  }
1246 
1247  int size = Height();
1248  double *Adiag_data = hypre_CSRMatrixData(A->diag);
1249  HYPRE_Int *Adiag_i = hypre_CSRMatrixI(A->diag);
1250 
1251 
1252  double *Aoffd_data = hypre_CSRMatrixData(A->offd);
1253  HYPRE_Int *Aoffd_i = hypre_CSRMatrixI(A->offd);
1254  double val;
1255  HYPRE_Int jj;
1256  for (int i(0); i < size; ++i)
1257  {
1258 #ifdef MFEM_DEBUG
1259  if (0.0 == diag(i))
1260  {
1261  mfem_error("HypreParMatrix::InvDiagScale : Division by 0");
1262  }
1263 #endif
1264  val = 1./diag(i);
1265  for (jj = Adiag_i[i]; jj < Adiag_i[i+1]; ++jj)
1266  {
1267  Adiag_data[jj] *= val;
1268  }
1269  for (jj = Aoffd_i[i]; jj < Aoffd_i[i+1]; ++jj)
1270  {
1271  Aoffd_data[jj] *= val;
1272  }
1273  }
1274 }
1275 
1277 {
1278  if (hypre_CSRMatrixNumRows(A->diag) != hypre_CSRMatrixNumRows(A->offd))
1279  {
1280  mfem_error("Row does not match");
1281  }
1282 
1283  HYPRE_Int size=hypre_CSRMatrixNumRows(A->diag);
1284  HYPRE_Int jj;
1285 
1286  double *Adiag_data = hypre_CSRMatrixData(A->diag);
1287  HYPRE_Int *Adiag_i = hypre_CSRMatrixI(A->diag);
1288  for (jj = 0; jj < Adiag_i[size]; ++jj)
1289  {
1290  Adiag_data[jj] *= s;
1291  }
1292 
1293  double *Aoffd_data = hypre_CSRMatrixData(A->offd);
1294  HYPRE_Int *Aoffd_i = hypre_CSRMatrixI(A->offd);
1295  for (jj = 0; jj < Aoffd_i[size]; ++jj)
1296  {
1297  Aoffd_data[jj] *= s;
1298  }
1299 }
1300 
1301 static void get_sorted_rows_cols(const Array<int> &rows_cols,
1302  Array<HYPRE_Int> &hypre_sorted)
1303 {
1304  hypre_sorted.SetSize(rows_cols.Size());
1305  bool sorted = true;
1306  for (int i = 0; i < rows_cols.Size(); i++)
1307  {
1308  hypre_sorted[i] = rows_cols[i];
1309  if (i && rows_cols[i-1] > rows_cols[i]) { sorted = false; }
1310  }
1311  if (!sorted) { hypre_sorted.Sort(); }
1312 }
1313 
1314 void HypreParMatrix::Threshold(double threshold)
1315 {
1316  int ierr = 0;
1317 
1318  MPI_Comm comm;
1319  hypre_CSRMatrix * csr_A;
1320  hypre_CSRMatrix * csr_A_wo_z;
1321  hypre_ParCSRMatrix * parcsr_A_ptr;
1322  HYPRE_Int * row_starts = NULL; HYPRE_Int * col_starts = NULL;
1323  HYPRE_Int row_start = -1; HYPRE_Int row_end = -1;
1324  HYPRE_Int col_start = -1; HYPRE_Int col_end = -1;
1325 
1326  comm = hypre_ParCSRMatrixComm(A);
1327 
1328  ierr += hypre_ParCSRMatrixGetLocalRange(A,
1329  &row_start,&row_end,
1330  &col_start,&col_end );
1331 
1332  row_starts = hypre_ParCSRMatrixRowStarts(A);
1333  col_starts = hypre_ParCSRMatrixColStarts(A);
1334 
1335  bool old_owns_row = hypre_ParCSRMatrixOwnsRowStarts(A);
1336  bool old_owns_col = hypre_ParCSRMatrixOwnsColStarts(A);
1337  HYPRE_Int global_num_rows = hypre_ParCSRMatrixGlobalNumRows(A);
1338  HYPRE_Int global_num_cols = hypre_ParCSRMatrixGlobalNumCols(A);
1339  parcsr_A_ptr = hypre_ParCSRMatrixCreate(comm, global_num_rows,
1340  global_num_cols,
1341  row_starts, col_starts,
1342  0, 0, 0);
1343  hypre_ParCSRMatrixOwnsRowStarts(parcsr_A_ptr) = old_owns_row;
1344  hypre_ParCSRMatrixOwnsColStarts(parcsr_A_ptr) = old_owns_col;
1345  hypre_ParCSRMatrixOwnsRowStarts(A) = 0;
1346  hypre_ParCSRMatrixOwnsColStarts(A) = 0;
1347 
1348  csr_A = hypre_MergeDiagAndOffd(A);
1349 
1350  // Free A, if owned
1351  Destroy();
1352  Init();
1353 
1354  csr_A_wo_z = hypre_CSRMatrixDeleteZeros(csr_A,threshold);
1355 
1356  /* hypre_CSRMatrixDeleteZeros will return a NULL pointer rather than a usable
1357  CSR matrix if it finds no non-zeros */
1358  if (csr_A_wo_z == NULL)
1359  {
1360  csr_A_wo_z = csr_A;
1361  }
1362  else
1363  {
1364  ierr += hypre_CSRMatrixDestroy(csr_A);
1365  }
1366 
1367  /* TODO: GenerateDiagAndOffd() uses an int array of size equal to the number
1368  of columns in csr_A_wo_z which is the global number of columns in A. This
1369  does not scale well. */
1370  ierr += GenerateDiagAndOffd(csr_A_wo_z,parcsr_A_ptr,
1371  col_start,col_end);
1372 
1373  ierr += hypre_CSRMatrixDestroy(csr_A_wo_z);
1374 
1375  MFEM_VERIFY(ierr == 0, "");
1376 
1377  A = parcsr_A_ptr;
1378 
1379  hypre_ParCSRMatrixSetNumNonzeros(A);
1380  /* Make sure that the first entry in each row is the diagonal one. */
1381  if (row_starts == col_starts)
1382  {
1383  hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
1384  }
1385  hypre_MatvecCommPkgCreate(A);
1386  height = GetNumRows();
1387  width = GetNumCols();
1388 }
1389 
1391  const HypreParVector &X,
1392  HypreParVector &B)
1393 {
1394  Array<HYPRE_Int> rc_sorted;
1395  get_sorted_rows_cols(rows_cols, rc_sorted);
1396 
1397  internal::hypre_ParCSRMatrixEliminateAXB(
1398  A, rc_sorted.Size(), rc_sorted.GetData(), X, B);
1399 }
1400 
1402 {
1403  Array<HYPRE_Int> rc_sorted;
1404  get_sorted_rows_cols(rows_cols, rc_sorted);
1405 
1406  hypre_ParCSRMatrix* Ae;
1407  internal::hypre_ParCSRMatrixEliminateAAe(
1408  A, &Ae, rc_sorted.Size(), rc_sorted.GetData());
1409 
1410  return new HypreParMatrix(Ae);
1411 }
1412 
1414 {
1415  Array<HYPRE_Int> rc_sorted;
1416  get_sorted_rows_cols(cols, rc_sorted);
1417 
1418  hypre_ParCSRMatrix* Ae;
1419  internal::hypre_ParCSRMatrixEliminateAAe(
1420  A, &Ae, rc_sorted.Size(), rc_sorted.GetData(), 1);
1421 
1422  return new HypreParMatrix(Ae);
1423 }
1424 
1426 {
1427  if (rows.Size() > 0)
1428  {
1429  Array<HYPRE_Int> r_sorted;
1430  get_sorted_rows_cols(rows, r_sorted);
1431  internal::hypre_ParCSRMatrixEliminateRows(A, r_sorted.Size(),
1432  r_sorted.GetData());
1433  }
1434 }
1435 
1436 void HypreParMatrix::Print(const char *fname, HYPRE_Int offi, HYPRE_Int offj)
1437 {
1438  hypre_ParCSRMatrixPrintIJ(A,offi,offj,fname);
1439 }
1440 
1441 void HypreParMatrix::Read(MPI_Comm comm, const char *fname)
1442 {
1443  Destroy();
1444  Init();
1445 
1446  HYPRE_Int base_i, base_j;
1447  hypre_ParCSRMatrixReadIJ(comm, fname, &base_i, &base_j, &A);
1448  hypre_ParCSRMatrixSetNumNonzeros(A);
1449 
1450  hypre_MatvecCommPkgCreate(A);
1451 
1452  height = GetNumRows();
1453  width = GetNumCols();
1454 }
1455 
1456 void HypreParMatrix::Read_IJMatrix(MPI_Comm comm, const char *fname)
1457 {
1458  Destroy();
1459  Init();
1460 
1461  HYPRE_IJMatrix A_ij;
1462  HYPRE_IJMatrixRead(fname, comm, 5555, &A_ij); // HYPRE_PARCSR = 5555
1463 
1464  HYPRE_ParCSRMatrix A_parcsr;
1465  HYPRE_IJMatrixGetObject(A_ij, (void**) &A_parcsr);
1466 
1467  A = (hypre_ParCSRMatrix*)A_parcsr;
1468 
1469  hypre_ParCSRMatrixSetNumNonzeros(A);
1470 
1471  hypre_MatvecCommPkgCreate(A);
1472 
1473  height = GetNumRows();
1474  width = GetNumCols();
1475 }
1476 
1477 void HypreParMatrix::PrintCommPkg(std::ostream &out) const
1478 {
1479  hypre_ParCSRCommPkg *comm_pkg = A->comm_pkg;
1480  MPI_Comm comm = A->comm;
1481  char c = '\0';
1482  const int tag = 46801;
1483  int myid, nproc;
1484  MPI_Comm_rank(comm, &myid);
1485  MPI_Comm_size(comm, &nproc);
1486 
1487  if (myid != 0)
1488  {
1489  MPI_Recv(&c, 1, MPI_CHAR, myid-1, tag, comm, MPI_STATUS_IGNORE);
1490  }
1491  else
1492  {
1493  out << "\nHypreParMatrix: hypre_ParCSRCommPkg:\n";
1494  }
1495  out << "Rank " << myid << ":\n"
1496  " number of sends = " << comm_pkg->num_sends <<
1497  " (" << sizeof(double)*comm_pkg->send_map_starts[comm_pkg->num_sends] <<
1498  " bytes)\n"
1499  " number of recvs = " << comm_pkg->num_recvs <<
1500  " (" << sizeof(double)*comm_pkg->recv_vec_starts[comm_pkg->num_recvs] <<
1501  " bytes)\n";
1502  if (myid != nproc-1)
1503  {
1504  out << std::flush;
1505  MPI_Send(&c, 1, MPI_CHAR, myid+1, tag, comm);
1506  }
1507  else
1508  {
1509  out << std::endl;
1510  }
1511  MPI_Barrier(comm);
1512 }
1513 
1514 inline void delete_hypre_CSRMatrixData(hypre_CSRMatrix *M)
1515 {
1516  HYPRE_Complex *data = hypre_CSRMatrixData(M);
1517  Memory<HYPRE_Complex>(data, M->num_nonzeros, true).Delete();
1518 }
1519 
1520 inline void delete_hypre_ParCSRMatrixColMapOffd(hypre_ParCSRMatrix *A)
1521 {
1522  HYPRE_Int *A_col_map_offd = hypre_ParCSRMatrixColMapOffd(A);
1523  int size = hypre_CSRMatrixNumCols(hypre_ParCSRMatrixOffd(A));
1524  Memory<HYPRE_Int>(A_col_map_offd, size, true).Delete();
1525 }
1526 
1527 inline void delete_hypre_CSRMatrixI(hypre_CSRMatrix *M)
1528 {
1529  HYPRE_Int *I = hypre_CSRMatrixI(M);
1530  int size = hypre_CSRMatrixNumRows(M) + 1;
1531  Memory<HYPRE_Int>(I, size, true).Delete();
1532 }
1533 
1534 inline void delete_hypre_CSRMatrixJ(hypre_CSRMatrix *M)
1535 {
1536  HYPRE_Int *J = hypre_CSRMatrixJ(M);
1537  int size = hypre_CSRMatrixNumNonzeros(M);
1538  Memory<HYPRE_Int>(J, size, true).Delete();
1539 }
1540 
1541 void HypreParMatrix::Destroy()
1542 {
1543  if ( X != NULL ) { delete X; }
1544  if ( Y != NULL ) { delete Y; }
1545 
1546  if (A == NULL) { return; }
1547 
1548  if (diagOwner >= 0)
1549  {
1550  if (diagOwner & 1)
1551  {
1552  delete_hypre_CSRMatrixI(A->diag);
1553  delete_hypre_CSRMatrixJ(A->diag);
1554  }
1555  hypre_CSRMatrixI(A->diag) = NULL;
1556  hypre_CSRMatrixJ(A->diag) = NULL;
1557  if (diagOwner & 2)
1558  {
1559  delete_hypre_CSRMatrixData(A->diag);
1560  }
1561  hypre_CSRMatrixData(A->diag) = NULL;
1562  }
1563  if (offdOwner >= 0)
1564  {
1565  if (offdOwner & 1)
1566  {
1567  delete_hypre_CSRMatrixI(A->offd);
1568  delete_hypre_CSRMatrixJ(A->offd);
1569  }
1570  hypre_CSRMatrixI(A->offd) = NULL;
1571  hypre_CSRMatrixJ(A->offd) = NULL;
1572  if (offdOwner & 2)
1573  {
1574  delete_hypre_CSRMatrixData(A->offd);
1575  }
1576  hypre_CSRMatrixData(A->offd) = NULL;
1577  }
1578  if (colMapOwner >= 0)
1579  {
1580  if (colMapOwner & 1)
1581  {
1583  }
1584  hypre_ParCSRMatrixColMapOffd(A) = NULL;
1585  }
1586 
1587  if (ParCSROwner)
1588  {
1589  hypre_ParCSRMatrixDestroy(A);
1590  }
1591 }
1592 
1594  double beta, const HypreParMatrix &B)
1595 {
1596  hypre_ParCSRMatrix *C_hypre =
1597  internal::hypre_ParCSRMatrixAdd(const_cast<HypreParMatrix &>(A),
1598  const_cast<HypreParMatrix &>(B));
1599  MFEM_VERIFY(C_hypre, "error in hypre_ParCSRMatrixAdd");
1600 
1601  hypre_MatvecCommPkgCreate(C_hypre);
1602  HypreParMatrix *C = new HypreParMatrix(C_hypre);
1603  *C = 0.0;
1604  C->Add(alpha, A);
1605  C->Add(beta, B);
1606 
1607  return C;
1608 }
1609 
1611  bool own_matrix)
1612 {
1613  hypre_ParCSRMatrix * ab;
1614  ab = hypre_ParMatmul(*A,*B);
1615  hypre_ParCSRMatrixSetNumNonzeros(ab);
1616 
1617  hypre_MatvecCommPkgCreate(ab);
1618  HypreParMatrix *C = new HypreParMatrix(ab);
1619  if (own_matrix)
1620  {
1621  C->CopyRowStarts();
1622  C->CopyColStarts();
1623  }
1624  return C;
1625 }
1626 
1628 {
1629  hypre_ParCSRMatrix * C = internal::hypre_ParCSRMatrixAdd(*A,*B);
1630 
1631  hypre_MatvecCommPkgCreate(C);
1632 
1633  return new HypreParMatrix(C);
1634 }
1635 
1637 {
1638  HYPRE_Int P_owns_its_col_starts =
1639  hypre_ParCSRMatrixOwnsColStarts((hypre_ParCSRMatrix*)(*P));
1640 
1641  hypre_ParCSRMatrix * rap;
1642  hypre_BoomerAMGBuildCoarseOperator(*P,*A,*P,&rap);
1643  hypre_ParCSRMatrixSetNumNonzeros(rap);
1644  // hypre_MatvecCommPkgCreate(rap);
1645 
1646  /* Warning: hypre_BoomerAMGBuildCoarseOperator steals the col_starts
1647  from P (even if it does not own them)! */
1648  hypre_ParCSRMatrixSetRowStartsOwner(rap,0);
1649  hypre_ParCSRMatrixSetColStartsOwner(rap,0);
1650 
1651  if (P_owns_its_col_starts)
1652  {
1653  hypre_ParCSRMatrixSetColStartsOwner(*P, 1);
1654  }
1655 
1656  return new HypreParMatrix(rap);
1657 }
1658 
1660  const HypreParMatrix *P)
1661 {
1662  HYPRE_Int P_owns_its_col_starts =
1663  hypre_ParCSRMatrixOwnsColStarts((hypre_ParCSRMatrix*)(*P));
1664  HYPRE_Int Rt_owns_its_col_starts =
1665  hypre_ParCSRMatrixOwnsColStarts((hypre_ParCSRMatrix*)(*Rt));
1666 
1667  hypre_ParCSRMatrix * rap;
1668  hypre_BoomerAMGBuildCoarseOperator(*Rt,*A,*P,&rap);
1669 
1670  hypre_ParCSRMatrixSetNumNonzeros(rap);
1671  // hypre_MatvecCommPkgCreate(rap);
1672 
1673  /* Warning: hypre_BoomerAMGBuildCoarseOperator steals the col_starts
1674  from Rt and P (even if they do not own them)! */
1675  hypre_ParCSRMatrixSetRowStartsOwner(rap,0);
1676  hypre_ParCSRMatrixSetColStartsOwner(rap,0);
1677 
1678  if (P_owns_its_col_starts)
1679  {
1680  hypre_ParCSRMatrixSetColStartsOwner(*P, 1);
1681  }
1682  if (Rt_owns_its_col_starts)
1683  {
1684  hypre_ParCSRMatrixSetColStartsOwner(*Rt, 1);
1685  }
1686 
1687  return new HypreParMatrix(rap);
1688 }
1689 
1691  const Array<int> &ess_dof_list,
1692  const Vector &X, Vector &B)
1693 {
1694  // B -= Ae*X
1695  Ae.Mult(-1.0, X, 1.0, B);
1696 
1697  hypre_CSRMatrix *A_diag = hypre_ParCSRMatrixDiag((hypre_ParCSRMatrix *)A);
1698  double *data = hypre_CSRMatrixData(A_diag);
1699  HYPRE_Int *I = hypre_CSRMatrixI(A_diag);
1700 #ifdef MFEM_DEBUG
1701  HYPRE_Int *J = hypre_CSRMatrixJ(A_diag);
1702  hypre_CSRMatrix *A_offd = hypre_ParCSRMatrixOffd((hypre_ParCSRMatrix *)A);
1703  HYPRE_Int *I_offd = hypre_CSRMatrixI(A_offd);
1704  double *data_offd = hypre_CSRMatrixData(A_offd);
1705 #endif
1706 
1707  for (int i = 0; i < ess_dof_list.Size(); i++)
1708  {
1709  int r = ess_dof_list[i];
1710  B(r) = data[I[r]] * X(r);
1711 #ifdef MFEM_DEBUG
1712  // Check that in the rows specified by the ess_dof_list, the matrix A has
1713  // only one entry -- the diagonal.
1714  // if (I[r+1] != I[r]+1 || J[I[r]] != r || I_offd[r] != I_offd[r+1])
1715  if (J[I[r]] != r)
1716  {
1717  MFEM_ABORT("the diagonal entry must be the first entry in the row!");
1718  }
1719  for (int j = I[r]+1; j < I[r+1]; j++)
1720  {
1721  if (data[j] != 0.0)
1722  {
1723  MFEM_ABORT("all off-diagonal entries must be zero!");
1724  }
1725  }
1726  for (int j = I_offd[r]; j < I_offd[r+1]; j++)
1727  {
1728  if (data_offd[j] != 0.0)
1729  {
1730  MFEM_ABORT("all off-diagonal entries must be zero!");
1731  }
1732  }
1733 #endif
1734  }
1735 }
1736 
1737 // Taubin or "lambda-mu" scheme, which alternates between positive and
1738 // negative step sizes to approximate low-pass filter effect.
1739 
1740 int ParCSRRelax_Taubin(hypre_ParCSRMatrix *A, // matrix to relax with
1741  hypre_ParVector *f, // right-hand side
1742  double lambda,
1743  double mu,
1744  int N,
1745  double max_eig,
1746  hypre_ParVector *u, // initial/updated approximation
1747  hypre_ParVector *r // another temp vector
1748  )
1749 {
1750  hypre_CSRMatrix *A_diag = hypre_ParCSRMatrixDiag(A);
1751  HYPRE_Int num_rows = hypre_CSRMatrixNumRows(A_diag);
1752 
1753  double *u_data = hypre_VectorData(hypre_ParVectorLocalVector(u));
1754  double *r_data = hypre_VectorData(hypre_ParVectorLocalVector(r));
1755 
1756  for (int i = 0; i < N; i++)
1757  {
1758  // get residual: r = f - A*u
1759  hypre_ParVectorCopy(f, r);
1760  hypre_ParCSRMatrixMatvec(-1.0, A, u, 1.0, r);
1761 
1762  double coef;
1763  (0 == (i % 2)) ? coef = lambda : coef = mu;
1764 
1765  for (HYPRE_Int j = 0; j < num_rows; j++)
1766  {
1767  u_data[j] += coef*r_data[j] / max_eig;
1768  }
1769  }
1770 
1771  return 0;
1772 }
1773 
1774 // FIR scheme, which uses Chebyshev polynomials and a window function
1775 // to approximate a low-pass step filter.
1776 
1777 int ParCSRRelax_FIR(hypre_ParCSRMatrix *A, // matrix to relax with
1778  hypre_ParVector *f, // right-hand side
1779  double max_eig,
1780  int poly_order,
1781  double* fir_coeffs,
1782  hypre_ParVector *u, // initial/updated approximation
1783  hypre_ParVector *x0, // temporaries
1784  hypre_ParVector *x1,
1785  hypre_ParVector *x2,
1786  hypre_ParVector *x3)
1787 
1788 {
1789  hypre_CSRMatrix *A_diag = hypre_ParCSRMatrixDiag(A);
1790  HYPRE_Int num_rows = hypre_CSRMatrixNumRows(A_diag);
1791 
1792  double *u_data = hypre_VectorData(hypre_ParVectorLocalVector(u));
1793 
1794  double *x0_data = hypre_VectorData(hypre_ParVectorLocalVector(x0));
1795  double *x1_data = hypre_VectorData(hypre_ParVectorLocalVector(x1));
1796  double *x2_data = hypre_VectorData(hypre_ParVectorLocalVector(x2));
1797  double *x3_data = hypre_VectorData(hypre_ParVectorLocalVector(x3));
1798 
1799  hypre_ParVectorCopy(u, x0);
1800 
1801  // x1 = f -A*x0/max_eig
1802  hypre_ParVectorCopy(f, x1);
1803  hypre_ParCSRMatrixMatvec(-1.0, A, x0, 1.0, x1);
1804 
1805  for (HYPRE_Int i = 0; i < num_rows; i++)
1806  {
1807  x1_data[i] /= -max_eig;
1808  }
1809 
1810  // x1 = x0 -x1
1811  for (HYPRE_Int i = 0; i < num_rows; i++)
1812  {
1813  x1_data[i] = x0_data[i] -x1_data[i];
1814  }
1815 
1816  // x3 = f0*x0 +f1*x1
1817  for (HYPRE_Int i = 0; i < num_rows; i++)
1818  {
1819  x3_data[i] = fir_coeffs[0]*x0_data[i] +fir_coeffs[1]*x1_data[i];
1820  }
1821 
1822  for (int n = 2; n <= poly_order; n++)
1823  {
1824  // x2 = f - A*x1/max_eig
1825  hypre_ParVectorCopy(f, x2);
1826  hypre_ParCSRMatrixMatvec(-1.0, A, x1, 1.0, x2);
1827 
1828  for (HYPRE_Int i = 0; i < num_rows; i++)
1829  {
1830  x2_data[i] /= -max_eig;
1831  }
1832 
1833  // x2 = (x1-x0) +(x1-2*x2)
1834  // x3 = x3 +f[n]*x2
1835  // x0 = x1
1836  // x1 = x2
1837 
1838  for (HYPRE_Int i = 0; i < num_rows; i++)
1839  {
1840  x2_data[i] = (x1_data[i]-x0_data[i]) +(x1_data[i]-2*x2_data[i]);
1841  x3_data[i] += fir_coeffs[n]*x2_data[i];
1842  x0_data[i] = x1_data[i];
1843  x1_data[i] = x2_data[i];
1844  }
1845  }
1846 
1847  for (HYPRE_Int i = 0; i < num_rows; i++)
1848  {
1849  u_data[i] = x3_data[i];
1850  }
1851 
1852  return 0;
1853 }
1854 
1856 {
1857  type = 2;
1858  relax_times = 1;
1859  relax_weight = 1.0;
1860  omega = 1.0;
1861  poly_order = 2;
1862  poly_fraction = .3;
1863  lambda = 0.5;
1864  mu = -0.5;
1865  taubin_iter = 40;
1866 
1867  l1_norms = NULL;
1868  pos_l1_norms = false;
1869  B = X = V = Z = NULL;
1870  X0 = X1 = NULL;
1871  fir_coeffs = NULL;
1872 }
1873 
1875  int _relax_times, double _relax_weight, double _omega,
1876  int _poly_order, double _poly_fraction)
1877 {
1878  type = _type;
1879  relax_times = _relax_times;
1880  relax_weight = _relax_weight;
1881  omega = _omega;
1882  poly_order = _poly_order;
1883  poly_fraction = _poly_fraction;
1884 
1885  l1_norms = NULL;
1886  pos_l1_norms = false;
1887  B = X = V = Z = NULL;
1888  X0 = X1 = NULL;
1889  fir_coeffs = NULL;
1890 
1891  SetOperator(_A);
1892 }
1893 
1894 void HypreSmoother::SetType(HypreSmoother::Type _type, int _relax_times)
1895 {
1896  type = static_cast<int>(_type);
1897  relax_times = _relax_times;
1898 }
1899 
1900 void HypreSmoother::SetSOROptions(double _relax_weight, double _omega)
1901 {
1902  relax_weight = _relax_weight;
1903  omega = _omega;
1904 }
1905 
1906 void HypreSmoother::SetPolyOptions(int _poly_order, double _poly_fraction)
1907 {
1908  poly_order = _poly_order;
1909  poly_fraction = _poly_fraction;
1910 }
1911 
1912 void HypreSmoother::SetTaubinOptions(double _lambda, double _mu,
1913  int _taubin_iter)
1914 {
1915  lambda = _lambda;
1916  mu = _mu;
1917  taubin_iter = _taubin_iter;
1918 }
1919 
1920 void HypreSmoother::SetWindowByName(const char* name)
1921 {
1922  double a = -1, b, c;
1923  if (!strcmp(name,"Rectangular")) { a = 1.0, b = 0.0, c = 0.0; }
1924  if (!strcmp(name,"Hanning")) { a = 0.5, b = 0.5, c = 0.0; }
1925  if (!strcmp(name,"Hamming")) { a = 0.54, b = 0.46, c = 0.0; }
1926  if (!strcmp(name,"Blackman")) { a = 0.42, b = 0.50, c = 0.08; }
1927  if (a < 0)
1928  {
1929  mfem_error("HypreSmoother::SetWindowByName : name not recognized!");
1930  }
1931 
1932  SetWindowParameters(a, b, c);
1933 }
1934 
1935 void HypreSmoother::SetWindowParameters(double a, double b, double c)
1936 {
1937  window_params[0] = a;
1938  window_params[1] = b;
1939  window_params[2] = c;
1940 }
1941 
1943 {
1944  A = const_cast<HypreParMatrix *>(dynamic_cast<const HypreParMatrix *>(&op));
1945  if (A == NULL)
1946  {
1947  mfem_error("HypreSmoother::SetOperator : not HypreParMatrix!");
1948  }
1949 
1950  height = A->Height();
1951  width = A->Width();
1952 
1953  if (B) { delete B; }
1954  if (X) { delete X; }
1955  if (V) { delete V; }
1956  if (Z) { delete Z; }
1957  if (l1_norms)
1958  {
1959  mfem_hypre_TFree(l1_norms);
1960  }
1961  delete X0;
1962  delete X1;
1963 
1964  X1 = X0 = Z = V = B = X = NULL;
1965 
1966  if (type >= 1 && type <= 4)
1967  {
1968  hypre_ParCSRComputeL1Norms(*A, type, NULL, &l1_norms);
1969  }
1970  else if (type == 5)
1971  {
1972  l1_norms = mfem_hypre_CTAlloc(double, height);
1973  Vector ones(height), diag(l1_norms, height);
1974  ones = 1.0;
1975  A->Mult(ones, diag);
1976  type = 1;
1977  }
1978  else
1979  {
1980  l1_norms = NULL;
1981  }
1982  if (l1_norms && pos_l1_norms)
1983  {
1984  for (int i = 0; i < height; i++)
1985  {
1986  l1_norms[i] = std::abs(l1_norms[i]);
1987  }
1988  }
1989 
1990  if (type == 16)
1991  {
1992  poly_scale = 1;
1993  hypre_ParCSRMaxEigEstimateCG(*A, poly_scale, 10,
1995  Z = new HypreParVector(*A);
1996  }
1997  else if (type == 1001 || type == 1002)
1998  {
1999  poly_scale = 0;
2000  hypre_ParCSRMaxEigEstimateCG(*A, poly_scale, 10,
2002 
2003  // The Taubin and FIR polynomials are defined on [0, 2]
2004  max_eig_est /= 2;
2005 
2006  // Compute window function, Chebyshev coefficients, and allocate temps.
2007  if (type == 1002)
2008  {
2009  // Temporaries for Chebyshev recursive evaluation
2010  Z = new HypreParVector(*A);
2011  X0 = new HypreParVector(*A);
2012  X1 = new HypreParVector(*A);
2013 
2015  }
2016  }
2017 }
2018 
2020 {
2021  if (fir_coeffs)
2022  {
2023  delete [] fir_coeffs;
2024  }
2025 
2026  fir_coeffs = new double[poly_order+1];
2027 
2028  double* window_coeffs = new double[poly_order+1];
2029  double* cheby_coeffs = new double[poly_order+1];
2030 
2031  double a = window_params[0];
2032  double b = window_params[1];
2033  double c = window_params[2];
2034  for (int i = 0; i <= poly_order; i++)
2035  {
2036  double t = (i*M_PI)/(poly_order+1);
2037  window_coeffs[i] = a + b*cos(t) +c*cos(2*t);
2038  }
2039 
2040  double k_pb = poly_fraction*max_eig;
2041  double theta_pb = acos(1.0 -0.5*k_pb);
2042  double sigma = 0.0;
2043  cheby_coeffs[0] = (theta_pb +sigma)/M_PI;
2044  for (int i = 1; i <= poly_order; i++)
2045  {
2046  double t = i*(theta_pb+sigma);
2047  cheby_coeffs[i] = 2.0*sin(t)/(i*M_PI);
2048  }
2049 
2050  for (int i = 0; i <= poly_order; i++)
2051  {
2052  fir_coeffs[i] = window_coeffs[i]*cheby_coeffs[i];
2053  }
2054 
2055  delete[] window_coeffs;
2056  delete[] cheby_coeffs;
2057 }
2058 
2060 {
2061  if (A == NULL)
2062  {
2063  mfem_error("HypreSmoother::Mult (...) : HypreParMatrix A is missing");
2064  return;
2065  }
2066 
2067  b.HostRead();
2068  if (!iterative_mode)
2069  {
2070  if (type == 0 && relax_times == 1)
2071  {
2072  x.HostWrite();
2073  HYPRE_ParCSRDiagScale(NULL, *A, b, x);
2074  if (relax_weight != 1.0)
2075  {
2076  x *= relax_weight;
2077  }
2078  return;
2079  }
2080  x = 0.0;
2081  }
2082  x.HostReadWrite();
2083 
2084  if (V == NULL)
2085  {
2086  V = new HypreParVector(*A);
2087  }
2088 
2089  if (type == 1001)
2090  {
2091  for (int sweep = 0; sweep < relax_times; sweep++)
2092  {
2094  max_eig_est,
2095  x, *V);
2096  }
2097  }
2098  else if (type == 1002)
2099  {
2100  for (int sweep = 0; sweep < relax_times; sweep++)
2101  {
2102  ParCSRRelax_FIR(*A, b,
2103  max_eig_est,
2104  poly_order,
2105  fir_coeffs,
2106  x,
2107  *X0, *X1, *V, *Z);
2108  }
2109  }
2110  else
2111  {
2112  if (Z == NULL)
2113  hypre_ParCSRRelax(*A, b, type,
2116  x, *V, NULL);
2117  else
2118  hypre_ParCSRRelax(*A, b, type,
2121  x, *V, *Z);
2122  }
2123 }
2124 
2125 void HypreSmoother::Mult(const Vector &b, Vector &x) const
2126 {
2127  if (A == NULL)
2128  {
2129  mfem_error("HypreSmoother::Mult (...) : HypreParMatrix A is missing");
2130  return;
2131  }
2132 
2133  auto b_data = b.HostRead();
2134  auto x_data = iterative_mode ? x.HostReadWrite() : x.HostWrite();
2135 
2136  if (B == NULL)
2137  {
2138  B = new HypreParVector(A->GetComm(),
2139  A -> GetGlobalNumRows(),
2140  const_cast<double*>(b_data),
2141  A -> GetRowStarts());
2142  X = new HypreParVector(A->GetComm(),
2143  A -> GetGlobalNumCols(),
2144  x_data,
2145  A -> GetColStarts());
2146  }
2147  else
2148  {
2149  B -> SetData(const_cast<double*>(b_data));
2150  X -> SetData(x_data);
2151  }
2152 
2153  Mult(*B, *X);
2154 }
2155 
2157 {
2158  if (B) { delete B; }
2159  if (X) { delete X; }
2160  if (V) { delete V; }
2161  if (Z) { delete Z; }
2162  if (l1_norms)
2163  {
2164  mfem_hypre_TFree(l1_norms);
2165  }
2166  if (fir_coeffs)
2167  {
2168  delete [] fir_coeffs;
2169  }
2170  if (X0) { delete X0; }
2171  if (X1) { delete X1; }
2172 }
2173 
2174 
2176 {
2177  A = NULL;
2178  setup_called = 0;
2179  B = X = NULL;
2181 }
2182 
2184  : Solver(_A->Height(), _A->Width())
2185 {
2186  A = _A;
2187  setup_called = 0;
2188  B = X = NULL;
2190 }
2191 
2193 {
2194  HYPRE_Int err;
2195  if (A == NULL)
2196  {
2197  mfem_error("HypreSolver::Mult (...) : HypreParMatrix A is missing");
2198  return;
2199  }
2200  if (!setup_called)
2201  {
2202  err = SetupFcn()(*this, *A, b, x);
2204  {
2205  if (err) { MFEM_WARNING("Error during setup! Error code: " << err); }
2206  }
2207  else if (error_mode == ABORT_HYPRE_ERRORS)
2208  {
2209  MFEM_VERIFY(!err, "Error during setup! Error code: " << err);
2210  }
2211  hypre_error_flag = 0;
2212  setup_called = 1;
2213  }
2214 
2215  if (!iterative_mode)
2216  {
2217  x = 0.0;
2218  }
2219  err = SolveFcn()(*this, *A, b, x);
2221  {
2222  if (err) { MFEM_WARNING("Error during solve! Error code: " << err); }
2223  }
2224  else if (error_mode == ABORT_HYPRE_ERRORS)
2225  {
2226  MFEM_VERIFY(!err, "Error during solve! Error code: " << err);
2227  }
2228  hypre_error_flag = 0;
2229 }
2230 
2231 void HypreSolver::Mult(const Vector &b, Vector &x) const
2232 {
2233  if (A == NULL)
2234  {
2235  mfem_error("HypreSolver::Mult (...) : HypreParMatrix A is missing");
2236  return;
2237  }
2238  auto b_data = b.HostRead();
2239  auto x_data = x.HostWrite();
2240  if (B == NULL)
2241  {
2242  B = new HypreParVector(A->GetComm(),
2243  A -> GetGlobalNumRows(),
2244  const_cast<double*>(b_data),
2245  A -> GetRowStarts());
2246  X = new HypreParVector(A->GetComm(),
2247  A -> GetGlobalNumCols(),
2248  x_data,
2249  A -> GetColStarts());
2250  }
2251  else
2252  {
2253  B -> SetData(const_cast<double*>(b_data));
2254  X -> SetData(x_data);
2255  }
2256 
2257  Mult(*B, *X);
2258 }
2259 
2261 {
2262  if (B) { delete B; }
2263  if (X) { delete X; }
2264 }
2265 
2266 
2267 HyprePCG::HyprePCG(MPI_Comm comm) : precond(NULL)
2268 {
2269  iterative_mode = true;
2270 
2271  HYPRE_ParCSRPCGCreate(comm, &pcg_solver);
2272 }
2273 
2275 {
2276  MPI_Comm comm;
2277 
2278  iterative_mode = true;
2279 
2280  HYPRE_ParCSRMatrixGetComm(*A, &comm);
2281 
2282  HYPRE_ParCSRPCGCreate(comm, &pcg_solver);
2283 }
2284 
2286 {
2287  const HypreParMatrix *new_A = dynamic_cast<const HypreParMatrix *>(&op);
2288  MFEM_VERIFY(new_A, "new Operator must be a HypreParMatrix!");
2289 
2290  // update base classes: Operator, Solver, HypreSolver
2291  height = new_A->Height();
2292  width = new_A->Width();
2293  A = const_cast<HypreParMatrix *>(new_A);
2294  if (precond)
2295  {
2296  precond->SetOperator(*A);
2297  this->SetPreconditioner(*precond);
2298  }
2299  setup_called = 0;
2300  delete X;
2301  delete B;
2302  B = X = NULL;
2303 }
2304 
2305 void HyprePCG::SetTol(double tol)
2306 {
2307  HYPRE_PCGSetTol(pcg_solver, tol);
2308 }
2309 
2310 void HyprePCG::SetMaxIter(int max_iter)
2311 {
2312  HYPRE_PCGSetMaxIter(pcg_solver, max_iter);
2313 }
2314 
2315 void HyprePCG::SetLogging(int logging)
2316 {
2317  HYPRE_PCGSetLogging(pcg_solver, logging);
2318 }
2319 
2320 void HyprePCG::SetPrintLevel(int print_lvl)
2321 {
2322  HYPRE_ParCSRPCGSetPrintLevel(pcg_solver, print_lvl);
2323 }
2324 
2326 {
2327  precond = &_precond;
2328 
2329  HYPRE_ParCSRPCGSetPrecond(pcg_solver,
2330  _precond.SolveFcn(),
2331  _precond.SetupFcn(),
2332  _precond);
2333 }
2334 
2335 void HyprePCG::SetResidualConvergenceOptions(int res_frequency, double rtol)
2336 {
2337  HYPRE_PCGSetTwoNorm(pcg_solver, 1);
2338  if (res_frequency > 0)
2339  {
2340  HYPRE_PCGSetRecomputeResidualP(pcg_solver, res_frequency);
2341  }
2342  if (rtol > 0.0)
2343  {
2344  HYPRE_PCGSetResidualTol(pcg_solver, rtol);
2345  }
2346 }
2347 
2349 {
2350  int myid;
2351  HYPRE_Int time_index = 0;
2352  HYPRE_Int num_iterations;
2353  double final_res_norm;
2354  MPI_Comm comm;
2355  HYPRE_Int print_level;
2356 
2357  HYPRE_PCGGetPrintLevel(pcg_solver, &print_level);
2358  HYPRE_ParCSRPCGSetPrintLevel(pcg_solver, print_level%3);
2359 
2360  HYPRE_ParCSRMatrixGetComm(*A, &comm);
2361 
2362  if (!setup_called)
2363  {
2364  if (print_level > 0 && print_level < 3)
2365  {
2366  time_index = hypre_InitializeTiming("PCG Setup");
2367  hypre_BeginTiming(time_index);
2368  }
2369 
2370  HYPRE_ParCSRPCGSetup(pcg_solver, *A, b, x);
2371  setup_called = 1;
2372 
2373  if (print_level > 0 && print_level < 3)
2374  {
2375  hypre_EndTiming(time_index);
2376  hypre_PrintTiming("Setup phase times", comm);
2377  hypre_FinalizeTiming(time_index);
2378  hypre_ClearTiming();
2379  }
2380  }
2381 
2382  if (print_level > 0 && print_level < 3)
2383  {
2384  time_index = hypre_InitializeTiming("PCG Solve");
2385  hypre_BeginTiming(time_index);
2386  }
2387 
2388  if (!iterative_mode)
2389  {
2390  x = 0.0;
2391  }
2392 
2393  b.HostRead();
2394  x.HostReadWrite();
2395 
2396  HYPRE_ParCSRPCGSolve(pcg_solver, *A, b, x);
2397 
2398  if (print_level > 0)
2399  {
2400  if (print_level < 3)
2401  {
2402  hypre_EndTiming(time_index);
2403  hypre_PrintTiming("Solve phase times", comm);
2404  hypre_FinalizeTiming(time_index);
2405  hypre_ClearTiming();
2406  }
2407 
2408  HYPRE_ParCSRPCGGetNumIterations(pcg_solver, &num_iterations);
2409  HYPRE_ParCSRPCGGetFinalRelativeResidualNorm(pcg_solver,
2410  &final_res_norm);
2411 
2412  MPI_Comm_rank(comm, &myid);
2413 
2414  if (myid == 0)
2415  {
2416  mfem::out << "PCG Iterations = " << num_iterations << endl
2417  << "Final PCG Relative Residual Norm = " << final_res_norm
2418  << endl;
2419  }
2420  }
2421  HYPRE_ParCSRPCGSetPrintLevel(pcg_solver, print_level);
2422 }
2423 
2425 {
2426  HYPRE_ParCSRPCGDestroy(pcg_solver);
2427 }
2428 
2429 
2430 HypreGMRES::HypreGMRES(MPI_Comm comm) : precond(NULL)
2431 {
2432  iterative_mode = true;
2433 
2434  HYPRE_ParCSRGMRESCreate(comm, &gmres_solver);
2435  SetDefaultOptions();
2436 }
2437 
2439 {
2440  MPI_Comm comm;
2441 
2442  iterative_mode = true;
2443 
2444  HYPRE_ParCSRMatrixGetComm(*A, &comm);
2445 
2446  HYPRE_ParCSRGMRESCreate(comm, &gmres_solver);
2447  SetDefaultOptions();
2448 }
2449 
2450 void HypreGMRES::SetDefaultOptions()
2451 {
2452  int k_dim = 50;
2453  int max_iter = 100;
2454  double tol = 1e-6;
2455 
2456  HYPRE_ParCSRGMRESSetKDim(gmres_solver, k_dim);
2457  HYPRE_ParCSRGMRESSetMaxIter(gmres_solver, max_iter);
2458  HYPRE_ParCSRGMRESSetTol(gmres_solver, tol);
2459 }
2460 
2462 {
2463  const HypreParMatrix *new_A = dynamic_cast<const HypreParMatrix *>(&op);
2464  MFEM_VERIFY(new_A, "new Operator must be a HypreParMatrix!");
2465 
2466  // update base classes: Operator, Solver, HypreSolver
2467  height = new_A->Height();
2468  width = new_A->Width();
2469  A = const_cast<HypreParMatrix *>(new_A);
2470  if (precond)
2471  {
2472  precond->SetOperator(*A);
2473  this->SetPreconditioner(*precond);
2474  }
2475  setup_called = 0;
2476  delete X;
2477  delete B;
2478  B = X = NULL;
2479 }
2480 
2481 void HypreGMRES::SetTol(double tol)
2482 {
2483  HYPRE_GMRESSetTol(gmres_solver, tol);
2484 }
2485 
2486 void HypreGMRES::SetMaxIter(int max_iter)
2487 {
2488  HYPRE_GMRESSetMaxIter(gmres_solver, max_iter);
2489 }
2490 
2491 void HypreGMRES::SetKDim(int k_dim)
2492 {
2493  HYPRE_GMRESSetKDim(gmres_solver, k_dim);
2494 }
2495 
2496 void HypreGMRES::SetLogging(int logging)
2497 {
2498  HYPRE_GMRESSetLogging(gmres_solver, logging);
2499 }
2500 
2501 void HypreGMRES::SetPrintLevel(int print_lvl)
2502 {
2503  HYPRE_GMRESSetPrintLevel(gmres_solver, print_lvl);
2504 }
2505 
2507 {
2508  precond = &_precond;
2509 
2510  HYPRE_ParCSRGMRESSetPrecond(gmres_solver,
2511  _precond.SolveFcn(),
2512  _precond.SetupFcn(),
2513  _precond);
2514 }
2515 
2517 {
2518  int myid;
2519  HYPRE_Int time_index = 0;
2520  HYPRE_Int num_iterations;
2521  double final_res_norm;
2522  MPI_Comm comm;
2523  HYPRE_Int print_level;
2524 
2525  HYPRE_GMRESGetPrintLevel(gmres_solver, &print_level);
2526 
2527  HYPRE_ParCSRMatrixGetComm(*A, &comm);
2528 
2529  if (!setup_called)
2530  {
2531  if (print_level > 0)
2532  {
2533  time_index = hypre_InitializeTiming("GMRES Setup");
2534  hypre_BeginTiming(time_index);
2535  }
2536 
2537  HYPRE_ParCSRGMRESSetup(gmres_solver, *A, b, x);
2538  setup_called = 1;
2539 
2540  if (print_level > 0)
2541  {
2542  hypre_EndTiming(time_index);
2543  hypre_PrintTiming("Setup phase times", comm);
2544  hypre_FinalizeTiming(time_index);
2545  hypre_ClearTiming();
2546  }
2547  }
2548 
2549  if (print_level > 0)
2550  {
2551  time_index = hypre_InitializeTiming("GMRES Solve");
2552  hypre_BeginTiming(time_index);
2553  }
2554 
2555  if (!iterative_mode)
2556  {
2557  x = 0.0;
2558  }
2559 
2560  HYPRE_ParCSRGMRESSolve(gmres_solver, *A, b, x);
2561 
2562  if (print_level > 0)
2563  {
2564  hypre_EndTiming(time_index);
2565  hypre_PrintTiming("Solve phase times", comm);
2566  hypre_FinalizeTiming(time_index);
2567  hypre_ClearTiming();
2568 
2569  HYPRE_ParCSRGMRESGetNumIterations(gmres_solver, &num_iterations);
2570  HYPRE_ParCSRGMRESGetFinalRelativeResidualNorm(gmres_solver,
2571  &final_res_norm);
2572 
2573  MPI_Comm_rank(comm, &myid);
2574 
2575  if (myid == 0)
2576  {
2577  mfem::out << "GMRES Iterations = " << num_iterations << endl
2578  << "Final GMRES Relative Residual Norm = " << final_res_norm
2579  << endl;
2580  }
2581  }
2582 }
2583 
2585 {
2586  HYPRE_ParCSRGMRESDestroy(gmres_solver);
2587 }
2588 
2589 
2591 {
2592  const HypreParMatrix *new_A = dynamic_cast<const HypreParMatrix *>(&op);
2593  MFEM_VERIFY(new_A, "new Operator must be a HypreParMatrix!");
2594 
2595  // update base classes: Operator, Solver, HypreSolver
2596  height = new_A->Height();
2597  width = new_A->Width();
2598  A = const_cast<HypreParMatrix *>(new_A);
2599  setup_called = 0;
2600  delete X;
2601  delete B;
2602  B = X = NULL;
2603 }
2604 
2605 
2607 {
2608  HYPRE_ParaSailsCreate(comm, &sai_precond);
2609  SetDefaultOptions();
2610 }
2611 
2613 {
2614  MPI_Comm comm;
2615 
2616  HYPRE_ParCSRMatrixGetComm(A, &comm);
2617 
2618  HYPRE_ParaSailsCreate(comm, &sai_precond);
2619  SetDefaultOptions();
2620 }
2621 
2622 void HypreParaSails::SetDefaultOptions()
2623 {
2624  int sai_max_levels = 1;
2625  double sai_threshold = 0.1;
2626  double sai_filter = 0.1;
2627  int sai_sym = 0;
2628  double sai_loadbal = 0.0;
2629  int sai_reuse = 0;
2630  int sai_logging = 1;
2631 
2632  HYPRE_ParaSailsSetParams(sai_precond, sai_threshold, sai_max_levels);
2633  HYPRE_ParaSailsSetFilter(sai_precond, sai_filter);
2634  HYPRE_ParaSailsSetSym(sai_precond, sai_sym);
2635  HYPRE_ParaSailsSetLoadbal(sai_precond, sai_loadbal);
2636  HYPRE_ParaSailsSetReuse(sai_precond, sai_reuse);
2637  HYPRE_ParaSailsSetLogging(sai_precond, sai_logging);
2638 }
2639 
2640 void HypreParaSails::ResetSAIPrecond(MPI_Comm comm)
2641 {
2642  HYPRE_Int sai_max_levels;
2643  HYPRE_Real sai_threshold;
2644  HYPRE_Real sai_filter;
2645  HYPRE_Int sai_sym;
2646  HYPRE_Real sai_loadbal;
2647  HYPRE_Int sai_reuse;
2648  HYPRE_Int sai_logging;
2649 
2650  // hypre_ParAMGData *amg_data = (hypre_ParAMGData *)sai_precond;
2651  HYPRE_ParaSailsGetNlevels(sai_precond, &sai_max_levels);
2652  HYPRE_ParaSailsGetThresh(sai_precond, &sai_threshold);
2653  HYPRE_ParaSailsGetFilter(sai_precond, &sai_filter);
2654  HYPRE_ParaSailsGetSym(sai_precond, &sai_sym);
2655  HYPRE_ParaSailsGetLoadbal(sai_precond, &sai_loadbal);
2656  HYPRE_ParaSailsGetReuse(sai_precond, &sai_reuse);
2657  HYPRE_ParaSailsGetLogging(sai_precond, &sai_logging);
2658 
2659  HYPRE_ParaSailsDestroy(sai_precond);
2660  HYPRE_ParaSailsCreate(comm, &sai_precond);
2661 
2662  HYPRE_ParaSailsSetParams(sai_precond, sai_threshold, sai_max_levels);
2663  HYPRE_ParaSailsSetFilter(sai_precond, sai_filter);
2664  HYPRE_ParaSailsSetSym(sai_precond, sai_sym);
2665  HYPRE_ParaSailsSetLoadbal(sai_precond, sai_loadbal);
2666  HYPRE_ParaSailsSetReuse(sai_precond, sai_reuse);
2667  HYPRE_ParaSailsSetLogging(sai_precond, sai_logging);
2668 }
2669 
2671 {
2672  const HypreParMatrix *new_A = dynamic_cast<const HypreParMatrix *>(&op);
2673  MFEM_VERIFY(new_A, "new Operator must be a HypreParMatrix!");
2674 
2675  if (A)
2676  {
2677  MPI_Comm comm;
2678  HYPRE_ParCSRMatrixGetComm(*A, &comm);
2679  ResetSAIPrecond(comm);
2680  }
2681 
2682  // update base classes: Operator, Solver, HypreSolver
2683  height = new_A->Height();
2684  width = new_A->Width();
2685  A = const_cast<HypreParMatrix *>(new_A);
2686  setup_called = 0;
2687  delete X;
2688  delete B;
2689  B = X = NULL;
2690 }
2691 
2693 {
2694  HYPRE_ParaSailsSetSym(sai_precond, sym);
2695 }
2696 
2698 {
2699  HYPRE_ParaSailsDestroy(sai_precond);
2700 }
2701 
2702 
2704 {
2705  HYPRE_EuclidCreate(comm, &euc_precond);
2706  SetDefaultOptions();
2707 }
2708 
2710 {
2711  MPI_Comm comm;
2712 
2713  HYPRE_ParCSRMatrixGetComm(A, &comm);
2714 
2715  HYPRE_EuclidCreate(comm, &euc_precond);
2716  SetDefaultOptions();
2717 }
2718 
2719 void HypreEuclid::SetDefaultOptions()
2720 {
2721  int euc_level = 1; // We use ILU(1)
2722  int euc_stats = 0; // No logging
2723  int euc_mem = 0; // No memory logging
2724  int euc_bj = 0; // 1: Use Block Jacobi
2725  int euc_ro_sc = 0; // 1: Use Row scaling
2726 
2727  HYPRE_EuclidSetLevel(euc_precond, euc_level);
2728  HYPRE_EuclidSetStats(euc_precond, euc_stats);
2729  HYPRE_EuclidSetMem(euc_precond, euc_mem);
2730  HYPRE_EuclidSetBJ(euc_precond, euc_bj);
2731  HYPRE_EuclidSetRowScale(euc_precond, euc_ro_sc);
2732 }
2733 
2734 void HypreEuclid::ResetEuclidPrecond(MPI_Comm comm)
2735 {
2736  // Euclid does not seem to offer access to its current configuration, so we
2737  // simply reset it to its default options.
2738  HYPRE_EuclidDestroy(euc_precond);
2739  HYPRE_EuclidCreate(comm, &euc_precond);
2740 
2741  SetDefaultOptions();
2742 }
2743 
2745 {
2746  const HypreParMatrix *new_A = dynamic_cast<const HypreParMatrix *>(&op);
2747  MFEM_VERIFY(new_A, "new Operator must be a HypreParMatrix!");
2748 
2749  if (A)
2750  {
2751  MPI_Comm comm;
2752  HYPRE_ParCSRMatrixGetComm(*new_A, &comm);
2753  ResetEuclidPrecond(comm);
2754  }
2755 
2756  // update base classes: Operator, Solver, HypreSolver
2757  height = new_A->Height();
2758  width = new_A->Width();
2759  A = const_cast<HypreParMatrix *>(new_A);
2760  setup_called = 0;
2761  delete X;
2762  delete B;
2763  B = X = NULL;
2764 }
2765 
2767 {
2768  HYPRE_EuclidDestroy(euc_precond);
2769 }
2770 
2771 
2773 {
2774  HYPRE_BoomerAMGCreate(&amg_precond);
2775  SetDefaultOptions();
2776 }
2777 
2779 {
2780  HYPRE_BoomerAMGCreate(&amg_precond);
2781  SetDefaultOptions();
2782 }
2783 
2784 void HypreBoomerAMG::SetDefaultOptions()
2785 {
2786  // AMG coarsening options:
2787  int coarsen_type = 10; // 10 = HMIS, 8 = PMIS, 6 = Falgout, 0 = CLJP
2788  int agg_levels = 1; // number of aggressive coarsening levels
2789  double theta = 0.25; // strength threshold: 0.25, 0.5, 0.8
2790 
2791  // AMG interpolation options:
2792  int interp_type = 6; // 6 = extended+i, 0 = classical
2793  int Pmax = 4; // max number of elements per row in P
2794 
2795  // AMG relaxation options:
2796  int relax_type = 8; // 8 = l1-GS, 6 = symm. GS, 3 = GS, 18 = l1-Jacobi
2797  int relax_sweeps = 1; // relaxation sweeps on each level
2798 
2799  // Additional options:
2800  int print_level = 1; // print AMG iterations? 1 = no, 2 = yes
2801  int max_levels = 25; // max number of levels in AMG hierarchy
2802 
2803  HYPRE_BoomerAMGSetCoarsenType(amg_precond, coarsen_type);
2804  HYPRE_BoomerAMGSetAggNumLevels(amg_precond, agg_levels);
2805  HYPRE_BoomerAMGSetRelaxType(amg_precond, relax_type);
2806  HYPRE_BoomerAMGSetNumSweeps(amg_precond, relax_sweeps);
2807  HYPRE_BoomerAMGSetStrongThreshold(amg_precond, theta);
2808  HYPRE_BoomerAMGSetInterpType(amg_precond, interp_type);
2809  HYPRE_BoomerAMGSetPMaxElmts(amg_precond, Pmax);
2810  HYPRE_BoomerAMGSetPrintLevel(amg_precond, print_level);
2811  HYPRE_BoomerAMGSetMaxLevels(amg_precond, max_levels);
2812 
2813  // Use as a preconditioner (one V-cycle, zero tolerance)
2814  HYPRE_BoomerAMGSetMaxIter(amg_precond, 1);
2815  HYPRE_BoomerAMGSetTol(amg_precond, 0.0);
2816 }
2817 
2818 void HypreBoomerAMG::ResetAMGPrecond()
2819 {
2820  HYPRE_Int coarsen_type;
2821  HYPRE_Int agg_levels;
2822  HYPRE_Int relax_type;
2823  HYPRE_Int relax_sweeps;
2824  HYPRE_Real theta;
2825  HYPRE_Int interp_type;
2826  HYPRE_Int Pmax;
2827  HYPRE_Int print_level;
2828  HYPRE_Int dim;
2829  HYPRE_Int nrbms = rbms.Size();
2830  HYPRE_Int nodal;
2831  HYPRE_Int nodal_diag;
2832  HYPRE_Int relax_coarse;
2833  HYPRE_Int interp_vec_variant;
2834  HYPRE_Int q_max;
2835  HYPRE_Int smooth_interp_vectors;
2836  HYPRE_Int interp_refine;
2837 
2838  hypre_ParAMGData *amg_data = (hypre_ParAMGData *)amg_precond;
2839 
2840  // read options from amg_precond
2841  HYPRE_BoomerAMGGetCoarsenType(amg_precond, &coarsen_type);
2842  agg_levels = hypre_ParAMGDataAggNumLevels(amg_data);
2843  relax_type = hypre_ParAMGDataUserRelaxType(amg_data);
2844  relax_sweeps = hypre_ParAMGDataUserNumSweeps(amg_data);
2845  HYPRE_BoomerAMGGetStrongThreshold(amg_precond, &theta);
2846  hypre_BoomerAMGGetInterpType(amg_precond, &interp_type);
2847  HYPRE_BoomerAMGGetPMaxElmts(amg_precond, &Pmax);
2848  HYPRE_BoomerAMGGetPrintLevel(amg_precond, &print_level);
2849  HYPRE_BoomerAMGGetNumFunctions(amg_precond, &dim);
2850  if (nrbms) // elasticity solver options
2851  {
2852  nodal = hypre_ParAMGDataNodal(amg_data);
2853  nodal_diag = hypre_ParAMGDataNodalDiag(amg_data);
2854  HYPRE_BoomerAMGGetCycleRelaxType(amg_precond, &relax_coarse, 3);
2855  interp_vec_variant = hypre_ParAMGInterpVecVariant(amg_data);
2856  q_max = hypre_ParAMGInterpVecQMax(amg_data);
2857  smooth_interp_vectors = hypre_ParAMGSmoothInterpVectors(amg_data);
2858  interp_refine = hypre_ParAMGInterpRefine(amg_data);
2859  }
2860 
2861  HYPRE_BoomerAMGDestroy(amg_precond);
2862  HYPRE_BoomerAMGCreate(&amg_precond);
2863 
2864  HYPRE_BoomerAMGSetCoarsenType(amg_precond, coarsen_type);
2865  HYPRE_BoomerAMGSetAggNumLevels(amg_precond, agg_levels);
2866  HYPRE_BoomerAMGSetRelaxType(amg_precond, relax_type);
2867  HYPRE_BoomerAMGSetNumSweeps(amg_precond, relax_sweeps);
2868  HYPRE_BoomerAMGSetMaxLevels(amg_precond, 25);
2869  HYPRE_BoomerAMGSetTol(amg_precond, 0.0);
2870  HYPRE_BoomerAMGSetMaxIter(amg_precond, 1); // one V-cycle
2871  HYPRE_BoomerAMGSetStrongThreshold(amg_precond, theta);
2872  HYPRE_BoomerAMGSetInterpType(amg_precond, interp_type);
2873  HYPRE_BoomerAMGSetPMaxElmts(amg_precond, Pmax);
2874  HYPRE_BoomerAMGSetPrintLevel(amg_precond, print_level);
2875  HYPRE_BoomerAMGSetNumFunctions(amg_precond, dim);
2876  if (nrbms)
2877  {
2878  HYPRE_BoomerAMGSetNodal(amg_precond, nodal);
2879  HYPRE_BoomerAMGSetNodalDiag(amg_precond, nodal_diag);
2880  HYPRE_BoomerAMGSetCycleRelaxType(amg_precond, relax_coarse, 3);
2881  HYPRE_BoomerAMGSetInterpVecVariant(amg_precond, interp_vec_variant);
2882  HYPRE_BoomerAMGSetInterpVecQMax(amg_precond, q_max);
2883  HYPRE_BoomerAMGSetSmoothInterpVectors(amg_precond, smooth_interp_vectors);
2884  HYPRE_BoomerAMGSetInterpRefine(amg_precond, interp_refine);
2885  RecomputeRBMs();
2886  HYPRE_BoomerAMGSetInterpVectors(amg_precond, rbms.Size(), rbms.GetData());
2887  }
2888 }
2889 
2891 {
2892  const HypreParMatrix *new_A = dynamic_cast<const HypreParMatrix *>(&op);
2893  MFEM_VERIFY(new_A, "new Operator must be a HypreParMatrix!");
2894 
2895  if (A) { ResetAMGPrecond(); }
2896 
2897  // update base classes: Operator, Solver, HypreSolver
2898  height = new_A->Height();
2899  width = new_A->Width();
2900  A = const_cast<HypreParMatrix *>(new_A);
2901  setup_called = 0;
2902  delete X;
2903  delete B;
2904  B = X = NULL;
2905 }
2906 
2908 {
2909  HYPRE_BoomerAMGSetNumFunctions(amg_precond, dim);
2910 
2911  // More robust options with respect to convergence
2912  HYPRE_BoomerAMGSetAggNumLevels(amg_precond, 0);
2913  HYPRE_BoomerAMGSetStrongThreshold(amg_precond, 0.5);
2914 }
2915 
2916 // Rotational rigid-body mode functions, used in SetElasticityOptions()
2917 static void func_rxy(const Vector &x, Vector &y)
2918 {
2919  y = 0.0; y(0) = x(1); y(1) = -x(0);
2920 }
2921 static void func_ryz(const Vector &x, Vector &y)
2922 {
2923  y = 0.0; y(1) = x(2); y(2) = -x(1);
2924 }
2925 static void func_rzx(const Vector &x, Vector &y)
2926 {
2927  y = 0.0; y(2) = x(0); y(0) = -x(2);
2928 }
2929 
2930 void HypreBoomerAMG::RecomputeRBMs()
2931 {
2932  int nrbms;
2933  Array<HypreParVector*> gf_rbms;
2934  int dim = fespace->GetParMesh()->Dimension();
2935 
2936  for (int i = 0; i < rbms.Size(); i++)
2937  {
2938  HYPRE_ParVectorDestroy(rbms[i]);
2939  }
2940 
2941  if (dim == 2)
2942  {
2943  nrbms = 1;
2944 
2945  VectorFunctionCoefficient coeff_rxy(2, func_rxy);
2946 
2947  ParGridFunction rbms_rxy(fespace);
2948  rbms_rxy.ProjectCoefficient(coeff_rxy);
2949 
2950  rbms.SetSize(nrbms);
2951  gf_rbms.SetSize(nrbms);
2952  gf_rbms[0] = rbms_rxy.ParallelAverage();
2953  }
2954  else if (dim == 3)
2955  {
2956  nrbms = 3;
2957 
2958  VectorFunctionCoefficient coeff_rxy(3, func_rxy);
2959  VectorFunctionCoefficient coeff_ryz(3, func_ryz);
2960  VectorFunctionCoefficient coeff_rzx(3, func_rzx);
2961 
2962  ParGridFunction rbms_rxy(fespace);
2963  ParGridFunction rbms_ryz(fespace);
2964  ParGridFunction rbms_rzx(fespace);
2965  rbms_rxy.ProjectCoefficient(coeff_rxy);
2966  rbms_ryz.ProjectCoefficient(coeff_ryz);
2967  rbms_rzx.ProjectCoefficient(coeff_rzx);
2968 
2969  rbms.SetSize(nrbms);
2970  gf_rbms.SetSize(nrbms);
2971  gf_rbms[0] = rbms_rxy.ParallelAverage();
2972  gf_rbms[1] = rbms_ryz.ParallelAverage();
2973  gf_rbms[2] = rbms_rzx.ParallelAverage();
2974  }
2975  else
2976  {
2977  nrbms = 0;
2978  rbms.SetSize(nrbms);
2979  }
2980 
2981  // Transfer the RBMs from the ParGridFunction to the HYPRE_ParVector objects
2982  for (int i = 0; i < nrbms; i++)
2983  {
2984  rbms[i] = gf_rbms[i]->StealParVector();
2985  delete gf_rbms[i];
2986  }
2987 }
2988 
2990 {
2991  // Save the finite element space to support multiple calls to SetOperator()
2992  this->fespace = fespace;
2993 
2994  // Make sure the systems AMG options are set
2995  int dim = fespace->GetParMesh()->Dimension();
2996  SetSystemsOptions(dim);
2997 
2998  // Nodal coarsening options (nodal coarsening is required for this solver)
2999  // See hypre's new_ij driver and the paper for descriptions.
3000  int nodal = 4; // strength reduction norm: 1, 3 or 4
3001  int nodal_diag = 1; // diagonal in strength matrix: 0, 1 or 2
3002  int relax_coarse = 8; // smoother on the coarsest grid: 8, 99 or 29
3003 
3004  // Elasticity interpolation options
3005  int interp_vec_variant = 2; // 1 = GM-1, 2 = GM-2, 3 = LN
3006  int q_max = 4; // max elements per row for each Q
3007  int smooth_interp_vectors = 1; // smooth the rigid-body modes?
3008 
3009  // Optionally pre-process the interpolation matrix through iterative weight
3010  // refinement (this is generally applicable for any system)
3011  int interp_refine = 1;
3012 
3013  HYPRE_BoomerAMGSetNodal(amg_precond, nodal);
3014  HYPRE_BoomerAMGSetNodalDiag(amg_precond, nodal_diag);
3015  HYPRE_BoomerAMGSetCycleRelaxType(amg_precond, relax_coarse, 3);
3016  HYPRE_BoomerAMGSetInterpVecVariant(amg_precond, interp_vec_variant);
3017  HYPRE_BoomerAMGSetInterpVecQMax(amg_precond, q_max);
3018  HYPRE_BoomerAMGSetSmoothInterpVectors(amg_precond, smooth_interp_vectors);
3019  HYPRE_BoomerAMGSetInterpRefine(amg_precond, interp_refine);
3020 
3021  RecomputeRBMs();
3022  HYPRE_BoomerAMGSetInterpVectors(amg_precond, rbms.Size(), rbms.GetData());
3023 
3024  // The above BoomerAMG options may result in singular matrices on the coarse
3025  // grids, which are handled correctly in hypre's Solve method, but can produce
3026  // hypre errors in the Setup (specifically in the l1 row norm computation).
3027  // See the documentation of SetErrorMode() for more details.
3029 }
3030 
3032 {
3033  for (int i = 0; i < rbms.Size(); i++)
3034  {
3035  HYPRE_ParVectorDestroy(rbms[i]);
3036  }
3037 
3038  HYPRE_BoomerAMGDestroy(amg_precond);
3039 }
3040 
3042 {
3043  Init(edge_fespace);
3044 }
3045 
3047  : HypreSolver(&A)
3048 {
3049  Init(edge_fespace);
3050 }
3051 
3052 void HypreAMS::Init(ParFiniteElementSpace *edge_fespace)
3053 {
3054  int cycle_type = 13;
3055  int rlx_type = 2;
3056  int rlx_sweeps = 1;
3057  double rlx_weight = 1.0;
3058  double rlx_omega = 1.0;
3059  int amg_coarsen_type = 10;
3060  int amg_agg_levels = 1;
3061  int amg_rlx_type = 8;
3062  double theta = 0.25;
3063  int amg_interp_type = 6;
3064  int amg_Pmax = 4;
3065 
3066  int dim = edge_fespace->GetMesh()->Dimension();
3067  int sdim = edge_fespace->GetMesh()->SpaceDimension();
3068  const FiniteElementCollection *edge_fec = edge_fespace->FEColl();
3069 
3070  bool trace_space, rt_trace_space;
3071  ND_Trace_FECollection *nd_tr_fec = NULL;
3072  trace_space = dynamic_cast<const ND_Trace_FECollection*>(edge_fec);
3073  rt_trace_space = dynamic_cast<const RT_Trace_FECollection*>(edge_fec);
3074  trace_space = trace_space || rt_trace_space;
3075 
3076  int p = 1;
3077  if (edge_fespace->GetNE() > 0)
3078  {
3079  if (trace_space)
3080  {
3081  p = edge_fespace->GetFaceOrder(0);
3082  if (dim == 2) { p++; }
3083  }
3084  else
3085  {
3086  p = edge_fespace->GetOrder(0);
3087  }
3088  }
3089 
3090  ParMesh *pmesh = edge_fespace->GetParMesh();
3091  if (rt_trace_space)
3092  {
3093  nd_tr_fec = new ND_Trace_FECollection(p, dim);
3094  edge_fespace = new ParFiniteElementSpace(pmesh, nd_tr_fec);
3095  }
3096 
3097  HYPRE_AMSCreate(&ams);
3098 
3099  HYPRE_AMSSetDimension(ams, sdim); // 2D H(div) and 3D H(curl) problems
3100  HYPRE_AMSSetTol(ams, 0.0);
3101  HYPRE_AMSSetMaxIter(ams, 1); // use as a preconditioner
3102  HYPRE_AMSSetCycleType(ams, cycle_type);
3103  HYPRE_AMSSetPrintLevel(ams, 1);
3104 
3105  // define the nodal linear finite element space associated with edge_fespace
3106  FiniteElementCollection *vert_fec;
3107  if (trace_space)
3108  {
3109  vert_fec = new H1_Trace_FECollection(p, dim);
3110  }
3111  else
3112  {
3113  vert_fec = new H1_FECollection(p, dim);
3114  }
3115  ParFiniteElementSpace *vert_fespace = new ParFiniteElementSpace(pmesh,
3116  vert_fec);
3117 
3118  // generate and set the vertex coordinates
3119  if (p == 1)
3120  {
3121  ParGridFunction x_coord(vert_fespace);
3122  ParGridFunction y_coord(vert_fespace);
3123  ParGridFunction z_coord(vert_fespace);
3124  double *coord;
3125  for (int i = 0; i < pmesh->GetNV(); i++)
3126  {
3127  coord = pmesh -> GetVertex(i);
3128  x_coord(i) = coord[0];
3129  y_coord(i) = coord[1];
3130  if (sdim == 3) { z_coord(i) = coord[2]; }
3131  }
3132  x = x_coord.ParallelProject();
3133  y = y_coord.ParallelProject();
3134  if (sdim == 2)
3135  {
3136  z = NULL;
3137  HYPRE_AMSSetCoordinateVectors(ams, *x, *y, NULL);
3138  }
3139  else
3140  {
3141  z = z_coord.ParallelProject();
3142  HYPRE_AMSSetCoordinateVectors(ams, *x, *y, *z);
3143  }
3144  }
3145  else
3146  {
3147  x = NULL;
3148  y = NULL;
3149  z = NULL;
3150  }
3151 
3152  // generate and set the discrete gradient
3153  ParDiscreteLinearOperator *grad;
3154  grad = new ParDiscreteLinearOperator(vert_fespace, edge_fespace);
3155  if (trace_space)
3156  {
3157  grad->AddTraceFaceInterpolator(new GradientInterpolator);
3158  }
3159  else
3160  {
3161  grad->AddDomainInterpolator(new GradientInterpolator);
3162  }
3163  grad->Assemble();
3164  grad->Finalize();
3165  G = grad->ParallelAssemble();
3166  HYPRE_AMSSetDiscreteGradient(ams, *G);
3167  delete grad;
3168 
3169  // generate and set the Nedelec interpolation matrices
3170  Pi = Pix = Piy = Piz = NULL;
3171  if (p > 1)
3172  {
3173  ParFiniteElementSpace *vert_fespace_d
3174  = new ParFiniteElementSpace(pmesh, vert_fec, sdim, Ordering::byVDIM);
3175 
3176  ParDiscreteLinearOperator *id_ND;
3177  id_ND = new ParDiscreteLinearOperator(vert_fespace_d, edge_fespace);
3178  if (trace_space)
3179  {
3180  id_ND->AddTraceFaceInterpolator(new IdentityInterpolator);
3181  }
3182  else
3183  {
3184  id_ND->AddDomainInterpolator(new IdentityInterpolator);
3185  }
3186  id_ND->Assemble();
3187  id_ND->Finalize();
3188 
3189  if (cycle_type < 10)
3190  {
3191  Pi = id_ND->ParallelAssemble();
3192  }
3193  else
3194  {
3195  Array2D<HypreParMatrix *> Pi_blocks;
3196  id_ND->GetParBlocks(Pi_blocks);
3197  Pix = Pi_blocks(0,0);
3198  Piy = Pi_blocks(0,1);
3199  if (sdim == 3) { Piz = Pi_blocks(0,2); }
3200  }
3201 
3202  delete id_ND;
3203 
3204  HYPRE_ParCSRMatrix HY_Pi = (Pi) ? (HYPRE_ParCSRMatrix) *Pi : NULL;
3205  HYPRE_ParCSRMatrix HY_Pix = (Pix) ? (HYPRE_ParCSRMatrix) *Pix : NULL;
3206  HYPRE_ParCSRMatrix HY_Piy = (Piy) ? (HYPRE_ParCSRMatrix) *Piy : NULL;
3207  HYPRE_ParCSRMatrix HY_Piz = (Piz) ? (HYPRE_ParCSRMatrix) *Piz : NULL;
3208  HYPRE_AMSSetInterpolations(ams, HY_Pi, HY_Pix, HY_Piy, HY_Piz);
3209 
3210  delete vert_fespace_d;
3211  }
3212 
3213  delete vert_fespace;
3214  delete vert_fec;
3215 
3216  if (rt_trace_space)
3217  {
3218  delete edge_fespace;
3219  delete nd_tr_fec;
3220  }
3221 
3222  // set additional AMS options
3223  HYPRE_AMSSetSmoothingOptions(ams, rlx_type, rlx_sweeps, rlx_weight, rlx_omega);
3224  HYPRE_AMSSetAlphaAMGOptions(ams, amg_coarsen_type, amg_agg_levels, amg_rlx_type,
3225  theta, amg_interp_type, amg_Pmax);
3226  HYPRE_AMSSetBetaAMGOptions(ams, amg_coarsen_type, amg_agg_levels, amg_rlx_type,
3227  theta, amg_interp_type, amg_Pmax);
3228 
3229  // The AMS preconditioner may sometimes require inverting singular matrices
3230  // with BoomerAMG, which are handled correctly in hypre's Solve method, but
3231  // can produce hypre errors in the Setup (specifically in the l1 row norm
3232  // computation). See the documentation of SetErrorMode() for more details.
3234 }
3235 
3237 {
3238  const HypreParMatrix *new_A = dynamic_cast<const HypreParMatrix *>(&op);
3239  MFEM_VERIFY(new_A, "new Operator must be a HypreParMatrix!");
3240 
3241  // update base classes: Operator, Solver, HypreSolver
3242  height = new_A->Height();
3243  width = new_A->Width();
3244  A = const_cast<HypreParMatrix *>(new_A);
3245 
3246  setup_called = 0;
3247  delete X;
3248  delete B;
3249  B = X = NULL;
3250 }
3251 
3253 {
3254  HYPRE_AMSDestroy(ams);
3255 
3256  delete x;
3257  delete y;
3258  delete z;
3259 
3260  delete G;
3261  delete Pi;
3262  delete Pix;
3263  delete Piy;
3264  delete Piz;
3265 }
3266 
3267 void HypreAMS::SetPrintLevel(int print_lvl)
3268 {
3269  HYPRE_AMSSetPrintLevel(ams, print_lvl);
3270 }
3271 
3273 {
3274  Init(face_fespace);
3275 }
3276 
3278  : HypreSolver(&A)
3279 {
3280  Init(face_fespace);
3281 }
3282 
3283 void HypreADS::Init(ParFiniteElementSpace *face_fespace)
3284 {
3285  int cycle_type = 11;
3286  int rlx_type = 2;
3287  int rlx_sweeps = 1;
3288  double rlx_weight = 1.0;
3289  double rlx_omega = 1.0;
3290  int amg_coarsen_type = 10;
3291  int amg_agg_levels = 1;
3292  int amg_rlx_type = 8;
3293  double theta = 0.25;
3294  int amg_interp_type = 6;
3295  int amg_Pmax = 4;
3296  int ams_cycle_type = 14;
3297 
3298  const FiniteElementCollection *face_fec = face_fespace->FEColl();
3299  bool trace_space =
3300  (dynamic_cast<const RT_Trace_FECollection*>(face_fec) != NULL);
3301  int p = 1;
3302  if (face_fespace->GetNE() > 0)
3303  {
3304  if (trace_space)
3305  {
3306  p = face_fespace->GetFaceOrder(0) + 1;
3307  }
3308  else
3309  {
3310  p = face_fespace->GetOrder(0);
3311  }
3312  }
3313 
3314  HYPRE_ADSCreate(&ads);
3315 
3316  HYPRE_ADSSetTol(ads, 0.0);
3317  HYPRE_ADSSetMaxIter(ads, 1); // use as a preconditioner
3318  HYPRE_ADSSetCycleType(ads, cycle_type);
3319  HYPRE_ADSSetPrintLevel(ads, 1);
3320 
3321  // define the nodal and edge finite element spaces associated with face_fespace
3322  ParMesh *pmesh = (ParMesh *) face_fespace->GetMesh();
3323  FiniteElementCollection *vert_fec, *edge_fec;
3324  if (trace_space)
3325  {
3326  vert_fec = new H1_Trace_FECollection(p, 3);
3327  edge_fec = new ND_Trace_FECollection(p, 3);
3328  }
3329  else
3330  {
3331  vert_fec = new H1_FECollection(p, 3);
3332  edge_fec = new ND_FECollection(p, 3);
3333  }
3334 
3335  ParFiniteElementSpace *vert_fespace = new ParFiniteElementSpace(pmesh,
3336  vert_fec);
3337  ParFiniteElementSpace *edge_fespace = new ParFiniteElementSpace(pmesh,
3338  edge_fec);
3339 
3340  // generate and set the vertex coordinates
3341  if (p == 1)
3342  {
3343  ParGridFunction x_coord(vert_fespace);
3344  ParGridFunction y_coord(vert_fespace);
3345  ParGridFunction z_coord(vert_fespace);
3346  double *coord;
3347  for (int i = 0; i < pmesh->GetNV(); i++)
3348  {
3349  coord = pmesh -> GetVertex(i);
3350  x_coord(i) = coord[0];
3351  y_coord(i) = coord[1];
3352  z_coord(i) = coord[2];
3353  }
3354  x = x_coord.ParallelProject();
3355  y = y_coord.ParallelProject();
3356  z = z_coord.ParallelProject();
3357  HYPRE_ADSSetCoordinateVectors(ads, *x, *y, *z);
3358  }
3359  else
3360  {
3361  x = NULL;
3362  y = NULL;
3363  z = NULL;
3364  }
3365 
3366  // generate and set the discrete curl
3367  ParDiscreteLinearOperator *curl;
3368  curl = new ParDiscreteLinearOperator(edge_fespace, face_fespace);
3369  if (trace_space)
3370  {
3371  curl->AddTraceFaceInterpolator(new CurlInterpolator);
3372  }
3373  else
3374  {
3375  curl->AddDomainInterpolator(new CurlInterpolator);
3376  }
3377  curl->Assemble();
3378  curl->Finalize();
3379  C = curl->ParallelAssemble();
3380  C->CopyColStarts(); // since we'll delete edge_fespace
3381  HYPRE_ADSSetDiscreteCurl(ads, *C);
3382  delete curl;
3383 
3384  // generate and set the discrete gradient
3385  ParDiscreteLinearOperator *grad;
3386  grad = new ParDiscreteLinearOperator(vert_fespace, edge_fespace);
3387  if (trace_space)
3388  {
3389  grad->AddTraceFaceInterpolator(new GradientInterpolator);
3390  }
3391  else
3392  {
3393  grad->AddDomainInterpolator(new GradientInterpolator);
3394  }
3395  grad->Assemble();
3396  grad->Finalize();
3397  G = grad->ParallelAssemble();
3398  G->CopyColStarts(); // since we'll delete vert_fespace
3399  G->CopyRowStarts(); // since we'll delete edge_fespace
3400  HYPRE_ADSSetDiscreteGradient(ads, *G);
3401  delete grad;
3402 
3403  // generate and set the Nedelec and Raviart-Thomas interpolation matrices
3404  RT_Pi = RT_Pix = RT_Piy = RT_Piz = NULL;
3405  ND_Pi = ND_Pix = ND_Piy = ND_Piz = NULL;
3406  if (p > 1)
3407  {
3408  ParFiniteElementSpace *vert_fespace_d
3409  = new ParFiniteElementSpace(pmesh, vert_fec, 3, Ordering::byVDIM);
3410 
3411  ParDiscreteLinearOperator *id_ND;
3412  id_ND = new ParDiscreteLinearOperator(vert_fespace_d, edge_fespace);
3413  if (trace_space)
3414  {
3415  id_ND->AddTraceFaceInterpolator(new IdentityInterpolator);
3416  }
3417  else
3418  {
3419  id_ND->AddDomainInterpolator(new IdentityInterpolator);
3420  }
3421  id_ND->Assemble();
3422  id_ND->Finalize();
3423 
3424  if (ams_cycle_type < 10)
3425  {
3426  ND_Pi = id_ND->ParallelAssemble();
3427  ND_Pi->CopyColStarts(); // since we'll delete vert_fespace_d
3428  ND_Pi->CopyRowStarts(); // since we'll delete edge_fespace
3429  }
3430  else
3431  {
3432  Array2D<HypreParMatrix *> ND_Pi_blocks;
3433  id_ND->GetParBlocks(ND_Pi_blocks);
3434  ND_Pix = ND_Pi_blocks(0,0);
3435  ND_Piy = ND_Pi_blocks(0,1);
3436  ND_Piz = ND_Pi_blocks(0,2);
3437  }
3438 
3439  delete id_ND;
3440 
3441  ParDiscreteLinearOperator *id_RT;
3442  id_RT = new ParDiscreteLinearOperator(vert_fespace_d, face_fespace);
3443  if (trace_space)
3444  {
3445  id_RT->AddTraceFaceInterpolator(new NormalInterpolator);
3446  }
3447  else
3448  {
3449  id_RT->AddDomainInterpolator(new IdentityInterpolator);
3450  }
3451  id_RT->Assemble();
3452  id_RT->Finalize();
3453 
3454  if (cycle_type < 10)
3455  {
3456  RT_Pi = id_RT->ParallelAssemble();
3457  RT_Pi->CopyColStarts(); // since we'll delete vert_fespace_d
3458  }
3459  else
3460  {
3461  Array2D<HypreParMatrix *> RT_Pi_blocks;
3462  id_RT->GetParBlocks(RT_Pi_blocks);
3463  RT_Pix = RT_Pi_blocks(0,0);
3464  RT_Piy = RT_Pi_blocks(0,1);
3465  RT_Piz = RT_Pi_blocks(0,2);
3466  }
3467 
3468  delete id_RT;
3469 
3470  HYPRE_ParCSRMatrix HY_RT_Pi, HY_RT_Pix, HY_RT_Piy, HY_RT_Piz;
3471  HY_RT_Pi = (RT_Pi) ? (HYPRE_ParCSRMatrix) *RT_Pi : NULL;
3472  HY_RT_Pix = (RT_Pix) ? (HYPRE_ParCSRMatrix) *RT_Pix : NULL;
3473  HY_RT_Piy = (RT_Piy) ? (HYPRE_ParCSRMatrix) *RT_Piy : NULL;
3474  HY_RT_Piz = (RT_Piz) ? (HYPRE_ParCSRMatrix) *RT_Piz : NULL;
3475  HYPRE_ParCSRMatrix HY_ND_Pi, HY_ND_Pix, HY_ND_Piy, HY_ND_Piz;
3476  HY_ND_Pi = (ND_Pi) ? (HYPRE_ParCSRMatrix) *ND_Pi : NULL;
3477  HY_ND_Pix = (ND_Pix) ? (HYPRE_ParCSRMatrix) *ND_Pix : NULL;
3478  HY_ND_Piy = (ND_Piy) ? (HYPRE_ParCSRMatrix) *ND_Piy : NULL;
3479  HY_ND_Piz = (ND_Piz) ? (HYPRE_ParCSRMatrix) *ND_Piz : NULL;
3480  HYPRE_ADSSetInterpolations(ads,
3481  HY_RT_Pi, HY_RT_Pix, HY_RT_Piy, HY_RT_Piz,
3482  HY_ND_Pi, HY_ND_Pix, HY_ND_Piy, HY_ND_Piz);
3483 
3484  delete vert_fespace_d;
3485  }
3486 
3487  delete vert_fec;
3488  delete vert_fespace;
3489  delete edge_fec;
3490  delete edge_fespace;
3491 
3492  // set additional ADS options
3493  HYPRE_ADSSetSmoothingOptions(ads, rlx_type, rlx_sweeps, rlx_weight, rlx_omega);
3494  HYPRE_ADSSetAMGOptions(ads, amg_coarsen_type, amg_agg_levels, amg_rlx_type,
3495  theta, amg_interp_type, amg_Pmax);
3496  HYPRE_ADSSetAMSOptions(ads, ams_cycle_type, amg_coarsen_type, amg_agg_levels,
3497  amg_rlx_type, theta, amg_interp_type, amg_Pmax);
3498 
3499  // The ADS preconditioner requires inverting singular matrices with BoomerAMG,
3500  // which are handled correctly in hypre's Solve method, but can produce hypre
3501  // errors in the Setup (specifically in the l1 row norm computation). See the
3502  // documentation of SetErrorMode() for more details.
3504 }
3505 
3507 {
3508  const HypreParMatrix *new_A = dynamic_cast<const HypreParMatrix *>(&op);
3509  MFEM_VERIFY(new_A, "new Operator must be a HypreParMatrix!");
3510 
3511  // update base classes: Operator, Solver, HypreSolver
3512  height = new_A->Height();
3513  width = new_A->Width();
3514  A = const_cast<HypreParMatrix *>(new_A);
3515 
3516  setup_called = 0;
3517  delete X;
3518  delete B;
3519  B = X = NULL;
3520 }
3521 
3523 {
3524  HYPRE_ADSDestroy(ads);
3525 
3526  delete x;
3527  delete y;
3528  delete z;
3529 
3530  delete G;
3531  delete C;
3532 
3533  delete RT_Pi;
3534  delete RT_Pix;
3535  delete RT_Piy;
3536  delete RT_Piz;
3537 
3538  delete ND_Pi;
3539  delete ND_Pix;
3540  delete ND_Piy;
3541  delete ND_Piz;
3542 }
3543 
3544 void HypreADS::SetPrintLevel(int print_lvl)
3545 {
3546  HYPRE_ADSSetPrintLevel(ads, print_lvl);
3547 }
3548 
3549 HypreLOBPCG::HypreMultiVector::HypreMultiVector(int n, HypreParVector & v,
3550  mv_InterfaceInterpreter & interpreter)
3551  : hpv(NULL),
3552  nv(n)
3553 {
3554  mv_ptr = mv_MultiVectorCreateFromSampleVector(&interpreter, nv,
3555  (HYPRE_ParVector)v);
3556 
3557  HYPRE_ParVector* vecs = NULL;
3558  {
3559  mv_TempMultiVector* tmp =
3560  (mv_TempMultiVector*)mv_MultiVectorGetData(mv_ptr);
3561  vecs = (HYPRE_ParVector*)(tmp -> vector);
3562  }
3563 
3564  hpv = new HypreParVector*[nv];
3565  for (int i=0; i<nv; i++)
3566  {
3567  hpv[i] = new HypreParVector(vecs[i]);
3568  }
3569 }
3570 
3571 HypreLOBPCG::HypreMultiVector::~HypreMultiVector()
3572 {
3573  if ( hpv != NULL )
3574  {
3575  for (int i=0; i<nv; i++)
3576  {
3577  delete hpv[i];
3578  }
3579  delete [] hpv;
3580  }
3581 
3582  mv_MultiVectorDestroy(mv_ptr);
3583 }
3584 
3585 void
3586 HypreLOBPCG::HypreMultiVector::Randomize(HYPRE_Int seed)
3587 {
3588  mv_MultiVectorSetRandom(mv_ptr, seed);
3589 }
3590 
3591 HypreParVector &
3592 HypreLOBPCG::HypreMultiVector::GetVector(unsigned int i)
3593 {
3594  MFEM_ASSERT((int)i < nv, "index out of range");
3595 
3596  return ( *hpv[i] );
3597 }
3598 
3599 HypreParVector **
3600 HypreLOBPCG::HypreMultiVector::StealVectors()
3601 {
3602  HypreParVector ** hpv_ret = hpv;
3603 
3604  hpv = NULL;
3605 
3606  mv_TempMultiVector * mv_tmp =
3607  (mv_TempMultiVector*)mv_MultiVectorGetData(mv_ptr);
3608 
3609  mv_tmp->ownsVectors = 0;
3610 
3611  for (int i=0; i<nv; i++)
3612  {
3613  hpv_ret[i]->SetOwnership(1);
3614  }
3615 
3616  return hpv_ret;
3617 }
3618 
3620  : comm(c),
3621  myid(0),
3622  numProcs(1),
3623  nev(10),
3624  seed(75),
3625  glbSize(-1),
3626  part(NULL),
3627  multi_vec(NULL),
3628  x(NULL),
3629  subSpaceProj(NULL)
3630 {
3631  MPI_Comm_size(comm,&numProcs);
3632  MPI_Comm_rank(comm,&myid);
3633 
3634  HYPRE_ParCSRSetupInterpreter(&interpreter);
3635  HYPRE_ParCSRSetupMatvec(&matvec_fn);
3636  HYPRE_LOBPCGCreate(&interpreter, &matvec_fn, &lobpcg_solver);
3637 }
3638 
3640 {
3641  delete multi_vec;
3642  delete x;
3643  delete [] part;
3644 
3645  HYPRE_LOBPCGDestroy(lobpcg_solver);
3646 }
3647 
3648 void
3650 {
3651  HYPRE_LOBPCGSetTol(lobpcg_solver, tol);
3652 }
3653 
3654 void
3655 HypreLOBPCG::SetRelTol(double rel_tol)
3656 {
3657 #if MFEM_HYPRE_VERSION >= 21101
3658  HYPRE_LOBPCGSetRTol(lobpcg_solver, rel_tol);
3659 #else
3660  MFEM_ABORT("This method requires HYPRE version >= 2.11.1");
3661 #endif
3662 }
3663 
3664 void
3666 {
3667  HYPRE_LOBPCGSetMaxIter(lobpcg_solver, max_iter);
3668 }
3669 
3670 void
3672 {
3673  if (myid == 0)
3674  {
3675  HYPRE_LOBPCGSetPrintLevel(lobpcg_solver, logging);
3676  }
3677 }
3678 
3679 void
3681 {
3682  HYPRE_LOBPCGSetPrecondUsageMode(lobpcg_solver, pcg_mode);
3683 }
3684 
3685 void
3687 {
3688  HYPRE_LOBPCGSetPrecond(lobpcg_solver,
3689  (HYPRE_PtrToSolverFcn)this->PrecondSolve,
3690  (HYPRE_PtrToSolverFcn)this->PrecondSetup,
3691  (HYPRE_Solver)&precond);
3692 }
3693 
3694 void
3696 {
3697  HYPRE_Int locSize = A.Width();
3698 
3699  if (HYPRE_AssumedPartitionCheck())
3700  {
3701  part = new HYPRE_Int[2];
3702 
3703  MPI_Scan(&locSize, &part[1], 1, HYPRE_MPI_INT, MPI_SUM, comm);
3704 
3705  part[0] = part[1] - locSize;
3706 
3707  MPI_Allreduce(&locSize, &glbSize, 1, HYPRE_MPI_INT, MPI_SUM, comm);
3708  }
3709  else
3710  {
3711  part = new HYPRE_Int[numProcs+1];
3712 
3713  MPI_Allgather(&locSize, 1, HYPRE_MPI_INT,
3714  &part[1], 1, HYPRE_MPI_INT, comm);
3715 
3716  part[0] = 0;
3717  for (int i=0; i<numProcs; i++)
3718  {
3719  part[i+1] += part[i];
3720  }
3721 
3722  glbSize = part[numProcs];
3723  }
3724 
3725  if ( x != NULL )
3726  {
3727  delete x;
3728  }
3729 
3730  // Create a distributed vector without a data array.
3731  x = new HypreParVector(comm,glbSize,NULL,part);
3732 
3733  matvec_fn.MatvecCreate = this->OperatorMatvecCreate;
3734  matvec_fn.Matvec = this->OperatorMatvec;
3735  matvec_fn.MatvecDestroy = this->OperatorMatvecDestroy;
3736 
3737  HYPRE_LOBPCGSetup(lobpcg_solver,(HYPRE_Matrix)&A,NULL,NULL);
3738 }
3739 
3740 void
3742 {
3743  matvec_fn.MatvecCreate = this->OperatorMatvecCreate;
3744  matvec_fn.Matvec = this->OperatorMatvec;
3745  matvec_fn.MatvecDestroy = this->OperatorMatvecDestroy;
3746 
3747  HYPRE_LOBPCGSetupB(lobpcg_solver,(HYPRE_Matrix)&M,NULL);
3748 }
3749 
3750 void
3752 {
3753  // Initialize eigenvalues array with marker values
3754  eigs.SetSize(nev);
3755 
3756  for (int i=0; i<nev; i++)
3757  {
3758  eigs[i] = eigenvalues[i];
3759  }
3760 }
3761 
3764 {
3765  return multi_vec->GetVector(i);
3766 }
3767 
3768 void
3770 {
3771  // Initialize HypreMultiVector object if necessary
3772  if ( multi_vec == NULL )
3773  {
3774  MFEM_ASSERT(x != NULL, "In HypreLOBPCG::SetInitialVectors()");
3775 
3776  multi_vec = new HypreMultiVector(nev, *x, interpreter);
3777  }
3778 
3779  // Copy the vectors provided
3780  for (int i=0; i < min(num_vecs,nev); i++)
3781  {
3782  multi_vec->GetVector(i) = *vecs[i];
3783  }
3784 
3785  // Randomize any remaining vectors
3786  for (int i=min(num_vecs,nev); i < nev; i++)
3787  {
3788  multi_vec->GetVector(i).Randomize(seed);
3789  }
3790 
3791  // Ensure all vectors are in the proper subspace
3792  if ( subSpaceProj != NULL )
3793  {
3794  HypreParVector y(*x);
3795  y = multi_vec->GetVector(0);
3796 
3797  for (int i=1; i<nev; i++)
3798  {
3799  subSpaceProj->Mult(multi_vec->GetVector(i),
3800  multi_vec->GetVector(i-1));
3801  }
3802  subSpaceProj->Mult(y,
3803  multi_vec->GetVector(nev-1));
3804  }
3805 }
3806 
3807 void
3809 {
3810  // Initialize HypreMultiVector object if necessary
3811  if ( multi_vec == NULL )
3812  {
3813  MFEM_ASSERT(x != NULL, "In HypreLOBPCG::Solve()");
3814 
3815  multi_vec = new HypreMultiVector(nev, *x, interpreter);
3816  multi_vec->Randomize(seed);
3817 
3818  if ( subSpaceProj != NULL )
3819  {
3820  HypreParVector y(*x);
3821  y = multi_vec->GetVector(0);
3822 
3823  for (int i=1; i<nev; i++)
3824  {
3825  subSpaceProj->Mult(multi_vec->GetVector(i),
3826  multi_vec->GetVector(i-1));
3827  }
3828  subSpaceProj->Mult(y, multi_vec->GetVector(nev-1));
3829  }
3830  }
3831 
3832  eigenvalues.SetSize(nev);
3833  eigenvalues = NAN;
3834 
3835  // Perform eigenmode calculation
3836  //
3837  // The eigenvalues are computed in ascending order (internally the
3838  // order is determined by the LAPACK routine 'dsydv'.)
3839  HYPRE_LOBPCGSolve(lobpcg_solver, NULL, *multi_vec, eigenvalues);
3840 }
3841 
3842 void *
3843 HypreLOBPCG::OperatorMatvecCreate( void *A,
3844  void *x )
3845 {
3846  void *matvec_data;
3847 
3848  matvec_data = NULL;
3849 
3850  return ( matvec_data );
3851 }
3852 
3853 HYPRE_Int
3854 HypreLOBPCG::OperatorMatvec( void *matvec_data,
3855  HYPRE_Complex alpha,
3856  void *A,
3857  void *x,
3858  HYPRE_Complex beta,
3859  void *y )
3860 {
3861  MFEM_VERIFY(alpha == 1.0 && beta == 0.0, "values not supported");
3862 
3863  Operator *Aop = (Operator*)A;
3864 
3865  int width = Aop->Width();
3866 
3867  hypre_ParVector * xPar = (hypre_ParVector *)x;
3868  hypre_ParVector * yPar = (hypre_ParVector *)y;
3869 
3870  Vector xVec(xPar->local_vector->data, width);
3871  Vector yVec(yPar->local_vector->data, width);
3872 
3873  Aop->Mult( xVec, yVec );
3874 
3875  return 0;
3876 }
3877 
3878 HYPRE_Int
3879 HypreLOBPCG::OperatorMatvecDestroy( void *matvec_data )
3880 {
3881  return 0;
3882 }
3883 
3884 HYPRE_Int
3885 HypreLOBPCG::PrecondSolve(void *solver,
3886  void *A,
3887  void *b,
3888  void *x)
3889 {
3890  Solver *PC = (Solver*)solver;
3891  Operator *OP = (Operator*)A;
3892 
3893  int width = OP->Width();
3894 
3895  hypre_ParVector * bPar = (hypre_ParVector *)b;
3896  hypre_ParVector * xPar = (hypre_ParVector *)x;
3897 
3898  Vector bVec(bPar->local_vector->data, width);
3899  Vector xVec(xPar->local_vector->data, width);
3900 
3901  PC->Mult( bVec, xVec );
3902 
3903  return 0;
3904 }
3905 
3906 HYPRE_Int
3907 HypreLOBPCG::PrecondSetup(void *solver,
3908  void *A,
3909  void *b,
3910  void *x)
3911 {
3912  return 0;
3913 }
3914 
3915 HypreAME::HypreAME(MPI_Comm comm)
3916  : myid(0),
3917  numProcs(1),
3918  nev(10),
3919  setT(false),
3920  ams_precond(NULL),
3921  eigenvalues(NULL),
3922  multi_vec(NULL),
3923  eigenvectors(NULL)
3924 {
3925  MPI_Comm_size(comm,&numProcs);
3926  MPI_Comm_rank(comm,&myid);
3927 
3928  HYPRE_AMECreate(&ame_solver);
3929  HYPRE_AMESetPrintLevel(ame_solver, 0);
3930 }
3931 
3933 {
3934  if ( multi_vec )
3935  {
3936  mfem_hypre_TFree(multi_vec);
3937  }
3938 
3939  if ( eigenvectors )
3940  {
3941  for (int i=0; i<nev; i++)
3942  {
3943  delete eigenvectors[i];
3944  }
3945  }
3946  delete [] eigenvectors;
3947 
3948  if ( eigenvalues )
3949  {
3950  mfem_hypre_TFree(eigenvalues);
3951  }
3952 
3953  HYPRE_AMEDestroy(ame_solver);
3954 }
3955 
3956 void
3958 {
3959  nev = num_eigs;
3960 
3961  HYPRE_AMESetBlockSize(ame_solver, nev);
3962 }
3963 
3964 void
3965 HypreAME::SetTol(double tol)
3966 {
3967  HYPRE_AMESetTol(ame_solver, tol);
3968 }
3969 
3970 void
3971 HypreAME::SetRelTol(double rel_tol)
3972 {
3973 #if MFEM_HYPRE_VERSION >= 21101
3974  HYPRE_AMESetRTol(ame_solver, rel_tol);
3975 #else
3976  MFEM_ABORT("This method requires HYPRE version >= 2.11.1");
3977 #endif
3978 }
3979 
3980 void
3982 {
3983  HYPRE_AMESetMaxIter(ame_solver, max_iter);
3984 }
3985 
3986 void
3988 {
3989  if (myid == 0)
3990  {
3991  HYPRE_AMESetPrintLevel(ame_solver, logging);
3992  }
3993 }
3994 
3995 void
3997 {
3998  ams_precond = &precond;
3999 }
4000 
4001 void
4003 {
4004  if ( !setT )
4005  {
4006  HYPRE_Solver ams_precond_ptr = (HYPRE_Solver)*ams_precond;
4007 
4008  ams_precond->SetupFcn()(*ams_precond,A,NULL,NULL);
4009 
4010  HYPRE_AMESetAMSSolver(ame_solver, ams_precond_ptr);
4011  }
4012 
4013  HYPRE_AMESetup(ame_solver);
4014 }
4015 
4016 void
4018 {
4019  HYPRE_ParCSRMatrix parcsr_M = M;
4020  HYPRE_AMESetMassMatrix(ame_solver,(HYPRE_ParCSRMatrix)parcsr_M);
4021 }
4022 
4023 void
4025 {
4026  HYPRE_AMESolve(ame_solver);
4027 }
4028 
4029 void
4031 {
4032  // Initialize eigenvalues array with marker values
4033  eigs.SetSize(nev); eigs = -1.0;
4034 
4035  if ( eigenvalues == NULL )
4036  {
4037  // Grab eigenvalues from AME
4038  HYPRE_AMEGetEigenvalues(ame_solver,&eigenvalues);
4039  }
4040 
4041  // Copy eigenvalues to eigs array
4042  for (int i=0; i<nev; i++)
4043  {
4044  eigs[i] = eigenvalues[i];
4045  }
4046 }
4047 
4048 void
4049 HypreAME::createDummyVectors()
4050 {
4051  if ( multi_vec == NULL )
4052  {
4053  HYPRE_AMEGetEigenvectors(ame_solver,&multi_vec);
4054  }
4055 
4056  eigenvectors = new HypreParVector*[nev];
4057  for (int i=0; i<nev; i++)
4058  {
4059  eigenvectors[i] = new HypreParVector(multi_vec[i]);
4060  eigenvectors[i]->SetOwnership(1);
4061  }
4062 
4063 }
4064 
4065 HypreParVector &
4067 {
4068  if ( eigenvectors == NULL )
4069  {
4070  this->createDummyVectors();
4071  }
4072 
4073  return *eigenvectors[i];
4074 }
4075 
4076 HypreParVector **
4078 {
4079  if ( eigenvectors == NULL )
4080  {
4081  this->createDummyVectors();
4082  }
4083 
4084  // Set the local pointers to NULL so that they won't be deleted later
4085  HypreParVector ** vecs = eigenvectors;
4086  eigenvectors = NULL;
4087  multi_vec = NULL;
4088 
4089  return vecs;
4090 }
4091 
4092 }
4093 
4094 #endif
virtual ~HypreBoomerAMG()
Definition: hypre.cpp:3031
void SetTol(double tol)
Definition: hypre.cpp:2305
void SetPreconditioner(HypreSolver &precond)
Set the hypre solver to be used as a preconditioner.
Definition: hypre.cpp:2506
int Size() const
Logical size of the array.
Definition: array.hpp:124
void EliminateRowsCols(const Array< int > &rows_cols, const HypreParVector &X, HypreParVector &B)
Definition: hypre.cpp:1390
void delete_hypre_CSRMatrixData(hypre_CSRMatrix *M)
Definition: hypre.cpp:1514
HypreADS(ParFiniteElementSpace *face_fespace)
Definition: hypre.cpp:3272
virtual int NumNonZeroElems() const
Returns the number of the nonzero elements in the matrix.
Definition: sparsemat.cpp:1162
double * HostReadWrite()
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), false).
Definition: vector.hpp:353
Vector()
Default constructor for Vector. Sets size = 0 and data = NULL.
Definition: vector.hpp:58
MPI_Comm GetComm() const
MPI communicator.
Definition: hypre.hpp:336
HypreEuclid(MPI_Comm comm)
Definition: hypre.cpp:2703
Vector * GlobalVector() const
Returns the global vector in each processor.
Definition: hypre.cpp:176
int * GetJ()
Definition: table.hpp:114
HypreParVector * X0
FIR Filter Temporary Vectors.
Definition: hypre.hpp:591
HypreParVector & GetEigenvector(unsigned int i)
Extract a single eigenvector.
Definition: hypre.cpp:3763
double min_eig_est
Minimal eigenvalue estimate for polynomial smoothing.
Definition: hypre.hpp:621
int NumCols() const
Definition: array.hpp:338
void MakeDataOwner() const
Set the Vector data (host pointer) ownership flag.
Definition: vector.hpp:151
void SetPrintLevel(int print_lvl)
Definition: hypre.cpp:3544
void Print(const char *fname, HYPRE_Int offi=0, HYPRE_Int offj=0)
Prints the locally owned rows in parallel.
Definition: hypre.cpp:1436
HYPRE_Int N() const
Returns the global number of columns.
Definition: hypre.hpp:388
HypreParMatrix * RAP(const HypreParMatrix *A, const HypreParMatrix *P)
Returns the matrix P^t * A * P.
Definition: hypre.cpp:1636
virtual ~HypreEuclid()
Definition: hypre.cpp:2766
int setup_called
Was hypre&#39;s Setup function called already?
Definition: hypre.hpp:703
virtual void SetOperator(const Operator &op)
Set/update the solver for the given operator.
Definition: hypre.cpp:2285
void MakeRef(const HypreParMatrix &master)
Make this HypreParMatrix a reference to &#39;master&#39;.
Definition: hypre.cpp:837
void Read_IJMatrix(MPI_Comm comm, const char *fname)
Read a matrix saved as a HYPRE_IJMatrix.
Definition: hypre.cpp:1456
HypreParMatrix * LeftDiagMult(const SparseMatrix &D, HYPRE_Int *row_starts=NULL) const
Multiply the HypreParMatrix on the left by a block-diagonal parallel matrix D and return the result a...
Definition: hypre.cpp:1103
HYPRE_Int MultTranspose(HypreParVector &x, HypreParVector &y, double alpha=1.0, double beta=0.0)
Computes y = alpha * A^t * x + beta * y.
Definition: hypre.cpp:1097
void SetSize(int s)
Resize the vector to size s.
Definition: vector.hpp:407
HypreParMatrix & Add(const double beta, const HypreParMatrix &B)
Definition: hypre.hpp:487
HypreParVector * B
Right-hand side and solution vector.
Definition: hypre.hpp:700
double window_params[3]
Parameters for windowing function of FIR filter.
Definition: hypre.hpp:623
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
Definition: table.cpp:476
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition: operator.hpp:63
void SetInitialVectors(int num_vecs, HypreParVector **vecs)
Definition: hypre.cpp:3769
virtual void SetOperator(const Operator &op)
Set/update the solver for the given operator.
Definition: hypre.cpp:2461
int * GetJ()
Return the array J.
Definition: sparsemat.hpp:146
void SetWindowByName(const char *window_name)
Convenience function for setting canonical windowing parameters.
Definition: hypre.cpp:1920
int GetFaceOrder(int i) const
Returns the order of the i&#39;th face finite element.
Definition: fespace.cpp:101
T * GetData()
Returns the data.
Definition: array.hpp:98
void GetEigenvalues(Array< double > &eigenvalues)
Collect the converged eigenvalues.
Definition: hypre.cpp:4030
Issue warnings on hypre errors.
Definition: hypre.hpp:691
void SetPreconditioner(HypreSolver &precond)
Definition: hypre.cpp:3996
int Size() const
Returns the size of the vector.
Definition: vector.hpp:157
HyprePCG(MPI_Comm comm)
Definition: hypre.cpp:2267
virtual N_Vector ToNVector()
Return a new wrapper SUNDIALS N_Vector of type SUNDIALS_NVEC_PARHYP.
Definition: hypre.hpp:168
void SetTol(double tol)
Definition: hypre.cpp:3965
int * GetI()
Return the array I.
Definition: sparsemat.hpp:141
HypreAMS(ParFiniteElementSpace *edge_fespace)
Definition: hypre.cpp:3041
virtual ~HypreGMRES()
Definition: hypre.cpp:2584
virtual void SetOperator(const Operator &op)
Set/update the solver for the given operator.
Definition: hypre.cpp:3506
void SetPreconditioner(Solver &precond)
Definition: hypre.cpp:3686
virtual void Mult(const Vector &x, Vector &y) const =0
Operator application: y=A(x).
void SetMassMatrix(Operator &M)
Definition: hypre.cpp:3741
Abstract parallel finite element space.
Definition: pfespace.hpp:28
double Normlinf() const
Returns the l_infinity norm of the vector.
Definition: vector.cpp:729
void SetPrintLevel(int logging)
Definition: hypre.cpp:3671
bool iterative_mode
If true, use the second argument of Mult() as an initial guess.
Definition: operator.hpp:504
virtual ~HypreAMS()
Definition: hypre.cpp:3252
void SetTol(double tol)
Definition: hypre.cpp:2481
void SetOperator(HypreParMatrix &A)
Definition: hypre.cpp:4002
void LoseData()
Lose the ownership of the graph (I, J) and data (A) arrays.
Definition: sparsemat.hpp:571
bool pos_l1_norms
If set, take absolute values of the computed l1_norms.
Definition: hypre.hpp:617
HypreParMatrix * ParMult(const HypreParMatrix *A, const HypreParMatrix *B, bool own_matrix)
Definition: hypre.cpp:1610
HYPRE_Int Mult(HypreParVector &x, HypreParVector &y, double alpha=1.0, double beta=0.0)
Computes y = alpha * A * x + beta * y.
Definition: hypre.cpp:1021
void SetPrintLevel(int print_lvl)
Definition: hypre.cpp:2501
void ScaleRows(const Vector &s)
Scale the local row i by s(i).
Definition: hypre.cpp:1200
int Size_of_connections() const
Definition: table.hpp:98
double poly_fraction
Fraction of spectrum to smooth for polynomial relaxation.
Definition: hypre.hpp:605
void SetPrintLevel(int print_lvl)
Definition: hypre.cpp:2320
void CopyRowStarts()
Definition: hypre.cpp:861
int poly_scale
Apply the polynomial smoother to A or D^{-1/2} A D^{-1/2}.
Definition: hypre.hpp:607
void SetTol(double tol)
Definition: hypre.cpp:3649
HypreParVector * X1
Definition: hypre.hpp:591
double * GetData()
Return the element data, i.e. the array A.
Definition: sparsemat.hpp:151
void SetWindowParameters(double a, double b, double c)
Set parameters for windowing function for FIR smoother.
Definition: hypre.cpp:1935
HypreGMRES(MPI_Comm comm)
Definition: hypre.cpp:2430
Vector & operator=(const double *v)
Copy Size() entries from v.
Definition: vector.cpp:106
virtual void SetOperator(const Operator &op)
Set/update the solver for the given operator.
Definition: hypre.cpp:2670
virtual void Mult(const HypreParVector &b, HypreParVector &x) const
Solve Ax=b with hypre&#39;s GMRES.
Definition: hypre.cpp:2516
void Print(const char *fname) const
Prints the locally owned rows in parallel.
Definition: hypre.cpp:216
struct _p_PC * PC
Definition: petsc.hpp:57
void EliminateBC(HypreParMatrix &A, HypreParMatrix &Ae, const Array< int > &ess_dof_list, const Vector &X, Vector &B)
Definition: hypre.cpp:1690
void SetSystemsOptions(int dim)
Definition: hypre.cpp:2907
HypreLOBPCG(MPI_Comm comm)
Definition: hypre.cpp:3619
void Add(const DenseMatrix &A, const DenseMatrix &B, double alpha, DenseMatrix &C)
C = A + alpha*B.
Definition: densemat.cpp:1926
virtual void Mult(const HypreParVector &b, HypreParVector &x) const
Relax the linear system Ax=b.
Definition: hypre.cpp:2059
int GetNE() const
Returns number of elements in the mesh.
Definition: fespace.hpp:408
const double * HostRead() const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), false).
Definition: vector.hpp:337
virtual void SetOperator(const Operator &op)
Set/update the solver for the given operator.
Definition: hypre.cpp:2590
HYPRE_Int GetGlobalNumRows() const
Return the global number of rows.
Definition: hypre.hpp:421
void SetSymmetry(int sym)
Definition: hypre.cpp:2692
virtual ~HypreParaSails()
Definition: hypre.cpp:2697
MPI_Comm GetComm() const
Definition: pfespace.hpp:239
HYPRE_Int GetGlobalNumCols() const
Return the global number of columns.
Definition: hypre.hpp:425
void SetMaxIter(int max_iter)
Definition: hypre.cpp:3665
double * l1_norms
l1 norms of the rows of A
Definition: hypre.hpp:615
Data type sparse matrix.
Definition: sparsemat.hpp:40
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition: operator.hpp:57
void SetLogging(int logging)
Definition: hypre.cpp:2315
Mesh * GetMesh() const
Returns the mesh.
Definition: fespace.hpp:295
virtual ~HypreSolver()
Definition: hypre.cpp:2260
virtual HYPRE_PtrToParSolverFcn SolveFcn() const =0
hypre&#39;s internal Solve function
void SetRelTol(double rel_tol)
Definition: hypre.cpp:3971
void SetKDim(int dim)
Definition: hypre.cpp:2491
void mfem_error(const char *msg)
Function called when an error is encountered. Used by the macros MFEM_ABORT, MFEM_ASSERT, MFEM_VERIFY.
Definition: error.cpp:153
void SetResidualConvergenceOptions(int res_frequency=-1, double rtol=0.0)
Definition: hypre.cpp:2335
double b
Definition: lissajous.cpp:42
int to_int(const std::string &str)
Definition: text.hpp:70
Abort on hypre errors (default in base class)
Definition: hypre.hpp:692
void GetBlocks(Array2D< HypreParMatrix * > &blocks, bool interleaved_rows=false, bool interleaved_cols=false) const
Definition: hypre.cpp:981
virtual void Mult(const HypreParVector &b, HypreParVector &x) const
Solve the linear system Ax=b.
Definition: hypre.cpp:2192
HypreParaSails(MPI_Comm comm)
Definition: hypre.cpp:2606
HYPRE_Int GlobalTrueVSize() const
Definition: pfespace.hpp:251
virtual void SetOperator(const Operator &op)
Set/update the solver for the given operator.
Definition: hypre.cpp:3236
HypreParVector ** StealEigenvectors()
Transfer ownership of the converged eigenvectors.
Definition: hypre.cpp:4077
HypreParMatrix * Transpose() const
Returns the transpose of *this.
Definition: hypre.cpp:1003
HYPRE_Int Randomize(HYPRE_Int seed)
Set random values.
Definition: hypre.cpp:211
void delete_hypre_CSRMatrixI(hypre_CSRMatrix *M)
Definition: hypre.cpp:1527
Ignore hypre errors (see e.g. HypreADS)
Definition: hypre.hpp:690
double relax_weight
Damping coefficient (usually &lt;= 1)
Definition: hypre.hpp:599
void SetElasticityOptions(ParFiniteElementSpace *fespace)
Definition: hypre.cpp:2989
void GetDiag(Vector &diag) const
Get the local diagonal of the matrix.
Definition: hypre.cpp:939
void Sort()
Sorts the array. This requires operator&lt; to be defined for T.
Definition: array.hpp:229
int Size() const
Returns the number of TYPE I elements.
Definition: table.hpp:92
void SetData(double *d)
Definition: vector.hpp:118
int Dimension() const
Definition: mesh.hpp:744
HypreParMatrix * A
The linear system matrix.
Definition: hypre.hpp:585
Dynamic 2D array using row-major layout.
Definition: array.hpp:316
virtual void SetOperator(const Operator &op)
Definition: hypre.cpp:1942
virtual HYPRE_PtrToParSolverFcn SetupFcn() const =0
hypre&#39;s internal Setup function
void SetLogging(int logging)
Definition: hypre.cpp:2496
virtual ~HypreADS()
Definition: hypre.cpp:3522
HypreParMatrix()
An empty matrix to be used as a reference to an existing matrix.
Definition: hypre.cpp:298
void SetMaxIter(int max_iter)
Definition: hypre.cpp:2310
int ParCSRRelax_FIR(hypre_ParCSRMatrix *A, hypre_ParVector *f, double max_eig, int poly_order, double *fir_coeffs, hypre_ParVector *u, hypre_ParVector *x0, hypre_ParVector *x1, hypre_ParVector *x2, hypre_ParVector *x3)
Definition: hypre.cpp:1777
void SetSOROptions(double relax_weight, double omega)
Set SOR-related parameters.
Definition: hypre.cpp:1900
int SpaceDimension() const
Definition: mesh.hpp:745
Wrapper for hypre&#39;s parallel vector class.
Definition: hypre.hpp:73
HypreParMatrix * EliminateCols(const Array< int > &cols)
Definition: hypre.cpp:1413
HypreParVector * X
Definition: hypre.hpp:700
double Norml1() const
Returns the l_1 norm of the vector.
Definition: vector.cpp:739
int ParCSRRelax_Taubin(hypre_ParCSRMatrix *A, hypre_ParVector *f, double lambda, double mu, int N, double max_eig, hypre_ParVector *u, hypre_ParVector *r)
Definition: hypre.cpp:1740
void GetEigenvalues(Array< double > &eigenvalues)
Collect the converged eigenvalues.
Definition: hypre.cpp:3751
OutStream err(std::cerr)
Global stream used by the library for standard error output. Initially it uses the same std::streambu...
Definition: globals.hpp:71
void SetPrintLevel(int print_lvl)
Definition: hypre.cpp:3267
HypreParVector * X
Definition: hypre.hpp:587
void SetSize(int nsize)
Change logical size of the array, keep existing entries.
Definition: array.hpp:635
void Solve()
Solve the eigenproblem.
Definition: hypre.cpp:4024
int GetOrder(int i) const
Returns the order of the i&#39;th finite element.
Definition: fespace.cpp:95
void SetNumModes(int num_eigs)
Definition: hypre.cpp:3957
int GetNumRows() const
Returns the number of rows in the diagonal block of the ParCSRMatrix.
Definition: hypre.hpp:407
virtual void SetOperator(const Operator &op)
Set/update the solver for the given operator.
Definition: hypre.hpp:721
HypreParMatrix * ParAdd(const HypreParMatrix *A, const HypreParMatrix *B)
Returns the matrix A + B.
Definition: hypre.cpp:1627
double max_eig_est
Maximal eigenvalue estimate for polynomial smoothing.
Definition: hypre.hpp:619
A class to initialize the size of a Tensor.
Definition: dtensor.hpp:54
void SetRelTol(double rel_tol)
Definition: hypre.cpp:3655
HypreAME(MPI_Comm comm)
Definition: hypre.cpp:3915
int height
Dimension of the output / number of rows in the matrix.
Definition: operator.hpp:27
void SetMaxIter(int max_iter)
Definition: hypre.cpp:3981
void SetFIRCoefficients(double max_eig)
Compute window and Chebyshev coefficients for given polynomial order.
Definition: hypre.cpp:2019
double a
Definition: lissajous.cpp:41
void EliminateRows(const Array< int > &rows)
Eliminate rows from the diagonal and off-diagonal blocks of the matrix.
Definition: hypre.cpp:1425
double * fir_coeffs
Combined coefficients for windowing and Chebyshev polynomials.
Definition: hypre.hpp:626
void Threshold(double threshold=0.0)
Remove values smaller in absolute value than some threshold.
Definition: hypre.cpp:1314
double InnerProduct(HypreParVector *x, HypreParVector *y)
Definition: hypre.cpp:246
virtual ~HypreSmoother()
Definition: hypre.cpp:2156
HypreParVector(MPI_Comm comm, HYPRE_Int glob_size, HYPRE_Int *col)
Creates vector with given global size and parallel partitioning of the rows/columns given by col...
Definition: hypre.cpp:98
virtual void SetOperator(const Operator &op)
Set/update the solver for the given operator.
Definition: hypre.cpp:2890
void SetData(double *_data)
Sets the data of the Vector and the hypre_ParVector to _data.
Definition: hypre.cpp:205
void InvScaleRows(const Vector &s)
Scale the local row i by 1./s(i)
Definition: hypre.cpp:1235
void SetTaubinOptions(double lambda, double mu, int iter)
Set parameters for Taubin&#39;s lambda-mu method.
Definition: hypre.cpp:1912
HypreParVector * B
Right-hand side and solution vectors.
Definition: hypre.hpp:587
virtual void SetOperator(const Operator &op)
Set/update the solver for the given operator.
Definition: hypre.cpp:2744
int dim
Definition: ex24.cpp:43
void SetMassMatrix(HypreParMatrix &M)
Definition: hypre.cpp:4017
HYPRE_Int M() const
Returns the global number of rows.
Definition: hypre.hpp:386
virtual ~HyprePCG()
Definition: hypre.cpp:2424
void delete_hypre_CSRMatrixJ(hypre_CSRMatrix *M)
Definition: hypre.cpp:1534
int GetNumCols() const
Returns the number of columns in the diagonal block of the ParCSRMatrix.
Definition: hypre.hpp:414
void SetOperator(Operator &A)
Definition: hypre.cpp:3695
void SetPreconditioner(HypreSolver &precond)
Set the hypre solver to be used as a preconditioner.
Definition: hypre.cpp:2325
void SetPolyOptions(int poly_order, double poly_fraction)
Set parameters for polynomial smoothing.
Definition: hypre.cpp:1906
void CopyColStarts()
Definition: hypre.cpp:898
int relax_times
Number of relaxation sweeps.
Definition: hypre.hpp:597
void operator*=(double s)
Scale all entries by s: A_scaled = s*A.
Definition: hypre.cpp:1276
void SetPrintLevel(int logging)
Definition: hypre.cpp:3987
double infinity()
Define a shortcut for std::numeric_limits&lt;double&gt;::infinity()
Definition: vector.hpp:42
double ParNormlp(const Vector &vec, double p, MPI_Comm comm)
Compute the l_p norm of the Vector which is split without overlap across the given communicator...
Definition: hypre.cpp:257
void SetOwnership(int own)
Sets ownership of the internal hypre_ParVector.
Definition: hypre.hpp:137
void SetDataOwner(bool owna)
Set the data ownership flag (A array).
Definition: sparsemat.hpp:562
Abstract class for hypre&#39;s solvers and preconditioners.
Definition: hypre.hpp:684
ErrorMode error_mode
How to treat hypre errors.
Definition: hypre.hpp:706
double * HostWrite()
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), false).
Definition: vector.hpp:345
HypreParVector & operator=(double d)
Set constant values.
Definition: hypre.cpp:186
HYPRE_Int * GetTrueDofOffsets() const
Definition: pfespace.hpp:248
const double alpha
Definition: ex15.cpp:336
Vector data type.
Definition: vector.hpp:48
const FiniteElementCollection * FEColl() const
Definition: fespace.hpp:395
void PrintCommPkg(std::ostream &out=mfem::out) const
Print information about the hypre_ParCSRCommPkg of the HypreParMatrix.
Definition: hypre.cpp:1477
void delete_hypre_ParCSRMatrixColMapOffd(hypre_ParCSRMatrix *A)
Definition: hypre.cpp:1520
hypre_ParCSRMatrix * StealData()
Changes the ownership of the the matrix.
Definition: hypre.cpp:847
void SetPrecondUsageMode(int pcg_mode)
Definition: hypre.cpp:3680
HypreParMatrix * A
The linear system matrix.
Definition: hypre.hpp:697
void SetMaxIter(int max_iter)
Definition: hypre.cpp:2486
void GetOffd(SparseMatrix &offd, HYPRE_Int *&cmap) const
Get the local off-diagonal block. NOTE: &#39;offd&#39; will not own any data.
Definition: hypre.cpp:975
HYPRE_Int * GetColStarts() const
Return the parallel column partitioning array.
Definition: hypre.hpp:436
HypreParVector & GetEigenvector(unsigned int i)
Extract a single eigenvector.
Definition: hypre.cpp:4066
double omega
SOR parameter (usually in (0,2))
Definition: hypre.hpp:601
HYPRE_Int * GetRowStarts() const
Return the parallel row partitioning array.
Definition: hypre.hpp:431
Base class for solvers.
Definition: operator.hpp:500
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
Definition: globals.hpp:66
Abstract operator.
Definition: operator.hpp:24
Wrapper for hypre&#39;s ParCSR matrix class.
Definition: hypre.hpp:187
void Swap(SparseMatrix &other)
Definition: sparsemat.cpp:3656
~HypreParVector()
Calls hypre&#39;s destroy function.
Definition: hypre.cpp:221
virtual void Mult(const HypreParVector &b, HypreParVector &x) const
Solve Ax=b with hypre&#39;s PCG.
Definition: hypre.cpp:2348
HypreParVector * Z
Definition: hypre.hpp:589
void Solve()
Solve the eigenproblem.
Definition: hypre.cpp:3808
void Read(MPI_Comm comm, const char *fname)
Reads the matrix from a file.
Definition: hypre.cpp:1441
HypreParVector * V
Temporary vectors.
Definition: hypre.hpp:589
void SetType(HypreSmoother::Type type, int relax_times=1)
Set the relaxation type and number of sweeps.
Definition: hypre.cpp:1894
int NumRows() const
Definition: array.hpp:337
int width
Dimension of the input / number of columns in the matrix.
Definition: operator.hpp:28
int poly_order
Order of the smoothing polynomial.
Definition: hypre.hpp:603
double lambda
Taubin&#39;s lambda-mu method parameters.
Definition: hypre.hpp:610
double sigma(const Vector &x)
Definition: maxwell.cpp:102