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