Zoltan2
Loading...
Searching...
No Matches
directoryTest_findUniqueGids.cpp
Go to the documentation of this file.
1// @HEADER
2// *****************************************************************************
3// Zoltan2: A package of combinatorial algorithms for scientific computing
4//
5// Copyright 2012 NTESS and the Zoltan2 contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10// Program to testing Zoltan2::findUniqueGids capability
11// Input: Vector of keys: each key is an array with N entries
12// Result vector to be filled by findUniqueGids
13// Output: Filled result vector
14
15
16#include <iostream>
17#include <vector>
18#include <array>
19#include <unordered_set>
20#include <string>
21#include <typeinfo>
22
23#include <Zoltan2_Standards.hpp>
25
26namespace Zoltan2
27{
28
29template <typename key_t, typename gno_t>
31 const std::vector<key_t> &keys,
32 std::vector<gno_t> &gids,
33 Teuchos::RCP<const Teuchos::Comm<int> > &comm
34)
35{
36 // Compute the new GIDs
37 const bool bUseLocalIDs = false; // Local IDs not needed
38 int debug_level = 0;
39
40 typedef int lno_t; // unused
41
43
44 directory_t directory(comm, bUseLocalIDs, debug_level);
45
46 directory.update(keys.size(), &keys[0], NULL, &gids[0], NULL,
47 directory_t::Update_Mode::Replace);
48
49 directory.remap_user_data_as_unique_gids();
50
51 // Retrieve the global numbers and put in the result gids vector
52 directory.find(keys.size(), &keys[0], NULL, &gids[0], NULL, NULL, false);
53
54 // using ssize_t can be long* on clang and I get warnings here or in the original
55 // findUniqueGids - using long long specifically is ok. Can we do an MPI type
56 // as size_t safely or is a conversion necessary? TODO but this gives a clean
57 // build result.
58 typedef long long mpi_t;
59 mpi_t nDDEntries = static_cast<mpi_t>(directory.node_map_size());
60 mpi_t nUnique = 0;
61
62 // TODO use Teuchos
63#ifdef HAVE_MPI
64 MPI_Allreduce(&nDDEntries, &nUnique, 1, MPI_LONG_LONG, MPI_SUM,
65 Teuchos::getRawMpiComm(*comm));
66#else
67 MPI_Allreduce(&nDDEntries, &nUnique, 1, MPI_LONG_LONG, MPI_SUM, MPI_COMM_WORLD);
68#endif
69
70 return size_t(nUnique);
71}
72
73template<typename T>
75{
76 static const char* name() {
77 std::cout << "You are missing a DECL_TYPE_NAME" << std::endl;
78 return(NULL);
79 }
80};
81
82#define DECL_TYPE_NAME(x) \
83 template<> struct type_name<x> { static const char* name() {return #x;} }
84
86DECL_TYPE_NAME(long long);
87
89// Tests for correctness
90static const std::string fail = "FAIL ";
91static const std::string pass = " ";
92
93// Test for correct number of unique Gids
94void checkNUnique(std::string &name, size_t nUniqueGids, size_t nExpected)
95{
96 if (nUniqueGids != nExpected)
97 std::cout << fail << name
98 << "nUniqueGids " << nUniqueGids << " != " << nExpected
99 << std::endl;
100}
101
102// Test for correct maximum Gid
103template <typename gno_t>
105 std::string &name,
106 std::vector<gno_t> &gids,
107 gno_t maxExpected,
108 Teuchos::RCP<const Teuchos::Comm<int> > &comm
109)
110{
111 gno_t maxGid = 0, gmaxGid = 0;
112 size_t len = gids.size();
113 for (size_t i = 0; i < len; i++)
114 if (gids[i] > maxGid) maxGid = gids[i];
115
116 Teuchos::reduceAll<int, gno_t>(*comm, Teuchos::REDUCE_MAX, 1,
117 &maxGid, &gmaxGid);
118 if (gmaxGid != maxExpected)
119 std::cout << fail << name
120 << "max Gid " << gmaxGid << " != " << maxExpected
121 << std::endl;
122}
123
124// Test for correct minimum Gid
125template <typename gno_t>
127 std::string &name,
128 std::vector<gno_t> &gids,
129 gno_t minExpected,
130 Teuchos::RCP<const Teuchos::Comm<int> > &comm
131)
132{
133 gno_t minGid = std::numeric_limits<gno_t>::max(), gminGid;
134 size_t len = gids.size();
135 for (size_t i = 0; i < len; i++)
136 if (gids[i] < minGid) minGid = gids[i];
137
138 Teuchos::reduceAll<int, gno_t>(*comm, Teuchos::REDUCE_MIN, 1,
139 &minGid, &gminGid);
140 if (gminGid != minExpected)
141 std::cout << fail << name
142 << "min Gid " << gminGid << " != " << minExpected
143 << std::endl;
144}
145
146// Test for number of locally unique Gids
147template <typename gno_t>
149 std::string &name,
150 std::vector<gno_t> &gids,
151 size_t nExpected)
152{
153 size_t gidsLen = gids.size();
154 std::unordered_set<gno_t> gidsSet(gidsLen);
155
156 size_t nDups = 0;
157 for (size_t i = 0; i < gidsLen; i++) {
158 if (gidsSet.find(gids[i]) != gidsSet.end()) {
159 // Gid is already found locally
160 nDups++;
161 }
162 else
163 gidsSet.insert(gids[i]);
164 }
165 size_t nUnique = gidsLen - nDups;
166 if (nUnique != nExpected)
167 std::cout << fail << name
168 << "num locally unique Gids " << nUnique << " != " << nExpected
169 << std::endl;
170}
171
173
174template <typename gno_t>
175void test1(Teuchos::RCP<const Teuchos::Comm<int> > &comm)
176{
177 // Test 1:
178 // Key has only one entry
179 // Each proc has me+1 keys
180 // Keys are in range [1,np]
181 int me = comm->getRank();
182 int np = comm->getSize();
183
184 std::string name = std::string(" test1: ")
185 + std::string(type_name<gno_t>::name());
186 if (me == 0) std::cout << "--------\n Starting " << name << std::endl;
187
188 typedef std::array<gno_t, 1> zkey_t;
189 typedef std::vector<zkey_t> keyvec_t;
190 typedef std::vector<gno_t> gidvec_t;
191
192 const size_t nKeys = me+1;
193 keyvec_t keys(nKeys);
194 gidvec_t gids(nKeys);
195
196 for (size_t i = 0; i < nKeys; i++) {
197 zkey_t k;
198 k[0] = i+1;
199 keys[i] = k;
200 }
201
202 size_t nUniqueGids = findUniqueGids<zkey_t, gno_t>(keys,gids,comm);
203
204 // Test for correctness
205 if (me == 0)
206 std::cout << " " << name << " nUniqueGids " << nUniqueGids << std::endl;
207
208 checkNUnique(name, nUniqueGids, size_t(np));
209
210 checkMaxGid(name, gids, gno_t(np-1), comm);
211
212 checkMinGid(name, gids, gno_t(0), comm);
213
214 checkNLocallyUnique(name, gids, nKeys);
215}
216
218
219template <typename gno_t>
220void test2(Teuchos::RCP<const Teuchos::Comm<int> > &comm)
221{
222 // Test 2:
223 // Key has two entries
224 // Each proc has six keys
225 // Three Keys are {rank, x} for x in {1, 2, 3}
226 // Three Keys are {(rank+x)%np, x} for x in {1, 2, 3}
227 // Each rank has three unique and three non-unique keys
228 int me = comm->getRank();
229 int np = comm->getSize();
230
231 std::string name = std::string(" test2: ")
232 + std::string(type_name<gno_t>::name());
233 if (me == 0) std::cout << "--------\n Starting " << name << std::endl;
234
235 typedef std::array<gno_t, 2> zkey_t;
236 typedef std::vector<zkey_t> keyvec_t;
237 typedef std::vector<gno_t> gidvec_t;
238
239 const size_t nKeys = 6;
240 const size_t nKeysHalf = 3;
241 keyvec_t keys(nKeys);
242 gidvec_t gids(nKeys);
243
244 for (size_t i = 0; i < nKeysHalf; i++) {
245 zkey_t k;
246 k[0] = gno_t(me);
247 k[1] = gno_t(i+1);
248 keys[i] = k;
249 }
250 for (size_t i = 0; i < nKeysHalf; i++) {
251 zkey_t k;
252 k[0] = gno_t((me+i+1)%np);
253 k[1] = gno_t(i+1);
254 keys[i+nKeysHalf] = k;
255 }
256
257 size_t nUniqueGids = findUniqueGids<zkey_t,gno_t>(keys,gids,comm);
258
259 // Test for correctness
260 if (me == 0)
261 std::cout << " " << name << " nUniqueGids " << nUniqueGids << std::endl;
262
263 checkNUnique(name, nUniqueGids, size_t(nKeysHalf*np));
264
265 checkMaxGid(name, gids, gno_t(nKeysHalf*np-1), comm);
266
267 checkMinGid(name, gids, gno_t(0), comm);
268}
269
271template <typename gno_t>
272void test3(Teuchos::RCP<const Teuchos::Comm<int> > &comm)
273{
274 // Test 3:
275 // Key has three entries
276 // Each proc has 2*np keys
277 // np Keys are {x, x, x} for x in {0, 1, ..., np-1}
278 // np Keys are {rank, rank, x} for x in {0, 1, ..., np-1}
279 // Each proc has one locally duplicated key
280 // Each proc contributes np unique keys
281 int me = comm->getRank();
282 int np = comm->getSize();
283
284 std::string name = std::string(" test3: ")
285 + std::string(type_name<gno_t>::name());
286 if (me == 0) std::cout << "--------\n Starting " << name << std::endl;
287
288 typedef std::array<gno_t, 3> zkey_t;
289 typedef std::vector<zkey_t> keyvec_t;
290 typedef std::vector<gno_t> gidvec_t;
291
292 const size_t nKeys = 2*np;
293 const size_t nKeysHalf = np;
294 keyvec_t keys(nKeys);
295 gidvec_t gids(nKeys);
296
297 for (size_t i = 0; i < nKeysHalf; i++) {
298 zkey_t k;
299 k[0] = gno_t(me);
300 k[1] = gno_t(me);
301 k[2] = gno_t(i);
302 keys[i+nKeysHalf] = k;
303 }
304 for (size_t i = 0; i < nKeysHalf; i++) {
305 zkey_t k;
306 k[0] = gno_t(i);
307 k[1] = gno_t(i);
308 k[2] = gno_t(i);
309 keys[i] = k;
310 }
311
312 size_t nUniqueGids = findUniqueGids<zkey_t,gno_t>(keys,gids,comm);
313
314 // for (size_t i = 0; i < nKeys; i++)
315 // std::cout << me << " Key " << i << ": "
316 // << keys[i][0] << " " << keys[i][1] << " " << keys[i][2]
317 // << " GID " << gids[i]
318 // << std::endl;
319
320 // Test for correctness
321 if (me == 0)
322 std::cout << " " << name << " nUniqueGids " << nUniqueGids << std::endl;
323
324 checkNUnique(name, nUniqueGids, size_t(np*np));
325
326 checkMaxGid(name, gids, gno_t(np*np-1), comm);
327
328 checkMinGid(name, gids, gno_t(0), comm);
329
330 checkNLocallyUnique(name, gids, size_t(nKeys-1));
331}
332
334
335template <typename gno_t>
336void test4(Teuchos::RCP<const Teuchos::Comm<int> > &comm)
337{
338 // Test 4:
339 // Key has four entries
340 // Each proc has (rank+1)%2 keys; odd-numbered ranks are empty
341 // Keys are all identical {0, 1, 2, 3}
342 int me = comm->getRank();
343
344 std::string name = std::string(" test4: ")
345 + std::string(type_name<gno_t>::name());
346 if (me == 0) std::cout << "--------\n Starting " << name << std::endl;
347
348 typedef std::array<gno_t, 4> zkey_t;
349 typedef std::vector<zkey_t> keyvec_t;
350 typedef std::vector<gno_t> gidvec_t;
351
352 const size_t nKeys = (me+1)%2;
353 keyvec_t keys(nKeys);
354 gidvec_t gids(nKeys);
355
356 for (size_t i = 0; i < nKeys; i++) {
357 zkey_t k;
358 k[0] = gno_t(0);
359 k[1] = gno_t(1);
360 k[2] = gno_t(2);
361 k[3] = gno_t(3);
362 keys[i] = k;
363 }
364
365 size_t nUniqueGids = findUniqueGids<zkey_t,gno_t>(keys,gids,comm);
366
367 // Test for correctness
368 if (me == 0)
369 std::cout << " " << name << " nUniqueGids " << nUniqueGids << std::endl;
370
371 checkNUnique(name, nUniqueGids, size_t(1));
372
373 checkMaxGid(name, gids, gno_t(0), comm);
374
375 checkMinGid(name, gids, gno_t(0), comm);
376
377 checkNLocallyUnique(name, gids, (nKeys ? size_t(1): size_t(0)));
378}
379
380} // namespace Zoltan2
381
382int main(int argc, char *argv[])
383{
384 Tpetra::ScopeGuard tscope(&argc, &argv);
385 Teuchos::RCP<const Teuchos::Comm<int> > comm =
386 Teuchos::DefaultComm<int>::getComm();
387
388 Zoltan2::test1<int>(comm);
389 Zoltan2::test2<int>(comm);
390 Zoltan2::test3<int>(comm);
391 Zoltan2::test4<int>(comm);
392
393 Zoltan2::test1<long long>(comm);
394 Zoltan2::test2<long long>(comm);
395 Zoltan2::test3<long long>(comm);
396 Zoltan2::test4<long long>(comm);
397
398 return 0;
399}
Gathering definitions used in software development.
int main()
#define DECL_TYPE_NAME(x)
map_t::local_ordinal_type lno_t
map_t::global_ordinal_type gno_t
Created by mbenlioglu on Aug 31, 2020.
void test3(Teuchos::RCP< const Teuchos::Comm< int > > &comm)
void checkNUnique(std::string &name, size_t nUniqueGids, size_t nExpected)
size_t findUniqueGids(Tpetra::MultiVector< gno_t, lno_t, gno_t > &keys, Tpetra::Vector< gno_t, lno_t, gno_t > &gids)
void checkNLocallyUnique(std::string &name, std::vector< gno_t > &gids, size_t nExpected)
static const std::string fail
void test1(Teuchos::RCP< const Teuchos::Comm< int > > &comm)
void test2(Teuchos::RCP< const Teuchos::Comm< int > > &comm)
void checkMaxGid(std::string &name, std::vector< gno_t > &gids, gno_t maxExpected, Teuchos::RCP< const Teuchos::Comm< int > > &comm)
void test4(Teuchos::RCP< const Teuchos::Comm< int > > &comm)
void checkMinGid(std::string &name, std::vector< gno_t > &gids, gno_t minExpected, Teuchos::RCP< const Teuchos::Comm< int > > &comm)
static const std::string pass