Tpetra parallel linear algebra Version of the Day
Loading...
Searching...
No Matches
Tpetra_Distribution2D.hpp
1// @HEADER
2// *****************************************************************************
3// Tpetra: Templated Linear Algebra Services Package
4//
5// Copyright 2008 NTESS and the Tpetra contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10// 2D matrix distribution
11// Assumes square matrix
12// Karen Devine, SNL
13//
14
15#ifndef __TPETRA_DISTRIBUTION2D_HPP
16#define __TPETRA_DISTRIBUTION2D_HPP
17
18namespace Tpetra {
19
21template <typename gno_t, typename scalar_t>
22class Distribution2D : public Distribution<gno_t, scalar_t> {
23 // Processors will be laid out logically first down columns then
24 // across rows. For example, assume np = 8, npRows=2, npCols=4.
25 // Then the processors will be laid out in 2D as
26 // 0 2 4 6
27 // 1 3 5 7
28 //
29 // The matrix will be distributed using np=8 row blocks:
30 // 0 2 4 6
31 // 1 3 5 7
32 // 0 2 4 6
33 // 1 3 5 7
34 // 0 2 4 6
35 // 1 3 5 7
36 // 0 2 4 6
37 // 1 3 5 7
38 //
39 // The vector will be distributed linearly or randomly. The row and
40 // column maps will be built to allow only row- or column-based
41 // communication in the matvec.
42
43 public:
44 using Distribution<gno_t, scalar_t>::me;
45 using Distribution<gno_t, scalar_t>::np;
46 using Distribution<gno_t, scalar_t>::comm;
47 using Distribution<gno_t, scalar_t>::nrows;
48 using Distribution<gno_t, scalar_t>::Mine;
49
50 Distribution2D(size_t nrows_,
51 const Teuchos::RCP<const Teuchos::Comm<int> > &comm_,
52 const Teuchos::ParameterList &params)
53 : Distribution<gno_t, scalar_t>(nrows_, comm_, params)
54 , npRows(-1)
55 , npCols(-1) {
56 {
57 const Teuchos::ParameterEntry *pe = params.getEntryPtr("nProcessorRows");
58 if (pe != NULL)
59 npRows = pe->getValue<int>(&npRows);
60 }
61
62 {
63 const Teuchos::ParameterEntry *pe = params.getEntryPtr("nProcessorCols");
64 if (pe != NULL)
65 npCols = pe->getValue<int>(&npCols);
66 }
67
68 // Compute the processor configuration npRows * npCols
69
70 if (npRows == -1 && npCols == -1) { // Compute both npRows and npCols
71 // First guess
72 npRows = (int)(sqrt(np));
73 npCols = np / npRows;
74 // Adjust npRows so that npRows * npCols == np
75 while (npRows * npCols != np) {
76 npRows++;
77 npCols = np / npRows;
78 }
79 } else { // User specified either npRows or npCols
80 if (npRows == -1) // npCols specified; compute npRows
81 npRows = np / npCols;
82 else if (npCols == -1) // npRows specified; compute npCols
83 npCols = np / npRows;
84
85 if (npCols * npRows != np) {
86 TEUCHOS_TEST_FOR_EXCEPTION(npRows * npCols != np, std::logic_error,
87 "nProcessorCols " << npCols << " * nProcessorRows " << npRows << " = " << npCols * npRows << " must equal nProcessors " << np << " for 2D distribution");
88 }
89 }
90 if (me == 0)
91 std::cout << "\n2D Distribution: "
92 << "\n npRows = " << npRows
93 << "\n npCols = " << npCols
94 << "\n np = " << np << std::endl;
95
96 mypCol = this->TWODPCOL(me);
97 mypRow = this->TWODPROW(me);
98 }
99
100 virtual ~Distribution2D(){};
101
102 protected:
103 // Return the processor row for rank p
104 inline int TWODPROW(int p) { return (p % npRows); }
105
106 // Return the processor column for rank p
107 inline int TWODPCOL(int p) { return (p / npRows); }
108
109 // Return the rank for processor row i and processor column j
110 inline int TWODPRANK(int i, int j) { return (j * npRows + (j + i) % npRows); }
111
112 int npRows; // Number of processor rows
113 int npCols; // Number of processor columns
114 int mypRow; // This rank's processor row
115 int mypCol; // This rank's processor column
116};
117
119template <typename gno_t, typename scalar_t>
120class Distribution2DLinear : public Distribution2D<gno_t, scalar_t> {
121 public:
122 using Distribution<gno_t, scalar_t>::me;
123 using Distribution<gno_t, scalar_t>::np;
124 using Distribution<gno_t, scalar_t>::nrows;
125 using Distribution2D<gno_t, scalar_t>::npRows;
126 using Distribution2D<gno_t, scalar_t>::npCols;
127 using Distribution2D<gno_t, scalar_t>::mypRow;
128 using Distribution2D<gno_t, scalar_t>::mypCol;
129
130 Distribution2DLinear(size_t nrows_,
131 const Teuchos::RCP<const Teuchos::Comm<int> > &comm_,
132 const Teuchos::ParameterList &params)
133 : Distribution2D<gno_t, scalar_t>(nrows_, comm_, params) {
134 // Build vector describing distribution of vector entries across ranks
135 entries.assign(np + 1, nrows / np);
136 int nExtraEntries = nrows % np;
137
138 // Distribute the extra entries evenly among processors.
139 // To evenly distribute them extra entries among processor rows and
140 // columns, we distribute them along diagonals of the matrix distribution.
141 // For our example, assume we have seven extra values (the max possible
142 // with np=8). Then we give one extra entry each to ranks
143 // [0, 3, 4, 7, 1, 2, 5]. For fewer extra entries, we follow the same
144 // order of assignment, and just stop early.
145
146 for (int cnt = 0, i = 0; (cnt < nExtraEntries) && (i < npRows); i++) {
147 for (int j = 0; (cnt < nExtraEntries) && (j < npCols); cnt++, j++) {
148 int rankForExtra = Distribution2D<gno_t, scalar_t>::TWODPRANK(i, j);
149 entries[rankForExtra + 1]++; // Store in rankForExtra+1 to simplify
150 // prefix sum.
151 }
152 }
153
154 // Perform prefix sum of entries.
155 entries[0] = 0;
156 for (int i = 1; i <= np; i++)
157 entries[i] = entries[i - 1] + entries[i];
158 // Now entries contains the first vector entry for each rank.
159
160 // Column map: Easy; consecutive entries for all ranks in column.
161 int firstRank = mypCol * npRows; // First rank in my column
162 myFirstCol = entries[firstRank];
163
164 gno_t nMyCols = 0;
165 for (int i = firstRank; i < firstRank + npRows; i++)
166 nMyCols += entries[i + 1] - entries[i];
167 myLastCol = myFirstCol + nMyCols - 1;
168 }
169
170 inline enum DistributionType DistType() { return TwoDLinear; }
171
172 bool Mine(gno_t i, gno_t j) {
173 int idx = int(float(i) * float(np) / float(nrows));
174 while (i < entries[idx]) idx--;
175 while (i >= entries[idx + 1]) idx++;
176 return ((mypRow == Distribution2D<gno_t, scalar_t>::TWODPROW(idx)) // RowMine
177 && (j >= myFirstCol && j <= myLastCol)); // ColMine
178 }
179 inline bool Mine(gno_t i, gno_t j, int p) { return Mine(i, j); }
180
181 inline bool VecMine(gno_t i) {
182 return (i >= entries[me] && i < entries[me + 1]);
183 }
184
185 private:
186 std::vector<gno_t> entries; // Describes vector entries' distribution to ranks
187 // Organized like vtxdist
188 gno_t myFirstCol; // First column owned by this rank
189 gno_t myLastCol; // Last column owned by this rank
190};
191
193template <typename gno_t, typename scalar_t>
194class Distribution2DRandom : public Distribution2D<gno_t, scalar_t> {
195 public:
196 using Distribution<gno_t, scalar_t>::me;
197 using Distribution2D<gno_t, scalar_t>::mypRow;
198 using Distribution2D<gno_t, scalar_t>::mypCol;
199
200 Distribution2DRandom(size_t nrows_,
201 const Teuchos::RCP<const Teuchos::Comm<int> > &comm_,
202 const Teuchos::ParameterList &params)
203 : Distribution2D<gno_t, scalar_t>(nrows_, comm_, params) {
204 if (me == 0) std::cout << " randomize = true" << std::endl;
205 }
206
207 inline enum DistributionType DistType() { return TwoDRandom; }
208
209 inline bool Mine(gno_t i, gno_t j) {
210 return ((mypRow == this->TWODPROW(this->HashToProc(i))) && // RowMine
211 (mypCol == this->TWODPCOL(this->HashToProc(j)))); // ColMine
212 }
213 inline bool Mine(gno_t i, gno_t j, int p) { return Mine(i, j); }
214
215 inline bool VecMine(gno_t i) { return (me == this->HashToProc(i)); }
216};
217
219
220template <typename gno_t, typename scalar_t>
221class Distribution2DVec : public Distribution2D<gno_t, scalar_t> {
222 // Distribute non-zeros in a 2D manner based on the vector distribution
223 // and the nprows x npcols configuration;
224 // rows are assigned to same process owning the vector entry.
225 public:
226 using Distribution<gno_t, scalar_t>::me;
227 using Distribution<gno_t, scalar_t>::np;
228 using Distribution<gno_t, scalar_t>::comm;
229 using Distribution<gno_t, scalar_t>::nrows;
230 using Distribution2D<gno_t, scalar_t>::npRows;
231 using Distribution2D<gno_t, scalar_t>::npCols;
232
233 Distribution2DVec(size_t nrows_,
234 const Teuchos::RCP<const Teuchos::Comm<int> > &comm_,
235 const Teuchos::ParameterList &params,
236 std::string &distributionfile)
237 : Distribution2D<gno_t, scalar_t>(nrows_, comm_, params) {
238 if (me == 0) std::cout << "\n 2DVec Distribution: "
239 << "\n np = " << np << std::endl;
240 std::ifstream fpin;
241 if (me == 0) {
242 fpin.open(distributionfile.c_str(), std::ios::in);
243 if (!fpin.is_open()) {
244 std::cout << "Error: distributionfile " << distributionfile
245 << " not found" << std::endl;
246 exit(-1);
247 }
248 }
249
250 // Read the vector part assignment and broadcast it to all processes.
251 // Broadcast in chunks of bcastsize values.
252 // TODO: Make the vector part assignment more scalable instead of
253 // TODO: storing entire vector on every process.
254
255 vecpart = new int[nrows];
256
257 const int bcastsize = 1000000;
258
259 gno_t start = 0;
260 int cnt = 0;
261 for (size_t i = 0; i < nrows; i++) {
262 if (me == 0) fpin >> vecpart[i];
263 cnt++;
264 if (cnt == bcastsize || i == nrows - 1) {
265 Teuchos::broadcast(*comm, 0, cnt, &(vecpart[start]));
266 start += cnt;
267 cnt = 0;
268 }
269 }
270
271 if (me == 0) fpin.close();
272 }
273
274 ~Distribution2DVec() { delete[] vecpart; }
275
276 inline enum DistributionType DistType() { return TwoDVec; }
277
278 bool Mine(gno_t i, gno_t j) {
279 return (me == (vecpart[i] % npRows + (vecpart[j] / npRows) * npRows));
280 }
281 inline bool Mine(gno_t i, gno_t j, int p) { return Mine(i, j); }
282
283 inline bool VecMine(gno_t i) { return (vecpart[i] == me); }
284
285 private:
286 int *vecpart;
287};
288
289} // namespace Tpetra
290#endif
void start()
Start the deep_copy counter.
Namespace Tpetra contains the class and methods constituting the Tpetra library.