Block-Structured AMR Software Framework
Loading...
Searching...
No Matches
AMReX_SpMatUtil.H
Go to the documentation of this file.
1#ifndef AMREX_SPMAT_UTIL_H_
2#define AMREX_SPMAT_UTIL_H_
3#include <AMReX_Config.H>
4
5#include <AMReX_BLProfiler.H>
6#include <AMReX_SpMatrix.H>
7#include <AMReX_Random.H>
8
9namespace amrex {
10
24template <typename IO = Long, typename T, template <typename> class V, typename I>
26{
27 Long nnz = csr.nnz;
28
29 CSR<T,V,IO> csrt;
30 csrt.mat.resize(nnz);
31 csrt.col_index.resize(nnz);
32 csrt.row_offset.resize(ncols+1);
33 csrt.nnz = nnz;
34
35 detail::transpose(csrt.view(), csr.const_view());
36
37 return csrt;
38}
39
48template <typename T, template<typename> class Allocator>
50 AlgPartition const& col_partition)
51{
52 BL_PROFILE("SpMatrix::transpose");
53
54 auto& Am = const_cast<SpMatrix<T,Allocator>&>(A);
55 Am.setColumnPartition(col_partition);
56 Am.startComm_tr(col_partition);
57
58 // The transpose is built directly in split form: its local block is
59 // the transpose of A's local block (columns are A's local row
60 // indices), and its remote block comes from the other ranks.
62 AT.m_row_begin = col_partition[ParallelContext::MyProcSub()];
63 AT.m_row_end = col_partition[ParallelContext::MyProcSub()+1];
64 AT.m_partition = col_partition;
65 AT.m_nnz = A.m_csr_local.nnz;
66 AT.m_csr_local = transpose<int>(A.m_csr_local, AT.numLocalRows());
67 AT.m_col_partition = A.partition();
68 AT.m_col_begin = A.globalRowBegin();
69 AT.m_col_end = A.globalRowEnd();
70 AT.m_split = true;
71#ifdef AMREX_USE_MPI
72 AT.m_ri_ltor.resize(AT.numLocalRows(), -1);
73 AT.m_remote_cols_vv.resize(ParallelContext::NProcsSub());
74#endif
75
76 Am.finishComm_tr(AT);
77
78 return AT;
79}
80
82template <typename T, template<typename> class Allocator = DefaultAllocator>
84{
85 SpMatrix<T,Allocator> I(std::move(partition), 1);
86 I.setVal([=] AMREX_GPU_DEVICE (Long row, Long* col, T* val) {
87 *col = row; *val = T(1);
88 }, CsrSorted{true});
89 return I;
90}
91
107template <typename T, template<typename> class Allocator = DefaultAllocator>
109 Real lambda, int nnz_per_row_max)
110{
111 AMREX_ALWAYS_ASSERT(partition.numGlobalRows() == nrows);
112
113 auto nlrows = partition.numLocalRows();
114 Long lnnz = nlrows * nnz_per_row_max;
115 typename SpMatrix<T,Allocator>::template container_type<T> mat(lnnz);
116 typename SpMatrix<T,Allocator>::template container_type<Long> col_index(lnnz);
117 typename SpMatrix<T,Allocator>::template container_type<Long> row_offset(nlrows+1, 0);
118 auto* pmat = mat.data();
119 auto* pcol = col_index.data();
120 auto* prow = row_offset.data();
121
122 auto ncols_max = (unsigned int)
123 std::min(ncols, Long(std::numeric_limits<unsigned int>::max()));
124 // A row cannot have more distinct columns than ncols.
125 auto nnz_row_cap = int(std::min(Long(nnz_per_row_max), ncols));
126
127 ParallelForRNG(nlrows, [=] AMREX_GPU_DEVICE (Long lrow, RandomEngine const& eng)
128 {
129 auto os = lrow * nnz_per_row_max;
130 prow[lrow] = os;
131 if (lrow+1 == nlrows) {
132 prow[lrow+1] = lnnz;
133 }
134
135 auto nnz_row = int(std::min(Long(amrex::RandomPoisson(lambda, eng)),
136 Long(nnz_row_cap)));
137
138 for (int j = 0; j < nnz_row; ++j) {
139 pmat[os+j] = Random(eng);
140 while (true) {
141 auto c = Long(Random_int(ncols_max, eng));
142 bool new_c = true;
143 for (int jj = 0; jj < j; ++jj) {
144 new_c = new_c && (c != pcol[os+jj]);
145 }
146 if (new_c) {
147 pcol[os+j] = c;
148 break;
149 }
150 }
151 }
152
153 for (int j = nnz_row; j < nnz_per_row_max; ++j) {
154 pcol[os+j] = -1;
155 pmat[os+j] = T(0);
156 }
157 });
158
160 r.define(std::move(partition), pmat, pcol, lnnz, prow,
161 CsrSorted{false}, CsrValid{false});
162
163 return r;
164}
165
188template <typename T, template<typename> class Allocator = DefaultAllocator>
190 int ulp = 2)
191{
192 auto const& col_partition_A = A.columnPartition();
193 auto const& col_partition_B = B.columnPartition();
194 if (col_partition_A.empty() && ! col_partition_B.empty()) {
195 const_cast<SpMatrix<T,Allocator>&>(A).setColumnPartition(col_partition_B);
196 } else if (! col_partition_A.empty() && col_partition_B.empty()) {
197 const_cast<SpMatrix<T,Allocator>&>(B).setColumnPartition(col_partition_A);
198 } else if (col_partition_A.empty() && col_partition_B.empty()) {
199 // Neither has been split: compare the unsplit CSR with global columns.
200 auto& a = const_cast<SpMatrix<T,Allocator>&>(A);
201 auto& b = const_cast<SpMatrix<T,Allocator>&>(B);
202 Long const nnz = a.numLocalNonZeros();
203 Long const nrows = a.numLocalRows();
204 if (a.globalRowBegin() != b.globalRowBegin() ||
205 nnz != b.numLocalNonZeros() || nrows != b.numLocalRows())
206 {
207 return false;
208 }
209 T const* amat = a.data();
210 T const* bmat = b.data();
211 Long const* acol = a.columnIndex();
212 Long const* bcol = b.columnIndex();
213 Long const* arow = a.rowOffset();
214 Long const* brow = b.rowOffset();
215 Long N = std::max(nnz, nrows);
216 auto r = Reduce::Min<int>(N, [=] AMREX_GPU_DEVICE (Long i) {
217 bool t = true;
218 if (i < nnz) {
219 t = amrex::almostEqual(amat[i], bmat[i], ulp) && acol[i] == bcol[i];
220 }
221 if (t && i < nrows) {
222 t = arow[i] == brow[i];
223 }
224 return int(t);
225 }, 1);
226 return r;
227 }
228
229 auto const& pca = A.const_parcsr();
230 auto const& pcb = B.const_parcsr();
231
232 if (pca.row_begin != pcb.row_begin ||
233 pca.col_begin != pcb.col_begin ||
234 pca.csr0.nnz != pcb.csr0.nnz ||
235 pca.csr0.nrows != pcb.csr0.nrows ||
236 pca.csr1.nnz != pcb.csr1.nnz ||
237 pca.csr1.nrows != pcb.csr1.nrows)
238 {
239 return false;
240 }
241
242 Long N = std::max({pca.csr0.nnz, pca.csr0.nrows, pca.csr1.nnz, pca.csr1.nrows});
243 auto r = Reduce::Min<int>(N, [=] AMREX_GPU_DEVICE (Long i) {
244 bool t = true;
245 if (i < pca.csr0.nnz) {
246 t = amrex::almostEqual(pca.csr0.mat[i], pcb.csr0.mat[i], ulp) &&
247 pca.csr0.col_index[i] == pcb.csr0.col_index[i];
248 }
249 if (t && i < pca.csr0.nrows) {
250 t = pca.csr0.row_offset[i] == pcb.csr0.row_offset[i];
251 // Which local rows have remote entries.
252 if (t && pca.csr1.nnz > 0) {
253 t = pca.row_map[i] == pcb.row_map[i];
254 }
255 }
256 if (t && i < pca.csr1.nnz) {
257 // Remote column indices are local; compare the global ones.
258 t = amrex::almostEqual(pca.csr1.mat[i], pcb.csr1.mat[i], ulp) &&
259 pca.col_map[pca.csr1.col_index[i]] == pcb.col_map[pcb.csr1.col_index[i]];
260 }
261 if (t && i < pca.csr1.nrows) {
262 t = pca.csr1.row_offset[i] == pcb.csr1.row_offset[i];
263 }
264 return int(t);
265 }, 1);
266
267 return r;
268}
269
270}
271
272#endif
#define BL_PROFILE(a)
Definition AMReX_BLProfiler.H:562
#define AMREX_ALWAYS_ASSERT(EX)
Definition AMReX_BLassert.H:50
#define AMREX_GPU_DEVICE
Definition AMReX_GpuQualifiers.H:18
Definition AMReX_AlgPartition.H:26
Long numGlobalRows() const
Total number of rows covered by the partition.
Definition AMReX_AlgPartition.H:55
Long numLocalRows() const
Number of local rows.
Definition AMReX_AlgPartition.H:50
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
Long globalRowBegin() const
Inclusive global index begin on this process.
Definition AMReX_SpMatrix.H:201
Long * rowOffset()
Don't use this beyond initial setup.
Definition AMReX_SpMatrix.H:218
T * data()
Don't use this beyond initial setup.
Definition AMReX_SpMatrix.H:206
Long globalRowEnd() const
Exclusive global index end on this process.
Definition AMReX_SpMatrix.H:203
Long numLocalNonZeros() const
Number of nonzeros stored locally.
Definition AMReX_SpMatrix.H:198
AlgPartition const & columnPartition() const
Return the column partition used for matrix-vector and matrix-matrix multiplications.
Definition AMReX_SpMatrix.H:191
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
Long * columnIndex()
Don't use this beyond initial setup.
Definition AMReX_SpMatrix.H:212
void setVal(F const &f, CsrSorted is_sorted)
Initialize matrix entries using a row-wise functor.
Definition AMReX_SpMatrix.H:1124
void define(AlgPartition partition, int nnz_per_row)
Allocate storage for a default-constructed matrix with a fixed number of nonzeros per row.
Definition AMReX_SpMatrix.H:917
amrex_real Real
Floating Point Type for Fields.
Definition AMReX_REAL.H:80
amrex_long Long
Definition AMReX_INT.H:30
unsigned int Random_int(unsigned int n)
Generates one pseudorandom unsigned integer which is uniformly distributed on [0,n-1]-interval for ea...
Definition AMReX_Random.cpp:186
Real Random()
Generate a psuedo-random real from uniform distribution.
Definition AMReX_Random.cpp:155
unsigned int RandomPoisson(Real lambda)
Generate a psuedo-random integer from a Poisson distribution.
Definition AMReX_Random.cpp:172
__host__ __device__ bool almostEqual(T x, T y, int ulp=2)
Definition AMReX_Algorithm.H:139
int MyProcSub() noexcept
my sub-rank in current frame
Definition AMReX_ParallelContext.H:76
int NProcsSub() noexcept
number of ranks in current frame
Definition AMReX_ParallelContext.H:74
Definition AMReX_Amr.cpp:50
SpMatrix< T, Allocator > RandomMatrix(AlgPartition partition, Long nrows, Long ncols, Real lambda, int nnz_per_row_max)
Return a random sparse matrix.
Definition AMReX_SpMatUtil.H:108
amrex::ArenaAllocator< T > DefaultAllocator
Definition AMReX_GpuAllocators.H:205
SpMatrix< T, Allocator > IdentityMatrix(AlgPartition partition)
Return an identity matrix with given partition.
Definition AMReX_SpMatUtil.H:83
AMREX_ATTRIBUTE_FLATTEN_FOR void ParallelForRNG(T n, L const &f) noexcept
Definition AMReX_GpuLaunchFunctsC.H:1157
CSR< T, V, IO > transpose(CSR< T, V, I > const &csr, Long ncols)
Build the transpose CSR of csr.
Definition AMReX_SpMatUtil.H:25
const int[]
Definition AMReX_BLProfiler.cpp:1665
Owning CSR container backed by AMReX resizable vectors.
Definition AMReX_CSR.H:53
CsrView< T const, I > const_view() const
Convenience alias for view() const.
Definition AMReX_CSR.H:97
V< I > row_offset
Definition AMReX_CSR.H:57
CsrView< T, I > view()
Mutable view of the underlying buffers.
Definition AMReX_CSR.H:82
Long nnz
Definition AMReX_CSR.H:58
V< I > col_index
Definition AMReX_CSR.H:56
V< T > mat
Definition AMReX_CSR.H:55
Sorted CSR means for each row the column indices are sorted.
Definition AMReX_SpMatrix.H:49
Valid CSR means all entries are valid. It may be sorted ro unsorted.
Definition AMReX_SpMatrix.H:55
Definition AMReX_RandomEngine.H:72