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