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