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