Zoltan2
Loading...
Searching...
No Matches
directoryTest_findUniqueGids.cpp
Go to the documentation of this file.
1// @HEADER
2//
3// ***********************************************************************
4//
5// Zoltan2: A package of combinatorial algorithms for scientific computing
6// Copyright 2012 Sandia Corporation
7//
8// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9// the U.S. Government retains certain rights in this software.
10//
11// Redistribution and use in source and binary forms, with or without
12// modification, are permitted provided that the following conditions are
13// met:
14//
15// 1. Redistributions of source code must retain the above copyright
16// notice, this list of conditions and the following disclaimer.
17//
18// 2. Redistributions in binary form must reproduce the above copyright
19// notice, this list of conditions and the following disclaimer in the
20// documentation and/or other materials provided with the distribution.
21//
22// 3. Neither the name of the Corporation nor the names of the
23// contributors may be used to endorse or promote products derived from
24// this software without specific prior written permission.
25//
26// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37//
38// Questions? Contact Karen Devine (kddevin@sandia.gov)
39// Erik Boman (egboman@sandia.gov)
40// Siva Rajamanickam (srajama@sandia.gov)
41//
42// ***********************************************************************
43//
44// @HEADER
45
46// Program to testing Zoltan2::findUniqueGids capability
47// Input: Vector of keys: each key is an array with N entries
48// Result vector to be filled by findUniqueGids
49// Output: Filled result vector
50
51
52#include <iostream>
53#include <vector>
54#include <array>
55#include <unordered_set>
56#include <string>
57#include <typeinfo>
58
59#include <Zoltan2_Standards.hpp>
61
62namespace Zoltan2
63{
64
65template <typename key_t, typename gno_t>
67 const std::vector<key_t> &keys,
68 std::vector<gno_t> &gids,
69 Teuchos::RCP<const Teuchos::Comm<int> > &comm
70)
71{
72 // Compute the new GIDs
73 const bool bUseLocalIDs = false; // Local IDs not needed
74 int debug_level = 0;
75
76 typedef int lno_t; // unused
77
79
80 directory_t directory(comm, bUseLocalIDs, debug_level);
81
82 directory.update(keys.size(), &keys[0], NULL, &gids[0], NULL,
83 directory_t::Update_Mode::Replace);
84
85 directory.remap_user_data_as_unique_gids();
86
87 // Retrieve the global numbers and put in the result gids vector
88 directory.find(keys.size(), &keys[0], NULL, &gids[0], NULL, NULL, false);
89
90 // using ssize_t can be long* on clang and I get warnings here or in the original
91 // findUniqueGids - using long long specifically is ok. Can we do an MPI type
92 // as size_t safely or is a conversion necessary? TODO but this gives a clean
93 // build result.
94 typedef long long mpi_t;
95 mpi_t nDDEntries = static_cast<mpi_t>(directory.node_map_size());
96 mpi_t nUnique = 0;
97
98 // TODO use Teuchos
99#ifdef HAVE_MPI
100 MPI_Allreduce(&nDDEntries, &nUnique, 1, MPI_LONG_LONG, MPI_SUM,
101 Teuchos::getRawMpiComm(*comm));
102#else
103 MPI_Allreduce(&nDDEntries, &nUnique, 1, MPI_LONG_LONG, MPI_SUM, MPI_COMM_WORLD);
104#endif
105
106 return size_t(nUnique);
107}
108
109template<typename T>
111{
112 static const char* name() {
113 std::cout << "You are missing a DECL_TYPE_NAME" << std::endl;
114 return(NULL);
115 }
116};
117
118#define DECL_TYPE_NAME(x) \
119 template<> struct type_name<x> { static const char* name() {return #x;} }
120
122DECL_TYPE_NAME(long long);
123
125// Tests for correctness
126static const std::string fail = "FAIL ";
127static const std::string pass = " ";
128
129// Test for correct number of unique Gids
130void checkNUnique(std::string &name, size_t nUniqueGids, size_t nExpected)
131{
132 if (nUniqueGids != nExpected)
133 std::cout << fail << name
134 << "nUniqueGids " << nUniqueGids << " != " << nExpected
135 << std::endl;
136}
137
138// Test for correct maximum Gid
139template <typename gno_t>
141 std::string &name,
142 std::vector<gno_t> &gids,
143 gno_t maxExpected,
144 Teuchos::RCP<const Teuchos::Comm<int> > &comm
145)
146{
147 gno_t maxGid = 0, gmaxGid = 0;
148 size_t len = gids.size();
149 for (size_t i = 0; i < len; i++)
150 if (gids[i] > maxGid) maxGid = gids[i];
151
152 Teuchos::reduceAll<int, gno_t>(*comm, Teuchos::REDUCE_MAX, 1,
153 &maxGid, &gmaxGid);
154 if (gmaxGid != maxExpected)
155 std::cout << fail << name
156 << "max Gid " << gmaxGid << " != " << maxExpected
157 << std::endl;
158}
159
160// Test for correct minimum Gid
161template <typename gno_t>
163 std::string &name,
164 std::vector<gno_t> &gids,
165 gno_t minExpected,
166 Teuchos::RCP<const Teuchos::Comm<int> > &comm
167)
168{
169 gno_t minGid = std::numeric_limits<gno_t>::max(), gminGid;
170 size_t len = gids.size();
171 for (size_t i = 0; i < len; i++)
172 if (gids[i] < minGid) minGid = gids[i];
173
174 Teuchos::reduceAll<int, gno_t>(*comm, Teuchos::REDUCE_MIN, 1,
175 &minGid, &gminGid);
176 if (gminGid != minExpected)
177 std::cout << fail << name
178 << "min Gid " << gminGid << " != " << minExpected
179 << std::endl;
180}
181
182// Test for number of locally unique Gids
183template <typename gno_t>
185 std::string &name,
186 std::vector<gno_t> &gids,
187 size_t nExpected)
188{
189 size_t gidsLen = gids.size();
190 std::unordered_set<gno_t> gidsSet(gidsLen);
191
192 size_t nDups = 0;
193 for (size_t i = 0; i < gidsLen; i++) {
194 if (gidsSet.find(gids[i]) != gidsSet.end()) {
195 // Gid is already found locally
196 nDups++;
197 }
198 else
199 gidsSet.insert(gids[i]);
200 }
201 size_t nUnique = gidsLen - nDups;
202 if (nUnique != nExpected)
203 std::cout << fail << name
204 << "num locally unique Gids " << nUnique << " != " << nExpected
205 << std::endl;
206}
207
209
210template <typename gno_t>
211void test1(Teuchos::RCP<const Teuchos::Comm<int> > &comm)
212{
213 // Test 1:
214 // Key has only one entry
215 // Each proc has me+1 keys
216 // Keys are in range [1,np]
217 int me = comm->getRank();
218 int np = comm->getSize();
219
220 std::string name = std::string(" test1: ")
221 + std::string(type_name<gno_t>::name());
222 if (me == 0) std::cout << "--------\n Starting " << name << std::endl;
223
224 typedef std::array<gno_t, 1> zkey_t;
225 typedef std::vector<zkey_t> keyvec_t;
226 typedef std::vector<gno_t> gidvec_t;
227
228 const size_t nKeys = me+1;
229 keyvec_t keys(nKeys);
230 gidvec_t gids(nKeys);
231
232 for (size_t i = 0; i < nKeys; i++) {
233 zkey_t k;
234 k[0] = i+1;
235 keys[i] = k;
236 }
237
238 size_t nUniqueGids = findUniqueGids<zkey_t, gno_t>(keys,gids,comm);
239
240 // Test for correctness
241 if (me == 0)
242 std::cout << " " << name << " nUniqueGids " << nUniqueGids << std::endl;
243
244 checkNUnique(name, nUniqueGids, size_t(np));
245
246 checkMaxGid(name, gids, gno_t(np-1), comm);
247
248 checkMinGid(name, gids, gno_t(0), comm);
249
250 checkNLocallyUnique(name, gids, nKeys);
251}
252
254
255template <typename gno_t>
256void test2(Teuchos::RCP<const Teuchos::Comm<int> > &comm)
257{
258 // Test 2:
259 // Key has two entries
260 // Each proc has six keys
261 // Three Keys are {rank, x} for x in {1, 2, 3}
262 // Three Keys are {(rank+x)%np, x} for x in {1, 2, 3}
263 // Each rank has three unique and three non-unique keys
264 int me = comm->getRank();
265 int np = comm->getSize();
266
267 std::string name = std::string(" test2: ")
268 + std::string(type_name<gno_t>::name());
269 if (me == 0) std::cout << "--------\n Starting " << name << std::endl;
270
271 typedef std::array<gno_t, 2> zkey_t;
272 typedef std::vector<zkey_t> keyvec_t;
273 typedef std::vector<gno_t> gidvec_t;
274
275 const size_t nKeys = 6;
276 const size_t nKeysHalf = 3;
277 keyvec_t keys(nKeys);
278 gidvec_t gids(nKeys);
279
280 for (size_t i = 0; i < nKeysHalf; i++) {
281 zkey_t k;
282 k[0] = gno_t(me);
283 k[1] = gno_t(i+1);
284 keys[i] = k;
285 }
286 for (size_t i = 0; i < nKeysHalf; i++) {
287 zkey_t k;
288 k[0] = gno_t((me+i+1)%np);
289 k[1] = gno_t(i+1);
290 keys[i+nKeysHalf] = k;
291 }
292
293 size_t nUniqueGids = findUniqueGids<zkey_t,gno_t>(keys,gids,comm);
294
295 // Test for correctness
296 if (me == 0)
297 std::cout << " " << name << " nUniqueGids " << nUniqueGids << std::endl;
298
299 checkNUnique(name, nUniqueGids, size_t(nKeysHalf*np));
300
301 checkMaxGid(name, gids, gno_t(nKeysHalf*np-1), comm);
302
303 checkMinGid(name, gids, gno_t(0), comm);
304}
305
307template <typename gno_t>
308void test3(Teuchos::RCP<const Teuchos::Comm<int> > &comm)
309{
310 // Test 3:
311 // Key has three entries
312 // Each proc has 2*np keys
313 // np Keys are {x, x, x} for x in {0, 1, ..., np-1}
314 // np Keys are {rank, rank, x} for x in {0, 1, ..., np-1}
315 // Each proc has one locally duplicated key
316 // Each proc contributes np unique keys
317 int me = comm->getRank();
318 int np = comm->getSize();
319
320 std::string name = std::string(" test3: ")
321 + std::string(type_name<gno_t>::name());
322 if (me == 0) std::cout << "--------\n Starting " << name << std::endl;
323
324 typedef std::array<gno_t, 3> zkey_t;
325 typedef std::vector<zkey_t> keyvec_t;
326 typedef std::vector<gno_t> gidvec_t;
327
328 const size_t nKeys = 2*np;
329 const size_t nKeysHalf = np;
330 keyvec_t keys(nKeys);
331 gidvec_t gids(nKeys);
332
333 for (size_t i = 0; i < nKeysHalf; i++) {
334 zkey_t k;
335 k[0] = gno_t(me);
336 k[1] = gno_t(me);
337 k[2] = gno_t(i);
338 keys[i+nKeysHalf] = k;
339 }
340 for (size_t i = 0; i < nKeysHalf; i++) {
341 zkey_t k;
342 k[0] = gno_t(i);
343 k[1] = gno_t(i);
344 k[2] = gno_t(i);
345 keys[i] = k;
346 }
347
348 size_t nUniqueGids = findUniqueGids<zkey_t,gno_t>(keys,gids,comm);
349
350 // for (size_t i = 0; i < nKeys; i++)
351 // std::cout << me << " Key " << i << ": "
352 // << keys[i][0] << " " << keys[i][1] << " " << keys[i][2]
353 // << " GID " << gids[i]
354 // << std::endl;
355
356 // Test for correctness
357 if (me == 0)
358 std::cout << " " << name << " nUniqueGids " << nUniqueGids << std::endl;
359
360 checkNUnique(name, nUniqueGids, size_t(np*np));
361
362 checkMaxGid(name, gids, gno_t(np*np-1), comm);
363
364 checkMinGid(name, gids, gno_t(0), comm);
365
366 checkNLocallyUnique(name, gids, size_t(nKeys-1));
367}
368
370
371template <typename gno_t>
372void test4(Teuchos::RCP<const Teuchos::Comm<int> > &comm)
373{
374 // Test 4:
375 // Key has four entries
376 // Each proc has (rank+1)%2 keys; odd-numbered ranks are empty
377 // Keys are all identical {0, 1, 2, 3}
378 int me = comm->getRank();
379
380 std::string name = std::string(" test4: ")
381 + std::string(type_name<gno_t>::name());
382 if (me == 0) std::cout << "--------\n Starting " << name << std::endl;
383
384 typedef std::array<gno_t, 4> zkey_t;
385 typedef std::vector<zkey_t> keyvec_t;
386 typedef std::vector<gno_t> gidvec_t;
387
388 const size_t nKeys = (me+1)%2;
389 keyvec_t keys(nKeys);
390 gidvec_t gids(nKeys);
391
392 for (size_t i = 0; i < nKeys; i++) {
393 zkey_t k;
394 k[0] = gno_t(0);
395 k[1] = gno_t(1);
396 k[2] = gno_t(2);
397 k[3] = gno_t(3);
398 keys[i] = k;
399 }
400
401 size_t nUniqueGids = findUniqueGids<zkey_t,gno_t>(keys,gids,comm);
402
403 // Test for correctness
404 if (me == 0)
405 std::cout << " " << name << " nUniqueGids " << nUniqueGids << std::endl;
406
407 checkNUnique(name, nUniqueGids, size_t(1));
408
409 checkMaxGid(name, gids, gno_t(0), comm);
410
411 checkMinGid(name, gids, gno_t(0), comm);
412
413 checkNLocallyUnique(name, gids, (nKeys ? size_t(1): size_t(0)));
414}
415
416} // namespace Zoltan2
417
418int main(int argc, char *argv[])
419{
420 Tpetra::ScopeGuard tscope(&argc, &argv);
421 Teuchos::RCP<const Teuchos::Comm<int> > comm =
422 Teuchos::DefaultComm<int>::getComm();
423
424 Zoltan2::test1<int>(comm);
425 Zoltan2::test2<int>(comm);
426 Zoltan2::test3<int>(comm);
427 Zoltan2::test4<int>(comm);
428
429 Zoltan2::test1<long long>(comm);
430 Zoltan2::test2<long long>(comm);
431 Zoltan2::test3<long long>(comm);
432 Zoltan2::test4<long long>(comm);
433
434 return 0;
435}
Gathering definitions used in software development.
int main()
#define DECL_TYPE_NAME(x)
map_t::local_ordinal_type lno_t
Definition: mapRemotes.cpp:17
map_t::global_ordinal_type gno_t
Definition: mapRemotes.cpp:18
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