MFEM  v4.3.0
Finite element discretization library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
hypre.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
2 // at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3 // LICENSE and NOTICE for details. LLNL-CODE-806117.
4 //
5 // This file is part of the MFEM library. For more information and source code
6 // availability visit https://mfem.org.
7 //
8 // MFEM is free software; you can redistribute it and/or modify it under the
9 // terms of the BSD-3 license. We welcome feedback and contributions, see file
10 // CONTRIBUTING.md for details.
11 
12 #include "../config/config.hpp"
13 
14 #ifdef MFEM_USE_MPI
15 
16 #include "linalg.hpp"
17 #include "../fem/fem.hpp"
18 #include "../general/forall.hpp"
19 
20 #include <fstream>
21 #include <iomanip>
22 #include <cmath>
23 #include <cstdlib>
24 
25 #ifdef MFEM_USE_SUNDIALS
26 #include <nvector/nvector_parallel.h>
27 #endif
28 
29 using namespace std;
30 
31 namespace mfem
32 {
33 
34 template<typename TargetT, typename SourceT>
35 static TargetT *DuplicateAs(const SourceT *array, int size,
36  bool cplusplus = true)
37 {
38  TargetT *target_array = cplusplus ? (TargetT*) Memory<TargetT>(size)
39  /* */ : mfem_hypre_TAlloc_host(TargetT, size);
40  for (int i = 0; i < size; i++)
41  {
42  target_array[i] = array[i];
43  }
44  return target_array;
45 }
46 
47 
48 /// Return true if the @a src Memory can be used with the MemoryClass @a mc.
49 /** If this function returns true then src.{Read,Write,ReadWrite} can be called
50  safely with the MemoryClass @a mc. */
51 template <typename T>
52 bool CanShallowCopy(const Memory<T> &src, MemoryClass mc)
53 {
54  MemoryType src_h_mt = src.GetHostMemoryType();
55  MemoryType src_d_mt = src.GetDeviceMemoryType();
56  if (src_d_mt == MemoryType::DEFAULT)
57  {
58  src_d_mt = MemoryManager::GetDualMemoryType(src_h_mt);
59  }
60  return (MemoryClassContainsType(mc, src_h_mt) ||
61  MemoryClassContainsType(mc, src_d_mt));
62 }
63 
64 
65 inline void HypreParVector::_SetDataAndSize_()
66 {
67  hypre_Vector *x_loc = hypre_ParVectorLocalVector(x);
68 #ifndef HYPRE_USING_CUDA
69  SetDataAndSize(hypre_VectorData(x_loc),
70  internal::to_int(hypre_VectorSize(x_loc)));
71 #else
72  size = internal::to_int(hypre_VectorSize(x_loc));
73  MemoryType mt = (hypre_VectorMemoryLocation(x_loc) == HYPRE_MEMORY_HOST
74  ? MemoryType::HOST : GetHypreMemoryType());
75  if (hypre_VectorData(x_loc) != NULL)
76  {
77  data.Wrap(hypre_VectorData(x_loc), size, mt, false);
78  }
79  else
80  {
81  data.Reset();
82  }
83 #endif
84 }
85 
86 HypreParVector::HypreParVector(MPI_Comm comm, HYPRE_BigInt glob_size,
87  HYPRE_BigInt *col) : Vector()
88 {
89  x = hypre_ParVectorCreate(comm,glob_size,col);
90  hypre_ParVectorInitialize(x);
91  hypre_ParVectorSetPartitioningOwner(x,0);
92  // The data will be destroyed by hypre (this is the default)
93  hypre_ParVectorSetDataOwner(x,1);
94  hypre_SeqVectorSetDataOwner(hypre_ParVectorLocalVector(x),1);
95  _SetDataAndSize_();
96  own_ParVector = 1;
97 }
98 
100  double *data_, HYPRE_BigInt *col,
101  bool is_device_ptr)
102  : Vector()
103 {
104  x = hypre_ParVectorCreate(comm,glob_size,col);
105  hypre_ParVectorSetDataOwner(x,1); // owns the seq vector
106  hypre_Vector *x_loc = hypre_ParVectorLocalVector(x);
107  hypre_SeqVectorSetDataOwner(x_loc,0);
108  hypre_ParVectorSetPartitioningOwner(x,0);
109  double tmp = 0.0;
110  hypre_VectorData(x_loc) = &tmp;
111 #ifdef HYPRE_USING_CUDA
112  hypre_VectorMemoryLocation(x_loc) =
113  is_device_ptr ? HYPRE_MEMORY_DEVICE : HYPRE_MEMORY_HOST;
114 #else
115  (void)is_device_ptr;
116 #endif
117  // If hypre_ParVectorLocalVector(x) and &tmp are non-NULL,
118  // hypre_ParVectorInitialize(x) does not allocate memory!
119  hypre_ParVectorInitialize(x);
120  // Set the internal data array to the one passed in
121  hypre_VectorData(x_loc) = data_;
122  _SetDataAndSize_();
123  own_ParVector = 1;
124 }
125 
127 {
128  x = hypre_ParVectorCreate(y.x -> comm, y.x -> global_size,
129  y.x -> partitioning);
130  hypre_ParVectorInitialize(x);
131  hypre_ParVectorSetPartitioningOwner(x,0);
132  hypre_ParVectorSetDataOwner(x,1);
133  hypre_SeqVectorSetDataOwner(hypre_ParVectorLocalVector(x),1);
134  _SetDataAndSize_();
135  own_ParVector = 1;
136 }
137 
139  int transpose) : Vector()
140 {
141  if (!transpose)
142  {
143  x = hypre_ParVectorInDomainOf(const_cast<HypreParMatrix&>(A));
144  }
145  else
146  {
147  x = hypre_ParVectorInRangeOf(const_cast<HypreParMatrix&>(A));
148  }
149  _SetDataAndSize_();
150  own_ParVector = 1;
151 }
152 
154 {
155  x = (hypre_ParVector *) y;
156  _SetDataAndSize_();
157  own_ParVector = 0;
158 }
159 
161 {
162  x = hypre_ParVectorCreate(pfes->GetComm(), pfes->GlobalTrueVSize(),
163  pfes->GetTrueDofOffsets());
164  hypre_ParVectorInitialize(x);
165  hypre_ParVectorSetPartitioningOwner(x,0);
166  // The data will be destroyed by hypre (this is the default)
167  hypre_ParVectorSetDataOwner(x,1);
168  hypre_SeqVectorSetDataOwner(hypre_ParVectorLocalVector(x),1);
169  _SetDataAndSize_();
170  own_ParVector = 1;
171 }
172 
173 void HypreParVector::WrapHypreParVector(hypre_ParVector *y, bool owner)
174 {
175  if (own_ParVector) { hypre_ParVectorDestroy(x); }
176  Destroy();
177  x = y;
178  _SetDataAndSize_();
179  own_ParVector = owner;
180 }
181 
183 {
184  hypre_Vector *hv = hypre_ParVectorToVectorAll(*this);
185  Vector *v = new Vector(hv->data, internal::to_int(hv->size));
186  v->MakeDataOwner();
187  hypre_SeqVectorSetDataOwner(hv,0);
188  hypre_SeqVectorDestroy(hv);
189  return v;
190 }
191 
193 {
195  return *this;
196 }
197 
199 {
200 #ifdef MFEM_DEBUG
201  if (size != y.Size())
202  {
203  mfem_error("HypreParVector::operator=");
204  }
205 #endif
206 
208  return *this;
209 }
210 
211 void HypreParVector::SetData(double *data_)
212 {
213  hypre_VectorData(hypre_ParVectorLocalVector(x)) = data_;
214  Vector::SetData(data_);
215 }
216 
218 {
219  hypre_Vector *x_loc = hypre_ParVectorLocalVector(x);
220  hypre_VectorData(x_loc) =
221  const_cast<double*>(data.Read(GetHypreMemoryClass(), size));
222 #ifdef HYPRE_USING_CUDA
223  hypre_VectorMemoryLocation(x_loc) = HYPRE_MEMORY_DEVICE;
224 #endif
225 }
226 
228 {
229  hypre_Vector *x_loc = hypre_ParVectorLocalVector(x);
230  hypre_VectorData(x_loc) = data.ReadWrite(GetHypreMemoryClass(), size);
231 #ifdef HYPRE_USING_CUDA
232  hypre_VectorMemoryLocation(x_loc) = HYPRE_MEMORY_DEVICE;
233 #endif
234 }
235 
237 {
238  hypre_Vector *x_loc = hypre_ParVectorLocalVector(x);
239  hypre_VectorData(x_loc) = data.Write(GetHypreMemoryClass(), size);
240 #ifdef HYPRE_USING_CUDA
241  hypre_VectorMemoryLocation(x_loc) = HYPRE_MEMORY_DEVICE;
242 #endif
243 }
244 
246 {
247  MFEM_ASSERT(CanShallowCopy(mem, GetHypreMemoryClass()), "");
248  MFEM_ASSERT(mem.Capacity() >= size, "");
249 
250  data.Delete();
251  hypre_Vector *x_loc = hypre_ParVectorLocalVector(x);
252  hypre_VectorData(x_loc) =
253  const_cast<double*>(mem.Read(GetHypreMemoryClass(), size));
254 #ifdef HYPRE_USING_CUDA
255  hypre_VectorMemoryLocation(x_loc) = HYPRE_MEMORY_DEVICE;
256 #endif
257  data.MakeAlias(mem, 0, size);
258 }
259 
261 {
262  MFEM_ASSERT(CanShallowCopy(mem, GetHypreMemoryClass()), "");
263  MFEM_ASSERT(mem.Capacity() >= size, "");
264 
265  data.Delete();
266  hypre_Vector *x_loc = hypre_ParVectorLocalVector(x);
267  hypre_VectorData(x_loc) = mem.ReadWrite(GetHypreMemoryClass(), size);
268 #ifdef HYPRE_USING_CUDA
269  hypre_VectorMemoryLocation(x_loc) = HYPRE_MEMORY_DEVICE;
270 #endif
271  data.MakeAlias(mem, 0, size);
272 }
273 
275 {
276  MFEM_ASSERT(CanShallowCopy(mem, GetHypreMemoryClass()), "");
277  MFEM_ASSERT(mem.Capacity() >= size, "");
278 
279  data.Delete();
280  hypre_Vector *x_loc = hypre_ParVectorLocalVector(x);
281  hypre_VectorData(x_loc) = mem.Write(GetHypreMemoryClass(), size);
282 #ifdef HYPRE_USING_CUDA
283  hypre_VectorMemoryLocation(x_loc) = HYPRE_MEMORY_DEVICE;
284 #endif
285  data.MakeAlias(mem, 0, size);
286 }
287 
288 HYPRE_Int HypreParVector::Randomize(HYPRE_Int seed)
289 {
290  return hypre_ParVectorSetRandomValues(x,seed);
291 }
292 
293 void HypreParVector::Print(const char *fname) const
294 {
295  hypre_ParVectorPrint(x,fname);
296 }
297 
299 {
300  if (own_ParVector)
301  {
302  hypre_ParVectorDestroy(x);
303  }
304 }
305 
306 #ifdef MFEM_USE_SUNDIALS
307 
309 {
310  return N_VMake_Parallel(GetComm(), Size(), GlobalSize(), GetData());
311 }
312 
313 #endif // MFEM_USE_SUNDIALS
314 
315 
317 {
318  return hypre_ParVectorInnerProd(*x, *y);
319 }
320 
322 {
323  return hypre_ParVectorInnerProd(x, y);
324 }
325 
326 
327 double ParNormlp(const Vector &vec, double p, MPI_Comm comm)
328 {
329  double norm = 0.0;
330  if (p == 1.0)
331  {
332  double loc_norm = vec.Norml1();
333  MPI_Allreduce(&loc_norm, &norm, 1, MPI_DOUBLE, MPI_SUM, comm);
334  }
335  if (p == 2.0)
336  {
337  double loc_norm = vec*vec;
338  MPI_Allreduce(&loc_norm, &norm, 1, MPI_DOUBLE, MPI_SUM, comm);
339  norm = sqrt(norm);
340  }
341  if (p < infinity())
342  {
343  double sum = 0.0;
344  for (int i = 0; i < vec.Size(); i++)
345  {
346  sum += pow(fabs(vec(i)), p);
347  }
348  MPI_Allreduce(&sum, &norm, 1, MPI_DOUBLE, MPI_SUM, comm);
349  norm = pow(norm, 1.0/p);
350  }
351  else
352  {
353  double loc_norm = vec.Normlinf();
354  MPI_Allreduce(&loc_norm, &norm, 1, MPI_DOUBLE, MPI_MAX, comm);
355  }
356  return norm;
357 }
358 
359 /** @brief Shallow or deep copy @a src to @a dst with the goal to make the
360  array @a src accessible through @a dst with the MemoryClass @a dst_mc. If
361  one of the host/device MemoryType%s of @a src is contained in @a dst_mc,
362  then a shallow copy will be used and @a dst will simply be an alias of
363  @a src. Otherwise, @a dst will be properly allocated and @a src will be deep
364  copied to @a dst. */
365 /** If @a dst_owner is set to true and shallow copy is being used, then @a dst
366  will not be an alias of @a src; instead, @a src is copied to @a dst and all
367  ownership flags of @a src are reset.
368 
369  In both cases (deep or shallow copy), when @a dst is no longer needed,
370  dst.Delete() must be called to ensure all associated memory allocations are
371  freed.
372 
373  The input contents of @a dst, if any, is not used and it is overwritten by
374  this function. In particular, @a dst should be empty or deleted before
375  calling this function. */
376 template <typename T>
377 void CopyMemory(Memory<T> &src, Memory<T> &dst, MemoryClass dst_mc,
378  bool dst_owner)
379 {
380  if (CanShallowCopy(src, dst_mc))
381  {
382  // shallow copy
383  if (!dst_owner)
384  {
385  src.Read(dst_mc, src.Capacity()); // Registers src if on host only
386  dst.MakeAlias(src, 0, src.Capacity());
387  }
388  else
389  {
390  dst = src;
391  src.ClearOwnerFlags();
392  }
393  }
394  else
395  {
396  // deep copy
397  dst.New(src.Capacity(), GetMemoryType(dst_mc));
398  dst.CopyFrom(src, src.Capacity());
399  }
400 }
401 
402 /** @brief Deep copy and convert @a src to @a dst with the goal to make the
403  array @a src accessible through @a dst with the MemoryClass @a dst_mc and
404  convert it from type SrcT to type DstT. */
405 /** When @a dst is no longer needed, dst.Delete() must be called to ensure all
406  associated memory allocations are freed.
407 
408  The input contents of @a dst, if any, is not used and it is overwritten by
409  this function. In particular, @a dst should be empty or deleted before
410  calling this function. */
411 template <typename SrcT, typename DstT>
413 {
414  auto capacity = src.Capacity();
415  dst.New(capacity, GetMemoryType(dst_mc));
416  // Perform the copy using the configured mfem Device
417  auto src_p = mfem::Read(src, capacity);
418  auto dst_p = mfem::Write(dst, capacity);
419  MFEM_FORALL(i, capacity, dst_p[i] = src_p[i];);
420 }
421 
422 
423 void HypreParMatrix::Init()
424 {
425  A = NULL;
426  X = Y = NULL;
427  auxX.Reset(); auxY.Reset();
428  diagOwner = offdOwner = colMapOwner = -1;
429  ParCSROwner = 1;
430  mem_diag.I.Reset();
431  mem_diag.J.Reset();
432  mem_diag.data.Reset();
433  mem_offd.I.Reset();
434  mem_offd.J.Reset();
435  mem_offd.data.Reset();
436 }
437 
438 void HypreParMatrix::Read(MemoryClass mc) const
439 {
440  hypre_CSRMatrix *diag = hypre_ParCSRMatrixDiag(A);
441  hypre_CSRMatrix *offd = hypre_ParCSRMatrixOffd(A);
442  const int num_rows = NumRows();
443  const int diag_nnz = internal::to_int(diag->num_nonzeros);
444  const int offd_nnz = internal::to_int(offd->num_nonzeros);
445  diag->i = const_cast<HYPRE_Int*>(mem_diag.I.Read(mc, num_rows+1));
446  diag->j = const_cast<HYPRE_Int*>(mem_diag.J.Read(mc, diag_nnz));
447  diag->data = const_cast<double*>(mem_diag.data.Read(mc, diag_nnz));
448  offd->i = const_cast<HYPRE_Int*>(mem_offd.I.Read(mc, num_rows+1));
449  offd->j = const_cast<HYPRE_Int*>(mem_offd.J.Read(mc, offd_nnz));
450  offd->data = const_cast<double*>(mem_offd.data.Read(mc, offd_nnz));
451 #if MFEM_HYPRE_VERSION >= 21800
452  decltype(diag->memory_location) ml =
453  (mc != GetHypreMemoryClass() ? HYPRE_MEMORY_HOST : HYPRE_MEMORY_DEVICE);
454  diag->memory_location = ml;
455  offd->memory_location = ml;
456 #endif
457 }
458 
459 void HypreParMatrix::ReadWrite(MemoryClass mc)
460 {
461  hypre_CSRMatrix *diag = hypre_ParCSRMatrixDiag(A);
462  hypre_CSRMatrix *offd = hypre_ParCSRMatrixOffd(A);
463  const int num_rows = NumRows();
464  const int diag_nnz = internal::to_int(diag->num_nonzeros);
465  const int offd_nnz = internal::to_int(offd->num_nonzeros);
466  diag->i = mem_diag.I.ReadWrite(mc, num_rows+1);
467  diag->j = mem_diag.J.ReadWrite(mc, diag_nnz);
468  diag->data = mem_diag.data.ReadWrite(mc, diag_nnz);
469  offd->i = mem_offd.I.ReadWrite(mc, num_rows+1);
470  offd->j = mem_offd.J.ReadWrite(mc, offd_nnz);
471  offd->data = mem_offd.data.ReadWrite(mc, offd_nnz);
472 #if MFEM_HYPRE_VERSION >= 21800
473  decltype(diag->memory_location) ml =
474  (mc != GetHypreMemoryClass() ? HYPRE_MEMORY_HOST : HYPRE_MEMORY_DEVICE);
475  diag->memory_location = ml;
476  offd->memory_location = ml;
477 #endif
478 }
479 
480 void HypreParMatrix::Write(MemoryClass mc, bool set_diag, bool set_offd)
481 {
482  hypre_CSRMatrix *diag = hypre_ParCSRMatrixDiag(A);
483  hypre_CSRMatrix *offd = hypre_ParCSRMatrixOffd(A);
484  if (set_diag)
485  {
486  diag->i = mem_diag.I.Write(mc, mem_diag.I.Capacity());
487  diag->j = mem_diag.J.Write(mc, mem_diag.J.Capacity());
488  diag->data = mem_diag.data.Write(mc, mem_diag.data.Capacity());
489  }
490  if (set_offd)
491  {
492  offd->i = mem_offd.I.Write(mc, mem_offd.I.Capacity());
493  offd->j = mem_offd.J.Write(mc, mem_offd.J.Capacity());
494  offd->data = mem_offd.data.Write(mc, mem_offd.data.Capacity());
495  }
496 #if MFEM_HYPRE_VERSION >= 21800
497  decltype(diag->memory_location) ml =
498  (mc != GetHypreMemoryClass() ? HYPRE_MEMORY_HOST : HYPRE_MEMORY_DEVICE);
499  if (set_diag) { diag->memory_location = ml; }
500  if (set_offd) { offd->memory_location = ml; }
501 #endif
502 }
503 
505 {
506  Init();
507  height = width = 0;
508 }
509 
510 void HypreParMatrix::WrapHypreParCSRMatrix(hypre_ParCSRMatrix *a, bool owner)
511 {
512  Destroy();
513  Init();
514  A = a;
515  ParCSROwner = owner;
516  height = GetNumRows();
517  width = GetNumCols();
518 #if MFEM_HYPRE_VERSION >= 21800
519  MemoryType diag_mt = (A->diag->memory_location == HYPRE_MEMORY_HOST
521  MemoryType offd_mt = (A->offd->memory_location == HYPRE_MEMORY_HOST
523 #else
524  const MemoryType diag_mt = MemoryType::HOST;
525  const MemoryType offd_mt = MemoryType::HOST;
526 #endif
527  diagOwner = HypreCsrToMem(A->diag, diag_mt, false, mem_diag);
528  offdOwner = HypreCsrToMem(A->offd, offd_mt, false, mem_offd);
529  HypreRead();
530 }
531 
532 signed char HypreParMatrix::CopyCSR(SparseMatrix *csr,
533  MemoryIJData &mem_csr,
534  hypre_CSRMatrix *hypre_csr,
535  bool mem_owner)
536 {
537  const MemoryClass hypre_mc = GetHypreMemoryClass();
538 #ifndef HYPRE_BIGINT
539  // code for the case HYPRE_Int == int
540  CopyMemory(csr->GetMemoryI(), mem_csr.I, hypre_mc, mem_owner);
541  CopyMemory(csr->GetMemoryJ(), mem_csr.J, hypre_mc, mem_owner);
542 #else
543  // code for the case HYPRE_Int == long long int
544  CopyConvertMemory(csr->GetMemoryI(), hypre_mc, mem_csr.I);
545  CopyConvertMemory(csr->GetMemoryJ(), hypre_mc, mem_csr.J);
546 #endif
547  CopyMemory(csr->GetMemoryData(), mem_csr.data, hypre_mc, mem_owner);
548 
549  const int num_rows = csr->Height();
550  const int nnz = csr->NumNonZeroElems();
551  hypre_csr->i = const_cast<HYPRE_Int*>(mem_csr.I.Read(hypre_mc, num_rows+1));
552  hypre_csr->j = const_cast<HYPRE_Int*>(mem_csr.J.Read(hypre_mc, nnz));
553  hypre_csr->data = const_cast<double*>(mem_csr.data.Read(hypre_mc, nnz));
554 
555  MFEM_ASSERT(mem_csr.I.OwnsHostPtr() == mem_csr.J.OwnsHostPtr(),
556  "invalid state: host ownership for I and J differ!");
557  return (mem_csr.I.OwnsHostPtr() ? 1 : 0) +
558  (mem_csr.data.OwnsHostPtr() ? 2 : 0);
559 }
560 
561 signed char HypreParMatrix::CopyBoolCSR(Table *bool_csr,
562  MemoryIJData &mem_csr,
563  hypre_CSRMatrix *hypre_csr)
564 {
565  const MemoryClass hypre_mc = GetHypreMemoryClass();
566 #ifndef HYPRE_BIGINT
567  // code for the case HYPRE_Int == int
568  CopyMemory(bool_csr->GetIMemory(), mem_csr.I, hypre_mc, false);
569  CopyMemory(bool_csr->GetJMemory(), mem_csr.J, hypre_mc, false);
570 #else
571  // code for the case HYPRE_Int == long long int
572  CopyConvertMemory(bool_csr->GetIMemory(), hypre_mc, mem_csr.I);
573  CopyConvertMemory(bool_csr->GetJMemory(), hypre_mc, mem_csr.J);
574 #endif
575  const int num_rows = bool_csr->Size();
576  const int nnz = bool_csr->Size_of_connections();
577  mem_csr.data.New(nnz, GetHypreMemoryType());
578  double *data = mfem::HostWrite(mem_csr.data, nnz);
579  for (int i = 0; i < nnz; i++)
580  {
581  data[i] = 1.0;
582  }
583  hypre_csr->i = const_cast<HYPRE_Int*>(mem_csr.I.Read(hypre_mc, num_rows+1));
584  hypre_csr->j = const_cast<HYPRE_Int*>(mem_csr.J.Read(hypre_mc, nnz));
585  hypre_csr->data = const_cast<double*>(mem_csr.data.Read(hypre_mc, nnz));
586 
587  MFEM_ASSERT(mem_csr.I.OwnsHostPtr() == mem_csr.J.OwnsHostPtr(),
588  "invalid state: host ownership for I and J differ!");
589  return (mem_csr.I.OwnsHostPtr() ? 1 : 0) +
590  (mem_csr.data.OwnsHostPtr() ? 2 : 0);
591 }
592 
593 void HypreParMatrix::CopyCSR_J(hypre_CSRMatrix *hypre_csr, int *J)
594 {
595  HYPRE_Int nnz = hypre_CSRMatrixNumNonzeros(hypre_csr);
596 #if MFEM_HYPRE_VERSION >= 21600
597  if (hypre_CSRMatrixBigJ(hypre_csr))
598  {
599  for (HYPRE_Int j = 0; j < nnz; j++)
600  {
601  J[j] = internal::to_int(hypre_CSRMatrixBigJ(hypre_csr)[j]);
602  }
603  return;
604  }
605 #endif
606  for (HYPRE_Int j = 0; j < nnz; j++)
607  {
608  J[j] = internal::to_int(hypre_CSRMatrixJ(hypre_csr)[j]);
609  }
610 }
611 
612 // static method
613 signed char HypreParMatrix::HypreCsrToMem(hypre_CSRMatrix *h_mat,
614  MemoryType h_mat_mt,
615  bool own_ija,
616  MemoryIJData &mem)
617 {
618  const int nr1 = internal::to_int(h_mat->num_rows) + 1;
619  const int nnz = internal::to_int(h_mat->num_nonzeros);
620  mem.I.Wrap(h_mat->i, nr1, h_mat_mt, own_ija);
621  mem.J.Wrap(h_mat->j, nnz, h_mat_mt, own_ija);
622  mem.data.Wrap(h_mat->data, nnz, h_mat_mt, own_ija);
623  const MemoryClass hypre_mc = GetHypreMemoryClass();
624  if (!CanShallowCopy(mem.I, hypre_mc))
625  {
626  const MemoryType hypre_mt = GetHypreMemoryType();
627  MemoryIJData h_mem;
628  h_mem.I.New(nr1, hypre_mt);
629  h_mem.I.CopyFrom(mem.I, nr1);
630  mem.I.Delete();
631  h_mem.J.New(nnz, hypre_mt);
632  h_mem.J.CopyFrom(mem.J, nnz);
633  mem.J.Delete();
634  h_mem.data.New(nnz, hypre_mt);
635  h_mem.data.CopyFrom(mem.data, nnz);
636  mem.data.Delete();
637  mem = h_mem;
638  if (!own_ija)
639  {
640  // FIXME: Even if own_ija == false, it does not necessarily mean we
641  // need to delete h_mat->{i,j,data} even if h_mat->owns_data == true.
642 
643  // h_mat owns i; owns j,data if h_mat->owns_data
644 #if MFEM_HYPRE_VERSION < 21400
645  hypre_TFree(h_mat->i);
646 #elif MFEM_HYPRE_VERSION < 21800
647  hypre_TFree(h_mat->i, HYPRE_MEMORY_SHARED);
648 #else
649  hypre_TFree(h_mat->i, h_mat->memory_location);
650 #endif
651  if (h_mat->owns_data)
652  {
653 #if MFEM_HYPRE_VERSION < 21400
654  hypre_TFree(h_mat->j);
655  hypre_TFree(h_mat->data);
656 #elif MFEM_HYPRE_VERSION < 21800
657  hypre_TFree(h_mat->j, HYPRE_MEMORY_SHARED);
658  hypre_TFree(h_mat->data, HYPRE_MEMORY_SHARED);
659 #else
660  hypre_TFree(h_mat->j, h_mat->memory_location);
661  hypre_TFree(h_mat->data, h_mat->memory_location);
662 #endif
663  }
664  }
665  h_mat->i = mem.I.ReadWrite(hypre_mc, nr1);
666  h_mat->j = mem.J.ReadWrite(hypre_mc, nnz);
667  h_mat->data = mem.data.ReadWrite(hypre_mc, nnz);
668  h_mat->owns_data = 0;
669 #if MFEM_HYPRE_VERSION >= 21800
670  h_mat->memory_location = HYPRE_MEMORY_DEVICE;
671 #endif
672  return 3;
673  }
674  return own_ija ? 3 : (h_mat_mt == GetHypreMemoryType() ? -2 : -1);
675 }
676 
677 // Square block-diagonal constructor (4 arguments, v1)
679  HYPRE_BigInt *row_starts, SparseMatrix *diag)
680  : Operator(diag->Height(), diag->Width())
681 {
682  Init();
683  A = hypre_ParCSRMatrixCreate(comm, glob_size, glob_size, row_starts,
684  row_starts, 0, diag->NumNonZeroElems(), 0);
685  hypre_ParCSRMatrixSetDataOwner(A,1);
686  hypre_ParCSRMatrixSetRowStartsOwner(A,0);
687  hypre_ParCSRMatrixSetColStartsOwner(A,0);
688 
689  hypre_CSRMatrixSetDataOwner(A->diag,0);
690  diagOwner = CopyCSR(diag, mem_diag, A->diag, false);
691  hypre_CSRMatrixSetRownnz(A->diag);
692 
693  hypre_CSRMatrixSetDataOwner(A->offd,1);
694  hypre_CSRMatrixI(A->offd) = mfem_hypre_CTAlloc(HYPRE_Int, diag->Height()+1);
695  offdOwner = HypreCsrToMem(A->offd, GetHypreMemoryType(), false, mem_offd);
696 
697  /* Don't need to call these, since they allocate memory only
698  if it was not already allocated */
699  // hypre_CSRMatrixInitialize(A->diag);
700  // hypre_ParCSRMatrixInitialize(A);
701 
702  hypre_ParCSRMatrixSetNumNonzeros(A);
703 
704  /* Make sure that the first entry in each row is the diagonal one. */
705  hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
706 
707  // FIXME:
708 #ifdef HYPRE_BIGINT
709  CopyCSR_J(A->diag, diag->GetJ());
710 #endif
711 
712  hypre_MatvecCommPkgCreate(A);
713 }
714 
715 // Rectangular block-diagonal constructor (6 arguments, v1)
717  HYPRE_BigInt global_num_rows,
718  HYPRE_BigInt global_num_cols,
719  HYPRE_BigInt *row_starts,
720  HYPRE_BigInt *col_starts,
721  SparseMatrix *diag)
722  : Operator(diag->Height(), diag->Width())
723 {
724  Init();
725  A = hypre_ParCSRMatrixCreate(comm, global_num_rows, global_num_cols,
726  row_starts, col_starts,
727  0, diag->NumNonZeroElems(), 0);
728  hypre_ParCSRMatrixSetDataOwner(A,1);
729  hypre_ParCSRMatrixSetRowStartsOwner(A,0);
730  hypre_ParCSRMatrixSetColStartsOwner(A,0);
731 
732  hypre_CSRMatrixSetDataOwner(A->diag,0);
733  diagOwner = CopyCSR(diag, mem_diag, A->diag, false);
734  hypre_CSRMatrixSetRownnz(A->diag);
735 
736  hypre_CSRMatrixSetDataOwner(A->offd,1);
737  hypre_CSRMatrixI(A->offd) = mfem_hypre_CTAlloc(HYPRE_Int, diag->Height()+1);
738  offdOwner = HypreCsrToMem(A->offd, GetHypreMemoryType(), false, mem_offd);
739 
740  hypre_ParCSRMatrixSetNumNonzeros(A);
741 
742  /* Make sure that the first entry in each row is the diagonal one. */
743  if (row_starts == col_starts)
744  {
745  hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
746  // FIXME:
747 #ifdef HYPRE_BIGINT
748  CopyCSR_J(A->diag, diag->GetJ());
749 #endif
750  }
751 
752  hypre_MatvecCommPkgCreate(A);
753 }
754 
755 // General rectangular constructor with diagonal and off-diagonal (8+1
756 // arguments)
758  HYPRE_BigInt global_num_rows,
759  HYPRE_BigInt global_num_cols,
760  HYPRE_BigInt *row_starts,
761  HYPRE_BigInt *col_starts,
762  SparseMatrix *diag, SparseMatrix *offd,
763  HYPRE_BigInt *cmap,
764  bool own_diag_offd)
765  : Operator(diag->Height(), diag->Width())
766 {
767  Init();
768  A = hypre_ParCSRMatrixCreate(comm, global_num_rows, global_num_cols,
769  row_starts, col_starts,
770  offd->Width(), diag->NumNonZeroElems(),
771  offd->NumNonZeroElems());
772  hypre_ParCSRMatrixSetDataOwner(A,1);
773  hypre_ParCSRMatrixSetRowStartsOwner(A,0);
774  hypre_ParCSRMatrixSetColStartsOwner(A,0);
775 
776  hypre_CSRMatrixSetDataOwner(A->diag,0);
777  diagOwner = CopyCSR(diag, mem_diag, A->diag, own_diag_offd);
778  if (own_diag_offd) { delete diag; }
779  hypre_CSRMatrixSetRownnz(A->diag);
780 
781  hypre_CSRMatrixSetDataOwner(A->offd,0);
782  offdOwner = CopyCSR(offd, mem_offd, A->offd, own_diag_offd);
783  if (own_diag_offd) { delete offd; }
784  hypre_CSRMatrixSetRownnz(A->offd);
785 
786  hypre_ParCSRMatrixColMapOffd(A) = cmap;
787  // Prevent hypre from destroying A->col_map_offd
788  colMapOwner = 0;
789 
790  hypre_ParCSRMatrixSetNumNonzeros(A);
791 
792  /* Make sure that the first entry in each row is the diagonal one. */
793  if (row_starts == col_starts)
794  {
795  hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
796  // FIXME:
797 #ifdef HYPRE_BIGINT
798  CopyCSR_J(A->diag, diag->GetJ());
799 #endif
800  }
801 
802  hypre_MatvecCommPkgCreate(A);
803 }
804 
805 // General rectangular constructor with diagonal and off-diagonal (13+1
806 // arguments)
808  MPI_Comm comm,
809  HYPRE_BigInt global_num_rows, HYPRE_BigInt global_num_cols,
810  HYPRE_BigInt *row_starts, HYPRE_BigInt *col_starts,
811  HYPRE_Int *diag_i, HYPRE_Int *diag_j, double *diag_data,
812  HYPRE_Int *offd_i, HYPRE_Int *offd_j, double *offd_data,
813  HYPRE_Int offd_num_cols, HYPRE_BigInt *offd_col_map,
814  bool hypre_arrays)
815 {
816  Init();
817  A = hypre_ParCSRMatrixCreate(comm, global_num_rows, global_num_cols,
818  row_starts, col_starts, offd_num_cols, 0, 0);
819  hypre_ParCSRMatrixSetDataOwner(A,1);
820  hypre_ParCSRMatrixSetRowStartsOwner(A,0);
821  hypre_ParCSRMatrixSetColStartsOwner(A,0);
822 
823  HYPRE_Int local_num_rows = hypre_CSRMatrixNumRows(A->diag);
824 
825  hypre_CSRMatrixSetDataOwner(A->diag, hypre_arrays);
826  hypre_CSRMatrixI(A->diag) = diag_i;
827  hypre_CSRMatrixJ(A->diag) = diag_j;
828  hypre_CSRMatrixData(A->diag) = diag_data;
829  hypre_CSRMatrixNumNonzeros(A->diag) = diag_i[local_num_rows];
830 #ifdef HYPRE_USING_CUDA
831  hypre_CSRMatrixMemoryLocation(A->diag) = HYPRE_MEMORY_HOST;
832 #endif
833  hypre_CSRMatrixSetRownnz(A->diag);
834 
835  hypre_CSRMatrixSetDataOwner(A->offd, hypre_arrays);
836  hypre_CSRMatrixI(A->offd) = offd_i;
837  hypre_CSRMatrixJ(A->offd) = offd_j;
838  hypre_CSRMatrixData(A->offd) = offd_data;
839  hypre_CSRMatrixNumNonzeros(A->offd) = offd_i[local_num_rows];
840 #ifdef HYPRE_USING_CUDA
841  hypre_CSRMatrixMemoryLocation(A->offd) = HYPRE_MEMORY_HOST;
842 #endif
843  hypre_CSRMatrixSetRownnz(A->offd);
844 
845  hypre_ParCSRMatrixColMapOffd(A) = offd_col_map;
846  // Prevent hypre from destroying A->col_map_offd, own A->col_map_offd
847  colMapOwner = hypre_arrays ? -1 : 1;
848 
849  hypre_ParCSRMatrixSetNumNonzeros(A);
850 
851  /* Make sure that the first entry in each row is the diagonal one. */
852  if (row_starts == col_starts)
853  {
854  hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
855  }
856 
857  hypre_MatvecCommPkgCreate(A);
858 
859  height = GetNumRows();
860  width = GetNumCols();
861 
862  if (!hypre_arrays)
863  {
864  const MemoryType host_mt = Device::GetHostMemoryType();
865  diagOwner = HypreCsrToMem(A->diag, host_mt, true, mem_diag);
866  offdOwner = HypreCsrToMem(A->offd, host_mt, true, mem_offd);
867  }
868  else
869  {
870  const MemoryType host_mt = MemoryType::HOST;
871  diagOwner = HypreCsrToMem(A->diag, host_mt, false, mem_diag);
872  offdOwner = HypreCsrToMem(A->offd, host_mt, false, mem_offd);
873  }
874  HypreRead();
875 }
876 
877 // Constructor from a CSR matrix on rank 0 (4 arguments, v2)
879  HYPRE_BigInt *row_starts,
880  HYPRE_BigInt *col_starts,
881  SparseMatrix *sm_a)
882 {
883  MFEM_ASSERT(sm_a != NULL, "invalid input");
884  MFEM_VERIFY(!HYPRE_AssumedPartitionCheck(),
885  "this method can not be used with assumed partition");
886 
887  Init();
888 
889  hypre_CSRMatrix *csr_a;
890  csr_a = hypre_CSRMatrixCreate(sm_a -> Height(), sm_a -> Width(),
891  sm_a -> NumNonZeroElems());
892 
893  hypre_CSRMatrixSetDataOwner(csr_a,0);
894  MemoryIJData mem_a;
895  CopyCSR(sm_a, mem_a, csr_a, false);
896  hypre_CSRMatrixSetRownnz(csr_a);
897 
898  // NOTE: this call creates a matrix on host even when device support is
899  // enabled in hypre.
900  hypre_ParCSRMatrix *new_A =
901  hypre_CSRMatrixToParCSRMatrix(comm, csr_a, row_starts, col_starts);
902 
903  mem_a.I.Delete();
904  mem_a.J.Delete();
905  mem_a.data.Delete();
906 
907  hypre_CSRMatrixI(csr_a) = NULL;
908  hypre_CSRMatrixDestroy(csr_a);
909 
910  /* Make sure that the first entry in each row is the diagonal one. */
911  if (row_starts == col_starts)
912  {
913  hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(new_A));
914  }
915 
916  hypre_MatvecCommPkgCreate(A);
917 
918  WrapHypreParCSRMatrix(new_A);
919 }
920 
921 // Boolean, rectangular, block-diagonal constructor (6 arguments, v2)
923  HYPRE_BigInt global_num_rows,
924  HYPRE_BigInt global_num_cols,
925  HYPRE_BigInt *row_starts,
926  HYPRE_BigInt *col_starts,
927  Table *diag)
928 {
929  Init();
930  int nnz = diag->Size_of_connections();
931  A = hypre_ParCSRMatrixCreate(comm, global_num_rows, global_num_cols,
932  row_starts, col_starts, 0, nnz, 0);
933  hypre_ParCSRMatrixSetDataOwner(A,1);
934  hypre_ParCSRMatrixSetRowStartsOwner(A,0);
935  hypre_ParCSRMatrixSetColStartsOwner(A,0);
936 
937  hypre_CSRMatrixSetDataOwner(A->diag,0);
938  diagOwner = CopyBoolCSR(diag, mem_diag, A->diag);
939  hypre_CSRMatrixSetRownnz(A->diag);
940 
941  hypre_CSRMatrixSetDataOwner(A->offd,1);
942  hypre_CSRMatrixI(A->offd) = mfem_hypre_CTAlloc(HYPRE_Int, diag->Size()+1);
943  offdOwner = HypreCsrToMem(A->offd, GetHypreMemoryType(), false, mem_offd);
944 
945  hypre_ParCSRMatrixSetNumNonzeros(A);
946 
947  /* Make sure that the first entry in each row is the diagonal one. */
948  if (row_starts == col_starts)
949  {
950  hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
951  // FIXME:
952 #ifdef HYPRE_BIGINT
953  CopyCSR_J(A->diag, diag->GetJ());
954 #endif
955  }
956 
957  hypre_MatvecCommPkgCreate(A);
958 
959  height = GetNumRows();
960  width = GetNumCols();
961 }
962 
963 // Boolean, general rectangular constructor with diagonal and off-diagonal
964 // (11 arguments)
965 HypreParMatrix::HypreParMatrix(MPI_Comm comm, int id, int np,
966  HYPRE_BigInt *row, HYPRE_BigInt *col,
967  HYPRE_Int *i_diag, HYPRE_Int *j_diag,
968  HYPRE_Int *i_offd, HYPRE_Int *j_offd,
969  HYPRE_BigInt *cmap, HYPRE_Int cmap_size)
970 {
971  HYPRE_Int diag_nnz, offd_nnz;
972 
973  Init();
974  if (HYPRE_AssumedPartitionCheck())
975  {
976  diag_nnz = i_diag[row[1]-row[0]];
977  offd_nnz = i_offd[row[1]-row[0]];
978 
979  A = hypre_ParCSRMatrixCreate(comm, row[2], col[2], row, col,
980  cmap_size, diag_nnz, offd_nnz);
981  }
982  else
983  {
984  diag_nnz = i_diag[row[id+1]-row[id]];
985  offd_nnz = i_offd[row[id+1]-row[id]];
986 
987  A = hypre_ParCSRMatrixCreate(comm, row[np], col[np], row, col,
988  cmap_size, diag_nnz, offd_nnz);
989  }
990 
991  hypre_ParCSRMatrixSetDataOwner(A,1);
992  hypre_ParCSRMatrixSetRowStartsOwner(A,0);
993  hypre_ParCSRMatrixSetColStartsOwner(A,0);
994 
995  mem_diag.data.New(diag_nnz);
996  for (HYPRE_Int i = 0; i < diag_nnz; i++)
997  {
998  mem_diag.data[i] = 1.0;
999  }
1000 
1001  mem_offd.data.New(offd_nnz);
1002  for (HYPRE_Int i = 0; i < offd_nnz; i++)
1003  {
1004  mem_offd.data[i] = 1.0;
1005  }
1006 
1007  hypre_CSRMatrixSetDataOwner(A->diag,0);
1008  hypre_CSRMatrixI(A->diag) = i_diag;
1009  hypre_CSRMatrixJ(A->diag) = j_diag;
1010  hypre_CSRMatrixData(A->diag) = mem_diag.data;
1011 #ifdef HYPRE_USING_CUDA
1012  hypre_CSRMatrixMemoryLocation(A->diag) = HYPRE_MEMORY_HOST;
1013 #endif
1014  hypre_CSRMatrixSetRownnz(A->diag);
1015 
1016  hypre_CSRMatrixSetDataOwner(A->offd,0);
1017  hypre_CSRMatrixI(A->offd) = i_offd;
1018  hypre_CSRMatrixJ(A->offd) = j_offd;
1019  hypre_CSRMatrixData(A->offd) = mem_offd.data;
1020 #ifdef HYPRE_USING_CUDA
1021  hypre_CSRMatrixMemoryLocation(A->offd) = HYPRE_MEMORY_HOST;
1022 #endif
1023  hypre_CSRMatrixSetRownnz(A->offd);
1024 
1025  hypre_ParCSRMatrixColMapOffd(A) = cmap;
1026  // Prevent hypre from destroying A->col_map_offd, own A->col_map_offd
1027  colMapOwner = 1;
1028 
1029  hypre_ParCSRMatrixSetNumNonzeros(A);
1030 
1031  /* Make sure that the first entry in each row is the diagonal one. */
1032  if (row == col)
1033  {
1034  hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
1035  }
1036 
1037  hypre_MatvecCommPkgCreate(A);
1038 
1039  height = GetNumRows();
1040  width = GetNumCols();
1041 
1042  const MemoryType host_mt = Device::GetHostMemoryType();
1043  diagOwner = HypreCsrToMem(A->diag, host_mt, true, mem_diag);
1044  offdOwner = HypreCsrToMem(A->offd, host_mt, true, mem_offd);
1045  HypreRead();
1046 }
1047 
1048 // General rectangular constructor with diagonal and off-diagonal constructed
1049 // from a CSR matrix that contains both diagonal and off-diagonal blocks
1050 // (9 arguments)
1051 HypreParMatrix::HypreParMatrix(MPI_Comm comm, int nrows,
1052  HYPRE_BigInt glob_nrows,
1053  HYPRE_BigInt glob_ncols,
1054  int *I, HYPRE_BigInt *J,
1055  double *data,
1056  HYPRE_BigInt *rows,
1057  HYPRE_BigInt *cols)
1058 {
1059  Init();
1060 
1061  // Determine partitioning size, and my column start and end
1062  int part_size;
1063  HYPRE_BigInt my_col_start, my_col_end; // my range: [my_col_start, my_col_end)
1064  if (HYPRE_AssumedPartitionCheck())
1065  {
1066  part_size = 2;
1067  my_col_start = cols[0];
1068  my_col_end = cols[1];
1069  }
1070  else
1071  {
1072  int myid;
1073  MPI_Comm_rank(comm, &myid);
1074  MPI_Comm_size(comm, &part_size);
1075  part_size++;
1076  my_col_start = cols[myid];
1077  my_col_end = cols[myid+1];
1078  }
1079 
1080  // Copy in the row and column partitionings
1081  HYPRE_BigInt *row_starts, *col_starts;
1082  if (rows == cols)
1083  {
1084  row_starts = col_starts = mfem_hypre_TAlloc_host(HYPRE_BigInt, part_size);
1085  for (int i = 0; i < part_size; i++)
1086  {
1087  row_starts[i] = rows[i];
1088  }
1089  }
1090  else
1091  {
1092  row_starts = mfem_hypre_TAlloc_host(HYPRE_BigInt, part_size);
1093  col_starts = mfem_hypre_TAlloc_host(HYPRE_BigInt, part_size);
1094  for (int i = 0; i < part_size; i++)
1095  {
1096  row_starts[i] = rows[i];
1097  col_starts[i] = cols[i];
1098  }
1099  }
1100 
1101  // Create a map for the off-diagonal indices - global to local. Count the
1102  // number of diagonal and off-diagonal entries.
1103  HYPRE_Int diag_nnz = 0, offd_nnz = 0, offd_num_cols = 0;
1104  map<HYPRE_BigInt, HYPRE_Int> offd_map;
1105  for (HYPRE_Int j = 0, loc_nnz = I[nrows]; j < loc_nnz; j++)
1106  {
1107  HYPRE_BigInt glob_col = J[j];
1108  if (my_col_start <= glob_col && glob_col < my_col_end)
1109  {
1110  diag_nnz++;
1111  }
1112  else
1113  {
1114  offd_map.insert(pair<const HYPRE_BigInt, HYPRE_Int>(glob_col, -1));
1115  offd_nnz++;
1116  }
1117  }
1118  // count the number of columns in the off-diagonal and set the local indices
1119  for (auto it = offd_map.begin(); it != offd_map.end(); ++it)
1120  {
1121  it->second = offd_num_cols++;
1122  }
1123 
1124  // construct the global ParCSR matrix
1125  A = hypre_ParCSRMatrixCreate(comm, glob_nrows, glob_ncols,
1126  row_starts, col_starts, offd_num_cols,
1127  diag_nnz, offd_nnz);
1128  hypre_ParCSRMatrixInitialize(A);
1129 
1130  diagOwner = HypreCsrToMem(A->diag, GetHypreMemoryType(), false, mem_diag);
1131  offdOwner = HypreCsrToMem(A->offd, GetHypreMemoryType(), false, mem_offd);
1132  HostWrite();
1133 
1134  HYPRE_Int *diag_i, *diag_j, *offd_i, *offd_j;
1135  HYPRE_BigInt *offd_col_map;
1136  double *diag_data, *offd_data;
1137  diag_i = A->diag->i;
1138  diag_j = A->diag->j;
1139  diag_data = A->diag->data;
1140  offd_i = A->offd->i;
1141  offd_j = A->offd->j;
1142  offd_data = A->offd->data;
1143  offd_col_map = A->col_map_offd;
1144 
1145  diag_nnz = offd_nnz = 0;
1146  for (HYPRE_Int i = 0, j = 0; i < nrows; i++)
1147  {
1148  diag_i[i] = diag_nnz;
1149  offd_i[i] = offd_nnz;
1150  for (HYPRE_Int j_end = I[i+1]; j < j_end; j++)
1151  {
1152  HYPRE_BigInt glob_col = J[j];
1153  if (my_col_start <= glob_col && glob_col < my_col_end)
1154  {
1155  diag_j[diag_nnz] = glob_col - my_col_start;
1156  diag_data[diag_nnz] = data[j];
1157  diag_nnz++;
1158  }
1159  else
1160  {
1161  offd_j[offd_nnz] = offd_map[glob_col];
1162  offd_data[offd_nnz] = data[j];
1163  offd_nnz++;
1164  }
1165  }
1166  }
1167  diag_i[nrows] = diag_nnz;
1168  offd_i[nrows] = offd_nnz;
1169  for (auto it = offd_map.begin(); it != offd_map.end(); ++it)
1170  {
1171  offd_col_map[it->second] = it->first;
1172  }
1173 
1174  hypre_ParCSRMatrixSetNumNonzeros(A);
1175  /* Make sure that the first entry in each row is the diagonal one. */
1176  if (row_starts == col_starts)
1177  {
1178  hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
1179  }
1180  hypre_MatvecCommPkgCreate(A);
1181 
1182  height = GetNumRows();
1183  width = GetNumCols();
1184 
1185  HypreRead();
1186 }
1187 
1189 {
1190  hypre_ParCSRMatrix *Ph = static_cast<hypre_ParCSRMatrix *>(P);
1191 
1192  Init();
1193 
1194  // Clone the structure
1195  A = hypre_ParCSRMatrixCompleteClone(Ph);
1196  // Make a deep copy of the data from the source
1197  hypre_ParCSRMatrixCopy(Ph, A, 1);
1198 
1199  height = GetNumRows();
1200  width = GetNumCols();
1201 
1202  CopyRowStarts();
1203  CopyColStarts();
1204 
1205  hypre_ParCSRMatrixSetNumNonzeros(A);
1206 
1207  hypre_MatvecCommPkgCreate(A);
1208 
1209  diagOwner = HypreCsrToMem(A->diag, GetHypreMemoryType(), false, mem_diag);
1210  offdOwner = HypreCsrToMem(A->offd, GetHypreMemoryType(), false, mem_offd);
1211 }
1212 
1214 {
1215  Destroy();
1216  Init();
1217  A = master.A;
1218  ParCSROwner = 0;
1219  height = master.GetNumRows();
1220  width = master.GetNumCols();
1221  mem_diag.I.MakeAlias(master.mem_diag.I, 0, master.mem_diag.I.Capacity());
1222  mem_diag.J.MakeAlias(master.mem_diag.J, 0, master.mem_diag.J.Capacity());
1223  mem_diag.data.MakeAlias(master.mem_diag.data, 0,
1224  master.mem_diag.data.Capacity());
1225  mem_offd.I.MakeAlias(master.mem_offd.I, 0, master.mem_offd.I.Capacity());
1226  mem_offd.J.MakeAlias(master.mem_offd.J, 0, master.mem_offd.J.Capacity());
1227  mem_offd.data.MakeAlias(master.mem_offd.data, 0,
1228  master.mem_offd.data.Capacity());
1229 }
1230 
1231 hypre_ParCSRMatrix* HypreParMatrix::StealData()
1232 {
1233  // Only safe when (diagOwner < 0 && offdOwner < 0 && colMapOwner == -1)
1234  // Otherwise, there may be memory leaks or hypre may destroy arrays allocated
1235  // with operator new.
1236  MFEM_ASSERT(diagOwner < 0 && offdOwner < 0 && colMapOwner == -1, "");
1237  MFEM_ASSERT(diagOwner == offdOwner, "");
1238  MFEM_ASSERT(ParCSROwner, "");
1239  hypre_ParCSRMatrix *R = A;
1240 #ifdef HYPRE_USING_CUDA
1241  if (diagOwner == -1) { HostReadWrite(); }
1242  else { HypreReadWrite(); }
1243 #endif
1244  ParCSROwner = false;
1245  Destroy();
1246  Init();
1247  return R;
1248 }
1249 
1250 void HypreParMatrix::SetOwnerFlags(signed char diag, signed char offd,
1251  signed char colmap)
1252 {
1253  diagOwner = diag;
1254  mem_diag.I.SetHostPtrOwner((diag >= 0) && (diag & 1));
1255  mem_diag.J.SetHostPtrOwner((diag >= 0) && (diag & 1));
1256  mem_diag.data.SetHostPtrOwner((diag >= 0) && (diag & 2));
1257  offdOwner = offd;
1258  mem_offd.I.SetHostPtrOwner((offd >= 0) && (offd & 1));
1259  mem_offd.J.SetHostPtrOwner((offd >= 0) && (offd & 1));
1260  mem_offd.data.SetHostPtrOwner((offd >= 0) && (offd & 2));
1261  colMapOwner = colmap;
1262 }
1263 
1265 {
1266  if (!A || hypre_ParCSRMatrixOwnsRowStarts(A) ||
1267  (hypre_ParCSRMatrixRowStarts(A) == hypre_ParCSRMatrixColStarts(A) &&
1268  hypre_ParCSRMatrixOwnsColStarts(A)))
1269  {
1270  return;
1271  }
1272 
1273  int row_starts_size;
1274  if (HYPRE_AssumedPartitionCheck())
1275  {
1276  row_starts_size = 2;
1277  }
1278  else
1279  {
1280  MPI_Comm_size(hypre_ParCSRMatrixComm(A), &row_starts_size);
1281  row_starts_size++; // num_proc + 1
1282  }
1283 
1284  HYPRE_BigInt *old_row_starts = hypre_ParCSRMatrixRowStarts(A);
1285  HYPRE_BigInt *new_row_starts = mfem_hypre_CTAlloc_host(HYPRE_BigInt,
1286  row_starts_size);
1287  for (int i = 0; i < row_starts_size; i++)
1288  {
1289  new_row_starts[i] = old_row_starts[i];
1290  }
1291 
1292  hypre_ParCSRMatrixRowStarts(A) = new_row_starts;
1293  hypre_ParCSRMatrixOwnsRowStarts(A) = 1;
1294 
1295  if (hypre_ParCSRMatrixColStarts(A) == old_row_starts)
1296  {
1297  hypre_ParCSRMatrixColStarts(A) = new_row_starts;
1298  hypre_ParCSRMatrixOwnsColStarts(A) = 0;
1299  }
1300 }
1301 
1303 {
1304  if (!A || hypre_ParCSRMatrixOwnsColStarts(A) ||
1305  (hypre_ParCSRMatrixRowStarts(A) == hypre_ParCSRMatrixColStarts(A) &&
1306  hypre_ParCSRMatrixOwnsRowStarts(A)))
1307  {
1308  return;
1309  }
1310 
1311  int col_starts_size;
1312  if (HYPRE_AssumedPartitionCheck())
1313  {
1314  col_starts_size = 2;
1315  }
1316  else
1317  {
1318  MPI_Comm_size(hypre_ParCSRMatrixComm(A), &col_starts_size);
1319  col_starts_size++; // num_proc + 1
1320  }
1321 
1322  HYPRE_BigInt *old_col_starts = hypre_ParCSRMatrixColStarts(A);
1323  HYPRE_BigInt *new_col_starts = mfem_hypre_CTAlloc_host(HYPRE_BigInt,
1324  col_starts_size);
1325  for (int i = 0; i < col_starts_size; i++)
1326  {
1327  new_col_starts[i] = old_col_starts[i];
1328  }
1329 
1330  hypre_ParCSRMatrixColStarts(A) = new_col_starts;
1331 
1332  if (hypre_ParCSRMatrixRowStarts(A) == old_col_starts)
1333  {
1334  hypre_ParCSRMatrixRowStarts(A) = new_col_starts;
1335  hypre_ParCSRMatrixOwnsRowStarts(A) = 1;
1336  hypre_ParCSRMatrixOwnsColStarts(A) = 0;
1337  }
1338  else
1339  {
1340  hypre_ParCSRMatrixOwnsColStarts(A) = 1;
1341  }
1342 }
1343 
1345 {
1346  const int size = Height();
1347  diag.SetSize(size);
1348 #ifdef HYPRE_USING_CUDA
1350  {
1351  MFEM_ASSERT(A->diag->memory_location == HYPRE_MEMORY_DEVICE, "");
1352  double *d_diag = diag.Write();
1353  const HYPRE_Int *A_diag_i = A->diag->i;
1354  const double *A_diag_d = A->diag->data;
1355  MFEM_FORALL(i, size, d_diag[i] = A_diag_d[A_diag_i[i]];);
1356  }
1357  else
1358 #endif
1359  {
1360  diag.HostWrite();
1361  HostRead();
1362  for (int j = 0; j < size; j++)
1363  {
1364  diag(j) = A->diag->data[A->diag->i[j]];
1365  MFEM_ASSERT(A->diag->j[A->diag->i[j]] == j,
1366  "the first entry in each row must be the diagonal one");
1367  }
1368  HypreRead();
1369  }
1370 }
1371 
1372 static void MakeSparseMatrixWrapper(int nrows, int ncols,
1373  HYPRE_Int *I, HYPRE_Int *J, double *data,
1374  SparseMatrix &wrapper)
1375 {
1376 #ifndef HYPRE_BIGINT
1377  SparseMatrix tmp(I, J, data, nrows, ncols, false, false, false);
1378 #else
1379  int *mI = Memory<int>(nrows + 1);
1380  for (int i = 0; i <= nrows; i++)
1381  {
1382  mI[i] = internal::to_int(I[i]); // checks for overflow in debug mode
1383  }
1384  const int nnz = mI[nrows];
1385  int *mJ = Memory<int>(nnz);
1386  for (int j = 0; j < nnz; j++)
1387  {
1388  mJ[j] = internal::to_int(J[j]); // checks for overflow in debug mode
1389  }
1390  SparseMatrix tmp(mI, mJ, data, nrows, ncols, true, false, false);
1391 #endif
1392  wrapper.Swap(tmp);
1393 }
1394 
1395 static void MakeWrapper(const hypre_CSRMatrix *mat,
1396  const MemoryIJData &mem,
1397  SparseMatrix &wrapper)
1398 {
1399  const int nrows = internal::to_int(hypre_CSRMatrixNumRows(mat));
1400  const int ncols = internal::to_int(hypre_CSRMatrixNumCols(mat));
1401  const int nnz = internal::to_int(mat->num_nonzeros);
1402  const HYPRE_Int *I = mfem::HostRead(mem.I, nrows + 1);
1403  const HYPRE_Int *J = mfem::HostRead(mem.J, nnz);
1404  const double *data = mfem::HostRead(mem.data, nnz);
1405  MakeSparseMatrixWrapper(nrows, ncols,
1406  const_cast<HYPRE_Int*>(I),
1407  const_cast<HYPRE_Int*>(J),
1408  const_cast<double*>(data),
1409  wrapper);
1410 }
1411 
1413 {
1414  MakeWrapper(A->diag, mem_diag, diag);
1415 }
1416 
1418 {
1419  MakeWrapper(A->offd, mem_offd, offd);
1420  cmap = A->col_map_offd;
1421 }
1422 
1424 {
1425  HostRead();
1426  hypre_CSRMatrix *hypre_merged = hypre_MergeDiagAndOffd(A);
1427  HypreRead();
1428  // Wrap 'hypre_merged' as a SparseMatrix 'merged_tmp'
1429  SparseMatrix merged_tmp;
1430 #if MFEM_HYPRE_VERSION >= 21600
1431  hypre_CSRMatrixBigJtoJ(hypre_merged);
1432 #endif
1433  MakeSparseMatrixWrapper(
1434  internal::to_int(hypre_merged->num_rows),
1435  internal::to_int(hypre_merged->num_cols),
1436  hypre_merged->i,
1437  hypre_merged->j,
1438  hypre_merged->data,
1439  merged_tmp);
1440  // Deep copy 'merged_tmp' to 'merged' so that 'merged' does not need
1441  // 'hypre_merged'
1442  merged = merged_tmp;
1443  merged_tmp.Clear();
1444  hypre_CSRMatrixDestroy(hypre_merged);
1445 }
1446 
1448  bool interleaved_rows,
1449  bool interleaved_cols) const
1450 {
1451  int nr = blocks.NumRows();
1452  int nc = blocks.NumCols();
1453 
1454  hypre_ParCSRMatrix **hypre_blocks = new hypre_ParCSRMatrix*[nr * nc];
1455  HostRead();
1456  internal::hypre_ParCSRMatrixSplit(A, nr, nc, hypre_blocks,
1457  interleaved_rows, interleaved_cols);
1458  HypreRead();
1459 
1460  for (int i = 0; i < nr; i++)
1461  {
1462  for (int j = 0; j < nc; j++)
1463  {
1464  blocks[i][j] = new HypreParMatrix(hypre_blocks[i*nc + j]);
1465  }
1466  }
1467 
1468  delete [] hypre_blocks;
1469 }
1470 
1472 {
1473  hypre_ParCSRMatrix * At;
1474  hypre_ParCSRMatrixTranspose(A, &At, 1);
1475  hypre_ParCSRMatrixSetNumNonzeros(At);
1476 
1477  hypre_MatvecCommPkgCreate(At);
1478 
1479  if ( M() == N() )
1480  {
1481  /* If the matrix is square, make sure that the first entry in each
1482  row is the diagonal one. */
1483  hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(At));
1484  }
1485 
1486  return new HypreParMatrix(At);
1487 }
1488 
1489 #if MFEM_HYPRE_VERSION >= 21800
1491  double threshold) const
1492 {
1493  if (!(A->comm))
1494  {
1495  hypre_MatvecCommPkgCreate(A);
1496  }
1497 
1498  hypre_ParCSRMatrix *submat;
1499 
1500  // Get number of rows stored on this processor
1501  int local_num_vars = hypre_CSRMatrixNumRows(hypre_ParCSRMatrixDiag(A));
1502 
1503  // Form hypre CF-splitting array designating submatrix as F-points (-1)
1504  Array<HYPRE_Int> CF_marker(local_num_vars);
1505  CF_marker = 1;
1506  for (int j=0; j<indices.Size(); j++)
1507  {
1508  if (indices[j] > local_num_vars)
1509  {
1510  MFEM_WARNING("WARNING : " << indices[j] << " > " << local_num_vars);
1511  }
1512  CF_marker[indices[j]] = -1;
1513  }
1514 
1515  // Construct cpts_global array on hypre matrix structure
1516  HYPRE_BigInt *cpts_global;
1517  hypre_BoomerAMGCoarseParms(MPI_COMM_WORLD, local_num_vars, 1, NULL,
1518  CF_marker, NULL, &cpts_global);
1519 
1520  // Extract submatrix into *submat
1521  hypre_ParCSRMatrixExtractSubmatrixFC(A, CF_marker, cpts_global,
1522  "FF", &submat, threshold);
1523 
1524  mfem_hypre_TFree(cpts_global);
1525  return new HypreParMatrix(submat);
1526 }
1527 #endif
1528 
1530  double a, double b) const
1531 {
1532  x.HypreRead();
1533  (b == 0.0) ? y.HypreWrite() : y.HypreReadWrite();
1534  return hypre_ParCSRMatrixMatvec(a, A, x, b, y);
1535 }
1536 
1537 void HypreParMatrix::Mult(double a, const Vector &x, double b, Vector &y) const
1538 {
1539  MFEM_ASSERT(x.Size() == Width(), "invalid x.Size() = " << x.Size()
1540  << ", expected size = " << Width());
1541  MFEM_ASSERT(y.Size() == Height(), "invalid y.Size() = " << y.Size()
1542  << ", expected size = " << Height());
1543 
1544  if (X == NULL)
1545  {
1546  X = new HypreParVector(A->comm,
1547  GetGlobalNumCols(),
1548  nullptr,
1549  GetColStarts());
1550  Y = new HypreParVector(A->comm,
1551  GetGlobalNumRows(),
1552  nullptr,
1553  GetRowStarts());
1554  }
1555 
1556  const bool xshallow = CanShallowCopy(x.GetMemory(), GetHypreMemoryClass());
1557  const bool yshallow = CanShallowCopy(y.GetMemory(), GetHypreMemoryClass());
1558 
1559  if (xshallow)
1560  {
1561  X->WrapMemoryRead(x.GetMemory());
1562  }
1563  else
1564  {
1565  if (auxX.Empty()) { auxX.New(NumCols(), GetHypreMemoryType()); }
1566  auxX.CopyFrom(x.GetMemory(), auxX.Capacity()); // Deep copy
1567  X->WrapMemoryRead(auxX);
1568  }
1569 
1570  if (yshallow)
1571  {
1572  if (b != 0.0) { Y->WrapMemoryReadWrite(y.GetMemory()); }
1573  else { Y->WrapMemoryWrite(y.GetMemory()); }
1574  }
1575  else
1576  {
1577  if (auxY.Empty()) { auxY.New(NumRows(), GetHypreMemoryType()); }
1578  if (b != 0.0)
1579  {
1580  auxY.CopyFrom(y.GetMemory(), auxY.Capacity()); // Deep copy
1581  Y->WrapMemoryReadWrite(auxY);
1582  }
1583  else
1584  {
1585  Y->WrapMemoryWrite(auxY);
1586  }
1587  }
1588 
1589  hypre_ParCSRMatrixMatvec(a, A, *X, b, *Y);
1590 
1591  if (!yshallow) { y = *Y; } // Deep copy
1592 }
1593 
1595  double b, Vector &y) const
1596 {
1597  MFEM_ASSERT(x.Size() == Height(), "invalid x.Size() = " << x.Size()
1598  << ", expected size = " << Height());
1599  MFEM_ASSERT(y.Size() == Width(), "invalid y.Size() = " << y.Size()
1600  << ", expected size = " << Width());
1601 
1602  // Note: x has the dimensions of Y (height), and
1603  // y has the dimensions of X (width)
1604  if (X == NULL)
1605  {
1606  X = new HypreParVector(A->comm,
1607  GetGlobalNumCols(),
1608  nullptr,
1609  GetColStarts());
1610  Y = new HypreParVector(A->comm,
1611  GetGlobalNumRows(),
1612  nullptr,
1613  GetRowStarts());
1614  }
1615 
1616  const bool xshallow = CanShallowCopy(x.GetMemory(), GetHypreMemoryClass());
1617  const bool yshallow = CanShallowCopy(y.GetMemory(), GetHypreMemoryClass());
1618 
1619  // x <--> Y
1620  if (xshallow)
1621  {
1622  Y->WrapMemoryRead(x.GetMemory());
1623  }
1624  else
1625  {
1626  if (auxY.Empty()) { auxY.New(NumRows(), GetHypreMemoryType()); }
1627  auxY.CopyFrom(x.GetMemory(), auxY.Capacity()); // Deep copy
1628  Y->WrapMemoryRead(auxY);
1629  }
1630 
1631  // y <--> X
1632  if (yshallow)
1633  {
1634  if (b != 0.0) { X->WrapMemoryReadWrite(y.GetMemory()); }
1635  else { X->WrapMemoryWrite(y.GetMemory()); }
1636  }
1637  else
1638  {
1639  if (auxX.Empty()) { auxX.New(NumCols(), GetHypreMemoryType()); }
1640  if (b != 0.0)
1641  {
1642  auxX.CopyFrom(y.GetMemory(), auxX.Capacity()); // Deep copy
1643  X->WrapMemoryReadWrite(auxX);
1644  }
1645  else
1646  {
1647  X->WrapMemoryWrite(auxX);
1648  }
1649  }
1650 
1651  hypre_ParCSRMatrixMatvecT(a, A, *Y, b, *X);
1652 
1653  if (!yshallow) { y = *X; } // Deep copy
1654 }
1655 
1656 HYPRE_Int HypreParMatrix::Mult(HYPRE_ParVector x, HYPRE_ParVector y,
1657  double a, double b) const
1658 {
1659  return hypre_ParCSRMatrixMatvec(a, A, (hypre_ParVector *) x, b,
1660  (hypre_ParVector *) y);
1661 }
1662 
1664  double a, double b) const
1665 {
1666  x.HypreRead();
1667  (b == 0.0) ? y.HypreWrite() : y.HypreReadWrite();
1668  return hypre_ParCSRMatrixMatvecT(a, A, x, b, y);
1669 }
1670 
1671 void HypreParMatrix::AbsMult(double a, const Vector &x,
1672  double b, Vector &y) const
1673 {
1674  MFEM_ASSERT(x.Size() == Width(), "invalid x.Size() = " << x.Size()
1675  << ", expected size = " << Width());
1676  MFEM_ASSERT(y.Size() == Height(), "invalid y.Size() = " << y.Size()
1677  << ", expected size = " << Height());
1678 
1679  auto x_data = x.HostRead();
1680  auto y_data = (b == 0.0) ? y.HostWrite() : y.HostReadWrite();
1681 
1682  HostRead();
1683  internal::hypre_ParCSRMatrixAbsMatvec(A, a, const_cast<double*>(x_data),
1684  b, y_data);
1685  HypreRead();
1686 }
1687 
1689  double b, Vector &y) const
1690 {
1691  MFEM_ASSERT(x.Size() == Height(), "invalid x.Size() = " << x.Size()
1692  << ", expected size = " << Height());
1693  MFEM_ASSERT(y.Size() == Width(), "invalid y.Size() = " << y.Size()
1694  << ", expected size = " << Width());
1695 
1696  auto x_data = x.HostRead();
1697  auto y_data = (b == 0.0) ? y.HostWrite() : y.HostReadWrite();
1698 
1699  HostRead();
1700  internal::hypre_ParCSRMatrixAbsMatvecT(A, a, const_cast<double*>(x_data),
1701  b, y_data);
1702  HypreRead();
1703 }
1704 
1706  HYPRE_BigInt* row_starts) const
1707 {
1708  const bool assumed_partition = HYPRE_AssumedPartitionCheck();
1709  const bool row_starts_given = (row_starts != NULL);
1710  if (!row_starts_given)
1711  {
1712  row_starts = hypre_ParCSRMatrixRowStarts(A);
1713  MFEM_VERIFY(D.Height() == hypre_CSRMatrixNumRows(A->diag),
1714  "the matrix D is NOT compatible with the row starts of"
1715  " this HypreParMatrix, row_starts must be given.");
1716  }
1717  else
1718  {
1719  int offset;
1720  if (assumed_partition)
1721  {
1722  offset = 0;
1723  }
1724  else
1725  {
1726  MPI_Comm_rank(GetComm(), &offset);
1727  }
1728  int local_num_rows = row_starts[offset+1]-row_starts[offset];
1729  MFEM_VERIFY(local_num_rows == D.Height(), "the number of rows in D is "
1730  " not compatible with the given row_starts");
1731  }
1732  // D.Width() will be checked for compatibility by the SparseMatrix
1733  // multiplication function, mfem::Mult(), called below.
1734 
1735  int part_size;
1736  HYPRE_BigInt global_num_rows;
1737  if (assumed_partition)
1738  {
1739  part_size = 2;
1740  if (row_starts_given)
1741  {
1742  global_num_rows = row_starts[2];
1743  // Here, we use row_starts[2], so row_starts must come from the
1744  // methods GetDofOffsets/GetTrueDofOffsets of ParFiniteElementSpace
1745  // (HYPRE's partitions have only 2 entries).
1746  }
1747  else
1748  {
1749  global_num_rows = hypre_ParCSRMatrixGlobalNumRows(A);
1750  }
1751  }
1752  else
1753  {
1754  MPI_Comm_size(GetComm(), &part_size);
1755  global_num_rows = row_starts[part_size];
1756  part_size++;
1757  }
1758 
1759  HYPRE_BigInt *col_starts = hypre_ParCSRMatrixColStarts(A);
1760  HYPRE_BigInt *col_map_offd;
1761 
1762  // get the diag and offd blocks as SparseMatrix wrappers
1763  SparseMatrix A_diag, A_offd;
1764  GetDiag(A_diag);
1765  GetOffd(A_offd, col_map_offd);
1766 
1767  // Multiply the diag and offd blocks with D -- these products will be the
1768  // diag and offd blocks of the output HypreParMatrix, DA.
1769  SparseMatrix* DA_diag = mfem::Mult(D, A_diag);
1770  SparseMatrix* DA_offd = mfem::Mult(D, A_offd);
1771 
1772  // Copy row_starts, col_starts, and col_map_offd; ownership of these arrays
1773  // will be given to the newly constructed output HypreParMatrix, DA.
1774  HYPRE_BigInt *new_row_starts =
1775  DuplicateAs<HYPRE_BigInt>(row_starts, part_size, false);
1776  HYPRE_BigInt *new_col_starts =
1777  (row_starts == col_starts ? new_row_starts :
1778  DuplicateAs<HYPRE_BigInt>(col_starts, part_size, false));
1779  HYPRE_BigInt *new_col_map_offd =
1780  DuplicateAs<HYPRE_BigInt>(col_map_offd, A_offd.Width());
1781 
1782  // Ownership of DA_diag and DA_offd is transfered to the HypreParMatrix
1783  // constructor.
1784  const bool own_diag_offd = true;
1785 
1786  // Create the output HypreParMatrix, DA, from DA_diag and DA_offd
1787  HypreParMatrix* DA =
1788  new HypreParMatrix(GetComm(),
1789  global_num_rows, hypre_ParCSRMatrixGlobalNumCols(A),
1790  new_row_starts, new_col_starts,
1791  DA_diag, DA_offd, new_col_map_offd,
1792  own_diag_offd);
1793 
1794  // Give ownership of row_starts, col_starts, and col_map_offd to DA
1795  hypre_ParCSRMatrixSetRowStartsOwner(DA->A, 1);
1796  hypre_ParCSRMatrixSetColStartsOwner(DA->A, 1);
1797  DA->colMapOwner = 1;
1798 
1799  return DA;
1800 }
1801 
1803 {
1804  if (hypre_CSRMatrixNumRows(A->diag) != hypre_CSRMatrixNumRows(A->offd))
1805  {
1806  mfem_error("Row does not match");
1807  }
1808 
1809  if (hypre_CSRMatrixNumRows(A->diag) != diag.Size())
1810  {
1811  mfem_error("Note the Vector diag is not of compatible dimensions with A\n");
1812  }
1813 
1814  HostReadWrite();
1815  diag.HostRead();
1816 
1817  int size = Height();
1818  double *Adiag_data = hypre_CSRMatrixData(A->diag);
1819  HYPRE_Int *Adiag_i = hypre_CSRMatrixI(A->diag);
1820 
1821  double *Aoffd_data = hypre_CSRMatrixData(A->offd);
1822  HYPRE_Int *Aoffd_i = hypre_CSRMatrixI(A->offd);
1823  double val;
1824  HYPRE_Int jj;
1825  for (int i(0); i < size; ++i)
1826  {
1827  val = diag[i];
1828  for (jj = Adiag_i[i]; jj < Adiag_i[i+1]; ++jj)
1829  {
1830  Adiag_data[jj] *= val;
1831  }
1832  for (jj = Aoffd_i[i]; jj < Aoffd_i[i+1]; ++jj)
1833  {
1834  Aoffd_data[jj] *= val;
1835  }
1836  }
1837 
1838  HypreRead();
1839 }
1840 
1842 {
1843  if (hypre_CSRMatrixNumRows(A->diag) != hypre_CSRMatrixNumRows(A->offd))
1844  {
1845  mfem_error("Row does not match");
1846  }
1847 
1848  if (hypre_CSRMatrixNumRows(A->diag) != diag.Size())
1849  {
1850  mfem_error("Note the Vector diag is not of compatible dimensions with A\n");
1851  }
1852 
1853  HostReadWrite();
1854  diag.HostRead();
1855 
1856  int size = Height();
1857  double *Adiag_data = hypre_CSRMatrixData(A->diag);
1858  HYPRE_Int *Adiag_i = hypre_CSRMatrixI(A->diag);
1859 
1860 
1861  double *Aoffd_data = hypre_CSRMatrixData(A->offd);
1862  HYPRE_Int *Aoffd_i = hypre_CSRMatrixI(A->offd);
1863  double val;
1864  HYPRE_Int jj;
1865  for (int i(0); i < size; ++i)
1866  {
1867 #ifdef MFEM_DEBUG
1868  if (0.0 == diag(i))
1869  {
1870  mfem_error("HypreParMatrix::InvDiagScale : Division by 0");
1871  }
1872 #endif
1873  val = 1./diag(i);
1874  for (jj = Adiag_i[i]; jj < Adiag_i[i+1]; ++jj)
1875  {
1876  Adiag_data[jj] *= val;
1877  }
1878  for (jj = Aoffd_i[i]; jj < Aoffd_i[i+1]; ++jj)
1879  {
1880  Aoffd_data[jj] *= val;
1881  }
1882  }
1883 
1884  HypreRead();
1885 }
1886 
1888 {
1889  if (hypre_CSRMatrixNumRows(A->diag) != hypre_CSRMatrixNumRows(A->offd))
1890  {
1891  mfem_error("Row does not match");
1892  }
1893 
1894  HostReadWrite();
1895 
1896  HYPRE_Int size=hypre_CSRMatrixNumRows(A->diag);
1897  HYPRE_Int jj;
1898 
1899  double *Adiag_data = hypre_CSRMatrixData(A->diag);
1900  HYPRE_Int *Adiag_i = hypre_CSRMatrixI(A->diag);
1901  for (jj = 0; jj < Adiag_i[size]; ++jj)
1902  {
1903  Adiag_data[jj] *= s;
1904  }
1905 
1906  double *Aoffd_data = hypre_CSRMatrixData(A->offd);
1907  HYPRE_Int *Aoffd_i = hypre_CSRMatrixI(A->offd);
1908  for (jj = 0; jj < Aoffd_i[size]; ++jj)
1909  {
1910  Aoffd_data[jj] *= s;
1911  }
1912 
1913  HypreRead();
1914 }
1915 
1916 static void get_sorted_rows_cols(const Array<int> &rows_cols,
1917  Array<HYPRE_Int> &hypre_sorted)
1918 {
1919  rows_cols.HostRead();
1920  hypre_sorted.SetSize(rows_cols.Size());
1921  bool sorted = true;
1922  for (int i = 0; i < rows_cols.Size(); i++)
1923  {
1924  hypre_sorted[i] = rows_cols[i];
1925  if (i && rows_cols[i-1] > rows_cols[i]) { sorted = false; }
1926  }
1927  if (!sorted) { hypre_sorted.Sort(); }
1928 }
1929 
1930 void HypreParMatrix::Threshold(double threshold)
1931 {
1932  int ierr = 0;
1933 
1934  MPI_Comm comm;
1935  hypre_CSRMatrix * csr_A;
1936  hypre_CSRMatrix * csr_A_wo_z;
1937  hypre_ParCSRMatrix * parcsr_A_ptr;
1938  HYPRE_BigInt * row_starts = NULL; HYPRE_BigInt * col_starts = NULL;
1939  HYPRE_BigInt row_start = -1; HYPRE_BigInt row_end = -1;
1940  HYPRE_BigInt col_start = -1; HYPRE_BigInt col_end = -1;
1941 
1942  comm = hypre_ParCSRMatrixComm(A);
1943 
1944  ierr += hypre_ParCSRMatrixGetLocalRange(A,
1945  &row_start,&row_end,
1946  &col_start,&col_end );
1947 
1948  row_starts = hypre_ParCSRMatrixRowStarts(A);
1949  col_starts = hypre_ParCSRMatrixColStarts(A);
1950 
1951  bool old_owns_row = hypre_ParCSRMatrixOwnsRowStarts(A);
1952  bool old_owns_col = hypre_ParCSRMatrixOwnsColStarts(A);
1953  HYPRE_BigInt global_num_rows = hypre_ParCSRMatrixGlobalNumRows(A);
1954  HYPRE_BigInt global_num_cols = hypre_ParCSRMatrixGlobalNumCols(A);
1955  parcsr_A_ptr = hypre_ParCSRMatrixCreate(comm, global_num_rows,
1956  global_num_cols,
1957  row_starts, col_starts,
1958  0, 0, 0);
1959  hypre_ParCSRMatrixOwnsRowStarts(parcsr_A_ptr) = old_owns_row;
1960  hypre_ParCSRMatrixOwnsColStarts(parcsr_A_ptr) = old_owns_col;
1961  hypre_ParCSRMatrixOwnsRowStarts(A) = 0;
1962  hypre_ParCSRMatrixOwnsColStarts(A) = 0;
1963 
1964  csr_A = hypre_MergeDiagAndOffd(A);
1965 
1966  // Free A, if owned
1967  Destroy();
1968  Init();
1969 
1970  csr_A_wo_z = hypre_CSRMatrixDeleteZeros(csr_A,threshold);
1971 
1972  /* hypre_CSRMatrixDeleteZeros will return a NULL pointer rather than a usable
1973  CSR matrix if it finds no non-zeros */
1974  if (csr_A_wo_z == NULL)
1975  {
1976  csr_A_wo_z = csr_A;
1977  }
1978  else
1979  {
1980  ierr += hypre_CSRMatrixDestroy(csr_A);
1981  }
1982 
1983  /* TODO: GenerateDiagAndOffd() uses an int array of size equal to the number
1984  of columns in csr_A_wo_z which is the global number of columns in A. This
1985  does not scale well. */
1986  ierr += GenerateDiagAndOffd(csr_A_wo_z,parcsr_A_ptr,
1987  col_start,col_end);
1988 
1989  ierr += hypre_CSRMatrixDestroy(csr_A_wo_z);
1990 
1991  MFEM_VERIFY(ierr == 0, "");
1992 
1993  A = parcsr_A_ptr;
1994 
1995  hypre_ParCSRMatrixSetNumNonzeros(A);
1996  /* Make sure that the first entry in each row is the diagonal one. */
1997  if (row_starts == col_starts)
1998  {
1999  hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
2000  }
2001  hypre_MatvecCommPkgCreate(A);
2002  height = GetNumRows();
2003  width = GetNumCols();
2004 }
2005 
2007 {
2008  HYPRE_Int err = 0, old_err = hypre_error_flag;
2009  hypre_error_flag = 0;
2010 
2011 #if MFEM_HYPRE_VERSION < 21400
2012 
2013  double threshold = 0.0;
2014  if (tol > 0.0)
2015  {
2016  HYPRE_Int *diag_I = A->diag->i, *offd_I = A->offd->i;
2017  double *diag_d = A->diag->data, *offd_d = A->offd->data;
2018  HYPRE_Int local_num_rows = A->diag->num_rows;
2019  double max_l2_row_norm = 0.0;
2020  Vector row;
2021  for (HYPRE_Int r = 0; r < local_num_rows; r++)
2022  {
2023  row.SetDataAndSize(diag_d + diag_I[r], diag_I[r+1]-diag_I[r]);
2024  double l2_row_norm = row.Norml2();
2025  row.SetDataAndSize(offd_d + offd_I[r], offd_I[r+1]-offd_I[r]);
2026  l2_row_norm = std::hypot(l2_row_norm, row.Norml2());
2027  max_l2_row_norm = std::max(max_l2_row_norm, l2_row_norm);
2028  }
2029  double loc_max_l2_row_norm = max_l2_row_norm;
2030  MPI_Allreduce(&loc_max_l2_row_norm, &max_l2_row_norm, 1, MPI_DOUBLE,
2031  MPI_MAX, A->comm);
2032  threshold = tol * max_l2_row_norm;
2033  }
2034 
2035  Threshold(threshold);
2036 
2037 #elif MFEM_HYPRE_VERSION < 21800
2038 
2039  err = hypre_ParCSRMatrixDropSmallEntries(A, tol);
2040 
2041 #else
2042 
2043  err = hypre_ParCSRMatrixDropSmallEntries(A, tol, 2);
2044 
2045 #endif
2046 
2047  MFEM_VERIFY(!err, "error encountered: error code = " << err);
2048 
2049  hypre_error_flag = old_err;
2050 }
2051 
2053  const HypreParVector &X,
2054  HypreParVector &B)
2055 {
2056  Array<HYPRE_Int> rc_sorted;
2057  get_sorted_rows_cols(rows_cols, rc_sorted);
2058 
2059  internal::hypre_ParCSRMatrixEliminateAXB(
2060  A, rc_sorted.Size(), rc_sorted.GetData(), X, B);
2061 }
2062 
2064 {
2065  Array<HYPRE_Int> rc_sorted;
2066  get_sorted_rows_cols(rows_cols, rc_sorted);
2067 
2068  hypre_ParCSRMatrix* Ae;
2069  HostReadWrite();
2070  internal::hypre_ParCSRMatrixEliminateAAe(
2071  A, &Ae, rc_sorted.Size(), rc_sorted.GetData());
2072  HypreRead();
2073 
2074  return new HypreParMatrix(Ae, true);
2075 }
2076 
2078 {
2079  Array<HYPRE_Int> rc_sorted;
2080  get_sorted_rows_cols(cols, rc_sorted);
2081 
2082  hypre_ParCSRMatrix* Ae;
2083  HostReadWrite();
2084  internal::hypre_ParCSRMatrixEliminateAAe(
2085  A, &Ae, rc_sorted.Size(), rc_sorted.GetData(), 1);
2086  HypreRead();
2087 
2088  return new HypreParMatrix(Ae, true);
2089 }
2090 
2092 {
2093  if (rows.Size() > 0)
2094  {
2095  Array<HYPRE_Int> r_sorted;
2096  get_sorted_rows_cols(rows, r_sorted);
2097  HostReadWrite();
2098  internal::hypre_ParCSRMatrixEliminateRows(A, r_sorted.Size(),
2099  r_sorted.GetData());
2100  HypreRead();
2101  }
2102 }
2103 
2105  const Array<int> &ess_dof_list,
2106  const Vector &X, Vector &B) const
2107 {
2108  // B -= Ae*X
2109  Ae.Mult(-1.0, X, 1.0, B);
2110 
2111  // All operations below are local, so we can skip them if ess_dof_list is
2112  // empty on this processor to avoid potential host <--> device transfers.
2113  if (ess_dof_list.Size() == 0) { return; }
2114 
2115  HostRead();
2116  hypre_CSRMatrix *A_diag = hypre_ParCSRMatrixDiag(A);
2117  double *data = hypre_CSRMatrixData(A_diag);
2118  HYPRE_Int *I = hypre_CSRMatrixI(A_diag);
2119 #ifdef MFEM_DEBUG
2120  HYPRE_Int *J = hypre_CSRMatrixJ(A_diag);
2121  hypre_CSRMatrix *A_offd = hypre_ParCSRMatrixOffd(A);
2122  HYPRE_Int *I_offd = hypre_CSRMatrixI(A_offd);
2123  double *data_offd = hypre_CSRMatrixData(A_offd);
2124 #endif
2125 
2126  ess_dof_list.HostRead();
2127  X.HostRead();
2128  B.HostReadWrite();
2129 
2130  for (int i = 0; i < ess_dof_list.Size(); i++)
2131  {
2132  int r = ess_dof_list[i];
2133  B(r) = data[I[r]] * X(r);
2134 #ifdef MFEM_DEBUG
2135  MFEM_ASSERT(I[r] < I[r+1], "empty row found!");
2136  // Check that in the rows specified by the ess_dof_list, the matrix A has
2137  // only one entry -- the diagonal.
2138  // if (I[r+1] != I[r]+1 || J[I[r]] != r || I_offd[r] != I_offd[r+1])
2139  if (J[I[r]] != r)
2140  {
2141  MFEM_ABORT("the diagonal entry must be the first entry in the row!");
2142  }
2143  for (int j = I[r]+1; j < I[r+1]; j++)
2144  {
2145  if (data[j] != 0.0)
2146  {
2147  MFEM_ABORT("all off-diagonal entries must be zero!");
2148  }
2149  }
2150  for (int j = I_offd[r]; j < I_offd[r+1]; j++)
2151  {
2152  if (data_offd[j] != 0.0)
2153  {
2154  MFEM_ABORT("all off-diagonal entries must be zero!");
2155  }
2156  }
2157 #endif
2158  }
2159  HypreRead();
2160 }
2161 
2162 void HypreParMatrix::Print(const char *fname, HYPRE_Int offi,
2163  HYPRE_Int offj) const
2164 {
2165  HostRead();
2166  hypre_ParCSRMatrixPrintIJ(A,offi,offj,fname);
2167  HypreRead();
2168 }
2169 
2170 void HypreParMatrix::Read(MPI_Comm comm, const char *fname)
2171 {
2172  Destroy();
2173  Init();
2174 
2175  HYPRE_Int base_i, base_j;
2176  hypre_ParCSRMatrixReadIJ(comm, fname, &base_i, &base_j, &A);
2177  hypre_ParCSRMatrixSetNumNonzeros(A);
2178 
2179  hypre_MatvecCommPkgCreate(A);
2180 
2181  height = GetNumRows();
2182  width = GetNumCols();
2183 }
2184 
2185 void HypreParMatrix::Read_IJMatrix(MPI_Comm comm, const char *fname)
2186 {
2187  Destroy();
2188  Init();
2189 
2190  HYPRE_IJMatrix A_ij;
2191  HYPRE_IJMatrixRead(fname, comm, 5555, &A_ij); // HYPRE_PARCSR = 5555
2192 
2193  HYPRE_ParCSRMatrix A_parcsr;
2194  HYPRE_IJMatrixGetObject(A_ij, (void**) &A_parcsr);
2195 
2196  A = (hypre_ParCSRMatrix*)A_parcsr;
2197 
2198  hypre_ParCSRMatrixSetNumNonzeros(A);
2199 
2200  hypre_MatvecCommPkgCreate(A);
2201 
2202  height = GetNumRows();
2203  width = GetNumCols();
2204 }
2205 
2206 void HypreParMatrix::PrintCommPkg(std::ostream &out) const
2207 {
2208  hypre_ParCSRCommPkg *comm_pkg = A->comm_pkg;
2209  MPI_Comm comm = A->comm;
2210  char c = '\0';
2211  const int tag = 46801;
2212  int myid, nproc;
2213  MPI_Comm_rank(comm, &myid);
2214  MPI_Comm_size(comm, &nproc);
2215 
2216  if (myid != 0)
2217  {
2218  MPI_Recv(&c, 1, MPI_CHAR, myid-1, tag, comm, MPI_STATUS_IGNORE);
2219  }
2220  else
2221  {
2222  out << "\nHypreParMatrix: hypre_ParCSRCommPkg:\n";
2223  }
2224  out << "Rank " << myid << ":\n"
2225  " number of sends = " << comm_pkg->num_sends <<
2226  " (" << sizeof(double)*comm_pkg->send_map_starts[comm_pkg->num_sends] <<
2227  " bytes)\n"
2228  " number of recvs = " << comm_pkg->num_recvs <<
2229  " (" << sizeof(double)*comm_pkg->recv_vec_starts[comm_pkg->num_recvs] <<
2230  " bytes)\n";
2231  if (myid != nproc-1)
2232  {
2233  out << std::flush;
2234  MPI_Send(&c, 1, MPI_CHAR, myid+1, tag, comm);
2235  }
2236  else
2237  {
2238  out << std::endl;
2239  }
2240  MPI_Barrier(comm);
2241 }
2242 
2243 void HypreParMatrix::PrintHash(std::ostream &out) const
2244 {
2245  HashFunction hf;
2246 
2247  out << "global number of rows : " << A->global_num_rows << '\n'
2248  << "global number of columns : " << A->global_num_cols << '\n'
2249  << "first row index : " << A->first_row_index << '\n'
2250  << " last row index : " << A->last_row_index << '\n'
2251  << "first col diag : " << A->first_col_diag << '\n'
2252  << " last col diag : " << A->last_col_diag << '\n'
2253  << "number of nonzeros : " << A->num_nonzeros << '\n';
2254  // diagonal, off-diagonal
2255  hypre_CSRMatrix *csr = A->diag;
2256  const char *csr_name = "diag";
2257  for (int m = 0; m < 2; m++)
2258  {
2259  auto csr_nnz = csr->i[csr->num_rows];
2260  out << csr_name << " num rows : " << csr->num_rows << '\n'
2261  << csr_name << " num cols : " << csr->num_cols << '\n'
2262  << csr_name << " num nnz : " << csr->num_nonzeros << '\n'
2263  << csr_name << " i last : " << csr_nnz
2264  << (csr_nnz == csr->num_nonzeros ?
2265  " [good]" : " [** BAD **]") << '\n';
2266  hf.AppendInts(csr->i, csr->num_rows + 1);
2267  out << csr_name << " i hash : " << hf.GetHash() << '\n';
2268  out << csr_name << " j hash : ";
2269  if (csr->j == nullptr)
2270  {
2271  out << "(null)\n";
2272  }
2273  else
2274  {
2275  hf.AppendInts(csr->j, csr_nnz);
2276  out << hf.GetHash() << '\n';
2277  }
2278 #if MFEM_HYPRE_VERSION >= 21600
2279  out << csr_name << " big j hash : ";
2280  if (csr->big_j == nullptr)
2281  {
2282  out << "(null)\n";
2283  }
2284  else
2285  {
2286  hf.AppendInts(csr->big_j, csr_nnz);
2287  out << hf.GetHash() << '\n';
2288  }
2289 #endif
2290  out << csr_name << " data hash : ";
2291  if (csr->data == nullptr)
2292  {
2293  out << "(null)\n";
2294  }
2295  else
2296  {
2297  hf.AppendDoubles(csr->data, csr_nnz);
2298  out << hf.GetHash() << '\n';
2299  }
2300 
2301  csr = A->offd;
2302  csr_name = "offd";
2303  }
2304 
2305  hf.AppendInts(A->col_map_offd, A->offd->num_cols);
2306  out << "col map offd hash : " << hf.GetHash() << '\n';
2307 }
2308 
2309 inline void delete_hypre_ParCSRMatrixColMapOffd(hypre_ParCSRMatrix *A)
2310 {
2311  HYPRE_BigInt *A_col_map_offd = hypre_ParCSRMatrixColMapOffd(A);
2312  int size = hypre_CSRMatrixNumCols(hypre_ParCSRMatrixOffd(A));
2313  Memory<HYPRE_Int>(A_col_map_offd, size, true).Delete();
2314 }
2315 
2316 void HypreParMatrix::Destroy()
2317 {
2318  if ( X != NULL ) { delete X; }
2319  if ( Y != NULL ) { delete Y; }
2320  auxX.Delete();
2321  auxY.Delete();
2322 
2323  if (A == NULL) { return; }
2324 
2325 #ifdef HYPRE_USING_CUDA
2326  if (ParCSROwner && (diagOwner < 0 || offdOwner < 0))
2327  {
2328  // Put the "host" or "hypre" pointers in {i,j,data} of A->{diag,offd}, so
2329  // that they can be destroyed by hypre when hypre_ParCSRMatrixDestroy(A)
2330  // is called below.
2331 
2332  // Check that if both diagOwner and offdOwner are negative then they have
2333  // the same value.
2334  MFEM_VERIFY(!(diagOwner < 0 && offdOwner < 0) || diagOwner == offdOwner,
2335  "invalid state");
2336 
2337  MemoryClass mc = (diagOwner == -1 || offdOwner == -1) ?
2339  Write(mc, diagOwner < 0, offdOwner <0);
2340  }
2341 #endif
2342 
2343  mem_diag.I.Delete();
2344  mem_diag.J.Delete();
2345  mem_diag.data.Delete();
2346  if (diagOwner >= 0)
2347  {
2348  hypre_CSRMatrixI(A->diag) = NULL;
2349  hypre_CSRMatrixJ(A->diag) = NULL;
2350  hypre_CSRMatrixData(A->diag) = NULL;
2351  }
2352  mem_offd.I.Delete();
2353  mem_offd.J.Delete();
2354  mem_offd.data.Delete();
2355  if (offdOwner >= 0)
2356  {
2357  hypre_CSRMatrixI(A->offd) = NULL;
2358  hypre_CSRMatrixJ(A->offd) = NULL;
2359  hypre_CSRMatrixData(A->offd) = NULL;
2360  }
2361  if (colMapOwner >= 0)
2362  {
2363  if (colMapOwner & 1)
2364  {
2366  }
2367  hypre_ParCSRMatrixColMapOffd(A) = NULL;
2368  }
2369 
2370  if (ParCSROwner)
2371  {
2372  hypre_ParCSRMatrixDestroy(A);
2373  }
2374 }
2375 
2376 #if MFEM_HYPRE_VERSION >= 21800
2377 
2379  const Vector *b, HypreParVector *d,
2380  int blocksize, BlockInverseScaleJob job)
2381 {
2382  if (job == BlockInverseScaleJob::MATRIX_ONLY ||
2384  {
2385  hypre_ParCSRMatrix *C_hypre;
2386  hypre_ParcsrBdiagInvScal(*A, blocksize, &C_hypre);
2387  hypre_ParCSRMatrixDropSmallEntries(C_hypre, 1e-15, 1);
2388  C->WrapHypreParCSRMatrix(C_hypre);
2389  }
2390 
2391  if (job == BlockInverseScaleJob::RHS_ONLY ||
2393  {
2394  HypreParVector b_Hypre(A->GetComm(),
2395  A->GetGlobalNumRows(),
2396  b->GetData(), A->GetRowStarts());
2397  hypre_ParVector *d_hypre;
2398  hypre_ParvecBdiagInvScal(b_Hypre, blocksize, &d_hypre, *A);
2399 
2400  d->WrapHypreParVector(d_hypre, true);
2401  }
2402 }
2403 
2404 #endif
2405 
2406 #if MFEM_HYPRE_VERSION < 21400
2407 
2409  double beta, const HypreParMatrix &B)
2410 {
2411  hypre_ParCSRMatrix *C_hypre =
2412  internal::hypre_ParCSRMatrixAdd(const_cast<HypreParMatrix &>(A),
2413  const_cast<HypreParMatrix &>(B));
2414  MFEM_VERIFY(C_hypre, "error in hypre_ParCSRMatrixAdd");
2415 
2416  hypre_MatvecCommPkgCreate(C_hypre);
2417  HypreParMatrix *C = new HypreParMatrix(C_hypre);
2418  *C = 0.0;
2419  C->Add(alpha, A);
2420  C->Add(beta, B);
2421 
2422  return C;
2423 }
2424 
2426 {
2427  hypre_ParCSRMatrix * C = internal::hypre_ParCSRMatrixAdd(*A,*B);
2428 
2429  hypre_MatvecCommPkgCreate(C);
2430 
2431  return new HypreParMatrix(C);
2432 }
2433 
2434 #else
2435 
2436 HypreParMatrix *Add(double alpha, const HypreParMatrix &A,
2437  double beta, const HypreParMatrix &B)
2438 {
2439  hypre_ParCSRMatrix *C;
2440 #if MFEM_HYPRE_VERSION <= 22000
2441  hypre_ParcsrAdd(alpha, A, beta, B, &C);
2442 #else
2443  hypre_ParCSRMatrixAdd(alpha, A, beta, B, &C);
2444 #endif
2445  hypre_MatvecCommPkgCreate(C);
2446 
2447  return new HypreParMatrix(C);
2448 }
2449 
2450 HypreParMatrix * ParAdd(const HypreParMatrix *A, const HypreParMatrix *B)
2451 {
2452  hypre_ParCSRMatrix *C;
2453 #if MFEM_HYPRE_VERSION <= 22000
2454  hypre_ParcsrAdd(1.0, *A, 1.0, *B, &C);
2455 #else
2456  hypre_ParCSRMatrixAdd(1.0, *A, 1.0, *B, &C);
2457 #endif
2458 
2459  return new HypreParMatrix(C);
2460 }
2461 
2462 #endif
2463 
2465  bool own_matrix)
2466 {
2467  hypre_ParCSRMatrix * ab;
2468 #ifdef HYPRE_USING_CUDA
2469  ab = hypre_ParCSRMatMat(*A, *B);
2470 #else
2471  ab = hypre_ParMatmul(*A,*B);
2472 #endif
2473  hypre_ParCSRMatrixSetNumNonzeros(ab);
2474 
2475  hypre_MatvecCommPkgCreate(ab);
2476  HypreParMatrix *C = new HypreParMatrix(ab);
2477  if (own_matrix)
2478  {
2479  C->CopyRowStarts();
2480  C->CopyColStarts();
2481  }
2482  return C;
2483 }
2484 
2486 {
2487  hypre_ParCSRMatrix * rap;
2488 
2489 #ifdef HYPRE_USING_CUDA
2490  // FIXME: this way of computing Pt A P can completely eliminate zero rows
2491  // from the sparsity pattern of the product which prevents
2492  // EliminateZeroRows() from working correctly. This issue is observed
2493  // in ex28p.
2494  // Quick fix: add a diagonal matrix with 0 diagonal.
2495  // Maybe use hypre_CSRMatrixCheckDiagFirst to see if we need the fix.
2496  {
2497  hypre_ParCSRMatrix *Q = hypre_ParCSRMatMat(*A,*P);
2498  const bool keepTranspose = false;
2499  rap = hypre_ParCSRTMatMatKT(*P,Q,keepTranspose);
2500  hypre_ParCSRMatrixDestroy(Q);
2501 
2502  // alternative:
2503  // hypre_ParCSRMatrixRAPKT
2504  }
2505 #else
2506  HYPRE_Int P_owns_its_col_starts =
2507  hypre_ParCSRMatrixOwnsColStarts((hypre_ParCSRMatrix*)(*P));
2508 
2509  hypre_BoomerAMGBuildCoarseOperator(*P,*A,*P,&rap);
2510 
2511  /* Warning: hypre_BoomerAMGBuildCoarseOperator steals the col_starts
2512  from P (even if it does not own them)! */
2513  hypre_ParCSRMatrixSetRowStartsOwner(rap,0);
2514  hypre_ParCSRMatrixSetColStartsOwner(rap,0);
2515  if (P_owns_its_col_starts)
2516  {
2517  hypre_ParCSRMatrixSetColStartsOwner(*P, 1);
2518  }
2519 #endif
2520 
2521  hypre_ParCSRMatrixSetNumNonzeros(rap);
2522  // hypre_MatvecCommPkgCreate(rap);
2523 
2524  return new HypreParMatrix(rap);
2525 }
2526 
2528  const HypreParMatrix *P)
2529 {
2530  hypre_ParCSRMatrix * rap;
2531 
2532 #ifdef HYPRE_USING_CUDA
2533  {
2534  hypre_ParCSRMatrix *Q = hypre_ParCSRMatMat(*A,*P);
2535  rap = hypre_ParCSRTMatMat(*Rt,Q);
2536  hypre_ParCSRMatrixDestroy(Q);
2537  }
2538 #else
2539  HYPRE_Int P_owns_its_col_starts =
2540  hypre_ParCSRMatrixOwnsColStarts((hypre_ParCSRMatrix*)(*P));
2541  HYPRE_Int Rt_owns_its_col_starts =
2542  hypre_ParCSRMatrixOwnsColStarts((hypre_ParCSRMatrix*)(*Rt));
2543 
2544  hypre_BoomerAMGBuildCoarseOperator(*Rt,*A,*P,&rap);
2545 
2546  /* Warning: hypre_BoomerAMGBuildCoarseOperator steals the col_starts
2547  from Rt and P (even if they do not own them)! */
2548  hypre_ParCSRMatrixSetRowStartsOwner(rap,0);
2549  hypre_ParCSRMatrixSetColStartsOwner(rap,0);
2550  if (P_owns_its_col_starts)
2551  {
2552  hypre_ParCSRMatrixSetColStartsOwner(*P, 1);
2553  }
2554  if (Rt_owns_its_col_starts)
2555  {
2556  hypre_ParCSRMatrixSetColStartsOwner(*Rt, 1);
2557  }
2558 #endif
2559 
2560  hypre_ParCSRMatrixSetNumNonzeros(rap);
2561  // hypre_MatvecCommPkgCreate(rap);
2562 
2563  return new HypreParMatrix(rap);
2564 }
2565 
2566 // Helper function for HypreParMatrixFromBlocks. Note that scalability to
2567 // extremely large processor counts is limited by the use of MPI_Allgather.
2568 void GatherBlockOffsetData(MPI_Comm comm, const int rank, const int nprocs,
2569  const int num_loc, const Array<int> &offsets,
2570  std::vector<int> &all_num_loc, const int numBlocks,
2571  std::vector<std::vector<HYPRE_BigInt>> &blockProcOffsets,
2572  std::vector<HYPRE_BigInt> &procOffsets,
2573  std::vector<std::vector<int>> &procBlockOffsets,
2574  HYPRE_BigInt &firstLocal, HYPRE_BigInt &globalNum)
2575 {
2576  std::vector<std::vector<int>> all_block_num_loc(numBlocks);
2577 
2578  MPI_Allgather(&num_loc, 1, MPI_INT, all_num_loc.data(), 1, MPI_INT, comm);
2579 
2580  for (int j = 0; j < numBlocks; ++j)
2581  {
2582  all_block_num_loc[j].resize(nprocs);
2583  blockProcOffsets[j].resize(nprocs);
2584 
2585  const int blockNumRows = offsets[j + 1] - offsets[j];
2586  MPI_Allgather(&blockNumRows, 1, MPI_INT, all_block_num_loc[j].data(), 1,
2587  MPI_INT, comm);
2588  blockProcOffsets[j][0] = 0;
2589  for (int i = 0; i < nprocs - 1; ++i)
2590  {
2591  blockProcOffsets[j][i + 1] = blockProcOffsets[j][i]
2592  + all_block_num_loc[j][i];
2593  }
2594  }
2595 
2596  firstLocal = 0;
2597  globalNum = 0;
2598  procOffsets[0] = 0;
2599  for (int i = 0; i < nprocs; ++i)
2600  {
2601  globalNum += all_num_loc[i];
2602  if (rank == 0)
2603  {
2604  MFEM_VERIFY(globalNum >= 0, "overflow in global size");
2605  }
2606  if (i < rank)
2607  {
2608  firstLocal += all_num_loc[i];
2609  }
2610 
2611  if (i < nprocs - 1)
2612  {
2613  procOffsets[i + 1] = procOffsets[i] + all_num_loc[i];
2614  }
2615 
2616  procBlockOffsets[i].resize(numBlocks);
2617  procBlockOffsets[i][0] = 0;
2618  for (int j = 1; j < numBlocks; ++j)
2619  {
2620  procBlockOffsets[i][j] = procBlockOffsets[i][j - 1]
2621  + all_block_num_loc[j - 1][i];
2622  }
2623  }
2624 }
2625 
2627  Array2D<double> *blockCoeff)
2628 {
2629  const int numBlockRows = blocks.NumRows();
2630  const int numBlockCols = blocks.NumCols();
2631 
2632  MFEM_VERIFY(numBlockRows > 0 &&
2633  numBlockCols > 0, "Invalid input to HypreParMatrixFromBlocks");
2634 
2635  if (blockCoeff != NULL)
2636  {
2637  MFEM_VERIFY(numBlockRows == blockCoeff->NumRows() &&
2638  numBlockCols == blockCoeff->NumCols(),
2639  "Invalid input to HypreParMatrixFromBlocks");
2640  }
2641 
2642  Array<int> rowOffsets(numBlockRows+1);
2643  Array<int> colOffsets(numBlockCols+1);
2644 
2645  int nonNullBlockRow0 = -1;
2646  for (int j=0; j<numBlockCols; ++j)
2647  {
2648  if (blocks(0,j) != NULL)
2649  {
2650  nonNullBlockRow0 = j;
2651  break;
2652  }
2653  }
2654 
2655  MFEM_VERIFY(nonNullBlockRow0 >= 0, "Null row of blocks");
2656  MPI_Comm comm = blocks(0,nonNullBlockRow0)->GetComm();
2657 
2658  // Set offsets based on the number of rows or columns in each block.
2659  rowOffsets = 0;
2660  colOffsets = 0;
2661  for (int i=0; i<numBlockRows; ++i)
2662  {
2663  for (int j=0; j<numBlockCols; ++j)
2664  {
2665  if (blocks(i,j) != NULL)
2666  {
2667  const int nrows = blocks(i,j)->NumRows();
2668  const int ncols = blocks(i,j)->NumCols();
2669 
2670  MFEM_VERIFY(nrows > 0 &&
2671  ncols > 0, "Invalid block in HypreParMatrixFromBlocks");
2672 
2673  if (rowOffsets[i+1] == 0)
2674  {
2675  rowOffsets[i+1] = nrows;
2676  }
2677  else
2678  {
2679  MFEM_VERIFY(rowOffsets[i+1] == nrows,
2680  "Inconsistent blocks in HypreParMatrixFromBlocks");
2681  }
2682 
2683  if (colOffsets[j+1] == 0)
2684  {
2685  colOffsets[j+1] = ncols;
2686  }
2687  else
2688  {
2689  MFEM_VERIFY(colOffsets[j+1] == ncols,
2690  "Inconsistent blocks in HypreParMatrixFromBlocks");
2691  }
2692  }
2693  }
2694 
2695  MFEM_VERIFY(rowOffsets[i+1] > 0, "Invalid input blocks");
2696  rowOffsets[i+1] += rowOffsets[i];
2697  }
2698 
2699  for (int j=0; j<numBlockCols; ++j)
2700  {
2701  MFEM_VERIFY(colOffsets[j+1] > 0, "Invalid input blocks");
2702  colOffsets[j+1] += colOffsets[j];
2703  }
2704 
2705  const int num_loc_rows = rowOffsets[numBlockRows];
2706  const int num_loc_cols = colOffsets[numBlockCols];
2707 
2708  int nprocs, rank;
2709  MPI_Comm_rank(comm, &rank);
2710  MPI_Comm_size(comm, &nprocs);
2711 
2712  std::vector<int> all_num_loc_rows(nprocs);
2713  std::vector<int> all_num_loc_cols(nprocs);
2714  std::vector<HYPRE_BigInt> procRowOffsets(nprocs);
2715  std::vector<HYPRE_BigInt> procColOffsets(nprocs);
2716  std::vector<std::vector<HYPRE_BigInt>> blockRowProcOffsets(numBlockRows);
2717  std::vector<std::vector<HYPRE_BigInt>> blockColProcOffsets(numBlockCols);
2718  std::vector<std::vector<int>> procBlockRowOffsets(nprocs);
2719  std::vector<std::vector<int>> procBlockColOffsets(nprocs);
2720 
2721  HYPRE_BigInt first_loc_row, glob_nrows, first_loc_col, glob_ncols;
2722  GatherBlockOffsetData(comm, rank, nprocs, num_loc_rows, rowOffsets,
2723  all_num_loc_rows, numBlockRows, blockRowProcOffsets,
2724  procRowOffsets, procBlockRowOffsets, first_loc_row,
2725  glob_nrows);
2726 
2727  GatherBlockOffsetData(comm, rank, nprocs, num_loc_cols, colOffsets,
2728  all_num_loc_cols, numBlockCols, blockColProcOffsets,
2729  procColOffsets, procBlockColOffsets, first_loc_col,
2730  glob_ncols);
2731 
2732  std::vector<int> opI(num_loc_rows + 1);
2733  std::vector<int> cnt(num_loc_rows);
2734 
2735  for (int i = 0; i < num_loc_rows; ++i)
2736  {
2737  opI[i] = 0;
2738  cnt[i] = 0;
2739  }
2740 
2741  opI[num_loc_rows] = 0;
2742 
2743  Array2D<hypre_CSRMatrix *> csr_blocks(numBlockRows, numBlockCols);
2744 
2745  // Loop over all blocks, to determine nnz for each row.
2746  for (int i = 0; i < numBlockRows; ++i)
2747  {
2748  for (int j = 0; j < numBlockCols; ++j)
2749  {
2750  if (blocks(i, j) == NULL)
2751  {
2752  csr_blocks(i, j) = NULL;
2753  }
2754  else
2755  {
2756  blocks(i, j)->HostRead();
2757  csr_blocks(i, j) = hypre_MergeDiagAndOffd(*blocks(i, j));
2758  blocks(i, j)->HypreRead();
2759 
2760  for (int k = 0; k < csr_blocks(i, j)->num_rows; ++k)
2761  {
2762  opI[rowOffsets[i] + k + 1] +=
2763  csr_blocks(i, j)->i[k + 1] - csr_blocks(i, j)->i[k];
2764  }
2765  }
2766  }
2767  }
2768 
2769  // Now opI[i] is nnz for row i-1. Do a partial sum to get offsets.
2770  for (int i = 0; i < num_loc_rows; ++i)
2771  {
2772  opI[i + 1] += opI[i];
2773  }
2774 
2775  const int nnz = opI[num_loc_rows];
2776 
2777  std::vector<HYPRE_BigInt> opJ(nnz);
2778  std::vector<double> data(nnz);
2779 
2780  // Loop over all blocks, to set matrix data.
2781  for (int i = 0; i < numBlockRows; ++i)
2782  {
2783  for (int j = 0; j < numBlockCols; ++j)
2784  {
2785  if (csr_blocks(i, j) != NULL)
2786  {
2787  const int nrows = csr_blocks(i, j)->num_rows;
2788  const double cij = blockCoeff ? (*blockCoeff)(i, j) : 1.0;
2789 #if MFEM_HYPRE_VERSION >= 21600
2790  const bool usingBigJ = (csr_blocks(i, j)->big_j != NULL);
2791 #endif
2792 
2793  for (int k = 0; k < nrows; ++k)
2794  {
2795  const int rowg = rowOffsets[i] + k; // process-local row
2796  const int nnz_k = csr_blocks(i,j)->i[k+1]-csr_blocks(i,j)->i[k];
2797  const int osk = csr_blocks(i, j)->i[k];
2798 
2799  for (int l = 0; l < nnz_k; ++l)
2800  {
2801  // Find the column process offset for the block.
2802 #if MFEM_HYPRE_VERSION >= 21600
2803  const HYPRE_Int bcol = usingBigJ ?
2804  csr_blocks(i, j)->big_j[osk + l] :
2805  csr_blocks(i, j)->j[osk + l];
2806 #else
2807  const HYPRE_Int bcol = csr_blocks(i, j)->j[osk + l];
2808 #endif
2809 
2810  // find the processor 'bcolproc' that holds column 'bcol':
2811  const auto &offs = blockColProcOffsets[j];
2812  const int bcolproc =
2813  std::upper_bound(offs.begin() + 1, offs.end(), bcol)
2814  - offs.begin() - 1;
2815 
2816  opJ[opI[rowg] + cnt[rowg]] = procColOffsets[bcolproc] +
2817  procBlockColOffsets[bcolproc][j]
2818  + bcol
2819  - blockColProcOffsets[j][bcolproc];
2820  data[opI[rowg] + cnt[rowg]] = cij * csr_blocks(i, j)->data[osk + l];
2821  cnt[rowg]++;
2822  }
2823  }
2824  }
2825  }
2826  }
2827 
2828  for (int i = 0; i < numBlockRows; ++i)
2829  {
2830  for (int j = 0; j < numBlockCols; ++j)
2831  {
2832  if (csr_blocks(i, j) != NULL)
2833  {
2834  hypre_CSRMatrixDestroy(csr_blocks(i, j));
2835  }
2836  }
2837  }
2838 
2839  std::vector<HYPRE_BigInt> rowStarts2(2);
2840  rowStarts2[0] = first_loc_row;
2841  rowStarts2[1] = first_loc_row + all_num_loc_rows[rank];
2842 
2843  std::vector<HYPRE_BigInt> colStarts2(2);
2844  colStarts2[0] = first_loc_col;
2845  colStarts2[1] = first_loc_col + all_num_loc_cols[rank];
2846 
2847  MFEM_VERIFY(HYPRE_AssumedPartitionCheck(),
2848  "only 'assumed partition' mode is supported");
2849 
2850  return new HypreParMatrix(comm, num_loc_rows, glob_nrows, glob_ncols,
2851  opI.data(), opJ.data(),
2852  data.data(),
2853  rowStarts2.data(),
2854  colStarts2.data());
2855 }
2856 
2857 void EliminateBC(const HypreParMatrix &A, const HypreParMatrix &Ae,
2858  const Array<int> &ess_dof_list,
2859  const Vector &X, Vector &B)
2860 {
2861  A.EliminateBC(Ae, ess_dof_list, X, B);
2862 }
2863 
2864 // Taubin or "lambda-mu" scheme, which alternates between positive and
2865 // negative step sizes to approximate low-pass filter effect.
2866 
2867 int ParCSRRelax_Taubin(hypre_ParCSRMatrix *A, // matrix to relax with
2868  hypre_ParVector *f, // right-hand side
2869  double lambda,
2870  double mu,
2871  int N,
2872  double max_eig,
2873  hypre_ParVector *u, // initial/updated approximation
2874  hypre_ParVector *r // another temp vector
2875  )
2876 {
2877  hypre_CSRMatrix *A_diag = hypre_ParCSRMatrixDiag(A);
2878  HYPRE_Int num_rows = hypre_CSRMatrixNumRows(A_diag);
2879 
2880  double *u_data = hypre_VectorData(hypre_ParVectorLocalVector(u));
2881  double *r_data = hypre_VectorData(hypre_ParVectorLocalVector(r));
2882 
2883  for (int i = 0; i < N; i++)
2884  {
2885  // get residual: r = f - A*u
2886  hypre_ParVectorCopy(f, r);
2887  hypre_ParCSRMatrixMatvec(-1.0, A, u, 1.0, r);
2888 
2889  double coef;
2890  (0 == (i % 2)) ? coef = lambda : coef = mu;
2891 
2892  for (HYPRE_Int j = 0; j < num_rows; j++)
2893  {
2894  u_data[j] += coef*r_data[j] / max_eig;
2895  }
2896  }
2897 
2898  return 0;
2899 }
2900 
2901 // FIR scheme, which uses Chebyshev polynomials and a window function
2902 // to approximate a low-pass step filter.
2903 
2904 int ParCSRRelax_FIR(hypre_ParCSRMatrix *A, // matrix to relax with
2905  hypre_ParVector *f, // right-hand side
2906  double max_eig,
2907  int poly_order,
2908  double* fir_coeffs,
2909  hypre_ParVector *u, // initial/updated approximation
2910  hypre_ParVector *x0, // temporaries
2911  hypre_ParVector *x1,
2912  hypre_ParVector *x2,
2913  hypre_ParVector *x3)
2914 
2915 {
2916  hypre_CSRMatrix *A_diag = hypre_ParCSRMatrixDiag(A);
2917  HYPRE_Int num_rows = hypre_CSRMatrixNumRows(A_diag);
2918 
2919  double *u_data = hypre_VectorData(hypre_ParVectorLocalVector(u));
2920 
2921  double *x0_data = hypre_VectorData(hypre_ParVectorLocalVector(x0));
2922  double *x1_data = hypre_VectorData(hypre_ParVectorLocalVector(x1));
2923  double *x2_data = hypre_VectorData(hypre_ParVectorLocalVector(x2));
2924  double *x3_data = hypre_VectorData(hypre_ParVectorLocalVector(x3));
2925 
2926  hypre_ParVectorCopy(u, x0);
2927 
2928  // x1 = f -A*x0/max_eig
2929  hypre_ParVectorCopy(f, x1);
2930  hypre_ParCSRMatrixMatvec(-1.0, A, x0, 1.0, x1);
2931 
2932  for (HYPRE_Int i = 0; i < num_rows; i++)
2933  {
2934  x1_data[i] /= -max_eig;
2935  }
2936 
2937  // x1 = x0 -x1
2938  for (HYPRE_Int i = 0; i < num_rows; i++)
2939  {
2940  x1_data[i] = x0_data[i] -x1_data[i];
2941  }
2942 
2943  // x3 = f0*x0 +f1*x1
2944  for (HYPRE_Int i = 0; i < num_rows; i++)
2945  {
2946  x3_data[i] = fir_coeffs[0]*x0_data[i] +fir_coeffs[1]*x1_data[i];
2947  }
2948 
2949  for (int n = 2; n <= poly_order; n++)
2950  {
2951  // x2 = f - A*x1/max_eig
2952  hypre_ParVectorCopy(f, x2);
2953  hypre_ParCSRMatrixMatvec(-1.0, A, x1, 1.0, x2);
2954 
2955  for (HYPRE_Int i = 0; i < num_rows; i++)
2956  {
2957  x2_data[i] /= -max_eig;
2958  }
2959 
2960  // x2 = (x1-x0) +(x1-2*x2)
2961  // x3 = x3 +f[n]*x2
2962  // x0 = x1
2963  // x1 = x2
2964 
2965  for (HYPRE_Int i = 0; i < num_rows; i++)
2966  {
2967  x2_data[i] = (x1_data[i]-x0_data[i]) +(x1_data[i]-2*x2_data[i]);
2968  x3_data[i] += fir_coeffs[n]*x2_data[i];
2969  x0_data[i] = x1_data[i];
2970  x1_data[i] = x2_data[i];
2971  }
2972  }
2973 
2974  for (HYPRE_Int i = 0; i < num_rows; i++)
2975  {
2976  u_data[i] = x3_data[i];
2977  }
2978 
2979  return 0;
2980 }
2981 
2983 {
2984  type = default_type;
2985  relax_times = 1;
2986  relax_weight = 1.0;
2987  omega = 1.0;
2988  poly_order = 2;
2989  poly_fraction = .3;
2990  lambda = 0.5;
2991  mu = -0.5;
2992  taubin_iter = 40;
2993 
2994  l1_norms = NULL;
2995  pos_l1_norms = false;
2996  eig_est_cg_iter = 10;
2997  B = X = V = Z = NULL;
2998  auxB.Reset(); auxX.Reset();
2999  X0 = X1 = NULL;
3000  fir_coeffs = NULL;
3001  A_is_symmetric = false;
3002 }
3003 
3005  int relax_times_, double relax_weight_,
3006  double omega_, int poly_order_,
3007  double poly_fraction_, int eig_est_cg_iter_)
3008 {
3009  type = type_;
3010  relax_times = relax_times_;
3011  relax_weight = relax_weight_;
3012  omega = omega_;
3013  poly_order = poly_order_;
3014  poly_fraction = poly_fraction_;
3015  eig_est_cg_iter = eig_est_cg_iter_;
3016 
3017  l1_norms = NULL;
3018  pos_l1_norms = false;
3019  B = X = V = Z = NULL;
3020  auxB.Reset(); auxX.Reset();
3021  X0 = X1 = NULL;
3022  fir_coeffs = NULL;
3023  A_is_symmetric = false;
3024 
3025  SetOperator(A_);
3026 }
3027 
3028 void HypreSmoother::SetType(HypreSmoother::Type type_, int relax_times_)
3029 {
3030  type = static_cast<int>(type_);
3031  relax_times = relax_times_;
3032 }
3033 
3034 void HypreSmoother::SetSOROptions(double relax_weight_, double omega_)
3035 {
3036  relax_weight = relax_weight_;
3037  omega = omega_;
3038 }
3039 
3040 void HypreSmoother::SetPolyOptions(int poly_order_, double poly_fraction_,
3041  int eig_est_cg_iter_)
3042 {
3043  poly_order = poly_order_;
3044  poly_fraction = poly_fraction_;
3045  eig_est_cg_iter = eig_est_cg_iter_;
3046 }
3047 
3048 void HypreSmoother::SetTaubinOptions(double lambda_, double mu_,
3049  int taubin_iter_)
3050 {
3051  lambda = lambda_;
3052  mu = mu_;
3053  taubin_iter = taubin_iter_;
3054 }
3055 
3056 void HypreSmoother::SetWindowByName(const char* name)
3057 {
3058  double a = -1, b, c;
3059  if (!strcmp(name,"Rectangular")) { a = 1.0, b = 0.0, c = 0.0; }
3060  if (!strcmp(name,"Hanning")) { a = 0.5, b = 0.5, c = 0.0; }
3061  if (!strcmp(name,"Hamming")) { a = 0.54, b = 0.46, c = 0.0; }
3062  if (!strcmp(name,"Blackman")) { a = 0.42, b = 0.50, c = 0.08; }
3063  if (a < 0)
3064  {
3065  mfem_error("HypreSmoother::SetWindowByName : name not recognized!");
3066  }
3067 
3068  SetWindowParameters(a, b, c);
3069 }
3070 
3071 void HypreSmoother::SetWindowParameters(double a, double b, double c)
3072 {
3073  window_params[0] = a;
3074  window_params[1] = b;
3075  window_params[2] = c;
3076 }
3077 
3079 {
3080  A = const_cast<HypreParMatrix *>(dynamic_cast<const HypreParMatrix *>(&op));
3081  if (A == NULL)
3082  {
3083  mfem_error("HypreSmoother::SetOperator : not HypreParMatrix!");
3084  }
3085 
3086  height = A->Height();
3087  width = A->Width();
3088 
3089  auxX.Delete(); auxB.Delete();
3090  if (B) { delete B; }
3091  if (X) { delete X; }
3092  if (V) { delete V; }
3093  if (Z) { delete Z; }
3094  if (l1_norms)
3095  {
3096  mfem_hypre_TFree(l1_norms);
3097  }
3098  delete X0;
3099  delete X1;
3100 
3101  X1 = X0 = Z = V = B = X = NULL;
3102  auxB.Reset(); auxX.Reset();
3103 
3104  if (type >= 1 && type <= 4)
3105  {
3106  hypre_ParCSRComputeL1Norms(*A, type, NULL, &l1_norms);
3107  // The above call will set the hypre_error_flag when it encounters zero
3108  // rows in A.
3109  }
3110  else if (type == 5)
3111  {
3112  l1_norms = mfem_hypre_CTAlloc(double, height);
3113  Vector ones(height), diag(l1_norms, height);
3114  ones = 1.0;
3115  A->Mult(ones, diag);
3116  }
3117  else
3118  {
3119  l1_norms = NULL;
3120  }
3121  if (l1_norms && pos_l1_norms)
3122  {
3123 #ifdef HYPRE_USING_CUDA
3124  double *d_l1_norms = l1_norms; // avoid *this capture
3125  CuWrap1D(height, [=] MFEM_DEVICE (int i)
3126  {
3127  d_l1_norms[i] = std::abs(d_l1_norms[i]);
3128  });
3129 #else
3130  for (int i = 0; i < height; i++)
3131  {
3132  l1_norms[i] = std::abs(l1_norms[i]);
3133  }
3134 #endif
3135  }
3136 
3137  if (type == 16)
3138  {
3139  poly_scale = 1;
3140  if (eig_est_cg_iter > 0)
3141  {
3142  hypre_ParCSRMaxEigEstimateCG(*A, poly_scale, eig_est_cg_iter,
3144  }
3145  else
3146  {
3147  min_eig_est = 0;
3148  hypre_ParCSRMaxEigEstimate(*A, poly_scale, &max_eig_est);
3149  }
3150  Z = new HypreParVector(*A);
3151  }
3152  else if (type == 1001 || type == 1002)
3153  {
3154  poly_scale = 0;
3155  if (eig_est_cg_iter > 0)
3156  {
3157  hypre_ParCSRMaxEigEstimateCG(*A, poly_scale, eig_est_cg_iter,
3159  }
3160  else
3161  {
3162  min_eig_est = 0;
3163  hypre_ParCSRMaxEigEstimate(*A, poly_scale, &max_eig_est);
3164  }
3165 
3166  // The Taubin and FIR polynomials are defined on [0, 2]
3167  max_eig_est /= 2;
3168 
3169  // Compute window function, Chebyshev coefficients, and allocate temps.
3170  if (type == 1002)
3171  {
3172  // Temporaries for Chebyshev recursive evaluation
3173  Z = new HypreParVector(*A);
3174  X0 = new HypreParVector(*A);
3175  X1 = new HypreParVector(*A);
3176 
3178  }
3179  }
3180 }
3181 
3183 {
3184  if (fir_coeffs)
3185  {
3186  delete [] fir_coeffs;
3187  }
3188 
3189  fir_coeffs = new double[poly_order+1];
3190 
3191  double* window_coeffs = new double[poly_order+1];
3192  double* cheby_coeffs = new double[poly_order+1];
3193 
3194  double a = window_params[0];
3195  double b = window_params[1];
3196  double c = window_params[2];
3197  for (int i = 0; i <= poly_order; i++)
3198  {
3199  double t = (i*M_PI)/(poly_order+1);
3200  window_coeffs[i] = a + b*cos(t) +c*cos(2*t);
3201  }
3202 
3203  double k_pb = poly_fraction*max_eig;
3204  double theta_pb = acos(1.0 -0.5*k_pb);
3205  double sigma = 0.0;
3206  cheby_coeffs[0] = (theta_pb +sigma)/M_PI;
3207  for (int i = 1; i <= poly_order; i++)
3208  {
3209  double t = i*(theta_pb+sigma);
3210  cheby_coeffs[i] = 2.0*sin(t)/(i*M_PI);
3211  }
3212 
3213  for (int i = 0; i <= poly_order; i++)
3214  {
3215  fir_coeffs[i] = window_coeffs[i]*cheby_coeffs[i];
3216  }
3217 
3218  delete[] window_coeffs;
3219  delete[] cheby_coeffs;
3220 }
3221 
3223 {
3224  if (A == NULL)
3225  {
3226  mfem_error("HypreSmoother::Mult (...) : HypreParMatrix A is missing");
3227  return;
3228  }
3229 
3230  // TODO: figure out where each function needs A, b, and x ...
3231 
3232  b.HypreRead();
3233  if (!iterative_mode)
3234  {
3235  x.HypreWrite();
3236  if (type == 0 && relax_times == 1)
3237  {
3238  // Note: hypre_ParCSRDiagScale() is not exposed in older versions
3239  HYPRE_ParCSRDiagScale(NULL, *A, b, x);
3240  if (relax_weight != 1.0)
3241  {
3242  hypre_ParVectorScale(relax_weight, x);
3243  }
3244  return;
3245  }
3246  hypre_ParVectorSetConstantValues(x, 0.0);
3247  }
3248  else
3249  {
3250  x.HypreReadWrite();
3251  }
3252 
3253  if (V == NULL)
3254  {
3255  V = new HypreParVector(*A);
3256  }
3257 
3258  if (type == 1001)
3259  {
3260  for (int sweep = 0; sweep < relax_times; sweep++)
3261  {
3263  max_eig_est,
3264  x, *V);
3265  }
3266  }
3267  else if (type == 1002)
3268  {
3269  for (int sweep = 0; sweep < relax_times; sweep++)
3270  {
3271  ParCSRRelax_FIR(*A, b,
3272  max_eig_est,
3273  poly_order,
3274  fir_coeffs,
3275  x,
3276  *X0, *X1, *V, *Z);
3277  }
3278  }
3279  else
3280  {
3281  int hypre_type = type;
3282  // hypre doesn't have lumped Jacobi, so treat the action as l1-Jacobi
3283  if (type == 5) { hypre_type = 1; }
3284 
3285  if (Z == NULL)
3286  {
3287  hypre_ParCSRRelax(*A, b, hypre_type,
3290  x, *V, NULL);
3291  }
3292  else
3293  {
3294  hypre_ParCSRRelax(*A, b, hypre_type,
3297  x, *V, *Z);
3298  }
3299  }
3300 }
3301 
3302 void HypreSmoother::Mult(const Vector &b, Vector &x) const
3303 {
3304  MFEM_ASSERT(b.Size() == NumCols(), "");
3305  MFEM_ASSERT(x.Size() == NumRows(), "");
3306 
3307  if (A == NULL)
3308  {
3309  mfem_error("HypreSmoother::Mult (...) : HypreParMatrix A is missing");
3310  return;
3311  }
3312 
3313  if (B == NULL)
3314  {
3315  B = new HypreParVector(A->GetComm(),
3316  A -> GetGlobalNumRows(),
3317  nullptr,
3318  A -> GetRowStarts());
3319  X = new HypreParVector(A->GetComm(),
3320  A -> GetGlobalNumCols(),
3321  nullptr,
3322  A -> GetColStarts());
3323  }
3324 
3325  const bool bshallow = CanShallowCopy(b.GetMemory(), GetHypreMemoryClass());
3326  const bool xshallow = CanShallowCopy(x.GetMemory(), GetHypreMemoryClass());
3327 
3328  if (bshallow)
3329  {
3330  B->WrapMemoryRead(b.GetMemory());
3331  }
3332  else
3333  {
3334  if (auxB.Empty()) { auxB.New(NumCols(), GetHypreMemoryType()); }
3335  auxB.CopyFrom(b.GetMemory(), auxB.Capacity()); // Deep copy
3336  B->WrapMemoryRead(auxB);
3337  }
3338 
3339  if (xshallow)
3340  {
3342  else { X->WrapMemoryWrite(x.GetMemory()); }
3343  }
3344  else
3345  {
3346  if (auxX.Empty()) { auxX.New(NumRows(), GetHypreMemoryType()); }
3347  if (iterative_mode)
3348  {
3349  auxX.CopyFrom(x.GetMemory(), x.Size()); // Deep copy
3351  }
3352  else
3353  {
3355  }
3356  }
3357 
3358  Mult(*B, *X);
3359 
3360  if (!xshallow) { x = *X; } // Deep copy
3361 }
3362 
3364 {
3365  if (A_is_symmetric || type == 0 || type == 1 || type == 5)
3366  {
3367  Mult(b, x);
3368  return;
3369  }
3370  mfem_error("HypreSmoother::MultTranspose (...) : undefined!\n");
3371 }
3372 
3374 {
3375  auxX.Delete(); auxB.Delete();
3376  if (B) { delete B; }
3377  if (X) { delete X; }
3378  if (V) { delete V; }
3379  if (Z) { delete Z; }
3380  if (l1_norms)
3381  {
3382  mfem_hypre_TFree(l1_norms);
3383  }
3384  if (fir_coeffs)
3385  {
3386  delete [] fir_coeffs;
3387  }
3388  if (X0) { delete X0; }
3389  if (X1) { delete X1; }
3390 }
3391 
3392 
3394 {
3395  A = NULL;
3396  setup_called = 0;
3397  B = X = NULL;
3398  auxB.Reset();
3399  auxX.Reset();
3401 }
3402 
3404  : Solver(A_->Height(), A_->Width())
3405 {
3406  A = A_;
3407  setup_called = 0;
3408  B = X = NULL;
3409  auxB.Reset();
3410  auxX.Reset();
3412 }
3413 
3415 {
3416  HYPRE_Int err;
3417  if (A == NULL)
3418  {
3419  mfem_error("HypreSolver::Mult (...) : HypreParMatrix A is missing");
3420  return;
3421  }
3422 
3423  if (!iterative_mode)
3424  {
3425  x.HypreWrite();
3426  hypre_ParVectorSetConstantValues(x, 0.0);
3427  }
3428 
3429  b.HypreRead();
3430  x.HypreReadWrite();
3431 
3432  if (!setup_called)
3433  {
3434  err = SetupFcn()(*this, *A, b, x);
3436  {
3437  if (err) { MFEM_WARNING("Error during setup! Error code: " << err); }
3438  }
3439  else if (error_mode == ABORT_HYPRE_ERRORS)
3440  {
3441  MFEM_VERIFY(!err, "Error during setup! Error code: " << err);
3442  }
3443  hypre_error_flag = 0;
3444  setup_called = 1;
3445  }
3446 
3447  err = SolveFcn()(*this, *A, b, x);
3449  {
3450  if (err) { MFEM_WARNING("Error during solve! Error code: " << err); }
3451  }
3452  else if (error_mode == ABORT_HYPRE_ERRORS)
3453  {
3454  MFEM_VERIFY(!err, "Error during solve! Error code: " << err);
3455  }
3456  hypre_error_flag = 0;
3457 }
3458 
3459 void HypreSolver::Mult(const Vector &b, Vector &x) const
3460 {
3461  MFEM_ASSERT(b.Size() == NumCols(), "");
3462  MFEM_ASSERT(x.Size() == NumRows(), "");
3463 
3464  if (A == NULL)
3465  {
3466  mfem_error("HypreSolver::Mult (...) : HypreParMatrix A is missing");
3467  return;
3468  }
3469 
3470  if (B == NULL)
3471  {
3472  B = new HypreParVector(A->GetComm(),
3473  A -> GetGlobalNumRows(),
3474  nullptr,
3475  A -> GetRowStarts());
3476  X = new HypreParVector(A->GetComm(),
3477  A -> GetGlobalNumCols(),
3478  nullptr,
3479  A -> GetColStarts());
3480  }
3481 
3482  const bool bshallow = CanShallowCopy(b.GetMemory(), GetHypreMemoryClass());
3483  const bool xshallow = CanShallowCopy(x.GetMemory(), GetHypreMemoryClass());
3484 
3485  if (bshallow)
3486  {
3487  B->WrapMemoryRead(b.GetMemory());
3488  }
3489  else
3490  {
3491  if (auxB.Empty()) { auxB.New(NumCols(), GetHypreMemoryType()); }
3492  auxB.CopyFrom(b.GetMemory(), auxB.Capacity()); // Deep copy
3493  B->WrapMemoryRead(auxB);
3494  }
3495 
3496  if (xshallow)
3497  {
3499  else { X->WrapMemoryWrite(x.GetMemory()); }
3500  }
3501  else
3502  {
3503  if (auxX.Empty()) { auxX.New(NumRows(), GetHypreMemoryType()); }
3504  if (iterative_mode)
3505  {
3506  auxX.CopyFrom(x.GetMemory(), x.Size()); // Deep copy
3508  }
3509  else
3510  {
3512  }
3513  }
3514 
3515  Mult(*B, *X);
3516 
3517  if (!xshallow) { x = *X; } // Deep copy
3518 }
3519 
3521 {
3522  if (B) { delete B; }
3523  if (X) { delete X; }
3524  auxB.Delete();
3525  auxX.Delete();
3526 }
3527 
3528 
3529 HyprePCG::HyprePCG(MPI_Comm comm) : precond(NULL)
3530 {
3531  iterative_mode = true;
3532 
3533  HYPRE_ParCSRPCGCreate(comm, &pcg_solver);
3534 }
3535 
3536 HyprePCG::HyprePCG(const HypreParMatrix &A_) : HypreSolver(&A_), precond(NULL)
3537 {
3538  MPI_Comm comm;
3539 
3540  iterative_mode = true;
3541 
3542  HYPRE_ParCSRMatrixGetComm(*A, &comm);
3543 
3544  HYPRE_ParCSRPCGCreate(comm, &pcg_solver);
3545 }
3546 
3548 {
3549  const HypreParMatrix *new_A = dynamic_cast<const HypreParMatrix *>(&op);
3550  MFEM_VERIFY(new_A, "new Operator must be a HypreParMatrix!");
3551 
3552  // update base classes: Operator, Solver, HypreSolver
3553  height = new_A->Height();
3554  width = new_A->Width();
3555  A = const_cast<HypreParMatrix *>(new_A);
3556  if (precond)
3557  {
3558  precond->SetOperator(*A);
3559  this->SetPreconditioner(*precond);
3560  }
3561  setup_called = 0;
3562  delete X;
3563  delete B;
3564  B = X = NULL;
3565  auxB.Delete(); auxB.Reset();
3566  auxX.Delete(); auxX.Reset();
3567 }
3568 
3569 void HyprePCG::SetTol(double tol)
3570 {
3571  HYPRE_PCGSetTol(pcg_solver, tol);
3572 }
3573 
3574 void HyprePCG::SetAbsTol(double atol)
3575 {
3576  HYPRE_PCGSetAbsoluteTol(pcg_solver, atol);
3577 }
3578 
3579 void HyprePCG::SetMaxIter(int max_iter)
3580 {
3581  HYPRE_PCGSetMaxIter(pcg_solver, max_iter);
3582 }
3583 
3584 void HyprePCG::SetLogging(int logging)
3585 {
3586  HYPRE_PCGSetLogging(pcg_solver, logging);
3587 }
3588 
3589 void HyprePCG::SetPrintLevel(int print_lvl)
3590 {
3591  HYPRE_ParCSRPCGSetPrintLevel(pcg_solver, print_lvl);
3592 }
3593 
3595 {
3596  precond = &precond_;
3597 
3598  HYPRE_ParCSRPCGSetPrecond(pcg_solver,
3599  precond_.SolveFcn(),
3600  precond_.SetupFcn(),
3601  precond_);
3602 }
3603 
3604 void HyprePCG::SetResidualConvergenceOptions(int res_frequency, double rtol)
3605 {
3606  HYPRE_PCGSetTwoNorm(pcg_solver, 1);
3607  if (res_frequency > 0)
3608  {
3609  HYPRE_PCGSetRecomputeResidualP(pcg_solver, res_frequency);
3610  }
3611  if (rtol > 0.0)
3612  {
3613  HYPRE_PCGSetResidualTol(pcg_solver, rtol);
3614  }
3615 }
3616 
3618 {
3619  int myid;
3620  HYPRE_Int time_index = 0;
3621  HYPRE_Int num_iterations;
3622  double final_res_norm;
3623  MPI_Comm comm;
3624  HYPRE_Int print_level;
3625 
3626  HYPRE_PCGGetPrintLevel(pcg_solver, &print_level);
3627  HYPRE_ParCSRPCGSetPrintLevel(pcg_solver, print_level%3);
3628 
3629  HYPRE_ParCSRMatrixGetComm(*A, &comm);
3630 
3631  if (!iterative_mode)
3632  {
3633  x.HypreWrite();
3634  hypre_ParVectorSetConstantValues(x, 0.0);
3635  }
3636 
3637  b.HypreRead();
3638  x.HypreReadWrite();
3639 
3640  if (!setup_called)
3641  {
3642  if (print_level > 0 && print_level < 3)
3643  {
3644  time_index = hypre_InitializeTiming("PCG Setup");
3645  hypre_BeginTiming(time_index);
3646  }
3647 
3648  HYPRE_ParCSRPCGSetup(pcg_solver, *A, b, x);
3649  setup_called = 1;
3650 
3651  if (print_level > 0 && print_level < 3)
3652  {
3653  hypre_EndTiming(time_index);
3654  hypre_PrintTiming("Setup phase times", comm);
3655  hypre_FinalizeTiming(time_index);
3656  hypre_ClearTiming();
3657  }
3658  }
3659 
3660  if (print_level > 0 && print_level < 3)
3661  {
3662  time_index = hypre_InitializeTiming("PCG Solve");
3663  hypre_BeginTiming(time_index);
3664  }
3665 
3666  HYPRE_ParCSRPCGSolve(pcg_solver, *A, b, x);
3667 
3668  if (print_level > 0)
3669  {
3670  if (print_level < 3)
3671  {
3672  hypre_EndTiming(time_index);
3673  hypre_PrintTiming("Solve phase times", comm);
3674  hypre_FinalizeTiming(time_index);
3675  hypre_ClearTiming();
3676  }
3677 
3678  HYPRE_ParCSRPCGGetNumIterations(pcg_solver, &num_iterations);
3679  HYPRE_ParCSRPCGGetFinalRelativeResidualNorm(pcg_solver,
3680  &final_res_norm);
3681 
3682  MPI_Comm_rank(comm, &myid);
3683 
3684  if (myid == 0)
3685  {
3686  mfem::out << "PCG Iterations = " << num_iterations << endl
3687  << "Final PCG Relative Residual Norm = " << final_res_norm
3688  << endl;
3689  }
3690  }
3691  HYPRE_ParCSRPCGSetPrintLevel(pcg_solver, print_level);
3692 }
3693 
3695 {
3696  HYPRE_ParCSRPCGDestroy(pcg_solver);
3697 }
3698 
3699 
3700 HypreGMRES::HypreGMRES(MPI_Comm comm) : precond(NULL)
3701 {
3702  iterative_mode = true;
3703 
3704  HYPRE_ParCSRGMRESCreate(comm, &gmres_solver);
3705  SetDefaultOptions();
3706 }
3707 
3709  : HypreSolver(&A_), precond(NULL)
3710 {
3711  MPI_Comm comm;
3712 
3713  iterative_mode = true;
3714 
3715  HYPRE_ParCSRMatrixGetComm(*A, &comm);
3716 
3717  HYPRE_ParCSRGMRESCreate(comm, &gmres_solver);
3718  SetDefaultOptions();
3719 }
3720 
3721 void HypreGMRES::SetDefaultOptions()
3722 {
3723  int k_dim = 50;
3724  int max_iter = 100;
3725  double tol = 1e-6;
3726 
3727  HYPRE_ParCSRGMRESSetKDim(gmres_solver, k_dim);
3728  HYPRE_ParCSRGMRESSetMaxIter(gmres_solver, max_iter);
3729  HYPRE_ParCSRGMRESSetTol(gmres_solver, tol);
3730 }
3731 
3733 {
3734  const HypreParMatrix *new_A = dynamic_cast<const HypreParMatrix *>(&op);
3735  MFEM_VERIFY(new_A, "new Operator must be a HypreParMatrix!");
3736 
3737  // update base classes: Operator, Solver, HypreSolver
3738  height = new_A->Height();
3739  width = new_A->Width();
3740  A = const_cast<HypreParMatrix *>(new_A);
3741  if (precond)
3742  {
3743  precond->SetOperator(*A);
3744  this->SetPreconditioner(*precond);
3745  }
3746  setup_called = 0;
3747  delete X;
3748  delete B;
3749  B = X = NULL;
3750  auxB.Delete(); auxB.Reset();
3751  auxX.Delete(); auxX.Reset();
3752 }
3753 
3754 void HypreGMRES::SetTol(double tol)
3755 {
3756  HYPRE_GMRESSetTol(gmres_solver, tol);
3757 }
3758 
3759 void HypreGMRES::SetAbsTol(double tol)
3760 {
3761  HYPRE_GMRESSetAbsoluteTol(gmres_solver, tol);
3762 }
3763 
3764 void HypreGMRES::SetMaxIter(int max_iter)
3765 {
3766  HYPRE_GMRESSetMaxIter(gmres_solver, max_iter);
3767 }
3768 
3769 void HypreGMRES::SetKDim(int k_dim)
3770 {
3771  HYPRE_GMRESSetKDim(gmres_solver, k_dim);
3772 }
3773 
3774 void HypreGMRES::SetLogging(int logging)
3775 {
3776  HYPRE_GMRESSetLogging(gmres_solver, logging);
3777 }
3778 
3779 void HypreGMRES::SetPrintLevel(int print_lvl)
3780 {
3781  HYPRE_GMRESSetPrintLevel(gmres_solver, print_lvl);
3782 }
3783 
3785 {
3786  precond = &precond_;
3787 
3788  HYPRE_ParCSRGMRESSetPrecond(gmres_solver,
3789  precond_.SolveFcn(),
3790  precond_.SetupFcn(),
3791  precond_);
3792 }
3793 
3795 {
3796  int myid;
3797  HYPRE_Int time_index = 0;
3798  HYPRE_Int num_iterations;
3799  double final_res_norm;
3800  MPI_Comm comm;
3801  HYPRE_Int print_level;
3802 
3803  HYPRE_GMRESGetPrintLevel(gmres_solver, &print_level);
3804 
3805  HYPRE_ParCSRMatrixGetComm(*A, &comm);
3806 
3807  if (!iterative_mode)
3808  {
3809  x.HypreWrite();
3810  hypre_ParVectorSetConstantValues(x, 0.0);
3811  }
3812 
3813  b.HypreRead();
3814  x.HypreReadWrite();
3815 
3816  if (!setup_called)
3817  {
3818  if (print_level > 0)
3819  {
3820  time_index = hypre_InitializeTiming("GMRES Setup");
3821  hypre_BeginTiming(time_index);
3822  }
3823 
3824  HYPRE_ParCSRGMRESSetup(gmres_solver, *A, b, x);
3825  setup_called = 1;
3826 
3827  if (print_level > 0)
3828  {
3829  hypre_EndTiming(time_index);
3830  hypre_PrintTiming("Setup phase times", comm);
3831  hypre_FinalizeTiming(time_index);
3832  hypre_ClearTiming();
3833  }
3834  }
3835 
3836  if (print_level > 0)
3837  {
3838  time_index = hypre_InitializeTiming("GMRES Solve");
3839  hypre_BeginTiming(time_index);
3840  }
3841 
3842  HYPRE_ParCSRGMRESSolve(gmres_solver, *A, b, x);
3843 
3844  if (print_level > 0)
3845  {
3846  hypre_EndTiming(time_index);
3847  hypre_PrintTiming("Solve phase times", comm);
3848  hypre_FinalizeTiming(time_index);
3849  hypre_ClearTiming();
3850 
3851  HYPRE_ParCSRGMRESGetNumIterations(gmres_solver, &num_iterations);
3852  HYPRE_ParCSRGMRESGetFinalRelativeResidualNorm(gmres_solver,
3853  &final_res_norm);
3854 
3855  MPI_Comm_rank(comm, &myid);
3856 
3857  if (myid == 0)
3858  {
3859  mfem::out << "GMRES Iterations = " << num_iterations << endl
3860  << "Final GMRES Relative Residual Norm = " << final_res_norm
3861  << endl;
3862  }
3863  }
3864 }
3865 
3867 {
3868  HYPRE_ParCSRGMRESDestroy(gmres_solver);
3869 }
3870 
3871 
3872 HypreFGMRES::HypreFGMRES(MPI_Comm comm) : precond(NULL)
3873 {
3874  iterative_mode = true;
3875 
3876  HYPRE_ParCSRFlexGMRESCreate(comm, &fgmres_solver);
3877  SetDefaultOptions();
3878 }
3879 
3881  : HypreSolver(&A_), precond(NULL)
3882 {
3883  MPI_Comm comm;
3884 
3885  iterative_mode = true;
3886 
3887  HYPRE_ParCSRMatrixGetComm(*A, &comm);
3888 
3889  HYPRE_ParCSRFlexGMRESCreate(comm, &fgmres_solver);
3890  SetDefaultOptions();
3891 }
3892 
3893 void HypreFGMRES::SetDefaultOptions()
3894 {
3895  int k_dim = 50;
3896  int max_iter = 100;
3897  double tol = 1e-6;
3898 
3899  HYPRE_ParCSRFlexGMRESSetKDim(fgmres_solver, k_dim);
3900  HYPRE_ParCSRFlexGMRESSetMaxIter(fgmres_solver, max_iter);
3901  HYPRE_ParCSRFlexGMRESSetTol(fgmres_solver, tol);
3902 }
3903 
3905 {
3906  const HypreParMatrix *new_A = dynamic_cast<const HypreParMatrix *>(&op);
3907  MFEM_VERIFY(new_A, "new Operator must be a HypreParMatrix!");
3908 
3909  // update base classes: Operator, Solver, HypreSolver
3910  height = new_A->Height();
3911  width = new_A->Width();
3912  A = const_cast<HypreParMatrix *>(new_A);
3913  if (precond)
3914  {
3915  precond->SetOperator(*A);
3916  this->SetPreconditioner(*precond);
3917  }
3918  setup_called = 0;
3919  delete X;
3920  delete B;
3921  B = X = NULL;
3922  auxB.Delete(); auxB.Reset();
3923  auxX.Delete(); auxX.Reset();
3924 }
3925 
3926 void HypreFGMRES::SetTol(double tol)
3927 {
3928  HYPRE_ParCSRFlexGMRESSetTol(fgmres_solver, tol);
3929 }
3930 
3931 void HypreFGMRES::SetMaxIter(int max_iter)
3932 {
3933  HYPRE_ParCSRFlexGMRESSetMaxIter(fgmres_solver, max_iter);
3934 }
3935 
3936 void HypreFGMRES::SetKDim(int k_dim)
3937 {
3938  HYPRE_ParCSRFlexGMRESSetKDim(fgmres_solver, k_dim);
3939 }
3940 
3941 void HypreFGMRES::SetLogging(int logging)
3942 {
3943  HYPRE_ParCSRFlexGMRESSetLogging(fgmres_solver, logging);
3944 }
3945 
3946 void HypreFGMRES::SetPrintLevel(int print_lvl)
3947 {
3948  HYPRE_ParCSRFlexGMRESSetPrintLevel(fgmres_solver, print_lvl);
3949 }
3950 
3952 {
3953  precond = &precond_;
3954  HYPRE_ParCSRFlexGMRESSetPrecond(fgmres_solver,
3955  precond_.SolveFcn(),
3956  precond_.SetupFcn(),
3957  precond_);
3958 }
3959 
3961 {
3962  int myid;
3963  HYPRE_Int time_index = 0;
3964  HYPRE_Int num_iterations;
3965  double final_res_norm;
3966  MPI_Comm comm;
3967  HYPRE_Int print_level;
3968 
3969  HYPRE_FlexGMRESGetPrintLevel(fgmres_solver, &print_level);
3970 
3971  HYPRE_ParCSRMatrixGetComm(*A, &comm);
3972 
3973  if (!iterative_mode)
3974  {
3975  x.HypreWrite();
3976  hypre_ParVectorSetConstantValues(x, 0.0);
3977  }
3978 
3979  b.HypreRead();
3980  x.HypreReadWrite();
3981 
3982  if (!setup_called)
3983  {
3984  if (print_level > 0)
3985  {
3986  time_index = hypre_InitializeTiming("FGMRES Setup");
3987  hypre_BeginTiming(time_index);
3988  }
3989 
3990  HYPRE_ParCSRFlexGMRESSetup(fgmres_solver, *A, b, x);
3991  setup_called = 1;
3992 
3993  if (print_level > 0)
3994  {
3995  hypre_EndTiming(time_index);
3996  hypre_PrintTiming("Setup phase times", comm);
3997  hypre_FinalizeTiming(time_index);
3998  hypre_ClearTiming();
3999  }
4000  }
4001 
4002  if (print_level > 0)
4003  {
4004  time_index = hypre_InitializeTiming("FGMRES Solve");
4005  hypre_BeginTiming(time_index);
4006  }
4007 
4008  HYPRE_ParCSRFlexGMRESSolve(fgmres_solver, *A, b, x);
4009 
4010  if (print_level > 0)
4011  {
4012  hypre_EndTiming(time_index);
4013  hypre_PrintTiming("Solve phase times", comm);
4014  hypre_FinalizeTiming(time_index);
4015  hypre_ClearTiming();
4016 
4017  HYPRE_ParCSRFlexGMRESGetNumIterations(fgmres_solver, &num_iterations);
4018  HYPRE_ParCSRFlexGMRESGetFinalRelativeResidualNorm(fgmres_solver,
4019  &final_res_norm);
4020 
4021  MPI_Comm_rank(comm, &myid);
4022 
4023  if (myid == 0)
4024  {
4025  mfem::out << "FGMRES Iterations = " << num_iterations << endl
4026  << "Final FGMRES Relative Residual Norm = " << final_res_norm
4027  << endl;
4028  }
4029  }
4030 }
4031 
4033 {
4034  HYPRE_ParCSRFlexGMRESDestroy(fgmres_solver);
4035 }
4036 
4037 
4039 {
4040  const HypreParMatrix *new_A = dynamic_cast<const HypreParMatrix *>(&op);
4041  MFEM_VERIFY(new_A, "new Operator must be a HypreParMatrix!");
4042 
4043  // update base classes: Operator, Solver, HypreSolver
4044  height = new_A->Height();
4045  width = new_A->Width();
4046  A = const_cast<HypreParMatrix *>(new_A);
4047  setup_called = 0;
4048  delete X;
4049  delete B;
4050  B = X = NULL;
4051  auxB.Delete(); auxB.Reset();
4052  auxX.Delete(); auxX.Reset();
4053 }
4054 
4055 
4057 {
4058  HYPRE_ParaSailsCreate(comm, &sai_precond);
4059  SetDefaultOptions();
4060 }
4061 
4063 {
4064  MPI_Comm comm;
4065 
4066  HYPRE_ParCSRMatrixGetComm(A, &comm);
4067 
4068  HYPRE_ParaSailsCreate(comm, &sai_precond);
4069  SetDefaultOptions();
4070 }
4071 
4072 void HypreParaSails::SetDefaultOptions()
4073 {
4074  int sai_max_levels = 1;
4075  double sai_threshold = 0.1;
4076  double sai_filter = 0.1;
4077  int sai_sym = 0;
4078  double sai_loadbal = 0.0;
4079  int sai_reuse = 0;
4080  int sai_logging = 1;
4081 
4082  HYPRE_ParaSailsSetParams(sai_precond, sai_threshold, sai_max_levels);
4083  HYPRE_ParaSailsSetFilter(sai_precond, sai_filter);
4084  HYPRE_ParaSailsSetSym(sai_precond, sai_sym);
4085  HYPRE_ParaSailsSetLoadbal(sai_precond, sai_loadbal);
4086  HYPRE_ParaSailsSetReuse(sai_precond, sai_reuse);
4087  HYPRE_ParaSailsSetLogging(sai_precond, sai_logging);
4088 }
4089 
4090 void HypreParaSails::ResetSAIPrecond(MPI_Comm comm)
4091 {
4092  HYPRE_Int sai_max_levels;
4093  HYPRE_Real sai_threshold;
4094  HYPRE_Real sai_filter;
4095  HYPRE_Int sai_sym;
4096  HYPRE_Real sai_loadbal;
4097  HYPRE_Int sai_reuse;
4098  HYPRE_Int sai_logging;
4099 
4100  // hypre_ParAMGData *amg_data = (hypre_ParAMGData *)sai_precond;
4101  HYPRE_ParaSailsGetNlevels(sai_precond, &sai_max_levels);
4102  HYPRE_ParaSailsGetThresh(sai_precond, &sai_threshold);
4103  HYPRE_ParaSailsGetFilter(sai_precond, &sai_filter);
4104  HYPRE_ParaSailsGetSym(sai_precond, &sai_sym);
4105  HYPRE_ParaSailsGetLoadbal(sai_precond, &sai_loadbal);
4106  HYPRE_ParaSailsGetReuse(sai_precond, &sai_reuse);
4107  HYPRE_ParaSailsGetLogging(sai_precond, &sai_logging);
4108 
4109  HYPRE_ParaSailsDestroy(sai_precond);
4110  HYPRE_ParaSailsCreate(comm, &sai_precond);
4111 
4112  HYPRE_ParaSailsSetParams(sai_precond, sai_threshold, sai_max_levels);
4113  HYPRE_ParaSailsSetFilter(sai_precond, sai_filter);
4114  HYPRE_ParaSailsSetSym(sai_precond, sai_sym);
4115  HYPRE_ParaSailsSetLoadbal(sai_precond, sai_loadbal);
4116  HYPRE_ParaSailsSetReuse(sai_precond, sai_reuse);
4117  HYPRE_ParaSailsSetLogging(sai_precond, sai_logging);
4118 }
4119 
4121 {
4122  const HypreParMatrix *new_A = dynamic_cast<const HypreParMatrix *>(&op);
4123  MFEM_VERIFY(new_A, "new Operator must be a HypreParMatrix!");
4124 
4125  if (A)
4126  {
4127  MPI_Comm comm;
4128  HYPRE_ParCSRMatrixGetComm(*A, &comm);
4129  ResetSAIPrecond(comm);
4130  }
4131 
4132  // update base classes: Operator, Solver, HypreSolver
4133  height = new_A->Height();
4134  width = new_A->Width();
4135  A = const_cast<HypreParMatrix *>(new_A);
4136  setup_called = 0;
4137  delete X;
4138  delete B;
4139  B = X = NULL;
4140  auxB.Delete(); auxB.Reset();
4141  auxX.Delete(); auxX.Reset();
4142 }
4143 
4145 {
4146  HYPRE_ParaSailsSetSym(sai_precond, sym);
4147 }
4148 
4150 {
4151  HYPRE_ParaSailsDestroy(sai_precond);
4152 }
4153 
4154 
4156 {
4157  HYPRE_EuclidCreate(comm, &euc_precond);
4158  SetDefaultOptions();
4159 }
4160 
4162 {
4163  MPI_Comm comm;
4164 
4165  HYPRE_ParCSRMatrixGetComm(A, &comm);
4166 
4167  HYPRE_EuclidCreate(comm, &euc_precond);
4168  SetDefaultOptions();
4169 }
4170 
4171 void HypreEuclid::SetDefaultOptions()
4172 {
4173  int euc_level = 1; // We use ILU(1)
4174  int euc_stats = 0; // No logging
4175  int euc_mem = 0; // No memory logging
4176  int euc_bj = 0; // 1: Use Block Jacobi
4177  int euc_ro_sc = 0; // 1: Use Row scaling
4178 
4179  HYPRE_EuclidSetLevel(euc_precond, euc_level);
4180  HYPRE_EuclidSetStats(euc_precond, euc_stats);
4181  HYPRE_EuclidSetMem(euc_precond, euc_mem);
4182  HYPRE_EuclidSetBJ(euc_precond, euc_bj);
4183  HYPRE_EuclidSetRowScale(euc_precond, euc_ro_sc);
4184 }
4185 
4186 void HypreEuclid::ResetEuclidPrecond(MPI_Comm comm)
4187 {
4188  // Euclid does not seem to offer access to its current configuration, so we
4189  // simply reset it to its default options.
4190  HYPRE_EuclidDestroy(euc_precond);
4191  HYPRE_EuclidCreate(comm, &euc_precond);
4192 
4193  SetDefaultOptions();
4194 }
4195 
4197 {
4198  const HypreParMatrix *new_A = dynamic_cast<const HypreParMatrix *>(&op);
4199  MFEM_VERIFY(new_A, "new Operator must be a HypreParMatrix!");
4200 
4201  if (A)
4202  {
4203  MPI_Comm comm;
4204  HYPRE_ParCSRMatrixGetComm(*new_A, &comm);
4205  ResetEuclidPrecond(comm);
4206  }
4207 
4208  // update base classes: Operator, Solver, HypreSolver
4209  height = new_A->Height();
4210  width = new_A->Width();
4211  A = const_cast<HypreParMatrix *>(new_A);
4212  setup_called = 0;
4213  delete X;
4214  delete B;
4215  B = X = NULL;
4216  auxB.Delete(); auxB.Reset();
4217  auxX.Delete(); auxX.Reset();
4218 }
4219 
4221 {
4222  HYPRE_EuclidDestroy(euc_precond);
4223 }
4224 
4225 
4226 #if MFEM_HYPRE_VERSION >= 21900
4228 {
4229  HYPRE_ILUCreate(&ilu_precond);
4230  SetDefaultOptions();
4231 }
4232 
4233 void HypreILU::SetDefaultOptions()
4234 {
4235  // The type of incomplete LU used locally and globally (see class doc)
4236  HYPRE_Int ilu_type = 0; // ILU(k) locally and block Jacobi globally
4237  HYPRE_ILUSetType(ilu_precond, ilu_type);
4238 
4239  // Maximum iterations; 1 iter for preconditioning
4240  HYPRE_Int max_iter = 1;
4241  HYPRE_ILUSetMaxIter(ilu_precond, max_iter);
4242 
4243  // The tolerance when used as a smoother; set to 0.0 for preconditioner
4244  HYPRE_Real tol = 0.0;
4245  HYPRE_ILUSetTol(ilu_precond, tol);
4246 
4247  // Fill level for ILU(k)
4248  HYPRE_Int lev_fill = 1;
4249  HYPRE_ILUSetLevelOfFill(ilu_precond, lev_fill);
4250 
4251  // Local reordering scheme; 0 = no reordering, 1 = reverse Cuthill-McKee
4252  HYPRE_Int reorder_type = 1;
4253  HYPRE_ILUSetLocalReordering(ilu_precond, reorder_type);
4254 
4255  // Information print level; 0 = none, 1 = setup, 2 = solve, 3 = setup+solve
4256  HYPRE_Int print_level = 0;
4257  HYPRE_ILUSetPrintLevel(ilu_precond, print_level);
4258 }
4259 
4260 void HypreILU::ResetILUPrecond()
4261 {
4262  if (ilu_precond)
4263  {
4264  HYPRE_ILUDestroy(ilu_precond);
4265  }
4266  HYPRE_ILUCreate(&ilu_precond);
4267  SetDefaultOptions();
4268 }
4269 
4270 void HypreILU::SetLevelOfFill(HYPRE_Int lev_fill)
4271 {
4272  HYPRE_ILUSetLevelOfFill(ilu_precond, lev_fill);
4273 }
4274 
4275 void HypreILU::SetPrintLevel(HYPRE_Int print_level)
4276 {
4277  HYPRE_ILUSetPrintLevel(ilu_precond, print_level);
4278 }
4279 
4281 {
4282  const HypreParMatrix *new_A = dynamic_cast<const HypreParMatrix *>(&op);
4283  MFEM_VERIFY(new_A, "new Operator must be a HypreParMatrix!");
4284 
4285  if (A) { ResetILUPrecond(); }
4286 
4287  // update base classes: Operator, Solver, HypreSolver
4288  height = new_A->Height();
4289  width = new_A->Width();
4290  A = const_cast<HypreParMatrix *>(new_A);
4291  setup_called = 0;
4292  delete X;
4293  delete B;
4294  B = X = NULL;
4295  auxB.Delete(); auxB.Reset();
4296  auxX.Delete(); auxX.Reset();
4297 }
4298 
4300 {
4301  HYPRE_ILUDestroy(ilu_precond);
4302 }
4303 #endif
4304 
4305 
4307 {
4308  HYPRE_BoomerAMGCreate(&amg_precond);
4309  SetDefaultOptions();
4310 }
4311 
4313 {
4314  HYPRE_BoomerAMGCreate(&amg_precond);
4315  SetDefaultOptions();
4316 }
4317 
4318 void HypreBoomerAMG::SetDefaultOptions()
4319 {
4320 #ifndef HYPRE_USING_CUDA
4321  // AMG coarsening options:
4322  int coarsen_type = 10; // 10 = HMIS, 8 = PMIS, 6 = Falgout, 0 = CLJP
4323  int agg_levels = 1; // number of aggressive coarsening levels
4324  double theta = 0.25; // strength threshold: 0.25, 0.5, 0.8
4325 
4326  // AMG interpolation options:
4327  int interp_type = 6; // 6 = extended+i, 0 = classical
4328  int Pmax = 4; // max number of elements per row in P
4329 
4330  // AMG relaxation options:
4331  int relax_type = 8; // 8 = l1-GS, 6 = symm. GS, 3 = GS, 18 = l1-Jacobi
4332  int relax_sweeps = 1; // relaxation sweeps on each level
4333 
4334  // Additional options:
4335  int print_level = 1; // print AMG iterations? 1 = no, 2 = yes
4336  int max_levels = 25; // max number of levels in AMG hierarchy
4337 #else
4338  // AMG coarsening options:
4339  int coarsen_type = 8; // 10 = HMIS, 8 = PMIS, 6 = Falgout, 0 = CLJP
4340  int agg_levels = 0; // number of aggressive coarsening levels
4341  double theta = 0.25; // strength threshold: 0.25, 0.5, 0.8
4342 
4343  // AMG interpolation options:
4344  int interp_type = 6; // or 3 = direct
4345  int Pmax = 4; // max number of elements per row in P
4346 
4347  // AMG relaxation options:
4348  int relax_type = 18; // or 18 = l1-Jacobi
4349  int relax_sweeps = 1; // relaxation sweeps on each level
4350 
4351  // Additional options:
4352  int print_level = 1; // print AMG iterations? 1 = no, 2 = yes
4353  int max_levels = 25; // max number of levels in AMG hierarchy
4354 #endif
4355 
4356  HYPRE_BoomerAMGSetCoarsenType(amg_precond, coarsen_type);
4357  HYPRE_BoomerAMGSetAggNumLevels(amg_precond, agg_levels);
4358  HYPRE_BoomerAMGSetRelaxType(amg_precond, relax_type);
4359  // default in hypre is 1.0 with some exceptions, e.g. for relax_type = 7
4360  // HYPRE_BoomerAMGSetRelaxWt(amg_precond, 1.0);
4361  HYPRE_BoomerAMGSetNumSweeps(amg_precond, relax_sweeps);
4362  HYPRE_BoomerAMGSetStrongThreshold(amg_precond, theta);
4363  HYPRE_BoomerAMGSetInterpType(amg_precond, interp_type);
4364  HYPRE_BoomerAMGSetPMaxElmts(amg_precond, Pmax);
4365  HYPRE_BoomerAMGSetPrintLevel(amg_precond, print_level);
4366  HYPRE_BoomerAMGSetMaxLevels(amg_precond, max_levels);
4367 
4368  // Use as a preconditioner (one V-cycle, zero tolerance)
4369  HYPRE_BoomerAMGSetMaxIter(amg_precond, 1);
4370  HYPRE_BoomerAMGSetTol(amg_precond, 0.0);
4371 }
4372 
4373 void HypreBoomerAMG::ResetAMGPrecond()
4374 {
4375  HYPRE_Int coarsen_type;
4376  HYPRE_Int agg_levels;
4377  HYPRE_Int relax_type;
4378  HYPRE_Int relax_sweeps;
4379  HYPRE_Real theta;
4380  HYPRE_Int interp_type;
4381  HYPRE_Int Pmax;
4382  HYPRE_Int print_level;
4383  HYPRE_Int max_levels;
4384  HYPRE_Int dim;
4385  HYPRE_Int nrbms = rbms.Size();
4386  HYPRE_Int nodal;
4387  HYPRE_Int nodal_diag;
4388  HYPRE_Int relax_coarse;
4389  HYPRE_Int interp_vec_variant;
4390  HYPRE_Int q_max;
4391  HYPRE_Int smooth_interp_vectors;
4392  HYPRE_Int interp_refine;
4393 
4394  hypre_ParAMGData *amg_data = (hypre_ParAMGData *)amg_precond;
4395 
4396  // read options from amg_precond
4397  HYPRE_BoomerAMGGetCoarsenType(amg_precond, &coarsen_type);
4398  agg_levels = hypre_ParAMGDataAggNumLevels(amg_data);
4399  relax_type = hypre_ParAMGDataUserRelaxType(amg_data);
4400  relax_sweeps = hypre_ParAMGDataUserNumSweeps(amg_data);
4401  HYPRE_BoomerAMGGetStrongThreshold(amg_precond, &theta);
4402  hypre_BoomerAMGGetInterpType(amg_precond, &interp_type);
4403  HYPRE_BoomerAMGGetPMaxElmts(amg_precond, &Pmax);
4404  HYPRE_BoomerAMGGetPrintLevel(amg_precond, &print_level);
4405  HYPRE_BoomerAMGGetMaxLevels(amg_precond, &max_levels);
4406  HYPRE_BoomerAMGGetNumFunctions(amg_precond, &dim);
4407  if (nrbms) // elasticity solver options
4408  {
4409  nodal = hypre_ParAMGDataNodal(amg_data);
4410  nodal_diag = hypre_ParAMGDataNodalDiag(amg_data);
4411  HYPRE_BoomerAMGGetCycleRelaxType(amg_precond, &relax_coarse, 3);
4412  interp_vec_variant = hypre_ParAMGInterpVecVariant(amg_data);
4413  q_max = hypre_ParAMGInterpVecQMax(amg_data);
4414  smooth_interp_vectors = hypre_ParAMGSmoothInterpVectors(amg_data);
4415  interp_refine = hypre_ParAMGInterpRefine(amg_data);
4416  }
4417 
4418  HYPRE_BoomerAMGDestroy(amg_precond);
4419  HYPRE_BoomerAMGCreate(&amg_precond);
4420 
4421  HYPRE_BoomerAMGSetCoarsenType(amg_precond, coarsen_type);
4422  HYPRE_BoomerAMGSetAggNumLevels(amg_precond, agg_levels);
4423  HYPRE_BoomerAMGSetRelaxType(amg_precond, relax_type);
4424  HYPRE_BoomerAMGSetNumSweeps(amg_precond, relax_sweeps);
4425  HYPRE_BoomerAMGSetMaxLevels(amg_precond, max_levels);
4426  HYPRE_BoomerAMGSetTol(amg_precond, 0.0);
4427  HYPRE_BoomerAMGSetMaxIter(amg_precond, 1); // one V-cycle
4428  HYPRE_BoomerAMGSetStrongThreshold(amg_precond, theta);
4429  HYPRE_BoomerAMGSetInterpType(amg_precond, interp_type);
4430  HYPRE_BoomerAMGSetPMaxElmts(amg_precond, Pmax);
4431  HYPRE_BoomerAMGSetPrintLevel(amg_precond, print_level);
4432  HYPRE_BoomerAMGSetNumFunctions(amg_precond, dim);
4433  if (nrbms)
4434  {
4435  HYPRE_BoomerAMGSetNodal(amg_precond, nodal);
4436  HYPRE_BoomerAMGSetNodalDiag(amg_precond, nodal_diag);
4437  HYPRE_BoomerAMGSetCycleRelaxType(amg_precond, relax_coarse, 3);
4438  HYPRE_BoomerAMGSetInterpVecVariant(amg_precond, interp_vec_variant);
4439  HYPRE_BoomerAMGSetInterpVecQMax(amg_precond, q_max);
4440  HYPRE_BoomerAMGSetSmoothInterpVectors(amg_precond, smooth_interp_vectors);
4441  HYPRE_BoomerAMGSetInterpRefine(amg_precond, interp_refine);
4442  RecomputeRBMs();
4443  HYPRE_BoomerAMGSetInterpVectors(amg_precond, rbms.Size(), rbms.GetData());
4444  }
4445 }
4446 
4448 {
4449  const HypreParMatrix *new_A = dynamic_cast<const HypreParMatrix *>(&op);
4450  MFEM_VERIFY(new_A, "new Operator must be a HypreParMatrix!");
4451 
4452  if (A) { ResetAMGPrecond(); }
4453 
4454  // update base classes: Operator, Solver, HypreSolver
4455  height = new_A->Height();
4456  width = new_A->Width();
4457  A = const_cast<HypreParMatrix *>(new_A);
4458  setup_called = 0;
4459  delete X;
4460  delete B;
4461  B = X = NULL;
4462  auxB.Delete(); auxB.Reset();
4463  auxX.Delete(); auxX.Reset();
4464 }
4465 
4466 void HypreBoomerAMG::SetSystemsOptions(int dim, bool order_bynodes)
4467 {
4468  HYPRE_BoomerAMGSetNumFunctions(amg_precond, dim);
4469 
4470  // The default "system" ordering in hypre is Ordering::byVDIM. When we are
4471  // using Ordering::byNODES, we have to specify the ordering explicitly with
4472  // HYPRE_BoomerAMGSetDofFunc as in the following code.
4473  if (order_bynodes)
4474  {
4475  // hypre actually deletes the following pointer in HYPRE_BoomerAMGDestroy,
4476  // so we don't need to track it
4477  HYPRE_Int *mapping = mfem_hypre_CTAlloc_host(HYPRE_Int, height);
4478  int h_nnodes = height / dim; // nodes owned in linear algebra (not fem)
4479  MFEM_VERIFY(height % dim == 0, "Ordering does not work as claimed!");
4480  int k = 0;
4481  for (int i = 0; i < dim; ++i)
4482  {
4483  for (int j = 0; j < h_nnodes; ++j)
4484  {
4485  mapping[k++] = i;
4486  }
4487  }
4488  HYPRE_BoomerAMGSetDofFunc(amg_precond, mapping);
4489  }
4490 
4491  // More robust options with respect to convergence
4492  HYPRE_BoomerAMGSetAggNumLevels(amg_precond, 0);
4493  HYPRE_BoomerAMGSetStrongThreshold(amg_precond, 0.5);
4494 }
4495 
4496 // Rotational rigid-body mode functions, used in SetElasticityOptions()
4497 static void func_rxy(const Vector &x, Vector &y)
4498 {
4499  y = 0.0; y(0) = x(1); y(1) = -x(0);
4500 }
4501 static void func_ryz(const Vector &x, Vector &y)
4502 {
4503  y = 0.0; y(1) = x(2); y(2) = -x(1);
4504 }
4505 static void func_rzx(const Vector &x, Vector &y)
4506 {
4507  y = 0.0; y(2) = x(0); y(0) = -x(2);
4508 }
4509 
4510 void HypreBoomerAMG::RecomputeRBMs()
4511 {
4512  int nrbms;
4513  Array<HypreParVector*> gf_rbms;
4514  int dim = fespace->GetParMesh()->Dimension();
4515 
4516  for (int i = 0; i < rbms.Size(); i++)
4517  {
4518  HYPRE_ParVectorDestroy(rbms[i]);
4519  }
4520 
4521  if (dim == 2)
4522  {
4523  nrbms = 1;
4524 
4525  VectorFunctionCoefficient coeff_rxy(2, func_rxy);
4526 
4527  ParGridFunction rbms_rxy(fespace);
4528  rbms_rxy.ProjectCoefficient(coeff_rxy);
4529 
4530  rbms.SetSize(nrbms);
4531  gf_rbms.SetSize(nrbms);
4532  gf_rbms[0] = rbms_rxy.ParallelAverage();
4533  }
4534  else if (dim == 3)
4535  {
4536  nrbms = 3;
4537 
4538  VectorFunctionCoefficient coeff_rxy(3, func_rxy);
4539  VectorFunctionCoefficient coeff_ryz(3, func_ryz);
4540  VectorFunctionCoefficient coeff_rzx(3, func_rzx);
4541 
4542  ParGridFunction rbms_rxy(fespace);
4543  ParGridFunction rbms_ryz(fespace);
4544  ParGridFunction rbms_rzx(fespace);
4545  rbms_rxy.ProjectCoefficient(coeff_rxy);
4546  rbms_ryz.ProjectCoefficient(coeff_ryz);
4547  rbms_rzx.ProjectCoefficient(coeff_rzx);
4548 
4549  rbms.SetSize(nrbms);
4550  gf_rbms.SetSize(nrbms);
4551  gf_rbms[0] = rbms_rxy.ParallelAverage();
4552  gf_rbms[1] = rbms_ryz.ParallelAverage();
4553  gf_rbms[2] = rbms_rzx.ParallelAverage();
4554  }
4555  else
4556  {
4557  nrbms = 0;
4558  rbms.SetSize(nrbms);
4559  }
4560 
4561  // Transfer the RBMs from the ParGridFunction to the HYPRE_ParVector objects
4562  for (int i = 0; i < nrbms; i++)
4563  {
4564  rbms[i] = gf_rbms[i]->StealParVector();
4565  delete gf_rbms[i];
4566  }
4567 }
4568 
4570 {
4571 #ifdef HYPRE_USING_CUDA
4572  MFEM_ABORT("this method is not supported in hypre built with CUDA");
4573 #endif
4574 
4575  // Save the finite element space to support multiple calls to SetOperator()
4576  this->fespace = fespace;
4577 
4578  // Make sure the systems AMG options are set
4579  int dim = fespace->GetParMesh()->Dimension();
4580  SetSystemsOptions(dim);
4581 
4582  // Nodal coarsening options (nodal coarsening is required for this solver)
4583  // See hypre's new_ij driver and the paper for descriptions.
4584  int nodal = 4; // strength reduction norm: 1, 3 or 4
4585  int nodal_diag = 1; // diagonal in strength matrix: 0, 1 or 2
4586  int relax_coarse = 8; // smoother on the coarsest grid: 8, 99 or 29
4587 
4588  // Elasticity interpolation options
4589  int interp_vec_variant = 2; // 1 = GM-1, 2 = GM-2, 3 = LN
4590  int q_max = 4; // max elements per row for each Q
4591  int smooth_interp_vectors = 1; // smooth the rigid-body modes?
4592 
4593  // Optionally pre-process the interpolation matrix through iterative weight
4594  // refinement (this is generally applicable for any system)
4595  int interp_refine = 1;
4596 
4597  HYPRE_BoomerAMGSetNodal(amg_precond, nodal);
4598  HYPRE_BoomerAMGSetNodalDiag(amg_precond, nodal_diag);
4599  HYPRE_BoomerAMGSetCycleRelaxType(amg_precond, relax_coarse, 3);
4600  HYPRE_BoomerAMGSetInterpVecVariant(amg_precond, interp_vec_variant);
4601  HYPRE_BoomerAMGSetInterpVecQMax(amg_precond, q_max);
4602  HYPRE_BoomerAMGSetSmoothInterpVectors(amg_precond, smooth_interp_vectors);
4603  HYPRE_BoomerAMGSetInterpRefine(amg_precond, interp_refine);
4604 
4605  RecomputeRBMs();
4606  HYPRE_BoomerAMGSetInterpVectors(amg_precond, rbms.Size(), rbms.GetData());
4607 
4608  // The above BoomerAMG options may result in singular matrices on the coarse
4609  // grids, which are handled correctly in hypre's Solve method, but can produce
4610  // hypre errors in the Setup (specifically in the l1 row norm computation).
4611  // See the documentation of SetErrorMode() for more details.
4613 }
4614 
4615 #if MFEM_HYPRE_VERSION >= 21800
4616 
4618  const std::string &prerelax,
4619  const std::string &postrelax)
4620 {
4621  // Hypre parameters
4622  int Sabs = 0;
4623  int interp_type = 100;
4624  int relax_type = 10;
4625  int coarsen_type = 6;
4626  double strength_tolC = 0.1;
4627  double strength_tolR = 0.01;
4628  double filter_tolR = 0.0;
4629  double filterA_tol = 0.0;
4630 
4631  // Set relaxation on specified grid points
4632  int ns_down, ns_up, ns_coarse;
4633  if (distanceR > 0)
4634  {
4635  ns_down = prerelax.length();
4636  ns_up = postrelax.length();
4637  ns_coarse = 1;
4638 
4639  // Array to store relaxation scheme and pass to Hypre
4640  HYPRE_Int **grid_relax_points = mfem_hypre_TAlloc(HYPRE_Int*, 4);
4641  grid_relax_points[0] = NULL;
4642  grid_relax_points[1] = mfem_hypre_TAlloc(HYPRE_Int, ns_down);
4643  grid_relax_points[2] = mfem_hypre_TAlloc(HYPRE_Int, ns_up);
4644  grid_relax_points[3] = mfem_hypre_TAlloc(HYPRE_Int, 1);
4645  grid_relax_points[3][0] = 0;
4646 
4647  // set down relax scheme
4648  for (int i = 0; i<ns_down; i++)
4649  {
4650  if (prerelax[i] == 'F')
4651  {
4652  grid_relax_points[1][i] = -1;
4653  }
4654  else if (prerelax[i] == 'C')
4655  {
4656  grid_relax_points[1][i] = 1;
4657  }
4658  else if (prerelax[i] == 'A')
4659  {
4660  grid_relax_points[1][i] = 0;
4661  }
4662  }
4663 
4664  // set up relax scheme
4665  for (int i = 0; i<ns_up; i++)
4666  {
4667  if (postrelax[i] == 'F')
4668  {
4669  grid_relax_points[2][i] = -1;
4670  }
4671  else if (postrelax[i] == 'C')
4672  {
4673  grid_relax_points[2][i] = 1;
4674  }
4675  else if (postrelax[i] == 'A')
4676  {
4677  grid_relax_points[2][i] = 0;
4678  }
4679  }
4680 
4681  HYPRE_BoomerAMGSetRestriction(amg_precond, distanceR);
4682 
4683  HYPRE_BoomerAMGSetGridRelaxPoints(amg_precond, grid_relax_points);
4684 
4685  HYPRE_BoomerAMGSetInterpType(amg_precond, interp_type);
4686  }
4687 
4688  if (Sabs)
4689  {
4690  HYPRE_BoomerAMGSetSabs(amg_precond, Sabs);
4691  }
4692 
4693  HYPRE_BoomerAMGSetCoarsenType(amg_precond, coarsen_type);
4694 
4695  // does not support aggressive coarsening
4696  HYPRE_BoomerAMGSetAggNumLevels(amg_precond, 0);
4697 
4698  HYPRE_BoomerAMGSetStrongThreshold(amg_precond, strength_tolC);
4699 
4700  if (distanceR > 0)
4701  {
4702  HYPRE_BoomerAMGSetStrongThresholdR(amg_precond, strength_tolR);
4703  HYPRE_BoomerAMGSetFilterThresholdR(amg_precond, filter_tolR);
4704  }
4705 
4706  if (relax_type > -1)
4707  {
4708  HYPRE_BoomerAMGSetRelaxType(amg_precond, relax_type);
4709  }
4710 
4711  if (distanceR > 0)
4712  {
4713  HYPRE_BoomerAMGSetCycleNumSweeps(amg_precond, ns_coarse, 3);
4714  HYPRE_BoomerAMGSetCycleNumSweeps(amg_precond, ns_down, 1);
4715  HYPRE_BoomerAMGSetCycleNumSweeps(amg_precond, ns_up, 2);
4716 
4717  HYPRE_BoomerAMGSetADropTol(amg_precond, filterA_tol);
4718  // type = -1: drop based on row inf-norm
4719  HYPRE_BoomerAMGSetADropType(amg_precond, -1);
4720  }
4721 }
4722 
4723 #endif
4724 
4726 {
4727  for (int i = 0; i < rbms.Size(); i++)
4728  {
4729  HYPRE_ParVectorDestroy(rbms[i]);
4730  }
4731 
4732  HYPRE_BoomerAMGDestroy(amg_precond);
4733 }
4734 
4736 {
4737  Init(edge_fespace);
4738 }
4739 
4741  : HypreSolver(&A)
4742 {
4743  Init(edge_fespace);
4744 }
4745 
4746 void HypreAMS::Init(ParFiniteElementSpace *edge_fespace)
4747 {
4748  int cycle_type = 13;
4749  int rlx_sweeps = 1;
4750  double rlx_weight = 1.0;
4751  double rlx_omega = 1.0;
4752 #ifndef HYPRE_USING_CUDA
4753  int amg_coarsen_type = 10;
4754  int amg_agg_levels = 1;
4755  int amg_rlx_type = 8;
4756  int rlx_type = 2;
4757  double theta = 0.25;
4758  int amg_interp_type = 6;
4759  int amg_Pmax = 4;
4760 #else
4761  int amg_coarsen_type = 8;
4762  int amg_agg_levels = 0;
4763  int amg_rlx_type = 18;
4764  int rlx_type = 1;
4765  double theta = 0.25;
4766  int amg_interp_type = 6;
4767  int amg_Pmax = 4;
4768 #endif
4769 
4770  int dim = edge_fespace->GetMesh()->Dimension();
4771  int sdim = edge_fespace->GetMesh()->SpaceDimension();
4772  const FiniteElementCollection *edge_fec = edge_fespace->FEColl();
4773 
4774  bool trace_space, rt_trace_space;
4775  ND_Trace_FECollection *nd_tr_fec = NULL;
4776  trace_space = dynamic_cast<const ND_Trace_FECollection*>(edge_fec);
4777  rt_trace_space = dynamic_cast<const RT_Trace_FECollection*>(edge_fec);
4778  trace_space = trace_space || rt_trace_space;
4779 
4780  int p = 1;
4781  if (edge_fespace->GetNE() > 0)
4782  {
4783  MFEM_VERIFY(!edge_fespace->IsVariableOrder(), "");
4784  if (trace_space)
4785  {
4786  p = edge_fespace->GetFaceOrder(0);
4787  if (dim == 2) { p++; }
4788  }
4789  else
4790  {
4791  p = edge_fespace->GetElementOrder(0);
4792  }
4793  }
4794 
4795  ParMesh *pmesh = edge_fespace->GetParMesh();
4796  if (rt_trace_space)
4797  {
4798  nd_tr_fec = new ND_Trace_FECollection(p, dim);
4799  edge_fespace = new ParFiniteElementSpace(pmesh, nd_tr_fec);
4800  }
4801 
4802  HYPRE_AMSCreate(&ams);
4803 
4804  HYPRE_AMSSetDimension(ams, sdim); // 2D H(div) and 3D H(curl) problems
4805  HYPRE_AMSSetTol(ams, 0.0);
4806  HYPRE_AMSSetMaxIter(ams, 1); // use as a preconditioner
4807  HYPRE_AMSSetCycleType(ams, cycle_type);
4808  HYPRE_AMSSetPrintLevel(ams, 1);
4809 
4810  // define the nodal linear finite element space associated with edge_fespace
4811  FiniteElementCollection *vert_fec;
4812  if (trace_space)
4813  {
4814  vert_fec = new H1_Trace_FECollection(p, dim);
4815  }
4816  else
4817  {
4818  vert_fec = new H1_FECollection(p, dim);
4819  }
4820  ParFiniteElementSpace *vert_fespace = new ParFiniteElementSpace(pmesh,
4821  vert_fec);
4822 
4823  // generate and set the vertex coordinates
4824  if (p == 1 && pmesh->GetNodes() == NULL)
4825  {
4826  ParGridFunction x_coord(vert_fespace);
4827  ParGridFunction y_coord(vert_fespace);
4828  ParGridFunction z_coord(vert_fespace);
4829  double *coord;
4830  for (int i = 0; i < pmesh->GetNV(); i++)
4831  {
4832  coord = pmesh -> GetVertex(i);
4833  x_coord(i) = coord[0];
4834  y_coord(i) = coord[1];
4835  if (sdim == 3) { z_coord(i) = coord[2]; }
4836  }
4837  x = x_coord.ParallelProject();
4838  y = y_coord.ParallelProject();
4839 
4840  x->HypreReadWrite();
4841  y->HypreReadWrite();
4842  if (sdim == 2)
4843  {
4844  z = NULL;
4845  HYPRE_AMSSetCoordinateVectors(ams, *x, *y, NULL);
4846  }
4847  else
4848  {
4849  z = z_coord.ParallelProject();
4850  z->HypreReadWrite();
4851  HYPRE_AMSSetCoordinateVectors(ams, *x, *y, *z);
4852  }
4853  }
4854  else
4855  {
4856  x = NULL;
4857  y = NULL;
4858  z = NULL;
4859  }
4860 
4861  // generate and set the discrete gradient
4862  ParDiscreteLinearOperator *grad;
4863  grad = new ParDiscreteLinearOperator(vert_fespace, edge_fespace);
4864  if (trace_space)
4865  {
4866  grad->AddTraceFaceInterpolator(new GradientInterpolator);
4867  }
4868  else
4869  {
4870  grad->AddDomainInterpolator(new GradientInterpolator);
4871  }
4872  grad->Assemble();
4873  grad->Finalize();
4874  G = grad->ParallelAssemble();
4875  HYPRE_AMSSetDiscreteGradient(ams, *G);
4876  delete grad;
4877 
4878  // generate and set the Nedelec interpolation matrices
4879  Pi = Pix = Piy = Piz = NULL;
4880  if (p > 1 || pmesh->GetNodes() != NULL)
4881  {
4882  ParFiniteElementSpace *vert_fespace_d
4883  = new ParFiniteElementSpace(pmesh, vert_fec, sdim, Ordering::byVDIM);
4884 
4885  ParDiscreteLinearOperator *id_ND;
4886  id_ND = new ParDiscreteLinearOperator(vert_fespace_d, edge_fespace);
4887  if (trace_space)
4888  {
4889  id_ND->AddTraceFaceInterpolator(new IdentityInterpolator);
4890  }
4891  else
4892  {
4893  id_ND->AddDomainInterpolator(new IdentityInterpolator);
4894  }
4895  id_ND->Assemble();
4896  id_ND->Finalize();
4897 
4898  if (cycle_type < 10)
4899  {
4900  Pi = id_ND->ParallelAssemble();
4901  }
4902  else
4903  {
4904  Array2D<HypreParMatrix *> Pi_blocks;
4905  id_ND->GetParBlocks(Pi_blocks);
4906  Pix = Pi_blocks(0,0);
4907  Piy = Pi_blocks(0,1);
4908  if (sdim == 3) { Piz = Pi_blocks(0,2); }
4909  }
4910 
4911  delete id_ND;
4912 
4913  HYPRE_ParCSRMatrix HY_Pi = (Pi) ? (HYPRE_ParCSRMatrix) *Pi : NULL;
4914  HYPRE_ParCSRMatrix HY_Pix = (Pix) ? (HYPRE_ParCSRMatrix) *Pix : NULL;
4915  HYPRE_ParCSRMatrix HY_Piy = (Piy) ? (HYPRE_ParCSRMatrix) *Piy : NULL;
4916  HYPRE_ParCSRMatrix HY_Piz = (Piz) ? (HYPRE_ParCSRMatrix) *Piz : NULL;
4917  HYPRE_AMSSetInterpolations(ams, HY_Pi, HY_Pix, HY_Piy, HY_Piz);
4918 
4919  delete vert_fespace_d;
4920  }
4921 
4922  delete vert_fespace;
4923  delete vert_fec;
4924 
4925  if (rt_trace_space)
4926  {
4927  delete edge_fespace;
4928  delete nd_tr_fec;
4929  }
4930 
4931  // set additional AMS options
4932  HYPRE_AMSSetSmoothingOptions(ams, rlx_type, rlx_sweeps, rlx_weight, rlx_omega);
4933  HYPRE_AMSSetAlphaAMGOptions(ams, amg_coarsen_type, amg_agg_levels, amg_rlx_type,
4934  theta, amg_interp_type, amg_Pmax);
4935  HYPRE_AMSSetBetaAMGOptions(ams, amg_coarsen_type, amg_agg_levels, amg_rlx_type,
4936  theta, amg_interp_type, amg_Pmax);
4937 
4938  HYPRE_AMSSetAlphaAMGCoarseRelaxType(ams, amg_rlx_type);
4939  HYPRE_AMSSetBetaAMGCoarseRelaxType(ams, amg_rlx_type);
4940 
4941  // The AMS preconditioner may sometimes require inverting singular matrices
4942  // with BoomerAMG, which are handled correctly in hypre's Solve method, but
4943  // can produce hypre errors in the Setup (specifically in the l1 row norm
4944  // computation). See the documentation of SetErrorMode() for more details.
4946 }
4947 
4949 {
4950  const HypreParMatrix *new_A = dynamic_cast<const HypreParMatrix *>(&op);
4951  MFEM_VERIFY(new_A, "new Operator must be a HypreParMatrix!");
4952 
4953  // update base classes: Operator, Solver, HypreSolver
4954  height = new_A->Height();
4955  width = new_A->Width();
4956  A = const_cast<HypreParMatrix *>(new_A);
4957 
4958  setup_called = 0;
4959  delete X;
4960  delete B;
4961  B = X = NULL;
4962  auxB.Delete(); auxB.Reset();
4963  auxX.Delete(); auxX.Reset();
4964 }
4965 
4967 {
4968  HYPRE_AMSDestroy(ams);
4969 
4970  delete x;
4971  delete y;
4972  delete z;
4973 
4974  delete G;
4975  delete Pi;
4976  delete Pix;
4977  delete Piy;
4978  delete Piz;
4979 }
4980 
4981 void HypreAMS::SetPrintLevel(int print_lvl)
4982 {
4983  HYPRE_AMSSetPrintLevel(ams, print_lvl);
4984 }
4985 
4987 {
4988  Init(face_fespace);
4989 }
4990 
4992  : HypreSolver(&A)
4993 {
4994  Init(face_fespace);
4995 }
4996 
4997 void HypreADS::Init(ParFiniteElementSpace *face_fespace)
4998 {
4999  int cycle_type = 11;
5000  int rlx_type = 2;
5001  int rlx_sweeps = 1;
5002  double rlx_weight = 1.0;
5003  double rlx_omega = 1.0;
5004 #ifndef HYPRE_USING_CUDA
5005  int amg_coarsen_type = 10;
5006  int amg_agg_levels = 1;
5007  int amg_rlx_type = 8;
5008  double theta = 0.25;
5009  int amg_interp_type = 6;
5010  int amg_Pmax = 4;
5011 #else
5012  int amg_coarsen_type = 8;
5013  int amg_agg_levels = 0;
5014  int amg_rlx_type = 18;
5015  double theta = 0.25;
5016  int amg_interp_type = 6;
5017  int amg_Pmax = 4;
5018 #endif
5019  int ams_cycle_type = 14;
5020 
5021  const FiniteElementCollection *face_fec = face_fespace->FEColl();
5022  bool trace_space =
5023  (dynamic_cast<const RT_Trace_FECollection*>(face_fec) != NULL);
5024  int p = 1;
5025  if (face_fespace->GetNE() > 0)
5026  {
5027  MFEM_VERIFY(!face_fespace->IsVariableOrder(), "");
5028  if (trace_space)
5029  {
5030  p = face_fespace->GetFaceOrder(0) + 1;
5031  }
5032  else
5033  {
5034  p = face_fespace->GetElementOrder(0);
5035  }
5036  }
5037 
5038  HYPRE_ADSCreate(&ads);
5039 
5040  HYPRE_ADSSetTol(ads, 0.0);
5041  HYPRE_ADSSetMaxIter(ads, 1); // use as a preconditioner
5042  HYPRE_ADSSetCycleType(ads, cycle_type);
5043  HYPRE_ADSSetPrintLevel(ads, 1);
5044 
5045  // define the nodal and edge finite element spaces associated with face_fespace
5046  ParMesh *pmesh = (ParMesh *) face_fespace->GetMesh();
5047  FiniteElementCollection *vert_fec, *edge_fec;
5048  if (trace_space)
5049  {
5050  vert_fec = new H1_Trace_FECollection(p, 3);
5051  edge_fec = new ND_Trace_FECollection(p, 3);
5052  }
5053  else
5054  {
5055  vert_fec = new H1_FECollection(p, 3);
5056  edge_fec = new ND_FECollection(p, 3);
5057  }
5058 
5059  ParFiniteElementSpace *vert_fespace = new ParFiniteElementSpace(pmesh,
5060  vert_fec);
5061  ParFiniteElementSpace *edge_fespace = new ParFiniteElementSpace(pmesh,
5062  edge_fec);
5063 
5064  // generate and set the vertex coordinates
5065  if (p == 1 && pmesh->GetNodes() == NULL)
5066  {
5067  ParGridFunction x_coord(vert_fespace);
5068  ParGridFunction y_coord(vert_fespace);
5069  ParGridFunction z_coord(vert_fespace);
5070  double *coord;
5071  for (int i = 0; i < pmesh->GetNV(); i++)
5072  {
5073  coord = pmesh -> GetVertex(i);
5074  x_coord(i) = coord[0];
5075  y_coord(i) = coord[1];
5076  z_coord(i) = coord[2];
5077  }
5078  x = x_coord.ParallelProject();
5079  y = y_coord.ParallelProject();
5080  z = z_coord.ParallelProject();
5081  x->HypreReadWrite();
5082  y->HypreReadWrite();
5083  z->HypreReadWrite();
5084  HYPRE_ADSSetCoordinateVectors(ads, *x, *y, *z);
5085  }
5086  else
5087  {
5088  x = NULL;
5089  y = NULL;
5090  z = NULL;
5091  }
5092 
5093  // generate and set the discrete curl
5094  ParDiscreteLinearOperator *curl;
5095  curl = new ParDiscreteLinearOperator(edge_fespace, face_fespace);
5096  if (trace_space)
5097  {
5098  curl->AddTraceFaceInterpolator(new CurlInterpolator);
5099  }
5100  else
5101  {
5102  curl->AddDomainInterpolator(new CurlInterpolator);
5103  }
5104  curl->Assemble();
5105  curl->Finalize();
5106  C = curl->ParallelAssemble();
5107  C->CopyColStarts(); // since we'll delete edge_fespace
5108  HYPRE_ADSSetDiscreteCurl(ads, *C);
5109  delete curl;
5110 
5111  // generate and set the discrete gradient
5112  ParDiscreteLinearOperator *grad;
5113  grad = new ParDiscreteLinearOperator(vert_fespace, edge_fespace);
5114  if (trace_space)
5115  {
5116  grad->AddTraceFaceInterpolator(new GradientInterpolator);
5117  }
5118  else
5119  {
5120  grad->AddDomainInterpolator(new GradientInterpolator);
5121  }
5122  grad->Assemble();
5123  grad->Finalize();
5124  G = grad->ParallelAssemble();
5125  G->CopyColStarts(); // since we'll delete vert_fespace
5126  G->CopyRowStarts(); // since we'll delete edge_fespace
5127  HYPRE_ADSSetDiscreteGradient(ads, *G);
5128  delete grad;
5129 
5130  // generate and set the Nedelec and Raviart-Thomas interpolation matrices
5131  RT_Pi = RT_Pix = RT_Piy = RT_Piz = NULL;
5132  ND_Pi = ND_Pix = ND_Piy = ND_Piz = NULL;
5133  if (p > 1 || pmesh->GetNodes() != NULL)
5134  {
5135  ParFiniteElementSpace *vert_fespace_d
5136  = new ParFiniteElementSpace(pmesh, vert_fec, 3, Ordering::byVDIM);
5137 
5138  ParDiscreteLinearOperator *id_ND;
5139  id_ND = new ParDiscreteLinearOperator(vert_fespace_d, edge_fespace);
5140  if (trace_space)
5141  {
5142  id_ND->AddTraceFaceInterpolator(new IdentityInterpolator);
5143  }
5144  else
5145  {
5146  id_ND->AddDomainInterpolator(new IdentityInterpolator);
5147  }
5148  id_ND->Assemble();
5149  id_ND->Finalize();
5150 
5151  if (ams_cycle_type < 10)
5152  {
5153  ND_Pi = id_ND->ParallelAssemble();
5154  ND_Pi->CopyColStarts(); // since we'll delete vert_fespace_d
5155  ND_Pi->CopyRowStarts(); // since we'll delete edge_fespace
5156  }
5157  else
5158  {
5159  Array2D<HypreParMatrix *> ND_Pi_blocks;
5160  id_ND->GetParBlocks(ND_Pi_blocks);
5161  ND_Pix = ND_Pi_blocks(0,0);
5162  ND_Piy = ND_Pi_blocks(0,1);
5163  ND_Piz = ND_Pi_blocks(0,2);
5164  }
5165 
5166  delete id_ND;
5167 
5168  ParDiscreteLinearOperator *id_RT;
5169  id_RT = new ParDiscreteLinearOperator(vert_fespace_d, face_fespace);
5170  if (trace_space)
5171  {
5172  id_RT->AddTraceFaceInterpolator(new NormalInterpolator);
5173  }
5174  else
5175  {
5176  id_RT->AddDomainInterpolator(new IdentityInterpolator);
5177  }
5178  id_RT->Assemble();
5179  id_RT->Finalize();
5180 
5181  if (cycle_type < 10)
5182  {
5183  RT_Pi = id_RT->ParallelAssemble();
5184  RT_Pi->CopyColStarts(); // since we'll delete vert_fespace_d
5185  }
5186  else
5187  {
5188  Array2D<HypreParMatrix *> RT_Pi_blocks;
5189  id_RT->GetParBlocks(RT_Pi_blocks);
5190  RT_Pix = RT_Pi_blocks(0,0);
5191  RT_Piy = RT_Pi_blocks(0,1);
5192  RT_Piz = RT_Pi_blocks(0,2);
5193  }
5194 
5195  delete id_RT;
5196 
5197  HYPRE_ParCSRMatrix HY_RT_Pi, HY_RT_Pix, HY_RT_Piy, HY_RT_Piz;
5198  HY_RT_Pi = (RT_Pi) ? (HYPRE_ParCSRMatrix) *RT_Pi : NULL;
5199  HY_RT_Pix = (RT_Pix) ? (HYPRE_ParCSRMatrix) *RT_Pix : NULL;
5200  HY_RT_Piy = (RT_Piy) ? (HYPRE_ParCSRMatrix) *RT_Piy : NULL;
5201  HY_RT_Piz = (RT_Piz) ? (HYPRE_ParCSRMatrix) *RT_Piz : NULL;
5202  HYPRE_ParCSRMatrix HY_ND_Pi, HY_ND_Pix, HY_ND_Piy, HY_ND_Piz;
5203  HY_ND_Pi = (ND_Pi) ? (HYPRE_ParCSRMatrix) *ND_Pi : NULL;
5204  HY_ND_Pix = (ND_Pix) ? (HYPRE_ParCSRMatrix) *ND_Pix : NULL;
5205  HY_ND_Piy = (ND_Piy) ? (HYPRE_ParCSRMatrix) *ND_Piy : NULL;
5206  HY_ND_Piz = (ND_Piz) ? (HYPRE_ParCSRMatrix) *ND_Piz : NULL;
5207  HYPRE_ADSSetInterpolations(ads,
5208  HY_RT_Pi, HY_RT_Pix, HY_RT_Piy, HY_RT_Piz,
5209  HY_ND_Pi, HY_ND_Pix, HY_ND_Piy, HY_ND_Piz);
5210 
5211  delete vert_fespace_d;
5212  }
5213 
5214  delete vert_fec;
5215  delete vert_fespace;
5216  delete edge_fec;
5217  delete edge_fespace;
5218 
5219  // set additional ADS options
5220  HYPRE_ADSSetSmoothingOptions(ads, rlx_type, rlx_sweeps, rlx_weight, rlx_omega);
5221  HYPRE_ADSSetAMGOptions(ads, amg_coarsen_type, amg_agg_levels, amg_rlx_type,
5222  theta, amg_interp_type, amg_Pmax);
5223  HYPRE_ADSSetAMSOptions(ads, ams_cycle_type, amg_coarsen_type, amg_agg_levels,
5224  amg_rlx_type, theta, amg_interp_type, amg_Pmax);
5225 
5226  // The ADS preconditioner requires inverting singular matrices with BoomerAMG,
5227  // which are handled correctly in hypre's Solve method, but can produce hypre
5228  // errors in the Setup (specifically in the l1 row norm computation). See the
5229  // documentation of SetErrorMode() for more details.
5231 }
5232 
5234 {
5235  const HypreParMatrix *new_A = dynamic_cast<const HypreParMatrix *>(&op);
5236  MFEM_VERIFY(new_A, "new Operator must be a HypreParMatrix!");
5237 
5238  // update base classes: Operator, Solver, HypreSolver
5239  height = new_A->Height();
5240  width = new_A->Width();
5241  A = const_cast<HypreParMatrix *>(new_A);
5242 
5243  setup_called = 0;
5244  delete X;
5245  delete B;
5246  B = X = NULL;
5247  auxB.Delete(); auxB.Reset();
5248  auxX.Delete(); auxX.Reset();
5249 }
5250 
5252 {
5253  HYPRE_ADSDestroy(ads);
5254 
5255  delete x;
5256  delete y;
5257  delete z;
5258 
5259  delete G;
5260  delete C;
5261 
5262  delete RT_Pi;
5263  delete RT_Pix;
5264  delete RT_Piy;
5265  delete RT_Piz;
5266 
5267  delete ND_Pi;
5268  delete ND_Pix;
5269  delete ND_Piy;
5270  delete ND_Piz;
5271 }
5272 
5273 void HypreADS::SetPrintLevel(int print_lvl)
5274 {
5275  HYPRE_ADSSetPrintLevel(ads, print_lvl);
5276 }
5277 
5278 HypreLOBPCG::HypreMultiVector::HypreMultiVector(int n, HypreParVector & v,
5279  mv_InterfaceInterpreter & interpreter)
5280  : hpv(NULL),
5281  nv(n)
5282 {
5283  mv_ptr = mv_MultiVectorCreateFromSampleVector(&interpreter, nv,
5284  (HYPRE_ParVector)v);
5285 
5286  HYPRE_ParVector* vecs = NULL;
5287  {
5288  mv_TempMultiVector* tmp =
5289  (mv_TempMultiVector*)mv_MultiVectorGetData(mv_ptr);
5290  vecs = (HYPRE_ParVector*)(tmp -> vector);
5291  }
5292 
5293  hpv = new HypreParVector*[nv];
5294  for (int i=0; i<nv; i++)
5295  {
5296  hpv[i] = new HypreParVector(vecs[i]);
5297  }
5298 }
5299 
5300 HypreLOBPCG::HypreMultiVector::~HypreMultiVector()
5301 {
5302  if ( hpv != NULL )
5303  {
5304  for (int i=0; i<nv; i++)
5305  {
5306  delete hpv[i];
5307  }
5308  delete [] hpv;
5309  }
5310 
5311  mv_MultiVectorDestroy(mv_ptr);
5312 }
5313 
5314 void
5315 HypreLOBPCG::HypreMultiVector::Randomize(HYPRE_Int seed)
5316 {
5317  mv_MultiVectorSetRandom(mv_ptr, seed);
5318 }
5319 
5320 HypreParVector &
5321 HypreLOBPCG::HypreMultiVector::GetVector(unsigned int i)
5322 {
5323  MFEM_ASSERT((int)i < nv, "index out of range");
5324 
5325  return ( *hpv[i] );
5326 }
5327 
5328 HypreParVector **
5329 HypreLOBPCG::HypreMultiVector::StealVectors()
5330 {
5331  HypreParVector ** hpv_ret = hpv;
5332 
5333  hpv = NULL;
5334 
5335  mv_TempMultiVector * mv_tmp =
5336  (mv_TempMultiVector*)mv_MultiVectorGetData(mv_ptr);
5337 
5338  mv_tmp->ownsVectors = 0;
5339 
5340  for (int i=0; i<nv; i++)
5341  {
5342  hpv_ret[i]->SetOwnership(1);
5343  }
5344 
5345  return hpv_ret;
5346 }
5347 
5349  : comm(c),
5350  myid(0),
5351  numProcs(1),
5352  nev(10),
5353  seed(75),
5354  glbSize(-1),
5355  part(NULL),
5356  multi_vec(NULL),
5357  x(NULL),
5358  subSpaceProj(NULL)
5359 {
5360  MPI_Comm_size(comm,&numProcs);
5361  MPI_Comm_rank(comm,&myid);
5362 
5363  HYPRE_ParCSRSetupInterpreter(&interpreter);
5364  HYPRE_ParCSRSetupMatvec(&matvec_fn);
5365  HYPRE_LOBPCGCreate(&interpreter, &matvec_fn, &lobpcg_solver);
5366 }
5367 
5369 {
5370  delete multi_vec;
5371  delete x;
5372  delete [] part;
5373 
5374  HYPRE_LOBPCGDestroy(lobpcg_solver);
5375 }
5376 
5377 void
5379 {
5380  HYPRE_LOBPCGSetTol(lobpcg_solver, tol);
5381 }
5382 
5383 void
5384 HypreLOBPCG::SetRelTol(double rel_tol)
5385 {
5386 #if MFEM_HYPRE_VERSION >= 21101
5387  HYPRE_LOBPCGSetRTol(lobpcg_solver, rel_tol);
5388 #else
5389  MFEM_ABORT("This method requires HYPRE version >= 2.11.1");
5390 #endif
5391 }
5392 
5393 void
5395 {
5396  HYPRE_LOBPCGSetMaxIter(lobpcg_solver, max_iter);
5397 }
5398 
5399 void
5401 {
5402  if (myid == 0)
5403  {
5404  HYPRE_LOBPCGSetPrintLevel(lobpcg_solver, logging);
5405  }
5406 }
5407 
5408 void
5410 {
5411  HYPRE_LOBPCGSetPrecondUsageMode(lobpcg_solver, pcg_mode);
5412 }
5413 
5414 void
5416 {
5417  HYPRE_LOBPCGSetPrecond(lobpcg_solver,
5418  (HYPRE_PtrToSolverFcn)this->PrecondSolve,
5419  (HYPRE_PtrToSolverFcn)this->PrecondSetup,
5420  (HYPRE_Solver)&precond);
5421 }
5422 
5423 void
5425 {
5426  HYPRE_BigInt locSize = A.Width();
5427 
5428  if (HYPRE_AssumedPartitionCheck())
5429  {
5430  part = new HYPRE_BigInt[2];
5431 
5432  MPI_Scan(&locSize, &part[1], 1, HYPRE_MPI_BIG_INT, MPI_SUM, comm);
5433 
5434  part[0] = part[1] - locSize;
5435 
5436  MPI_Allreduce(&locSize, &glbSize, 1, HYPRE_MPI_BIG_INT, MPI_SUM, comm);
5437  }
5438  else
5439  {
5440  part = new HYPRE_BigInt[numProcs+1];
5441 
5442  MPI_Allgather(&locSize, 1, HYPRE_MPI_BIG_INT,
5443  &part[1], 1, HYPRE_MPI_BIG_INT, comm);
5444 
5445  part[0] = 0;
5446  for (int i=0; i<numProcs; i++)
5447  {
5448  part[i+1] += part[i];
5449  }
5450 
5451  glbSize = part[numProcs];
5452  }
5453 
5454  if ( x != NULL )
5455  {
5456  delete x;
5457  }
5458 
5459  // Create a distributed vector without a data array.
5460  const bool is_device_ptr = true;
5461  x = new HypreParVector(comm,glbSize,NULL,part,is_device_ptr);
5462 
5463  matvec_fn.MatvecCreate = this->OperatorMatvecCreate;
5464  matvec_fn.Matvec = this->OperatorMatvec;
5465  matvec_fn.MatvecDestroy = this->OperatorMatvecDestroy;
5466 
5467  HYPRE_LOBPCGSetup(lobpcg_solver,(HYPRE_Matrix)&A,NULL,NULL);
5468 }
5469 
5470 void
5472 {
5473  matvec_fn.MatvecCreate = this->OperatorMatvecCreate;
5474  matvec_fn.Matvec = this->OperatorMatvec;
5475  matvec_fn.MatvecDestroy = this->OperatorMatvecDestroy;
5476 
5477  HYPRE_LOBPCGSetupB(lobpcg_solver,(HYPRE_Matrix)&M,NULL);
5478 }
5479 
5480 void
5482 {
5483  // Initialize eigenvalues array with marker values
5484  eigs.SetSize(nev);
5485 
5486  for (int i=0; i<nev; i++)
5487  {
5488  eigs[i] = eigenvalues[i];
5489  }
5490 }
5491 
5492 const HypreParVector &
5493 HypreLOBPCG::GetEigenvector(unsigned int i) const
5494 {
5495  return multi_vec->GetVector(i);
5496 }
5497 
5498 void
5500 {
5501  // Initialize HypreMultiVector object if necessary
5502  if ( multi_vec == NULL )
5503  {
5504  MFEM_ASSERT(x != NULL, "In HypreLOBPCG::SetInitialVectors()");
5505 
5506  multi_vec = new HypreMultiVector(nev, *x, interpreter);
5507  }
5508 
5509  // Copy the vectors provided
5510  for (int i=0; i < min(num_vecs,nev); i++)
5511  {
5512  multi_vec->GetVector(i) = *vecs[i];
5513  }
5514 
5515  // Randomize any remaining vectors
5516  for (int i=min(num_vecs,nev); i < nev; i++)
5517  {
5518  multi_vec->GetVector(i).Randomize(seed);
5519  }
5520 
5521  // Ensure all vectors are in the proper subspace
5522  if ( subSpaceProj != NULL )
5523  {
5524  HypreParVector y(*x);
5525  y = multi_vec->GetVector(0);
5526 
5527  for (int i=1; i<nev; i++)
5528  {
5529  subSpaceProj->Mult(multi_vec->GetVector(i),
5530  multi_vec->GetVector(i-1));
5531  }
5532  subSpaceProj->Mult(y,
5533  multi_vec->GetVector(nev-1));
5534  }
5535 }
5536 
5537 void
5539 {
5540  // Initialize HypreMultiVector object if necessary
5541  if ( multi_vec == NULL )
5542  {
5543  MFEM_ASSERT(x != NULL, "In HypreLOBPCG::Solve()");
5544 
5545  multi_vec = new HypreMultiVector(nev, *x, interpreter);
5546  multi_vec->Randomize(seed);
5547 
5548  if ( subSpaceProj != NULL )
5549  {
5550  HypreParVector y(*x);
5551  y = multi_vec->GetVector(0);
5552 
5553  for (int i=1; i<nev; i++)
5554  {
5555  subSpaceProj->Mult(multi_vec->GetVector(i),
5556  multi_vec->GetVector(i-1));
5557  }
5558  subSpaceProj->Mult(y, multi_vec->GetVector(nev-1));
5559  }
5560  }
5561 
5562  eigenvalues.SetSize(nev);
5563  eigenvalues = NAN;
5564 
5565  // Perform eigenmode calculation
5566  //
5567  // The eigenvalues are computed in ascending order (internally the
5568  // order is determined by the LAPACK routine 'dsydv'.)
5569  HYPRE_LOBPCGSolve(lobpcg_solver, NULL, *multi_vec, eigenvalues);
5570 }
5571 
5572 void *
5573 HypreLOBPCG::OperatorMatvecCreate( void *A,
5574  void *x )
5575 {
5576  void *matvec_data;
5577 
5578  matvec_data = NULL;
5579 
5580  return ( matvec_data );
5581 }
5582 
5583 HYPRE_Int
5584 HypreLOBPCG::OperatorMatvec( void *matvec_data,
5585  HYPRE_Complex alpha,
5586  void *A,
5587  void *x,
5588  HYPRE_Complex beta,
5589  void *y )
5590 {
5591  MFEM_VERIFY(alpha == 1.0 && beta == 0.0, "values not supported");
5592 
5593  Operator *Aop = (Operator*)A;
5594 
5595  int width = Aop->Width();
5596 
5597  hypre_ParVector * xPar = (hypre_ParVector *)x;
5598  hypre_ParVector * yPar = (hypre_ParVector *)y;
5599 
5600  Vector xVec(xPar->local_vector->data, width);
5601  Vector yVec(yPar->local_vector->data, width);
5602 
5603  Aop->Mult( xVec, yVec );
5604 
5605  return 0;
5606 }
5607 
5608 HYPRE_Int
5609 HypreLOBPCG::OperatorMatvecDestroy( void *matvec_data )
5610 {
5611  return 0;
5612 }
5613 
5614 HYPRE_Int
5615 HypreLOBPCG::PrecondSolve(void *solver,
5616  void *A,
5617  void *b,
5618  void *x)
5619 {
5620  Solver *PC = (Solver*)solver;
5621  Operator *OP = (Operator*)A;
5622 
5623  int width = OP->Width();
5624 
5625  hypre_ParVector * bPar = (hypre_ParVector *)b;
5626  hypre_ParVector * xPar = (hypre_ParVector *)x;
5627 
5628  Vector bVec(bPar->local_vector->data, width);
5629  Vector xVec(xPar->local_vector->data, width);
5630 
5631  PC->Mult( bVec, xVec );
5632 
5633  return 0;
5634 }
5635 
5636 HYPRE_Int
5637 HypreLOBPCG::PrecondSetup(void *solver,
5638  void *A,
5639  void *b,
5640  void *x)
5641 {
5642  return 0;
5643 }
5644 
5645 HypreAME::HypreAME(MPI_Comm comm)
5646  : myid(0),
5647  numProcs(1),
5648  nev(10),
5649  setT(false),
5650  ams_precond(NULL),
5651  eigenvalues(NULL),
5652  multi_vec(NULL),
5653  eigenvectors(NULL)
5654 {
5655  MPI_Comm_size(comm,&numProcs);
5656  MPI_Comm_rank(comm,&myid);
5657 
5658  HYPRE_AMECreate(&ame_solver);
5659  HYPRE_AMESetPrintLevel(ame_solver, 0);
5660 }
5661 
5663 {
5664  if ( multi_vec )
5665  {
5666  mfem_hypre_TFree_host(multi_vec);
5667  }
5668 
5669  if ( eigenvectors )
5670  {
5671  for (int i=0; i<nev; i++)
5672  {
5673  delete eigenvectors[i];
5674  }
5675  }
5676  delete [] eigenvectors;
5677 
5678  if ( eigenvalues )
5679  {
5680  mfem_hypre_TFree_host(eigenvalues);
5681  }
5682 
5683  HYPRE_AMEDestroy(ame_solver);
5684 }
5685 
5686 void
5688 {
5689  nev = num_eigs;
5690 
5691  HYPRE_AMESetBlockSize(ame_solver, nev);
5692 }
5693 
5694 void
5695 HypreAME::SetTol(double tol)
5696 {
5697  HYPRE_AMESetTol(ame_solver, tol);
5698 }
5699 
5700 void
5701 HypreAME::SetRelTol(double rel_tol)
5702 {
5703 #if MFEM_HYPRE_VERSION >= 21101
5704  HYPRE_AMESetRTol(ame_solver, rel_tol);
5705 #else
5706  MFEM_ABORT("This method requires HYPRE version >= 2.11.1");
5707 #endif
5708 }
5709 
5710 void
5712 {
5713  HYPRE_AMESetMaxIter(ame_solver, max_iter);
5714 }
5715 
5716 void
5718 {
5719  if (myid == 0)
5720  {
5721  HYPRE_AMESetPrintLevel(ame_solver, logging);
5722  }
5723 }
5724 
5725 void
5727 {
5728  ams_precond = &precond;
5729 }
5730 
5731 void
5733 {
5734  if ( !setT )
5735  {
5736  HYPRE_Solver ams_precond_ptr = (HYPRE_Solver)*ams_precond;
5737 
5738  ams_precond->SetupFcn()(*ams_precond,A,NULL,NULL);
5739 
5740  HYPRE_AMESetAMSSolver(ame_solver, ams_precond_ptr);
5741  }
5742 
5743  HYPRE_AMESetup(ame_solver);
5744 }
5745 
5746 void
5748 {
5749  HYPRE_ParCSRMatrix parcsr_M = M;
5750  HYPRE_AMESetMassMatrix(ame_solver,(HYPRE_ParCSRMatrix)parcsr_M);
5751 }
5752 
5753 void
5755 {
5756  HYPRE_AMESolve(ame_solver);
5757 
5758  // Grab a pointer to the eigenvalues from AME
5759  HYPRE_AMEGetEigenvalues(ame_solver,&eigenvalues);
5760 
5761  // Grad a pointer to the eigenvectors from AME
5762  HYPRE_AMEGetEigenvectors(ame_solver,&multi_vec);
5763 }
5764 
5765 void
5767 {
5768  // Initialize eigenvalues array with marker values
5769  eigs.SetSize(nev); eigs = -1.0;
5770 
5771  // Copy eigenvalues to eigs array
5772  for (int i=0; i<nev; i++)
5773  {
5774  eigs[i] = eigenvalues[i];
5775  }
5776 }
5777 
5778 void
5779 HypreAME::createDummyVectors() const
5780 {
5781  eigenvectors = new HypreParVector*[nev];
5782  for (int i=0; i<nev; i++)
5783  {
5784  eigenvectors[i] = new HypreParVector(multi_vec[i]);
5785  eigenvectors[i]->SetOwnership(1);
5786  }
5787 }
5788 
5789 const HypreParVector &
5790 HypreAME::GetEigenvector(unsigned int i) const
5791 {
5792  if ( eigenvectors == NULL )
5793  {
5794  this->createDummyVectors();
5795  }
5796 
5797  return *eigenvectors[i];
5798 }
5799 
5800 HypreParVector **
5802 {
5803  if ( eigenvectors == NULL )
5804  {
5805  this->createDummyVectors();
5806  }
5807 
5808  // Set the local pointers to NULL so that they won't be deleted later
5809  HypreParVector ** vecs = eigenvectors;
5810  eigenvectors = NULL;
5811  multi_vec = NULL;
5812 
5813  return vecs;
5814 }
5815 
5816 }
5817 
5818 #endif
MemoryType GetHypreMemoryType()
The MemoryType used by MFEM when allocating arrays for Hypre objects.
Definition: hypre.hpp:87
virtual ~HypreBoomerAMG()
Definition: hypre.cpp:4725
void SetAbsTol(double atol)
Definition: hypre.cpp:3574
Hash function for data sequences.
Definition: hash.hpp:218
Memory< double > auxX
Definition: hypre.hpp:850
void SetTol(double tol)
Definition: hypre.cpp:3569
void SetPreconditioner(HypreSolver &precond)
Set the hypre solver to be used as a preconditioner.
Definition: hypre.cpp:3784
int Size() const
Return the logical size of the array.
Definition: array.hpp:134
void EliminateRowsCols(const Array< int > &rows_cols, const HypreParVector &X, HypreParVector &B)
Definition: hypre.cpp:2052
HypreADS(ParFiniteElementSpace *face_fespace)
Definition: hypre.cpp:4986
virtual int NumNonZeroElems() const
Returns the number of the nonzero elements in the matrix.
Definition: sparsemat.cpp:1443
static constexpr Type default_type
Definition: hypre.hpp:912
Vector()
Default constructor for Vector. Sets size = 0 and data = NULL.
Definition: vector.hpp:70
MPI_Comm GetComm() const
MPI communicator.
Definition: hypre.hpp:472
HypreEuclid(MPI_Comm comm)
Definition: hypre.cpp:4155
virtual void SetOperator(const Operator &op)
Set/update the solver for the given operator.
Definition: hypre.cpp:3904
Vector * GlobalVector() const
Returns the global vector in each processor.
Definition: hypre.cpp:182
void EliminateBC(const HypreParMatrix &A, const HypreParMatrix &Ae, const Array< int > &ess_dof_list, const Vector &X, Vector &B)
Eliminate essential BC specified by ess_dof_list from the solution X to the r.h.s. B.
Definition: hypre.cpp:2857
int * GetJ()
Definition: table.hpp:114
HypreParVector * X0
FIR Filter Temporary Vectors.
Definition: hypre.hpp:854
void Clear()
Clear the contents of the SparseMatrix.
Definition: sparsemat.hpp:170
double min_eig_est
Minimal eigenvalue estimate for polynomial smoothing.
Definition: hypre.hpp:886
int NumCols() const
Definition: array.hpp:369
void MakeDataOwner() const
Set the Vector data (host pointer) ownership flag.
Definition: vector.hpp:178
Memory< double > data
Definition: vector.hpp:64
static MemoryClass GetHostMemoryClass()
Get the current Host MemoryClass. This is the MemoryClass used by most MFEM host Memory objects...
Definition: device.hpp:268
bool IsVariableOrder() const
Returns true if the space contains elements of varying polynomial orders.
Definition: fespace.hpp:432
Memory< HYPRE_Int > I
void SetPrintLevel(int print_lvl)
Definition: hypre.cpp:5273
ParMesh * GetParMesh() const
Definition: pfespace.hpp:267
void SetMassMatrix(const HypreParMatrix &M)
Definition: hypre.cpp:5747
HypreParMatrix * RAP(const HypreParMatrix *A, const HypreParMatrix *P)
Returns the matrix P^t * A * P.
Definition: hypre.cpp:2485
virtual ~HypreEuclid()
Definition: hypre.cpp:4220
void WrapMemoryWrite(Memory< double > &mem)
Replace the HypreParVector&#39;s data with the given Memory, mem, and prepare the vector for write access...
Definition: hypre.cpp:274
int setup_called
Was hypre&#39;s Setup function called already?
Definition: hypre.hpp:991
void HypreRead() const
Prepare the HypreParVector for read access in hypre&#39;s device memory space, HYPRE_MEMORY_DEVICE.
Definition: hypre.cpp:217
void EliminateBC(const HypreParMatrix &Ae, const Array< int > &ess_dof_list, const Vector &X, Vector &B) const
Eliminate essential BC specified by ess_dof_list from the solution X to the r.h.s. B.
Definition: hypre.cpp:2104
Memory< double > data
void HypreRead() const
Update the internal hypre_ParCSRMatrix object, A, to be in hypre memory space.
Definition: hypre.hpp:743
HYPRE_BigInt GlobalSize() const
Returns the global number of rows.
Definition: hypre.hpp:171
virtual void SetOperator(const Operator &op)
Set/update the solver for the given operator.
Definition: hypre.cpp:3547
void SetPreconditioner(HypreSolver &precond)
Set the hypre solver to be used as a preconditioner.
Definition: hypre.cpp:3951
void MakeRef(const HypreParMatrix &master)
Make this HypreParMatrix a reference to &#39;master&#39;.
Definition: hypre.cpp:1213
void Read_IJMatrix(MPI_Comm comm, const char *fname)
Read a matrix saved as a HYPRE_IJMatrix.
Definition: hypre.cpp:2185
bool CanShallowCopy(const Memory< T > &src, MemoryClass mc)
Return true if the src Memory can be used with the MemoryClass mc.
Definition: hypre.cpp:52
void SetSize(int s)
Resize the vector to size s.
Definition: vector.hpp:513
HypreParMatrix & Add(const double beta, const HypreParMatrix &B)
Definition: hypre.hpp:660
HypreParVector * B
Right-hand side and solution vector.
Definition: hypre.hpp:986
void Delete()
Delete the owned pointers. The Memory is not reset by this method, i.e. it will, generally, not be Empty() after this call.
double window_params[3]
Parameters for windowing function of FIR filter.
Definition: hypre.hpp:888
const T * HostRead() const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), false).
Definition: array.hpp:304
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
Definition: table.cpp:476
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition: operator.hpp:72
void SetInitialVectors(int num_vecs, HypreParVector **vecs)
Definition: hypre.cpp:5499
double Norml2() const
Returns the l2 norm of the vector.
Definition: vector.cpp:783
virtual void SetOperator(const Operator &op)
Set/update the solver for the given operator.
Definition: hypre.cpp:3732
int * GetJ()
Return the array J.
Definition: sparsemat.hpp:185
void SetWindowByName(const char *window_name)
Convenience function for setting canonical windowing parameters.
Definition: hypre.cpp:3056
HYPRE_BigInt GlobalTrueVSize() const
Definition: pfespace.hpp:275
T * GetData()
Returns the data.
Definition: array.hpp:108
Issue warnings on hypre errors.
Definition: hypre.hpp:977
T * Write(Memory< T > &mem, int size, bool on_dev=true)
Get a pointer for write access to mem with the mfem::Device&#39;s DeviceMemoryClass, if on_dev = true...
Definition: device.hpp:336
void SetPreconditioner(HypreSolver &precond)
Definition: hypre.cpp:5726
virtual double * HostWrite()
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), false).
Definition: vector.hpp:438
int Size() const
Returns the size of the vector.
Definition: vector.hpp:190
HyprePCG(MPI_Comm comm)
Definition: hypre.cpp:3529
void SetTol(double tol)
Definition: hypre.cpp:5695
HypreILU()
Constructor; sets the default options.
Definition: hypre.cpp:4227
int GetElementOrder(int i) const
Returns the order of the i&#39;th finite element.
Definition: fespace.cpp:160
T * Write(MemoryClass mc, int size)
Get write-only access to the memory with the given MemoryClass.
HypreAMS(ParFiniteElementSpace *edge_fespace)
Definition: hypre.cpp:4735
void SetKDim(int dim)
Definition: hypre.cpp:3936
virtual ~HypreGMRES()
Definition: hypre.cpp:3866
void SetPrintLevel(int print_lvl)
Definition: hypre.cpp:3946
virtual void SetOperator(const Operator &op)
Set/update the solver for the given operator.
Definition: hypre.cpp:5233
std::string GetHash() const
Return the hash string for the current sequence and reset (clear) the sequence.
Definition: hash.cpp:60
void SetPreconditioner(Solver &precond)
Definition: hypre.cpp:5415
virtual void Mult(const Vector &x, Vector &y) const =0
Operator application: y=A(x).
void SetMassMatrix(Operator &M)
Definition: hypre.cpp:5471
Abstract parallel finite element space.
Definition: pfespace.hpp:28
HypreParVector()
Default constructor, no underlying hypre_ParVector is created.
Definition: hypre.hpp:115
double Normlinf() const
Returns the l_infinity norm of the vector.
Definition: vector.cpp:801
void SetPrintLevel(int logging)
Definition: hypre.cpp:5400
bool iterative_mode
If true, use the second argument of Mult() as an initial guess.
Definition: operator.hpp:652
void CopyFrom(const Memory &src, int size)
Copy size entries from src to *this.
virtual ~HypreAMS()
Definition: hypre.cpp:4966
void SetTol(double tol)
Definition: hypre.cpp:3754
virtual ~HypreILU()
Definition: hypre.cpp:4299
void SetAdvectiveOptions(int distance=15, const std::string &prerelax="", const std::string &postrelax="FFC")
Definition: hypre.cpp:4617
void BlockInverseScale(const HypreParMatrix *A, HypreParMatrix *C, const Vector *b, HypreParVector *d, int blocksize, BlockInverseScaleJob job)
Definition: hypre.cpp:2378
void HostWrite()
Update the internal hypre_ParCSRMatrix object, A, to be on host.
Definition: hypre.hpp:737
bool pos_l1_norms
If set, take absolute values of the computed l1_norms.
Definition: hypre.hpp:880
double * GetData() const
Return a pointer to the beginning of the Vector data.
Definition: vector.hpp:199
HypreParMatrix * ParMult(const HypreParMatrix *A, const HypreParMatrix *B, bool own_matrix)
Definition: hypre.cpp:2464
void SetPrintLevel(int print_lvl)
Definition: hypre.cpp:3779
MPI_Comm GetComm() const
MPI communicator.
Definition: hypre.hpp:154
void ScaleRows(const Vector &s)
Scale the local row i by s(i).
Definition: hypre.cpp:1802
virtual MFEM_DEPRECATED N_Vector ToNVector()
(DEPRECATED) Return a new wrapper SUNDIALS N_Vector of type SUNDIALS_NVEC_PARALLEL.
Definition: hypre.cpp:308
int Size_of_connections() const
Definition: table.hpp:98
double poly_fraction
Fraction of spectrum to smooth for polynomial relaxation.
Definition: hypre.hpp:868
Memory< double > & GetMemoryData()
Definition: sparsemat.hpp:227
int Capacity() const
Return the size of the allocated memory.
Memory< double > & GetMemory()
Return a reference to the Memory object used by the Vector.
Definition: vector.hpp:225
void SetPrintLevel(int print_lvl)
Definition: hypre.cpp:3589
virtual void SetOperator(const Operator &op)
Set/update the solver for the given operator.
Definition: hypre.cpp:4280
Memory< int > & GetMemoryI()
Definition: sparsemat.hpp:195
int poly_scale
Apply the polynomial smoother to A or D^{-1/2} A D^{-1/2}.
Definition: hypre.hpp:870
void MergeDiagAndOffd(SparseMatrix &merged)
Get a single SparseMatrix containing all rows from this processor, merged from the diagonal and off-d...
Definition: hypre.cpp:1423
HashFunction & AppendDoubles(const double *doubles, size_t num_doubles)
Add a sequence of doubles for hashing, given as a c-array.
Definition: hash.hpp:271
void GetEigenvalues(Array< double > &eigenvalues) const
Collect the converged eigenvalues.
Definition: hypre.cpp:5481
void SetTol(double tol)
Definition: hypre.cpp:5378
HypreParVector * X1
Definition: hypre.hpp:854
HypreFGMRES(MPI_Comm comm)
Definition: hypre.cpp:3872
HYPRE_BigInt N() const
Returns the global number of columns.
Definition: hypre.hpp:523
virtual void Mult(const HypreParVector &b, HypreParVector &x) const
Solve Ax=b with hypre&#39;s FGMRES.
Definition: hypre.cpp:3960
HYPRE_BigInt M() const
Returns the global number of rows.
Definition: hypre.hpp:521
Memory< int > & GetMemoryJ()
Definition: sparsemat.hpp:211
void SetWindowParameters(double a, double b, double c)
Set parameters for windowing function for FIR smoother.
Definition: hypre.cpp:3071
HypreGMRES(MPI_Comm comm)
Definition: hypre.cpp:3700
void GetOffd(SparseMatrix &offd, HYPRE_BigInt *&cmap) const
Get the local off-diagonal block. NOTE: &#39;offd&#39; will not own any data.
Definition: hypre.cpp:1417
Vector & operator=(const double *v)
Copy Size() entries from v.
Definition: vector.cpp:124
virtual void SetOperator(const Operator &op)
Set/update the solver for the given operator.
Definition: hypre.cpp:4120
virtual void Mult(const HypreParVector &b, HypreParVector &x) const
Solve Ax=b with hypre&#39;s GMRES.
Definition: hypre.cpp:3794
void Print(const char *fname) const
Prints the locally owned rows in parallel.
Definition: hypre.cpp:293
struct::_p_PC * PC
Definition: petsc.hpp:72
bool MemoryClassContainsType(MemoryClass mc, MemoryType mt)
Return true iff the MemoryType mt is contained in the MemoryClass mc.
Definition: mem_manager.cpp:69
void AbsMultTranspose(double a, const Vector &x, double b, Vector &y) const
Computes y = a * |At| * x + b * y, using entry-wise absolute values of the transpose of the matrix A...
Definition: hypre.cpp:1688
HypreLOBPCG(MPI_Comm comm)
Definition: hypre.cpp:5348
HYPRE_BigInt * GetRowStarts() const
Return the parallel row partitioning array.
Definition: hypre.hpp:583
void Add(const DenseMatrix &A, const DenseMatrix &B, double alpha, DenseMatrix &C)
C = A + alpha*B.
Definition: densemat.cpp:1931
virtual void Mult(const HypreParVector &b, HypreParVector &x) const
Relax the linear system Ax=b.
Definition: hypre.cpp:3222
int GetNE() const
Returns number of elements in the mesh.
Definition: fespace.hpp:567
virtual void SetOperator(const Operator &op)
Set/update the solver for the given operator.
Definition: hypre.cpp:4038
void SetSymmetry(int sym)
Definition: hypre.cpp:4144
virtual ~HypreParaSails()
Definition: hypre.cpp:4149
MPI_Comm GetComm() const
Definition: pfespace.hpp:263
int GetFaceOrder(int face, int variant=0) const
Returns the polynomial degree of the i&#39;th face finite element.
Definition: fespace.cpp:2270
double f(const Vector &xvec)
Definition: lor_mms.hpp:32
void SetMaxIter(int max_iter)
Definition: hypre.cpp:5394
double * l1_norms
l1 norms of the rows of A
Definition: hypre.hpp:878
Data type sparse matrix.
Definition: sparsemat.hpp:41
BlockInverseScaleJob
Definition: hypre.hpp:784
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition: operator.hpp:66
void SetOwnerFlags(signed char diag, signed char offd, signed char colmap)
Explicitly set the three ownership flags, see docs for diagOwner etc.
Definition: hypre.cpp:1250
void PrintHash(std::ostream &out) const
Print sizes and hashes for all data arrays of the HypreParMatrix from the local MPI rank...
Definition: hypre.cpp:2243
void SetLogging(int logging)
Definition: hypre.cpp:3584
Mesh * GetMesh() const
Returns the mesh.
Definition: fespace.hpp:410
virtual ~HypreSolver()
Definition: hypre.cpp:3520
virtual HYPRE_PtrToParSolverFcn SolveFcn() const =0
hypre&#39;s internal Solve function
virtual double * Write(bool on_dev=true)
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), on_dev).
Definition: vector.hpp:434
void SetRelTol(double rel_tol)
Definition: hypre.cpp:5701
void SetKDim(int dim)
Definition: hypre.cpp:3769
void mfem_error(const char *msg)
Function called when an error is encountered. Used by the macros MFEM_ABORT, MFEM_ASSERT, MFEM_VERIFY.
Definition: error.cpp:153
void SetResidualConvergenceOptions(int res_frequency=-1, double rtol=0.0)
Definition: hypre.cpp:3604
double b
Definition: lissajous.cpp:42
int to_int(const std::string &str)
Convert a string to an int.
Definition: text.hpp:62
Abort on hypre errors (default in base class)
Definition: hypre.hpp:978
void SetLogging(int logging)
Definition: hypre.cpp:3941
Arbitrary order H(curl)-trace finite elements defined on the interface between mesh elements (faces...
Definition: fe_coll.hpp:457
void GetBlocks(Array2D< HypreParMatrix * > &blocks, bool interleaved_rows=false, bool interleaved_cols=false) const
Definition: hypre.cpp:1447
virtual void Mult(const HypreParVector &b, HypreParVector &x) const
Solve the linear system Ax=b.
Definition: hypre.cpp:3414
HypreParaSails(MPI_Comm comm)
Definition: hypre.cpp:4056
void HypreWrite()
Prepare the HypreParVector for write access in hypre&#39;s device memory space, HYPRE_MEMORY_DEVICE.
Definition: hypre.cpp:236
void SetTol(double tol)
Definition: hypre.cpp:3926
void WrapHypreParVector(hypre_ParVector *y, bool owner=true)
Converts hypre&#39;s format to HypreParVector.
Definition: hypre.cpp:173
virtual void SetOperator(const Operator &op)
Set/update the solver for the given operator.
Definition: hypre.cpp:4948
HypreParVector ** StealEigenvectors()
Transfer ownership of the converged eigenvectors.
Definition: hypre.cpp:5801
const HypreParMatrix * A
The linear system matrix.
Definition: hypre.hpp:983
bool OwnsHostPtr() const
Return true if the host pointer is owned. Ownership indicates whether the pointer will be deleted by ...
HypreParMatrix * Transpose() const
Returns the transpose of *this.
Definition: hypre.cpp:1471
HYPRE_Int Randomize(HYPRE_Int seed)
Set random values.
Definition: hypre.cpp:288
Ignore hypre errors (see e.g. HypreADS)
Definition: hypre.hpp:976
double relax_weight
Damping coefficient (usually &lt;= 1)
Definition: hypre.hpp:862
Memory< HYPRE_Int > J
void SetElasticityOptions(ParFiniteElementSpace *fespace)
Definition: hypre.cpp:4569
Memory< double > auxB
Definition: hypre.hpp:988
void GetDiag(Vector &diag) const
Get the local diagonal of the matrix.
Definition: hypre.cpp:1344
void Sort()
Sorts the array in ascending order. This requires operator&lt; to be defined for T.
Definition: array.hpp:244
int Size() const
Returns the number of TYPE I elements.
Definition: table.hpp:92
void SetData(double *d)
Definition: vector.hpp:140
const T * Read(const Memory< T > &mem, int size, bool on_dev=true)
Get a pointer for read access to mem with the mfem::Device&#39;s DeviceMemoryClass, if on_dev = true...
Definition: device.hpp:319
int Dimension() const
Definition: mesh.hpp:911
void SetLevelOfFill(HYPRE_Int lev_fill)
Set the fill level for ILU(k); the default is k=1.
Definition: hypre.cpp:4270
void Reset()
Reset the memory to be empty, ensuring that Delete() will be a no-op.
HypreParMatrix * A
The linear system matrix.
Definition: hypre.hpp:844
virtual const double * HostRead() const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), false).
Definition: vector.hpp:430
Biwise-OR of all CUDA backends.
Definition: device.hpp:88
Dynamic 2D array using row-major layout.
Definition: array.hpp:347
virtual void SetOperator(const Operator &op)
Definition: hypre.cpp:3078
virtual HYPRE_PtrToParSolverFcn SetupFcn() const =0
hypre&#39;s internal Setup function
void SetLogging(int logging)
Definition: hypre.cpp:3774
virtual ~HypreADS()
Definition: hypre.cpp:5251
HYPRE_BigInt GetGlobalNumCols() const
Return the global number of columns.
Definition: hypre.hpp:577
HypreParMatrix()
An empty matrix to be used as a reference to an existing matrix.
Definition: hypre.cpp:504
bool A_is_symmetric
A flag that indicates whether the linear system matrix A is symmetric.
Definition: hypre.hpp:894
void SetMaxIter(int max_iter)
Definition: hypre.cpp:3579
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:2904
void SetMaxIter(int max_iter)
Definition: hypre.cpp:3931
void SetPolyOptions(int poly_order, double poly_fraction, int eig_est_cg_iter=10)
Set parameters for polynomial smoothing.
Definition: hypre.cpp:3040
void SetSOROptions(double relax_weight, double omega)
Set SOR-related parameters.
Definition: hypre.cpp:3034
int SpaceDimension() const
Definition: mesh.hpp:912
T * HostWrite(Memory< T > &mem, int size)
Shortcut to Write(const Memory&lt;T&gt; &amp;mem, int size, false)
Definition: device.hpp:343
void CopyMemory(Memory< T > &src, Memory< T > &dst, MemoryClass dst_mc, bool dst_owner)
Shallow or deep copy src to dst with the goal to make the array src accessible through dst with the M...
Definition: hypre.cpp:377
Wrapper for hypre&#39;s parallel vector class.
Definition: hypre.hpp:99
HypreParMatrix * EliminateCols(const Array< int > &cols)
Definition: hypre.cpp:2077
HypreParVector * X
Definition: hypre.hpp:986
double Norml1() const
Returns the l_1 norm of the vector.
Definition: vector.cpp:812
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:2867
HYPRE_BigInt * GetTrueDofOffsets() const
Definition: pfespace.hpp:272
void ClearOwnerFlags() const
Clear the ownership flags for the host and device pointers, as well as any internal data allocated by...
static MemoryType GetHostMemoryType()
Get the current Host MemoryType. This is the MemoryType used by most MFEM classes when allocating mem...
Definition: device.hpp:264
MemoryType GetDeviceMemoryType() const
Return the device MemoryType of the Memory object. If the device MemoryType is not set...
OutStream err(std::cerr)
Global stream used by the library for standard error output. Initially it uses the same std::streambu...
Definition: globals.hpp:71
int NumRows() const
Get the number of rows (size of output) of the Operator. Synonym with Height().
Definition: operator.hpp:69
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
Definition: fe_coll.hpp:26
void HostRead() const
Update the internal hypre_ParCSRMatrix object, A, to be on host.
Definition: hypre.hpp:726
MemoryType
Memory types supported by MFEM.
Definition: mem_manager.hpp:31
void SetPrintLevel(int print_lvl)
Definition: hypre.cpp:4981
void SetHostPtrOwner(bool own) const
Set/clear the ownership flag for the host pointer. Ownership indicates whether the pointer will be de...
Memory< double > auxX
Definition: hypre.hpp:988
HypreParVector * X
Definition: hypre.hpp:846
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition: array.hpp:674
void Solve()
Solve the eigenproblem.
Definition: hypre.cpp:5754
HYPRE_Int HYPRE_BigInt
void SetData(double *data_)
Sets the data of the Vector and the hypre_ParVector to data_.
Definition: hypre.cpp:211
int NumCols() const
Get the number of columns (size of input) of the Operator. Synonym with Width().
Definition: operator.hpp:75
void SetNumModes(int num_eigs)
Definition: hypre.cpp:5687
const HypreParVector & GetEigenvector(unsigned int i) const
Extract a single eigenvector.
Definition: hypre.cpp:5790
int GetNumRows() const
Returns the number of rows in the diagonal block of the ParCSRMatrix.
Definition: hypre.hpp:559
virtual void SetOperator(const Operator &op)
Set/update the solver for the given operator.
Definition: hypre.hpp:1009
HypreParMatrix * ParAdd(const HypreParMatrix *A, const HypreParMatrix *B)
Returns the matrix A + B.
Definition: hypre.cpp:2425
double max_eig_est
Maximal eigenvalue estimate for polynomial smoothing.
Definition: hypre.hpp:884
static bool Allows(unsigned long b_mask)
Return true if any of the backends in the backend mask, b_mask, are allowed.
Definition: device.hpp:258
A class to initialize the size of a Tensor.
Definition: dtensor.hpp:54
void SetDataAndSize(double *d, int s)
Set the Vector data and size.
Definition: vector.hpp:147
void SetRelTol(double rel_tol)
Definition: hypre.cpp:5384
void CuWrap1D(const int N, DBODY &&d_body)
Definition: forall.hpp:304
HashFunction & AppendInts(const int_type *ints, size_t num_ints)
Add a sequence of integers for hashing, given as a c-array.
Definition: hash.hpp:251
HypreAME(MPI_Comm comm)
Definition: hypre.cpp:5645
HYPRE_Int MultTranspose(HypreParVector &x, HypreParVector &y, double alpha=1.0, double beta=0.0) const
Computes y = alpha * A^t * x + beta * y.
Definition: hypre.cpp:1663
void MakeAlias(const Memory &base, int offset, int size)
Create a memory object that points inside the memory object base.
int height
Dimension of the output / number of rows in the matrix.
Definition: operator.hpp:27
void SetMaxIter(int max_iter)
Definition: hypre.cpp:5711
void SetFIRCoefficients(double max_eig)
Compute window and Chebyshev coefficients for given polynomial order.
Definition: hypre.cpp:3182
double a
Definition: lissajous.cpp:41
void EliminateRows(const Array< int > &rows)
Eliminate rows from the diagonal and off-diagonal blocks of the matrix.
Definition: hypre.cpp:2091
double * fir_coeffs
Combined coefficients for windowing and Chebyshev polynomials.
Definition: hypre.hpp:891
void Threshold(double threshold=0.0)
Remove values smaller in absolute value than some threshold.
Definition: hypre.cpp:1930
const T * HostRead(const Memory< T > &mem, int size)
Shortcut to Read(const Memory&lt;T&gt; &amp;mem, int size, false)
Definition: device.hpp:326
double InnerProduct(HypreParVector *x, HypreParVector *y)
Definition: hypre.cpp:316
void Print(const char *fname, HYPRE_Int offi=0, HYPRE_Int offj=0) const
Prints the locally owned rows in parallel.
Definition: hypre.cpp:2162
virtual ~HypreSmoother()
Definition: hypre.cpp:3373
void SetPrintLevel(HYPRE_Int print_level)
Set the print level: 0 = none, 1 = setup, 2 = solve, 3 = setup+solve.
Definition: hypre.cpp:4275
Host memory; using new[] and delete[].
constexpr MemoryClass GetHypreMemoryClass()
The MemoryClass used by Hypre objects.
Definition: hypre.hpp:75
HYPRE_BigInt GetGlobalNumRows() const
Return the global number of rows.
Definition: hypre.hpp:573
void HypreReadWrite()
Prepare the HypreParVector for read and write access in hypre&#39;s device memory space, HYPRE_MEMORY_DEVICE.
Definition: hypre.cpp:227
virtual void SetOperator(const Operator &op)
Set/update the solver for the given operator.
Definition: hypre.cpp:4447
void New(int size)
Allocate host memory for size entries with the current host memory type returned by MemoryManager::Ge...
void InvScaleRows(const Vector &s)
Scale the local row i by 1./s(i)
Definition: hypre.cpp:1841
void SetTaubinOptions(double lambda, double mu, int iter)
Set parameters for Taubin&#39;s lambda-mu method.
Definition: hypre.cpp:3048
bool Empty() const
Return true if the Memory object is empty, see Reset().
HypreParVector * B
Right-hand side and solution vectors.
Definition: hypre.hpp:846
virtual void SetOperator(const Operator &op)
Set/update the solver for the given operator.
Definition: hypre.cpp:4196
double mu
Definition: ex25.cpp:139
virtual void MultTranspose(const Vector &b, Vector &x) const
Apply transpose of the smoother to relax the linear system Ax=b.
Definition: hypre.cpp:3363
T * ReadWrite(MemoryClass mc, int size)
Get read-write access to the memory with the given MemoryClass.
int dim
Definition: ex24.cpp:53
MemoryType GetMemoryType(MemoryClass mc)
Return a suitable MemoryType for a given MemoryClass.
Definition: mem_manager.cpp:54
virtual ~HyprePCG()
Definition: hypre.cpp:3694
int GetNumCols() const
Returns the number of columns in the diagonal block of the ParCSRMatrix.
Definition: hypre.hpp:566
void SetOperator(Operator &A)
Definition: hypre.cpp:5424
void SetPreconditioner(HypreSolver &precond)
Set the hypre solver to be used as a preconditioner.
Definition: hypre.cpp:3594
void Destroy()
Destroy a vector.
Definition: vector.hpp:590
int relax_times
Number of relaxation sweeps.
Definition: hypre.hpp:860
void GetEigenvalues(Array< double > &eigenvalues) const
Collect the converged eigenvalues.
Definition: hypre.cpp:5766
Class used by MFEM to store pointers to host and/or device memory.
void operator*=(double s)
Scale all entries by s: A_scaled = s*A.
Definition: hypre.cpp:1887
void SetPrintLevel(int logging)
Definition: hypre.cpp:5717
double infinity()
Define a shortcut for std::numeric_limits&lt;double&gt;::infinity()
Definition: vector.hpp:46
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:327
int eig_est_cg_iter
Number of CG iterations to determine eigenvalue estimates.
Definition: hypre.hpp:882
void SetOwnership(int own)
Sets ownership of the internal hypre_ParVector.
Definition: hypre.hpp:183
Abstract class for hypre&#39;s solvers and preconditioners.
Definition: hypre.hpp:970
ErrorMode error_mode
How to treat hypre errors.
Definition: hypre.hpp:994
const HypreParVector & GetEigenvector(unsigned int i) const
Extract a single eigenvector.
Definition: hypre.cpp:5493
HYPRE_BigInt * GetColStarts() const
Return the parallel column partitioning array.
Definition: hypre.hpp:588
RefCoord t[3]
HypreParVector & operator=(double d)
Set constant values.
Definition: hypre.cpp:192
const double alpha
Definition: ex15.cpp:369
Vector data type.
Definition: vector.hpp:60
void SetAbsTol(double tol)
Definition: hypre.cpp:3759
const FiniteElementCollection * FEColl() const
Definition: fespace.hpp:554
void PrintCommPkg(std::ostream &out=mfem::out) const
Print information about the hypre_ParCSRCommPkg of the HypreParMatrix.
Definition: hypre.cpp:2206
void delete_hypre_ParCSRMatrixColMapOffd(hypre_ParCSRMatrix *A)
Definition: hypre.cpp:2309
void CopyConvertMemory(Memory< SrcT > &src, MemoryClass dst_mc, Memory< DstT > &dst)
Deep copy and convert src to dst with the goal to make the array src accessible through dst with the ...
Definition: hypre.cpp:412
HypreParMatrix * ExtractSubmatrix(const Array< int > &indices, double threshold=0.0) const
Definition: hypre.cpp:1490
Arbitrary order &quot;H^{-1/2}-conforming&quot; face finite elements defined on the interface between mesh elem...
Definition: fe_coll.hpp:396
hypre_ParCSRMatrix * StealData()
Changes the ownership of the matrix.
Definition: hypre.cpp:1231
void SetPrecondUsageMode(int pcg_mode)
Definition: hypre.cpp:5409
void SetOperator(const HypreParMatrix &A)
Definition: hypre.cpp:5732
void SetSystemsOptions(int dim, bool order_bynodes=false)
Definition: hypre.cpp:4466
HYPRE_Int Mult(HypreParVector &x, HypreParVector &y, double alpha=1.0, double beta=0.0) const
Computes y = alpha * A * x + beta * y.
Definition: hypre.cpp:1529
void DropSmallEntries(double tol)
Wrapper for hypre_ParCSRMatrixDropSmallEntries in different versions of hypre. Drop off-diagonal entr...
Definition: hypre.cpp:2006
void SetMaxIter(int max_iter)
Definition: hypre.cpp:3764
RefCoord s[3]
double omega
SOR parameter (usually in (0,2))
Definition: hypre.hpp:864
double u(const Vector &xvec)
Definition: lor_mms.hpp:24
HypreParMatrix * LeftDiagMult(const SparseMatrix &D, HYPRE_BigInt *row_starts=NULL) const
Multiply the HypreParMatrix on the left by a block-diagonal parallel matrix D and return the result a...
Definition: hypre.cpp:1705
Base class for solvers.
Definition: operator.hpp:648
void WrapHypreParCSRMatrix(hypre_ParCSRMatrix *a, bool owner=true)
Converts hypre&#39;s format to HypreParMatrix.
Definition: hypre.cpp:510
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
Definition: globals.hpp:66
Abstract operator.
Definition: operator.hpp:24
Wrapper for hypre&#39;s ParCSR matrix class.
Definition: hypre.hpp:277
void HostReadWrite()
Update the internal hypre_ParCSRMatrix object, A, to be on host.
Definition: hypre.hpp:732
void AbsMult(double a, const Vector &x, double b, Vector &y) const
Computes y = a * |A| * x + b * y, using entry-wise absolute values of the matrix A.
Definition: hypre.cpp:1671
Memory< double > auxB
Auxiliary buffers for the case when the input or output arrays in methods like Mult(const Vector &amp;...
Definition: hypre.hpp:850
void Swap(SparseMatrix &other)
Definition: sparsemat.cpp:3970
~HypreParVector()
Calls hypre&#39;s destroy function.
Definition: hypre.cpp:298
virtual void Mult(const HypreParVector &b, HypreParVector &x) const
Solve Ax=b with hypre&#39;s PCG.
Definition: hypre.cpp:3617
HypreParMatrix * HypreParMatrixFromBlocks(Array2D< HypreParMatrix * > &blocks, Array2D< double > *blockCoeff)
Returns a merged hypre matrix constructed from hypre matrix blocks.
Definition: hypre.cpp:2626
const T * Read(MemoryClass mc, int size) const
Get read-only access to the memory with the given MemoryClass.
HypreParVector * Z
Definition: hypre.hpp:852
void Solve()
Solve the eigenproblem.
Definition: hypre.cpp:5538
virtual ~HypreFGMRES()
Definition: hypre.cpp:4032
HypreParVector * V
Temporary vectors.
Definition: hypre.hpp:852
void SetType(HypreSmoother::Type type, int relax_times=1)
Set the relaxation type and number of sweeps.
Definition: hypre.cpp:3028
void GatherBlockOffsetData(MPI_Comm comm, const int rank, const int nprocs, const int num_loc, const Array< int > &offsets, std::vector< int > &all_num_loc, const int numBlocks, std::vector< std::vector< HYPRE_BigInt >> &blockProcOffsets, std::vector< HYPRE_BigInt > &procOffsets, std::vector< std::vector< int >> &procBlockOffsets, HYPRE_BigInt &firstLocal, HYPRE_BigInt &globalNum)
Definition: hypre.cpp:2568
MemoryType GetHostMemoryType() const
Return the host MemoryType of the Memory object.
virtual double * HostReadWrite()
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), false).
Definition: vector.hpp:446
MemoryClass
Memory classes identify sets of memory types.
Definition: mem_manager.hpp:73
int NumRows() const
Definition: array.hpp:368
void WrapMemoryReadWrite(Memory< double > &mem)
Replace the HypreParVector&#39;s data with the given Memory, mem, and prepare the vector for read and wri...
Definition: hypre.cpp:260
int width
Dimension of the input / number of columns in the matrix.
Definition: operator.hpp:28
int poly_order
Order of the smoothing polynomial.
Definition: hypre.hpp:866
double lambda
Taubin&#39;s lambda-mu method parameters.
Definition: hypre.hpp:873
void WrapMemoryRead(const Memory< double > &mem)
Replace the HypreParVector&#39;s data with the given Memory, mem, and prepare the vector for read access ...
Definition: hypre.cpp:245
double sigma(const Vector &x)
Definition: maxwell.cpp:102
void HypreReadWrite()
Update the internal hypre_ParCSRMatrix object, A, to be in hypre memory space.
Definition: hypre.hpp:750