Zoltan2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 
27 namespace 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.
35 template <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.
54 template <typename gid_t, typename lid_t>
55 class 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 */
61  int partition;
62  gid_t adjData[1]; /* TODO: refactor - includes gid & lid & user */
63 };
64 
65 template <typename gid_t, typename lid_t>
66 class Zoltan2_DD_Find_Msg { /* Only used by Zoltan_DD_Find() */
67  public:
68  int proc; /* destination or location */
69  int partition;
70  int index; /* to put things back in order afterward */
71  gid_t adjData[1]; /* TODO: refactor - includes gid and user */
72 };
73 
74 template <typename gid_t, typename lid_t>
75 class 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 
87 template <typename gid_t, typename lid_t, typename user_t>
89  public:
91  enum Update_Mode {
92  Replace = 0,
93  Add,
103  };
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 
117  virtual ~Zoltan2_Directory() {
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 
269 template <typename gid_t, typename lid_t, typename user_t>
270 class 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 
362 template <typename gid_t, typename lid_t, typename user_t>
363 class 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
453  Update_Mode::AggregateAdd) {
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) {
485  return (target_part > src.target_part);
486  }
487  bool operator==(const part_info & src) {
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
virtual size_t get_local_find_msg_size(gid_t *gid, bool throw_if_missing=true) 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.
virtual size_t get_local_find_msg_size(gid_t *gid, bool throw_if_missing=true) const
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 bool is_Zoltan2_Directory_Vector() const
For std::vector user data, aggregates all data so for example [1,2,5] and [3,5] becomes [1...
Zoltan2_Directory(Teuchos::RCP< const Teuchos::Comm< int > > comm_, bool use_lid_, int debug_level_)
Construct Zoltan2_Directory (abstract class).
virtual void update_local_user(const user_t *pRaw, user_t &dst)
All values from different procs are summed.
virtual bool is_Zoltan2_Directory_Vector() const
void stats() const
stats. New Kokkos mode needs further development.
virtual void raw_to_user(const user_t *pRaw, user_t &dst) const
int print() const
gids to remove.
virtual size_t size_of_value_type() const
void get_locally_managed_gids(std::vector< gid_t > &local_gids) const
virtual size_t get_update_msg_size(const user_t *pRaw) const
int copy(const Zoltan2_Directory< gid_t, lid_t, user_t > &dd)
virtual void user_to_raw(const user_t &src, user_t *pRaw) const
virtual size_t size_of_value_type() const
The new value replaces the original value.
int update_local(gid_t *gid, lid_t *lid, user_t *user, int partition, int owner)
Update_Mode
Update_Mode determines how update executes.
virtual size_t get_update_msg_size(const user_t *pRaw) const
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 void update_local_user(const user_t *pRaw, user_t &dst)
virtual size_t get_local_find_msg_size(gid_t *gid, bool throw_if_missing=true) const
virtual ~Zoltan2_Directory()
Destructor currently does nothing.
virtual void raw_to_user(const user_t *pRaw, user_t &dst) const
virtual size_t get_update_msg_size(const user_t &data) const
unsigned int hash_proc(const gid_t &gid) 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 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_update_msg_size(const user_t &data) const
int find_local(gid_t *gid, lid_t *lid, user_t *user, int *partition, int *owner, bool throw_if_missing=true) const
Kokkos::UnorderedMap< gid_t, Zoltan2_Directory_Node< gid_t, lid_t, user_t >, Kokkos::HostSpace > node_map_t
bool is_use_lid() const
returns true if the directory is handling local ids.
virtual bool is_Zoltan2_Directory_Vector() const
virtual size_t get_incoming_find_msg_size(Zoltan2_DD_Find_Msg< gid_t, lid_t > *msg) const
virtual size_t size_of_value_type() const
virtual void update_local_user(const user_t *pRaw, user_t &dst)
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 user_to_raw(const user_t &src, user_t *pRaw) const
Zoltan2_Directory is an abstract base class.
In progress and needs discussion. Currently this mode will use operator== to determine if two items m...
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 void raw_to_user(const user_t *pRaw, user_t &dst) const
Zoltan2_Directory_Simple(Teuchos::RCP< const Teuchos::Comm< int > > comm_, bool use_lid_, int debug_level_)
Constructo directory which handles simple user data types.
Zoltan2::BasicUserTypes< zscalar_t, zlno_t, zgno_t > user_t
Definition: Metric.cpp:39