1#ifndef AMREX_SMOOTHER_MV_H_
2#define AMREX_SMOOTHER_MV_H_
41 : m_A(a_A), m_l1(a_l1), m_weight(a_l1 ? T(1) : T(2./3.)) {}
49 int setNumIters (
int a_niters) {
return std::exchange(m_niters, a_niters); }
56 void setL1 (
bool b) { m_l1 = b; m_weight = b ? T(1) : T(2./3.); m_scaling.reset(); }
66 bool with_initial_guess =
false)
71 if ( ! with_initial_guess) {
75 for (
int iter = 0; iter < m_niters; ++iter) {
76 if ((iter == 0) && ! with_initial_guess) {
86 auto& Axvec = workspace(xvec.
partition());
87 SpMV(Axvec, *m_A, xvec);
88 ForEach(xvec, Axvec, bvec, diag,
107 std::shared_ptr<AlgVector<T>> m_scaling;
108 std::shared_ptr<AlgVector<T>> m_work;
112 if (!m_work || m_work->partition() != partition) {
113 m_work = std::make_shared<AlgVector<T>>(partition);
126 m_scaling = std::make_shared<AlgVector<T>>(m_A->
partition());
134 for (
auto idx = a.csr0.row_offset[i]; idx < a.csr0.row_offset[i+1]; ++idx) {
135 s += std::abs(a.csr0.mat[idx]);
137 if (detail::has_remote_row(a, i)) {
138 auto ii = a.row_map[i];
139 for (
auto idx = a.csr1.row_offset[ii]; idx < a.csr1.row_offset[ii+1]; ++idx) {
140 s += std::abs(a.csr1.mat[idx]);
143 p[i] = std::copysign(
s, pd[i]);
170 : m_jacobi(a_A, a_l1), m_A(a_A), m_l1(a_l1) {}
181 int setNumIters (
int a_niters) {
return std::exchange(m_niters, a_niters); }
188 if (m_lambda_max <= T(0)) {
bound(); }
200 bool with_initial_guess =
false)
205 T
const lmin = lmax / m_ratio;
206 T
const theta = (lmax + lmin) / T(2);
207 T
const delta = (lmax - lmin) / T(2);
208 T
const sigma = theta / delta;
210 auto const& diag = m_jacobi.scaling();
211 if (!m_work || (*m_work)[0].partition() != xvec.
partition()) {
212 m_work = std::make_shared<Array<AlgVector<T>,3>>();
213 for (
auto& v : *m_work) { v.define(xvec.
partition()); }
215 auto& r = (*m_work)[0];
216 auto& d = (*m_work)[1];
217 auto& ad = (*m_work)[2];
218 if ( ! with_initial_guess) { xvec.
setValAsync(0); }
220 T
const c0 = T(1) / theta;
221 for (
int it = 0; it < m_niters; ++it) {
223 if (it == 0 && ! with_initial_guess) {
224 ForEach(xvec, d, r, bvec, diag,
229 di = (dd != T(0)) ? c0 * ri / dd : T(0);
234 ForEach(xvec, d, r, bvec, diag,
239 di = (dd != T(0)) ? c0 * ri / dd : T(0);
243 T rho_old = T(1) /
sigma;
244 for (
int k = 1; k < m_degree; ++k) {
248 T
const rho = T(1) / (T(2)*
sigma - rho_old);
249 T
const c1 = rho * rho_old;
250 T
const c2 = T(2) * rho / delta;
256 di = c1 * di + ((dd != T(0)) ? c2 * ri / dd : T(0));
272 T m_lambda_max = T(-1);
273 std::shared_ptr<Array<AlgVector<T>,3>> m_work;
279 if (m_l1) { m_lambda_max = T(1);
return; }
286 if (pd[i] == T(0)) {
return T(0); }
288 for (
auto idx = a.csr0.row_offset[i]; idx < a.csr0.row_offset[i+1]; ++idx) {
289 s += std::abs(a.csr0.mat[idx]);
291 if (detail::has_remote_row(a, i)) {
292 auto ii = a.row_map[i];
293 for (
auto idx = a.csr1.row_offset[ii]; idx < a.csr1.row_offset[ii+1]; ++idx) {
294 s += std::abs(a.csr1.mat[idx]);
297 return s / std::abs(pd[i]);
300 m_lambda_max = (lmax > T(0)) ? lmax : T(1);
328 int setNumIters (
int a_niters) {
return std::exchange(m_niters, a_niters); }
339 bool with_initial_guess =
false,
bool backward =
false)
343 amrex::Abort(
"L1GaussSeidelSmoother is only available in CPU builds");
350 auto const& a = A.const_parcsr();
353 int const nblocks = m_nblocks;
354 bool const has_remote = this->has_remote();
361 m_work = std::make_shared<Array<AlgVector<T>,2>>();
362 if (nblocks > 1) { (*m_work)[0].define(xvec.
partition()); }
363 if (has_remote) { (*m_work)[1].define(xvec.
partition()); }
365 auto& xold = (*m_work)[0];
366 auto& yrem = (*m_work)[1];
367 T
const*
AMREX_RESTRICT px_old = (nblocks > 1) ? xold.data() :
nullptr;
368 T
const*
AMREX_RESTRICT py_rem = has_remote ? yrem.data() :
nullptr;
370 if ( ! with_initial_guess) { xvec.
setVal(0); }
373 auto sweep = [&] (
auto multi_block,
auto remote)
376#pragma omp parallel for
378 for (
int iblock = 0; iblock < nblocks; ++iblock) {
379 auto const [rlo, rhi] = row_block(nrows, iblock, nblocks);
380 auto const& c0 = a.csr0;
381 for (
Long n = 0; n < rhi-rlo; ++n) {
382 Long const i = backward ? (rhi-1-n) : (rlo+n);
384 if constexpr (remote) { r -= py_rem[i]; }
385 for (
Long idx = c0.row_offset[i]; idx < c0.row_offset[i+1]; ++idx) {
386 Long const j = c0.col_index[idx];
387 if constexpr (multi_block) {
389 r -= c0.mat[idx] * ((j >= rlo && j < rhi) ?
x[j] : px_old[j]);
391 r -= c0.mat[idx] *
x[j];
394 if (dl1[i] != T(0)) {
x[i] += r / dl1[i]; }
399 for (
int iter = 0; iter < m_niters; ++iter) {
400 bool const zero_guess = (iter == 0 && ! with_initial_guess);
402 if (zero_guess) { xold.setVal(0); }
else { xold.copy(xvec); }
408 A.startComm_mv(xvec);
409 A.finishComm_mv(yrem);
413 if (has_remote) { sweep(std::true_type{}, std::true_type{}); }
414 else { sweep(std::true_type{}, std::false_type{}); }
416 if (has_remote) { sweep(std::false_type{}, std::true_type{}); }
417 else { sweep(std::false_type{}, std::false_type{}); }
427 int m_has_remote = -1;
428 std::shared_ptr<AlgVector<T>> m_dl1;
429 std::shared_ptr<Array<AlgVector<T>,2>> m_work;
435 if (m_has_remote < 0) {
440 return m_has_remote == 1;
444 static std::pair<Long,Long> row_block (
Long nrows,
int iblock,
int nblocks)
446 Long const lo = (nrows * iblock) / nblocks;
447 Long const hi = (nrows * (iblock+1)) / nblocks;
451 template <
typename C>
452 static T diag_of (
C const& c0,
Long i)
454 for (
Long idx = c0.row_offset[i]; idx < c0.row_offset[i+1]; ++idx) {
455 if (c0.col_index[idx] == i) {
return c0.mat[idx]; }
461 AlgVector<T>
const& l1_diagonal ()
464 if (!m_dl1 || nb != m_nblocks) {
467 m_dl1 = std::make_shared<AlgVector<T>>(m_A->
partition());
470 Long const nrows = m_dl1->numLocalRows();
472#pragma omp parallel for
474 for (
int iblock = 0; iblock < nb; ++iblock) {
475 auto const [rlo, rhi] = row_block(nrows, iblock, nb);
476 auto const& c0 = a.csr0;
477 for (
Long i = rlo; i < rhi; ++i) {
478 T
const aii = diag_of(c0, i);
480 for (
Long idx = c0.row_offset[i]; idx < c0.row_offset[i+1]; ++idx) {
481 Long const j = c0.col_index[idx];
482 if (j != i && (j < rlo || j >= rhi)) {
483 l1 += std::abs(c0.mat[idx]);
486 if (detail::has_remote_row(a, i)) {
487 Long const ii = a.row_map[i];
488 for (
Long idx = a.csr1.row_offset[ii]; idx < a.csr1.row_offset[ii+1]; ++idx) {
489 l1 += std::abs(a.csr1.mat[idx]);
492 p[i] = aii + std::copysign(l1, aii);
Fixed-size array types for use on GPU and CPU.
#define BL_PROFILE(a)
Definition AMReX_BLProfiler.H:562
#define AMREX_ALWAYS_ASSERT_WITH_MESSAGE(EX, MSG)
Definition AMReX_BLassert.H:49
#define AMREX_ASSERT(EX)
Definition AMReX_BLassert.H:38
#define AMREX_RESTRICT
Definition AMReX_Extension.H:37
#define AMREX_GPU_DEVICE
Definition AMReX_GpuQualifiers.H:18
S sigma
Definition AMReX_MLEBNodeFDLaplacian.cpp:1876
GpuArray< MultiArray4< Real const >, 3 > s
Definition AMReX_MLEBNodeFDLaplacian.cpp:214
Definition AMReX_AlgPartition.H:26
Distributed dense vector that mirrors the layout of an AlgPartition.
Definition AMReX_AlgVector.H:29
void setVal(T val)
Definition AMReX_AlgVector.H:273
Long numLocalRows() const
Number of entries stored on this rank.
Definition AMReX_AlgVector.H:74
AlgPartition const & partition() const
Partition describing the global layout of the vector.
Definition AMReX_AlgVector.H:71
void setValAsync(T val)
Definition AMReX_AlgVector.H:280
T const * data() const
Definition AMReX_AlgVector.H:85
Chebyshev polynomial smoother for AlgVector/SpMatrix systems.
Definition AMReX_Smoother_MV.H:163
void setLambdaMax(T l)
Set the largest eigenvalue of the scaled operator instead of the bound.
Definition AMReX_Smoother_MV.H:183
void operator()(AlgVector< T > &xvec, AlgVector< T > const &bvec, bool with_initial_guess=false)
Apply the smoother to solve approximately for xvec.
Definition AMReX_Smoother_MV.H:199
void bound()
Gershgorin bound of the eigenvalues of D^{-1} A.
Definition AMReX_Smoother_MV.H:277
void setDegree(int d)
Polynomial degree (number of matrix-vector products per application, 2 by default).
Definition AMReX_Smoother_MV.H:173
ChebyshevSmoother(SpMatrix< T > const *a_A, bool a_l1=false)
Definition AMReX_Smoother_MV.H:169
T lambdaMax()
Definition AMReX_Smoother_MV.H:186
int setNumIters(int a_niters)
Number of polynomial applications per call (1 by default).
Definition AMReX_Smoother_MV.H:181
void setEigRatio(T r)
Definition AMReX_Smoother_MV.H:176
Jacobi smoother for AlgVector/SpMatrix linear systems.
Definition AMReX_Smoother_MV.H:32
JacobiSmoother(SpMatrix< T > const *a_A, bool a_l1=false)
Construct a smoother that operates on a_A.
Definition AMReX_Smoother_MV.H:40
int setNumIters(int a_niters)
Update how many Jacobi sweeps to perform per apply.
Definition AMReX_Smoother_MV.H:49
void setL1(bool b)
Definition AMReX_Smoother_MV.H:56
void operator()(AlgVector< T > &xvec, AlgVector< T > const &bvec, bool with_initial_guess=false)
Apply the smoother to solve approximately for xvec.
Definition AMReX_Smoother_MV.H:65
AlgVector< T > const & scaling()
Diagonal or l1 scaling vector. The first call is collective.
Definition AMReX_Smoother_MV.H:120
void setWeight(T w)
Set the relaxation weight. Call this after setL1(), which resets it.
Definition AMReX_Smoother_MV.H:52
l1 hybrid Gauss-Seidel smoother for CPUs.
Definition AMReX_Smoother_MV.H:318
L1GaussSeidelSmoother(SpMatrix< T > const *a_A)
Construct a smoother that operates on a_A.
Definition AMReX_Smoother_MV.H:325
int setNumIters(int a_niters)
Number of sweeps per application (2 by default).
Definition AMReX_Smoother_MV.H:328
void operator()(AlgVector< T > &xvec, AlgVector< T > const &bvec, bool with_initial_guess=false, bool backward=false)
Apply the smoother to solve approximately for xvec.
Definition AMReX_Smoother_MV.H:338
Distributed CSR matrix that manages storage and GPU-friendly partitions.
Definition AMReX_SpMatrix.H:65
void setColumnPartition(AlgPartition const &col_partition)
Set the column partition and split the matrix into local and remote blocks with 32-bit column indices...
Definition AMReX_SpMatrix.H:1019
T * data()
Don't use this beyond initial setup.
Definition AMReX_SpMatrix.H:206
ParCsr< T const > const_parcsr() const
Const-qualified alias of parcsr() for convenience.
Definition AMReX_SpMatrix.H:1226
Long numLocalRows() const
Number of rows owned by this rank.
Definition AMReX_SpMatrix.H:194
AlgPartition const & partition() const
Row partition describing how matrix rows are distributed across ranks.
Definition AMReX_SpMatrix.H:182
AlgVector< T, AllocT > const & diagonalVector() const
Return diagonal elements in a square matrix.
Definition AMReX_SpMatrix.H:1145
amrex_long Long
Definition AMReX_INT.H:30
void ParallelForOMP(T n, L const &f) noexcept
Performance-portable kernel launch function with optional OpenMP threading.
Definition AMReX_GpuLaunch.H:328
void Max(KeyValuePair< K, V > &vi, MPI_Comm comm)
Definition AMReX_ParallelReduce.H:133
void streamSynchronize() noexcept
Definition AMReX_GpuDevice.H:310
constexpr int get_max_threads()
Definition AMReX_OpenMP.H:36
MPI_Comm CommunicatorSub() noexcept
sub-communicator for current frame
Definition AMReX_ParallelContext.H:70
Definition AMReX_Amr.cpp:50
__host__ __device__ void ignore_unused(const Ts &...)
No-op helper that marks variables as intentionally unused.
Definition AMReX.H:273
constexpr void ForEach(TypeList< Ts... >, F &&f)
For each type t in TypeList, call f(t)
Definition AMReX_TypeList.H:83
void Abort(const std::string &msg)
Print a fatal-error message to stderr and abort execution.
Definition AMReX.cpp:244
void SpMV(Long nrows, Long ncols, T *__restrict__ py, CsrView< T const, I > const &A, T const *__restrict__ px)
Perform y = A * x using CSR data (GPU/CPU aware).
Definition AMReX_SpMV.H:30