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