Zoltan2
Loading...
Searching...
No Matches
Zoltan2_Directory.hpp
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#ifndef ZOLTAN2_DIRECTORY_H_
11#define ZOLTAN2_DIRECTORY_H_
12
13#include <Teuchos_DefaultComm.hpp> // currently using Teuchos comm throughout
14#include <Teuchos_CommHelpers.hpp>
15
16#ifndef HAVE_MPI
17// support mpi serial - directory currently has a mix of Teuchos mpi commands
18// and original MPI commands so as this gets better organized the serial support
19// can be handled more naturally. Currently the tests call an MPI_Init for serial
20// so this can all work. I've mostly added the serial support just to make
21// debugging easier.
22#include <mpi.h>
23#endif
24
25#include <Kokkos_UnorderedMap.hpp> // unordered map stores the local nodes
26
27namespace Zoltan2 {
28
29// The new Kokkos mode maps over the gid using unordered map
30// Originally was thinking we don't want ptrs here and want the user data
31// to be a natural type so it can cleanly support std::vector. However as this
32// evolved I am not sure this is the best decision and can be more costly for
33// memory. Now that all the unit testing is in place it would be easier to
34// refactor this back to the original packed ptr style if necessary.
35template <typename gid_t, typename lid_t, typename user_t>
37 public:
38 // TODO: This free is an outstanding issue - follows original format and
39 // allows me to search the Kokkos::UnorderedMap by index and distinguish
40 // between empty slots and filled. But I am not quite understanding this
41 // and is there a way to search the filled slots without referring to the
42 // keys.
44 int owner; /* processor hosting global ID object */
45 int partition; /* Optional data */
46 int errcheck; /* Error checking(inconsistent updates) */
47 lid_t lid; /* lid value */
48 user_t userData; /* user data */
49 int free; /* flag whether node is free or used */
50};
51
52// TODO: These message structures should become MPI datatypes(KDD)
53// Currently these are implemented as they were in the original zoltan code.
54template <typename gid_t, typename lid_t>
55class Zoltan2_DD_Update_Msg { /* Only used by Zoltan_DD_Update() */
56 public:
57 char lid_flag; /* indicates if LID data are present */
58 char user_flag; /* indicates if USER data are present */
59 char partition_flag; /* indicates if optional partition data */
60 int owner; /* range [0, nproc-1] or -1 */
62 gid_t adjData[1]; /* TODO: refactor - includes gid & lid & user */
63};
64
65template <typename gid_t, typename lid_t>
66class Zoltan2_DD_Find_Msg { /* Only used by Zoltan_DD_Find() */
67 public:
68 int proc; /* destination or location */
70 int index; /* to put things back in order afterward */
71 gid_t adjData[1]; /* TODO: refactor - includes gid and user */
72};
73
74template <typename gid_t, typename lid_t>
75class Zoltan2_DD_Remove_Msg { /* Only used by Zoltan_DD_Remove() */
76 public:
77 int owner; /* range [0, nproc-1] or -1 */
78 gid_t adjData[1]; /* TODO: refactor - includes gid */
79};
80
87template <typename gid_t, typename lid_t, typename user_t>
89 public:
104
107 Teuchos::RCP<const Teuchos::Comm<int> > comm_,
109 bool use_lid_,
110 int debug_level_)
111 : comm(comm_), use_lid(use_lid_),
112 debug_level(debug_level_)
113 {
114 }
115
118 }
119
121 int update(
122 size_t length, /* number of gids */
123 const gid_t * gid,
124 const lid_t * lid,
125 const user_t * user,
126 const int * partition,
127 Update_Mode update_mode);
130 int find(
131 size_t length, /* number of gids */
132 const gid_t * gid,
133 lid_t * lid,
134 user_t * user,
135 int * partition,
136 int * owner,
137 bool throw_if_missing = true);
142 int remove(
143 size_t length, /* number of gids */
144 const gid_t * gid);
147 int print() const;
148
150 void stats() const;
151
153 bool is_use_lid() const { return use_lid; }
154
155 void get_locally_managed_gids(std::vector<gid_t> & local_gids) const {
156 // resize
157 local_gids.resize(node_map.size());
158
159 // fill
160 size_t cnt = 0;
161 for(size_t n = 0; n < node_map.capacity(); ++n) {
162 if(node_map.value_at(n).free == 0) {
163 local_gids[cnt++] = node_map.key_at(n);
164 }
165 }
166
167 if(cnt != node_map.size()) {
168 throw std::logic_error("Unexpected counts. Internal error with the"
169 " node_map behavior.");
170 }
171 }
172
174 // This process follows the pattern of the original unique ids setup
175 // It assumes we have updated the directory with keys (as the gid_t) and
176 // also created empty user data. Each key is converted to a unique integer
177 // and written into the user data.
178 typedef long long mpi_t;
179 mpi_t nDDEntries = static_cast<mpi_t>(node_map.size());
180 mpi_t firstIdx;
181 Teuchos::scan(*comm, Teuchos::REDUCE_SUM,
182 1, &nDDEntries, &firstIdx);
183 firstIdx -= nDDEntries; // do not include this rank's entries in prefix sum
184 size_t cnt = 0;
185 for(size_t n = 0; n < node_map.capacity(); ++n) {
186 if(node_map.value_at(n).free == 0) {
188 node_map.value_at(n);
189 node.userData = firstIdx + cnt;
190 cnt++;
191 }
192 }
193 }
194
195 size_t node_map_size() const {
196 return node_map.size();
197 }
198
199 protected:
200 // handled updating the local node information when the proc receives
201 // a new gid to store or updated data for a preexisting node
202 int update_local(gid_t* gid, lid_t* lid, user_t *user,
203 int partition, int owner);
204
205 // collect data on the local proc which has been requested by the directory.
206 int find_local(gid_t* gid, lid_t* lid, user_t *user,
207 int *partition, int *owner, bool throw_if_missing = true) const;
208
209 // remove the locally stored node for this gid
210 int remove_local(gid_t* gid);
211
212 size_t find_msg_size; /* Total allocation for Zoltan2_DD_FindMsg */
213 size_t update_msg_size; /* Total allocation for Zoltan2_DD_Update_Msg */
214 size_t remove_msg_size; /* Total allocation for Zoltan2_DD_Remove_Msg */
215
216 // originally the nodes are stored in a hash but in the new Kokkos mode
217 // they are stored using Kokkos::UnorderedMap
218 typedef Kokkos::UnorderedMap<gid_t,
221
222 // this method exists so constructor and copy constructor don't duplicate
223 void allocate();
224
225 // this method exists so operator= and copy constructor don't duplicate
227
228 // TODO: Decide if this stays and how to incorporate with variable length
229 // data. See comments in Zoltan2_Directory_Impl.hpp
230 // size_t align_size_t(size_t a) const;
231
232 // take a gid and hash to proc - determines which proc wil own the gid data
233 unsigned int hash_proc(const gid_t & gid) const;
234
235 // stores the comm provided by the user
236 Teuchos::RCP<const Teuchos::Comm<int> > comm;
237
238 bool use_lid; /* If false not using lid */
239 int debug_level; /* Determines actions to multiple updates */
240
241 size_t max_id_size; /* Stores: max(sizeof(gid_t),sizeof(lid_t)) */
242 Update_Mode mode; /* Last mode sent using update */
243
244 // abstract methods are implemented below by Zoltan2_Directory_Simple
245 // or Zoltan2_Directory_Vector. These methods contain all the places where
246 // the code had to be specialized for normal user type (int, long, etc) or
247 // std::vector user type of variable length. Possibly we could consider
248 // making this all work by templating but exactly how to do that cleanly
249 // I am not sure. The class inheritance approach may be easier to understand
250 // but it does mean the user has to pick the right class to use.
251 virtual bool is_Zoltan2_Directory_Vector() const { return false; };
252 virtual void update_local_user(const user_t * pRaw, user_t & dst) {};
253 virtual void user_to_raw(const user_t & src, user_t * pRaw) const {};
254 virtual void raw_to_user(const user_t * pRaw, user_t & dst) const {};
255 virtual size_t size_of_value_type() const { return 0; };
256 virtual size_t get_update_msg_size(const user_t & data) const { return 0; };
257 virtual size_t get_update_msg_size(const user_t * pRaw) const { return 0; };
258 virtual size_t get_local_find_msg_size(gid_t *gid,
259 bool throw_if_missing = true) const { return 0; };
261 Zoltan2_DD_Find_Msg<gid_t,lid_t>* msg) const { return 0; };
262
263 private:
264 void rehash_node_map(size_t new_hash_size) {
265 node_map.rehash(new_hash_size);
266 }
267};
268
269template <typename gid_t, typename lid_t, typename user_t>
270class Zoltan2_Directory_Simple : public Zoltan2_Directory<gid_t, lid_t, user_t> {
271 public:
273
275 Zoltan2_Directory_Simple(Teuchos::RCP<const Teuchos::Comm<int> > comm_, bool use_lid_,
276 int debug_level_) :
277 Zoltan2_Directory<gid_t, lid_t, user_t>(comm_, use_lid_,
278 debug_level_) {
279 // Note that allocate() must be called in the derived class, not the
280 // base class or inheritance of the methods will break
281 this->allocate();
282 }
283
287 Zoltan2_Directory<gid_t, lid_t, user_t>(src.comm, src.use_lid,
288 src.debug_level) {
289 this->allocate();
290 this->copy(src);
291 }
292
296 this->comm = src.comm;
297 this->use_lid = src.use_lid;
298 this->debug_level = src.debug_level;
299 this->allocate(); // operator= was setup in derived class so this inherits
300 this->copy(src);
301 return *this;
302 }
303
304 protected:
305 // awkward to have this at all - so maybe to refactor out with future progress
306 virtual bool is_Zoltan2_Directory_Vector() const { return false; }
307
308 // given raw data from the MPI stream we update user data based on mode
309 virtual void update_local_user(const user_t * pRaw, user_t & dst) {
310 switch(this->mode) {
312 dst = *pRaw;
313 break;
315 dst += *pRaw;
316 break;
318 throw std::logic_error("Aggregate doesn't mean anything for single "
319 "types. Must use Zoltan2_Directory_Vector class.");
321 throw std::logic_error("AggregateAdd doesn't mean anything for single "
322 "types. Must use Zoltan2_Directory_Vector class.");
323 }
324 }
325
326 // convert user data to raw data - simple conversion for this class
327 virtual void user_to_raw(const user_t & src, user_t * pRaw) const {
328 *pRaw = src;
329 }
330
331 // convert raw data to user data - simple conversion for this class
332 virtual void raw_to_user(const user_t * pRaw, user_t & dst) const {
333 dst = *pRaw;
334 }
335
336 // get size of the user type which is simply sizeof(user_t) for this class
337 virtual size_t size_of_value_type() const { return sizeof(user_t); }
338
339 // for this class, update_msg_size is simple (not variable length)
340 virtual size_t get_update_msg_size(const user_t & data) const {
341 return this->update_msg_size;
342 }
343
344 // for this class, update_msg_size is simple (not variable length)
345 virtual size_t get_update_msg_size(const user_t * pRaw) const {
346 return this->update_msg_size;
347 }
348
349 // for this class, find_msg_size is simple (not variable length)
350 virtual size_t get_local_find_msg_size(gid_t *gid,
351 bool throw_if_missing = true) const {
352 return this->find_msg_size;
353 }
354
355 // for this class, find_msg_size is simple (not variable length)
358 return this->find_msg_size;
359 }
360};
361
362template <typename gid_t, typename lid_t, typename user_t>
363class Zoltan2_Directory_Vector : public Zoltan2_Directory<gid_t, lid_t, user_t> {
364 public:
365 typedef typename user_t::value_type user_val_t;
366
368 Zoltan2_Directory_Vector(Teuchos::RCP<const Teuchos::Comm<int> > comm_, bool use_lid_,
369 int debug_level_) :
370 Zoltan2_Directory<gid_t, lid_t, user_t>(comm_, use_lid_,
371 debug_level_) {
372 // Note that allocate() must be called in the derived class, not the
373 // base class or inheritance of the methods will break
374 this->allocate();
375 }
376
380 Zoltan2_Directory<gid_t, lid_t, user_t>(src.comm, src.use_lid,
381 src.debug_level) {
382 this->allocate(); // operator= was setup in derived class so this inherits
383 this->copy(src);
384 }
385
389 this->comm = src.comm;
390 this->use_lid = src.use_lid;
391 this->debug_level = src.debug_level;
392 this->allocate(); // operator= was setup in derived class so this inherits
393 this->copy(src);
394 return *this;
395 }
396
397 protected:
398 // awkward to have this at all - so maybe to refactor out with future progress
399 virtual bool is_Zoltan2_Directory_Vector() const { return true; }
400
401 // given raw data from the MPI stream we update user data based on mode
402 virtual void update_local_user(const user_t * pRaw, user_t & dst) {
403 // we're reading raw data of form: size_t, val, val, val ...
404 size_t * pLength = (size_t*)(pRaw);
405 size_t read_array_length = *pLength;
406 ++pLength; // move up to first element
407 user_val_t * pRead = (user_val_t*)(pLength);
408 switch(this->mode) {
410 // Note this is the raw_to_user method and we could just call it
411 // but Add and Aggregate don't have the equivalent so I've done it
412 // this way to keep the pattern.
413 dst.resize(read_array_length); // change to new
414 for(size_t i = 0; i < read_array_length; ++i) {
415 dst[i] = *pRead;
416 ++pRead;
417 }
418 }
419 break;
421 // ADD currently requires equal length vectors to add each element
422 if(dst.size() != static_cast<size_t>(read_array_length)) {
423 throw std::logic_error("The data lengths are not the same size");
424 }
425 // loop through and do the addition
426 for(size_t i = 0; i < dst.size(); ++i) {
427 dst[i] += *pRead;
428 ++pRead;
429 }
430 }
431 break;
433 // Add only unique elements
434 // Preserve ordering
435 // First scan the new incoming data
436 //
437 // For example we can have data of:
438 // [1,4,5,7]
439 // Then new incoming data is:
440 // [4,5,6,10]
441 // Then result would be:
442 // [1,4,5,6,7,10]
443 for(size_t i = 0; i < read_array_length; ++i) {
444 // handle the cases of dst no size or adding past last element
445 if(dst.size() == 0 || (*pRead) > dst[dst.size()-1]) {
446 dst.push_back(*pRead); // add first element or at end
447 }
448 else {
449 // otherwise we are going to insert unless it's not unique
450 for(auto itr = dst.begin(); itr != dst.end(); ++itr) {
451 if((*itr) == (*pRead)) { // do they match
454 (*itr) += (*pRead); // do the AggregateAdd action using +=
455 }
456 break; // break because it's already in there - do nothing
457 }
458 else if((*itr) > (*pRead)) { // is scanned element larger?
459 dst.insert(itr, (*pRead)); // preserve ordering
460 break; // break because once we add it we are done
461 }
462 }
463 }
464 ++pRead; // get the next incoming array element (*pRead)
465 }
466 }
467 break;
469 // AggregateAdd is similar to Aggregate except that when two items
470 // match through the operator==, they are combined using operator+=
471 // instead of excluding the duplicate. This reliance on operator==
472 // and operator+= allows the user to define the behavior for the
473 // struct but needs design discussion. This example struct was taken
474 // from Zoltan2_GraphMetricsUtility.hpp which was the origina reason
475 // for adding this mode.
476 /*
477 struct part_info {
478 part_info() : sum_weights(0) {
479 }
480 const part_info & operator+=(const part_info & src) {
481 sum_weights += src.sum_weights;
482 return *this; // return old value
483 }
484 bool operator>(const part_info & src) const {
485 return (target_part > src.target_part);
486 }
487 bool operator==(const part_info & src) const {
488 return (target_part == src.target_part);
489 }
490 part_t target_part; // the part this part_info refers to
491 t_scalar_t sum_weights; // the sum of weights
492 };
493 */
494 // Then if we use AggregateAdd the following example shows how the
495 // struct with part_t 1 will have sum_weights combined:
496 //
497 // Proc 1 Proc 2 Result
498 // part_t 0 1 1 3 0 1 3
499 // sum_weights 1.0 1.0 2.0 2.0 1.0 3.0 2.0
500 //
501 // TODO: We could make this almost identical to above Aggregate and
502 // preserve ordering. Then the only difference is that Aggregate just
503 // does nothing when two elements are the same while AggregateAdd will
504 // combine them with += operator. Did not implement yet since
505 // Zoltan2_GraphMetricsUtility.hpp didn't have parts ordered and I
506 // wasn't sure yet if we'd want to make that a requirement.
507 for(size_t i = 0; i < read_array_length; ++i) {
508 bool bMatch = false;
509 for(auto itr = dst.begin(); itr != dst.end(); ++itr) {
510 if((*itr) == (*pRead)) { // determine if they go together using ==
511 (*itr) += (*pRead); // do the AggregateAdd action using +=
512 bMatch = true;
513 break;
514 }
515 }
516 if(!bMatch) {
517 dst.push_back(*pRead); // add first element or at end
518 }
519 ++pRead; // get the next incoming array element (*pRead)
520 }
521 }
522 break;
523
524 }
525 }
526
527 // write the std::vector as length, x1, x2, x3 ...
528 virtual void user_to_raw(const user_t & src, user_t * pRaw) const {
529 // we're writing raw data of form: size_t, val, val, val ...
530 size_t *pLength = (size_t*)(pRaw);
531 *pLength = src.size(); // first write the length
532 ++pLength; // move up to first element
533 user_val_t *pWrite = (user_val_t*)(pLength);
534 for(size_t n = 0; n < src.size(); ++n) {
535 *pWrite = src[n]; // now write each element
536 ++pWrite;
537 }
538 }
539
540 // raw comes in as length, x1, x2, x3 ...
541 virtual void raw_to_user(const user_t * pRaw, user_t & dst) const {
542 // we're reading raw of form: size_t, val, val, val ...
543 size_t* pLength = (size_t*) pRaw;
544 dst.resize(static_cast<size_t>(*pLength)); // first read the length
545 ++pLength; // move up to first element
546 user_val_t* pRead = (user_val_t*) pLength;
547 for(size_t n = 0; n < dst.size(); ++n) {
548 dst[n] = *pRead; // now read each element
549 ++pRead;
550 }
551 }
552
553 // for the std::vector directory, value type is the size of the std::vector
554 // template parameter, so for std::vector<int> we want sizeof(int)(
555 virtual size_t size_of_value_type() const {
556 return sizeof(typename user_t::value_type);
557 }
558
559 // the update msg is the base size (includes vector length) plus the size
560 // of all the elements.
561 virtual size_t get_update_msg_size(const user_t & data) const {
562 return this->update_msg_size + data.size() * size_of_value_type();
563 }
564
565 // the update msg is the base size (includes vector length) plus the size
566 // of all the elements. This is same idea as above method but here we are
567 // intepreting raw data (which comes in as length, x1, x2, x3...) so we
568 // read the size as the first element. That's all we need to determine the
569 // total update_msg_size.
570 virtual size_t get_update_msg_size(const user_t * pRaw) const {
571 // the first element is size_t (length of the vector)
572 size_t * pLength = (size_t*) (pRaw);
573 return this->update_msg_size +
574 (pRaw ? ((*pLength) * size_of_value_type()) : 0);
575 }
576
577 // to get the local find msg size we need to verify the node exists and then
578 // read the std::vector size (which is added to base length find_msg_size.
579 virtual size_t get_local_find_msg_size(gid_t * gid,
580 bool throw_if_missing = true) const {
581 if(this->node_map.exists(*gid)) {
583 this->node_map.value_at(this->node_map.find(*gid));
584 return this->find_msg_size + node.userData.size() * sizeof(user_val_t);
585 }
586 else if(throw_if_missing) {
587 throw std::logic_error( "Could not find gid in map." );
588 }
589 else {
590 // not clear yet if we ever want to handle this case or always err out
591 // I'm using this right now for the unit testing to validate that the
592 // remove command actually works.
593 return this->find_msg_size; // will not have any data content
594 }
595 }
596
597 // here we have a find msg coming in and we need to extract the vector length
598 // which is always at the same place in the message.
601 if(msg->proc == -1) {
602 // this happens if we called find for an element which was removed
603 // eventually we might just throw on find_local but for the testing,
604 // this is allowed, the data is left untouched, and the test validates
605 // that the results are as expected based on remove events
606 return this->find_msg_size; // no extra data for unfound node
607 }
608 // the first element of the user data is size_t (length of the vector)
609 size_t * pVectorLength =
610 (size_t*)(reinterpret_cast<char*>(msg->adjData) + this->max_id_size);
611 return this->find_msg_size + (*pVectorLength) * sizeof(user_val_t);
612 }
613};
614
615} // end namespace Zoltan2
616
617#endif
Zoltan2::BasicUserTypes< zscalar_t, zlno_t, zgno_t > user_t
Definition Metric.cpp:39
Zoltan2_Directory_Simple(const Zoltan2_Directory_Simple< gid_t, lid_t, user_t > &src)
Copy constructor.
virtual size_t get_update_msg_size(const user_t *pRaw) const
virtual void update_local_user(const user_t *pRaw, user_t &dst)
Zoltan2_Directory_Simple(Teuchos::RCP< const Teuchos::Comm< int > > comm_, bool use_lid_, int debug_level_)
Constructo directory which handles simple user data types.
virtual void raw_to_user(const user_t *pRaw, user_t &dst) const
virtual size_t get_local_find_msg_size(gid_t *gid, bool throw_if_missing=true) const
virtual bool is_Zoltan2_Directory_Vector() const
virtual size_t size_of_value_type() const
virtual size_t get_update_msg_size(const user_t &data) const
virtual void user_to_raw(const user_t &src, user_t *pRaw) const
virtual size_t get_incoming_find_msg_size(Zoltan2_DD_Find_Msg< gid_t, lid_t > *msg) const
Zoltan2_Directory_Vector(const Zoltan2_Directory_Vector< gid_t, lid_t, user_t > &src)
Copy constructor.
virtual void update_local_user(const user_t *pRaw, user_t &dst)
virtual size_t get_incoming_find_msg_size(Zoltan2_DD_Find_Msg< gid_t, lid_t > *msg) const
Zoltan2_Directory_Vector(Teuchos::RCP< const Teuchos::Comm< int > > comm_, bool use_lid_, int debug_level_)
Constructo directory which handles std::vector user data types.
virtual size_t get_update_msg_size(const user_t &data) const
virtual void raw_to_user(const user_t *pRaw, user_t &dst) const
virtual size_t get_local_find_msg_size(gid_t *gid, bool throw_if_missing=true) const
virtual size_t size_of_value_type() const
virtual void user_to_raw(const user_t &src, user_t *pRaw) const
virtual size_t get_update_msg_size(const user_t *pRaw) const
virtual bool is_Zoltan2_Directory_Vector() const
Zoltan2_Directory is an abstract base class.
Update_Mode
Update_Mode determines how update executes.
@ Aggregate
For std::vector user data, aggregates all data so for example [1,2,5] and [3,5] becomes [1,...
@ AggregateAdd
In progress and needs discussion. Currently this mode will use operator== to determine if two items m...
@ Add
All values from different procs are summed.
@ Replace
The new value replaces the original value.
virtual size_t get_local_find_msg_size(gid_t *gid, bool throw_if_missing=true) const
Zoltan2_Directory(Teuchos::RCP< const Teuchos::Comm< int > > comm_, bool use_lid_, int debug_level_)
Construct Zoltan2_Directory (abstract class).
virtual bool is_Zoltan2_Directory_Vector() const
Kokkos::UnorderedMap< gid_t, Zoltan2_Directory_Node< gid_t, lid_t, user_t >, Kokkos::HostSpace > node_map_t
virtual size_t size_of_value_type() const
virtual void update_local_user(const user_t *pRaw, user_t &dst)
virtual size_t get_update_msg_size(const user_t &data) const
virtual void user_to_raw(const user_t &src, user_t *pRaw) const
int update_local(gid_t *gid, lid_t *lid, user_t *user, int partition, int owner)
virtual size_t get_incoming_find_msg_size(Zoltan2_DD_Find_Msg< gid_t, lid_t > *msg) const
Teuchos::RCP< const Teuchos::Comm< int > > comm
virtual ~Zoltan2_Directory()
Destructor currently does nothing.
bool is_use_lid() const
returns true if the directory is handling local ids.
virtual size_t get_update_msg_size(const user_t *pRaw) const
int print() const
gids to remove.
int remove(size_t length, const gid_t *gid)
if true will throw if a gid is not found. This is used by the unit tests to properly assess if remove...
int update(size_t length, const gid_t *gid, const lid_t *lid, const user_t *user, const int *partition, Update_Mode update_mode)
update is called by user to submit new data.
virtual void raw_to_user(const user_t *pRaw, user_t &dst) const
int copy(const Zoltan2_Directory< gid_t, lid_t, user_t > &dd)
int find_local(gid_t *gid, lid_t *lid, user_t *user, int *partition, int *owner, bool throw_if_missing=true) const
void get_locally_managed_gids(std::vector< gid_t > &local_gids) const
void stats() const
stats. New Kokkos mode needs further development.
unsigned int hash_proc(const gid_t &gid) const
int find(size_t length, const gid_t *gid, lid_t *lid, user_t *user, int *partition, int *owner, bool throw_if_missing=true)
Can be Replace, Add, or Aggregate.
Created by mbenlioglu on Aug 31, 2020.