Interface Documentation
Version: invalid
interface.hh
Go to the documentation of this file.
1 /*
2  @@@@@@@@ @@ @@@@@@ @@@@@@@@ @@
3  /@@///// /@@ @@////@@ @@////// /@@
4  /@@ /@@ @@@@@ @@ // /@@ /@@
5  /@@@@@@@ /@@ @@///@@/@@ /@@@@@@@@@/@@
6  /@@//// /@@/@@@@@@@/@@ ////////@@/@@
7  /@@ /@@/@@//// //@@ @@ /@@/@@
8  /@@ @@@//@@@@@@ //@@@@@@ @@@@@@@@ /@@
9  // /// ////// ////// //////// //
10 
11  Copyright (c) 2016, Triad National Security, LLC
12  All rights reserved.
13  */
14 #pragma once
15 
18 #if !defined(__FLECSI_PRIVATE__)
19 #error Do not include this file directly!
20 #endif
21 //#include "flecsi/run/backend.hh"
22 #include "flecsi/topo/core.hh" // base
23 //#include "flecsi/topo/unstructured/partition.hh"
26 //#include "flecsi/util/common.hh"
27 //#include "flecsi/util/set_intersection.hh"
28 //#include "flecsi/util/static_verify.hh"
29 
30 //#include <algorithm>
31 //#include <array>
32 //#include <cstddef>
33 //#include <cstring>
34 //#include <functional>
35 //#include <iostream>
36 //#include <map>
37 //#include <memory>
38 //#include <type_traits>
39 //#include <unordered_map>
40 //#include <vector>
41 
42 // static verification for required mesh type members such as entity types
43 // tuple, connectivities, bindings, etc.
44 
45 namespace flecsi {
46 namespace topo {
47 namespace verify_mesh {
48 
49 FLECSI_MEMBER_CHECKER(num_dimensions);
50 FLECSI_MEMBER_CHECKER(num_domains);
51 FLECSI_MEMBER_CHECKER(entity_types);
52 FLECSI_MEMBER_CHECKER(connectivities);
53 FLECSI_MEMBER_CHECKER(bindings);
54 FLECSI_MEMBER_CHECKER(create_entity);
55 
56 } // namespace verify_mesh
57 
58 //----------------------------------------------------------------------------//
59 // Mesh topology.
60 //----------------------------------------------------------------------------//
61 
111 template<typename POLICY_TYPE>
113 
114  //--------------------------------------------------------------------------//
115  // static verification of mesh policy
116  //--------------------------------------------------------------------------//
117 
118  static_assert(verify_mesh::has_member_num_dimensions<POLICY_TYPE>::value,
119  "mesh policy missing num_dimensions size_t");
120 
121  static_assert(
122  std::is_convertible<decltype(POLICY_TYPE::num_dimensions), size_t>::value,
123  "mesh policy num_dimensions must be size_t");
124 
125  static_assert(verify_mesh::has_member_num_domains<POLICY_TYPE>::value,
126  "mesh policy missing num_domains size_t");
127 
128  static_assert(
129  std::is_convertible<decltype(POLICY_TYPE::num_domains), size_t>::value,
130  "mesh policy num_domains must be size_t");
131 
132  static_assert(verify_mesh::has_member_entity_types<POLICY_TYPE>::value,
133  "mesh policy missing entity_types tuple");
134 
136  "mesh policy entity_types is not a tuple");
137 
138  static_assert(verify_mesh::has_member_connectivities<POLICY_TYPE>::value,
139  "mesh policy missing connectivities tuple");
140 
142  "mesh policy connectivities is not a tuple");
143 
144  static_assert(verify_mesh::has_member_bindings<POLICY_TYPE>::value,
145  "mesh policy missing bindings tuple");
146 
148  "mesh policy bindings is not a tuple");
149 
150  static_assert(verify_mesh::has_member_create_entity<POLICY_TYPE>::value,
151  "mesh policy missing create_entity()");
152 
153  template<std::size_t>
154  struct access;
155 
156  unstructured(const coloring &);
157 
158 #if 0
159  std::vector<base_data_t> entities;
160  std::vector<base_data_t> adjacencies;
161  std::vector<data::partition> exclusive;
162  std::vector<data::partition> shared;
163  std::vector<data::partition> ghost;
164  std::vector<data::partition> ghost_owners;
165 #endif
166 };
167 
168 template<class POLICY_TYPE>
169 template<std::size_t Priv>
170 struct unstructured<POLICY_TYPE>::access {
171 private:
172  mesh_storage<POLICY_TYPE::num_dimensions,
173  POLICY_TYPE::num_domains,
175  ms_;
176 };
177 
178 template<>
180  using type = unstructured_base;
181 };
182 
183 #if 0
184 template<class POLICY_TYPE>
185 class unstructured
186  : mesh_base<mesh_storage<POLICY_TYPE::num_dimensions,
187  POLICY_TYPE::num_domains,
188  num_index_subspaces<POLICY_TYPE>::value>>
189 {
190 public:
191  // mesh storage type definition
192  using storage_t = mesh_storage<POLICY_TYPE::num_dimensions,
193  POLICY_TYPE::num_domains,
195 
196  // mesh topology base definition
197  using base_t = mesh_base<storage_t>;
198 
199  // entity ID type
200  using id_t = util::id_t;
201 
202  // offset type use by connectivities to give offsets and counts
203  using offset_t = util::offset_t;
204 
205  // used to find the entity type of topological dimension DIM and domain DOM
206  template<size_t DIM, size_t DOM = 0>
207  using entity_type = typename find_entity_<POLICY_TYPE, DIM, DOM>::type;
208 
209  // Don't allow the mesh to be copied or copy constructed
210 
211  // don't allow mesh to be assigned unstructured & operator=(
212  const unstructured &) = delete;
213 
214  Allow move operations unstructured(
215  unstructured && o) = default;
216 
217  override default move assignement unstructured & operator=(
218  unstructured && o) = default;
219 
220  Constructor, takes as input a mesh storage or
221  storage can later be set unstructured(
222  storage_t * ms = nullptr)
223  : base_t(ms) {
224  if(ms != nullptr) {
225  initialize_storage();
226  } // if
227  } // unstructured()
228 
229  Copy constructor : alias another mesh unstructured(
230  const unstructured & m)
231  : base_t(m.ms_) {}
232 
233  // The mesh retains ownership of the entities and deletes them
234  // upon mesh destruction
235  virtual ~unstructured() {}
236 
242  void initialize_storage() {
243 
244  for(size_t from_domain = 0; from_domain < POLICY_TYPE::num_domains;
245  ++from_domain) {
246  for(size_t to_domain = 0; to_domain < POLICY_TYPE::num_domains;
247  ++to_domain) {
248  base_t::ms_->topology[from_domain][to_domain].init_(
249  from_domain, to_domain);
250  } // for
251  } // for
252 
253  for(size_t to_domain = 0; to_domain < POLICY_TYPE::num_domains; ++to_domain) {
254  for(size_t to_dim = 0; to_dim <= POLICY_TYPE::num_dimensions; ++to_dim) {
255  auto & master = base_t::ms_->index_spaces[to_domain][to_dim];
256 
257  for(size_t from_domain = 0; from_domain < POLICY_TYPE::num_domains;
258  ++from_domain) {
259  for(size_t from_dim = 0; from_dim <= POLICY_TYPE::num_dimensions;
260  ++from_dim) {
261  get_connectivity_(from_domain, to_domain, from_dim, to_dim)
262  .get_index_space()
263  .set_master(master);
264  } // for
265  } // for
266  } // for
267  } // for
268  } // intialize_storage
269 
279  template<size_t DOM, class CELL_TYPE, typename VERT_TYPE>
280  void init_cell(CELL_TYPE * cell, VERT_TYPE && verts) {
281  init_cell_<DOM>(cell, std::forward<VERT_TYPE>(verts));
282  } // init_cell
283 
293  template<size_t DOM, class CELL_TYPE, typename VERT_TYPE>
294  void init_cell(CELL_TYPE * cell, std::initializer_list<VERT_TYPE *> verts) {
295  init_cell_<DOM>(cell, verts);
296  } // init_cell
297 
311  template<size_t DOM,
312  size_t FROM_DIM,
313  size_t TO_DIM,
314  class ENT_TYPE1,
315  class ENT_TYPE2>
316  void init_entity(ENT_TYPE1 * super, ENT_TYPE2 && subs) {
317  init_entity_<DOM, FROM_DIM, TO_DIM>(super, std::forward<ENT_TYPE2>(subs));
318  } // init_entity
319 
333  template<size_t DOM,
334  size_t FROM_DIM,
335  size_t TO_DIM,
336  class ENT_TYPE1,
337  class ENT_TYPE2>
338  void init_entity(ENT_TYPE1 * super, std::initializer_list<ENT_TYPE2 *> subs) {
339  init_entity_<DOM, FROM_DIM, TO_DIM>(super, subs);
340  } // init_entity
341 
350  size_t num_entities(size_t dim, size_t domain = 0) const override {
351  return num_entities_(dim, domain);
352  } // num_entities
353 
361  template<size_t DOM = 0>
362  void init() {
363  // Compute mesh connectivity
364  using TP = typename POLICY_TYPE::connectivities;
366 
367  using BT = typename POLICY_TYPE::bindings;
369  } // init
370 
379  template<size_t DOM = 0>
380  void init_bindings() {
381  using BT = typename POLICY_TYPE::bindings;
383  } // init
384 
393  template<size_t DIM, size_t DOM = 0>
394  decltype(auto) num_entities() const {
395  return base_t::ms_->index_spaces[DOM][DIM].size();
396  } // num_entities
397 
408  template<size_t DIM, size_t DOM = 0>
409  decltype(auto) num_entities(partition_t partition) const {
410  return base_t::ms_->partition_index_spaces[partition][DOM][DIM].size();
411  } // num_entities
412 
418  const connectivity_t & get_connectivity(size_t from_domain,
419  size_t to_domain,
420  size_t from_dim,
421  size_t to_dim) const override {
422  return get_connectivity_(from_domain, to_domain, from_dim, to_dim);
423  } // get_connectivity
424 
430  connectivity_t & get_connectivity(size_t from_domain,
431  size_t to_domain,
432  size_t from_dim,
433  size_t to_dim) override {
434  return get_connectivity_(from_domain, to_domain, from_dim, to_dim);
435  } // get_connectivity
436 
442  const connectivity_t & get_connectivity(size_t domain,
443  size_t from_dim,
444  size_t to_dim) const override {
445  return get_connectivity_(domain, domain, from_dim, to_dim);
446  } // get_connectivity
447 
454  get_connectivity(size_t domain, size_t from_dim, size_t to_dim) override {
455  return get_connectivity_(domain, domain, from_dim, to_dim);
456  } // get_connectivity
457 
462  size_t topological_dimension() const override {
463  return POLICY_TYPE::num_dimensions;
464  }
465 
474  template<size_t DOM = 0>
475  const auto & get_index_space_(size_t dim) const {
476  return base_t::ms_->index_spaces[DOM][dim];
477  } // get_entities_
478 
487  template<size_t DOM = 0>
488  auto & get_index_space_(size_t dim) {
489  return base_t::ms_->index_spaces[DOM][dim];
490  } // get_entities_
491 
503  template<size_t DOM = 0>
504  const auto & get_index_space_(size_t dim, partition_t partition) const {
505  return base_t::ms_->partition_index_spaces[partition][DOM][dim];
506  } // get_entities_
507 
519  template<size_t DOM = 0>
520  auto & get_index_space_(size_t dim, partition_t partition) {
521  return base_t::ms_->partition_index_spaces[partition][DOM][dim];
522  } // get_entities_
523 
532  template<size_t DIM, size_t DOM = 0>
533  auto get_entity(id_t global_id) const {
534  using etype = entity_type<DIM, DOM>;
535  return static_cast<etype *>(
536  base_t::ms_->index_spaces[DOM][DIM][global_id.entity()]);
537  } // get_entity
538 
551  template<size_t DOM = 0>
552  auto get_entity(size_t dim, id_t global_id) {
553  return base_t::ms_->index_spaces[DOM][dim][global_id.entity()];
554  } // get_entity
555 
569  template<size_t DIM, size_t DOM = 0>
570  auto get_entity(id_t global_id, partition_t partition) const {
571  using etype = entity_type<DIM, DOM>;
572  return static_cast<etype *>(
573  base_t::ms_
574  ->partition_index_spaces[partition][DOM][DIM][global_id.entity()]);
575  } // get_entity
576 
589  template<size_t DOM = 0>
590  auto get_entity(size_t dim, id_t global_id, partition_t partition) {
591  return base_t::ms_
592  ->partition_index_spaces[partition][DOM][dim][global_id.entity()];
593  } // get_entity
594 
607  template<size_t DIM,
608  size_t FROM_DOM,
609  size_t TO_DOM = FROM_DOM,
610  class ENT_TYPE>
611  const auto entities(const ENT_TYPE * e) const {
612 
613  const connectivity_t & c =
614  get_connectivity(FROM_DOM, TO_DOM, ENT_TYPE::dimension, DIM);
615  flog_assert(!c.empty(), "empty connectivity");
616 
617  using etype = entity_type<DIM, TO_DOM>;
618  using dtype = domain_entity<TO_DOM, etype>;
619 
620  return c.get_index_space().slice<dtype>(
621  c.range(e->template id<FROM_DOM>()));
622  } // entities
623 
636  template<size_t DIM,
637  size_t FROM_DOM,
638  size_t TO_DOM = FROM_DOM,
639  class ENT_TYPE>
640  auto entities(ENT_TYPE * e) {
641  connectivity_t & c =
642  get_connectivity(FROM_DOM, TO_DOM, ENT_TYPE::dimension, DIM);
643  flog_assert(!c.empty(), "empty connectivity");
644 
645  using etype = entity_type<DIM, TO_DOM>;
646  using dtype = domain_entity<TO_DOM, etype>;
647 
648  return c.get_index_space().slice<dtype>(
649  c.range(e->template id<FROM_DOM>()));
650  } // entities
651 
664  template<size_t DIM,
665  size_t FROM_DOM = 0,
666  size_t TO_DOM = FROM_DOM,
667  class ENT_TYPE>
668  decltype(auto) entities(domain_entity<FROM_DOM, ENT_TYPE> & e) const {
669  return entities<DIM, FROM_DOM, TO_DOM>(e.entity());
670  } // entities
671 
684  template<size_t DIM,
685  size_t FROM_DOM = 0,
686  size_t TO_DOM = FROM_DOM,
687  class ENT_TYPE>
688  decltype(auto) entities(domain_entity<FROM_DOM, ENT_TYPE> & e) {
689  return entities<DIM, FROM_DOM, TO_DOM>(e.entity());
690  } // entities
691 
700  template<size_t DIM, size_t DOM = 0>
701  auto entities() const {
702  using etype = entity_type<DIM, DOM>;
703  using dtype = domain_entity<DOM, etype>;
704  return base_t::ms_->index_spaces[DOM][DIM].template slice<dtype>();
705  } // entities
706 
718  template<size_t DIM, size_t DOM = 0>
719  auto entities(partition_t partition) const {
720  using etype = entity_type<DIM, DOM>;
721  using dtype = domain_entity<DOM, etype>;
722  return base_t::ms_->partition_index_spaces[partition][DOM][DIM]
723  .template slice<dtype>();
724  } // entities
725 
734  template<size_t DIM, size_t DOM = 0>
735  auto entity_ids() const {
736  return base_t::ms_->index_spaces[DOM][DIM].ids();
737  } // entity_ids
738 
749  template<size_t DIM, size_t DOM = 0>
750  auto entity_ids(partition_t partition) const {
751  return base_t::ms_->partition_index_spaces[partition][DOM][DIM].ids();
752  } // entity_ids
753 
767  template<size_t DIM,
768  size_t FROM_DOM = 0,
769  size_t TO_DOM = FROM_DOM,
770  class ENT_TYPE>
771  decltype(auto) entity_ids(domain_entity<FROM_DOM, ENT_TYPE> & e) {
772  return entity_ids<DIM, FROM_DOM, TO_DOM>(e.entity());
773  } // entities
774 
788  template<size_t DIM,
789  size_t FROM_DOM = 0,
790  size_t TO_DOM = FROM_DOM,
791  class ENT_TYPE>
792  auto entity_ids(const ENT_TYPE * e) const {
793  const connectivity_t & c =
794  get_connectivity(FROM_DOM, TO_DOM, ENT_TYPE::dimension, DIM);
795  flog_assert(!c.empty(), "empty connectivity");
796  return c.get_index_space().ids(c.range(e->template id<FROM_DOM>()));
797  } // entities
798 
811  template<size_t DIM,
812  size_t FROM_DOM,
813  size_t TO_DOM = FROM_DOM,
814  class ENT_TYPE>
815  void reverse_entities(ENT_TYPE * e) {
816  auto & c = get_connectivity(FROM_DOM, TO_DOM, ENT_TYPE::dimension, DIM);
817  flog_assert(!c.empty(), "empty connectivity");
818  c.reverse_entities(e->template id<FROM_DOM>());
819  } // entities
820 
833  template<size_t DIM,
834  size_t FROM_DOM = 0,
835  size_t TO_DOM = FROM_DOM,
836  class ENT_TYPE>
837  void reverse_entities(domain_entity<FROM_DOM, ENT_TYPE> & e) {
838  return reverse_entities<DIM, FROM_DOM, TO_DOM>(e.entity());
839  } // entities
840 
854  template<size_t DIM,
855  size_t FROM_DOM,
856  size_t TO_DOM = FROM_DOM,
857  class ENT_TYPE,
858  class U>
859  void reorder_entities(ENT_TYPE * e, U && order) {
860  auto & c = get_connectivity(FROM_DOM, TO_DOM, ENT_TYPE::dimension, DIM);
861  flog_assert(!c.empty(), "empty connectivity");
862  c.reorder_entities(e->template id<FROM_DOM>(), std::forward<U>(order));
863  } // entities
864 
878  template<size_t DIM,
879  size_t FROM_DOM = 0,
880  size_t TO_DOM = FROM_DOM,
881  class ENT_TYPE,
882  class U>
883  void reverse_entities(domain_entity<FROM_DOM, ENT_TYPE> & e, U && order) {
884  return reorder_entities<DIM, FROM_DOM, TO_DOM>(
885  e.entity(), std::forward<U>(order));
886  } // entities
887 
894  template<size_t INDEX_SUBSPACE>
895  auto & subentities() {
896  return get_index_subspace<INDEX_SUBSPACE>();
897  }
898 
905  template<size_t INDEX_SUBSPACE>
906  const auto & subentities() const {
907  return get_index_subspace<INDEX_SUBSPACE>();
908  }
909 
916  template<size_t INDEX_SUBSPACE>
917  auto num_subentities() const {
918  return base_t::ms_->index_subspaces[INDEX_SUBSPACE].size();
919  }
920 
928  std::ostream & dump(std::ostream & stream) {
929  for(size_t from_domain = 0; from_domain < POLICY_TYPE::num_domains;
930  ++from_domain) {
931  stream << "=================== from domain: " << from_domain << std::endl;
932  for(size_t to_domain = 0; to_domain < POLICY_TYPE::num_domains;
933  ++to_domain) {
934  stream << "========== to domain: " << to_domain << std::endl;
935  base_t::ms_->topology[from_domain][to_domain].dump(stream);
936  }
937  }
938  return stream;
939  } // dump
940 
946  void dump() {
947  dump(std::cout);
948  } // dump
949 
954  template<typename A>
955  void save(A & archive) const {
956  size_t size;
957  char * data = serialize_(size);
958  archive.saveBinary(&size, sizeof(size));
959 
960  archive.saveBinary(data, size);
961  delete[] data;
962  } // save
963 
968  template<typename A>
969  void load(A & archive) {
970  size_t size;
971  archive.loadBinary(&size, sizeof(size));
972 
973  char * data = new char[size];
974  archive.loadBinary(data, size);
975  unserialize_(data);
976  delete[] data;
977  } // load
978 
983  char * serialize_(uint64_t & size) const {
984  const size_t alloc_size = 1048576;
985  size = alloc_size;
986 
987  char * buf = new char[alloc_size];
988  uint64_t pos = 0;
989 
990  uint32_t num_domains = POLICY_TYPE::num_domains;
991  std::memcpy(buf + pos, &num_domains, sizeof(num_domains));
992  pos += sizeof(num_domains);
993 
994  uint32_t num_dimensions = POLICY_TYPE::num_dimensions;
995  std::memcpy(buf + pos, &num_dimensions, sizeof(num_dimensions));
996  pos += sizeof(num_dimensions);
997 
998  for(size_t domain = 0; domain < POLICY_TYPE::num_domains; ++domain) {
999  for(size_t dimension = 0; dimension <= POLICY_TYPE::num_dimensions;
1000  ++dimension) {
1001  uint64_t num_entities = base_t::ms_->entities[domain][dimension].size();
1002  std::memcpy(buf + pos, &num_entities, sizeof(num_entities));
1003  pos += sizeof(num_entities);
1004  }
1005  }
1006 
1007  for(size_t from_domain = 0; from_domain < POLICY_TYPE::num_domains;
1008  ++from_domain) {
1009  for(size_t to_domain = 0; to_domain < POLICY_TYPE::num_domains;
1010  ++to_domain) {
1011 
1012  auto & dc = base_t::ms_->topology[from_domain][to_domain];
1013 
1014  for(size_t from_dim = 0; from_dim <= POLICY_TYPE::num_dimensions;
1015  ++from_dim) {
1016  for(size_t to_dim = 0; to_dim <= POLICY_TYPE::num_dimensions;
1017  ++to_dim) {
1018  const connectivity_t & c = dc.get(from_dim, to_dim);
1019 
1020  auto & tv = c.to_id_storage();
1021  uint64_t num_to = tv.size();
1022  std::memcpy(buf + pos, &num_to, sizeof(num_to));
1023  pos += sizeof(num_to);
1024 
1025  size_t bytes = num_to * sizeof(id_vector_t::value_type);
1026 
1027  if(size - pos < bytes) {
1028  size += bytes + alloc_size;
1029  buf = (char *)std::realloc(buf, size);
1030  }
1031 
1032  std::memcpy(buf + pos, tv.data(), bytes);
1033  pos += bytes;
1034 
1035  uint64_t num_offsets = c.offsets().size();
1036  std::memcpy(buf + pos, &num_offsets, sizeof(num_offsets));
1037  pos += sizeof(num_offsets);
1038 
1039  bytes = num_offsets * sizeof(offset_t);
1040 
1041  if(size - pos < bytes) {
1042  size += bytes + alloc_size;
1043  buf = (char *)std::realloc(buf, size);
1044  }
1045 
1046  std::memcpy(buf + pos, c.offsets().storage().buffer(), bytes);
1047  pos += bytes;
1048  }
1049  }
1050  }
1051  }
1052 
1053  size = pos;
1054 
1055  return buf;
1056  }
1057 
1062  void unserialize_(char * buf) {
1063  uint64_t pos = 0;
1064 
1065  uint32_t num_domains;
1066  std::memcpy(&num_domains, buf + pos, sizeof(num_domains));
1067  pos += sizeof(num_domains);
1068  flog_assert(num_domains == POLICY_TYPE::num_domains, "domain size mismatch");
1069 
1070  uint32_t num_dimensions;
1071  std::memcpy(&num_dimensions, buf + pos, sizeof(num_dimensions));
1072  pos += sizeof(num_dimensions);
1073  flog_assert(
1074  num_dimensions == POLICY_TYPE::num_dimensions, "dimension size mismatch");
1075 
1076  unserialize_domains_<storage_t,
1077  POLICY_TYPE,
1078  POLICY_TYPE::num_domains,
1079  POLICY_TYPE::num_dimensions,
1080  0>::unserialize(*this, buf, pos);
1081 
1082  for(size_t from_domain = 0; from_domain < POLICY_TYPE::num_domains;
1083  ++from_domain) {
1084  for(size_t to_domain = 0; to_domain < POLICY_TYPE::num_domains;
1085  ++to_domain) {
1086 
1087  auto & dc = base_t::ms_->topology[from_domain][to_domain];
1088 
1089  for(size_t from_dim = 0; from_dim <= POLICY_TYPE::num_dimensions;
1090  ++from_dim) {
1091  for(size_t to_dim = 0; to_dim <= POLICY_TYPE::num_dimensions;
1092  ++to_dim) {
1093  connectivity_t & c = dc.get(from_dim, to_dim);
1094 
1095  auto & tv = c.to_id_storage();
1096  uint64_t num_to;
1097  std::memcpy(&num_to, buf + pos, sizeof(num_to));
1098  pos += sizeof(num_to);
1099  auto ta = (id_vector_t::value_type *)(buf + pos);
1100  tv.resize(num_to);
1101  tv.assign(ta, ta + num_to);
1102  pos += num_to * sizeof(id_vector_t::value_type);
1103 
1104  auto offsets_buf = c.offsets().storage().buffer();
1105  uint64_t num_offsets;
1106  std::memcpy(&num_offsets, buf + pos, sizeof(num_offsets));
1107  pos += sizeof(num_offsets);
1108  std::memcpy(offsets_buf, buf + pos, num_offsets * sizeof(offset_t));
1109  pos += num_offsets * sizeof(offset_t);
1110  }
1111  }
1112  }
1113  }
1114  }
1115 
1120  void append_to_index_space_(size_t domain,
1121  size_t dim,
1122  std::vector<mesh_entity_base_ *> & ents,
1123  std::vector<id_t> & ids) override {
1124  auto & is = base_t::ms_->index_spaces[domain][dim];
1125  is.append_(ents, ids);
1126  }
1127 
1128  template<size_t INDEX_SUBSPACE>
1129  auto & get_index_subspace() {
1130  using entity_types_t = typename POLICY_TYPE::entity_types;
1131 
1132  using index_subspaces = typename get_index_subspaces<POLICY_TYPE>::type;
1133 
1134  constexpr size_t subspace_index =
1136  index_subspaces,
1137  INDEX_SUBSPACE>::find();
1138 
1139  static_assert(subspace_index != -1, "invalid index subspace");
1140 
1141  using subspace_entry_t =
1143 
1144  using index_space_t =
1146 
1147  constexpr size_t index =
1149  entity_types_t,
1150  index_space_t::value>::find();
1151 
1152  // never gonna happen since index is a size_t, and cant be negative
1153  static_assert(index != -1, "invalid index space");
1154 
1155  using entry_t = typename std::tuple_element<index, entity_types_t>::type;
1156 
1157  using domain_t = typename std::tuple_element<1, entry_t>::type;
1158 
1159  using entity_t = typename std::tuple_element<2, entry_t>::type;
1160 
1161  return base_t::ms_->index_subspaces[INDEX_SUBSPACE]
1162  .template cast<domain_entity<domain_t::value, entity_t>>();
1163  }
1164 
1165  template<size_t INDEX_SUBSPACE>
1166  const auto & get_index_subspace() const {
1167  using entity_types_t = typename POLICY_TYPE::entity_types;
1168 
1169  using index_subspaces = typename get_index_subspaces<POLICY_TYPE>::type;
1170 
1171  constexpr size_t subspace_index =
1173  index_subspaces,
1174  INDEX_SUBSPACE>::find();
1175 
1176  static_assert(subspace_index != -1, "invalid index subspace");
1177 
1178  using subspace_entry_t =
1180 
1181  using index_space_t =
1183 
1184  constexpr size_t index =
1186  entity_types_t,
1187  index_space_t::value>::find();
1188 
1189  // never gonna happen since index is a size_t, and cant be negative
1190  static_assert(index != -1, "invalid index space");
1191 
1192  using entry_t = typename std::tuple_element<index, entity_types_t>::type;
1193 
1194  using domain_t = typename std::tuple_element<1, entry_t>::type;
1195 
1196  using entity_t = typename std::tuple_element<2, entry_t>::type;
1197 
1198  return base_t::ms_->index_subspaces[INDEX_SUBSPACE]
1199  .template cast<domain_entity<domain_t::value, entity_t>>();
1200  }
1201 
1202  size_t get_index_subspace_size_(size_t index_subspace) {
1203  return base_t::ms_->index_subspaces[index_subspace].size();
1204  }
1205 
1206 private:
1207  template<size_t, size_t, class>
1208  friend struct compute_connectivity;
1209 
1210  template<size_t, size_t, class>
1211  friend struct compute_bindings;
1212 
1213  template<size_t DOM, typename VERT_TYPE>
1214  void init_cell_(entity_type<POLICY_TYPE::num_dimensions, DOM> * cell,
1215  VERT_TYPE && verts) {
1216  auto & c = get_connectivity_(DOM, POLICY_TYPE::num_dimensions, 0);
1217 
1218  flog_assert(cell->template id<DOM>() == c.from_size(), "id mismatch");
1219 
1220  for(entity_type<0, DOM> * v : std::forward<VERT_TYPE>(verts)) {
1221  c.push(v->template global_id<DOM>());
1222  } // for
1223 
1224  c.add_count(static_cast<std::uint32_t>(verts.size()));
1225  } // init_cell
1226 
1227  template<size_t DOM, size_t FROM_DIM, size_t TO_DIM, class ENT_TYPE2>
1228  void init_entity_(entity_type<FROM_DIM, DOM> * super, ENT_TYPE2 && subs) {
1229  auto & c = get_connectivity_(DOM, FROM_DIM, TO_DIM);
1230 
1231  flog_assert(super->template id<DOM>() == c.from_size(), "id mismatch");
1232 
1233  for(auto e : std::forward<ENT_TYPE2>(subs)) {
1234  c.push(e->template global_id<DOM>());
1235  } // for
1236 
1237  c.add_count(subs.size());
1238  } // init_entity
1239 
1240  // Get the number of entities in a given domain and topological dimension
1241  size_t num_entities_(size_t dim, size_t domain = 0) const {
1242  return base_t::ms_->index_spaces[domain][dim].size();
1243  } // num_entities_
1244 
1245  // Get the number of entities in a given domain and topological dimension
1246  size_t num_entities_(size_t dim, size_t domain, partition_t partition) const {
1247  return base_t::ms_->partition_index_spaces[partition][domain][dim].size();
1248  } // num_entities_
1249 
1258  template<size_t Domain, size_t DimensionToBuild, size_t UsingDimension>
1259  typename std::enable_if<(
1260  UsingDimension <= 1 || UsingDimension > POLICY_TYPE::num_dimensions)>::type
1261  build_connectivity() {
1262  flog_assert(false, "shouldn't be in here");
1263  }
1264 
1278  template<size_t Domain, size_t DimensionToBuild, size_t UsingDimension>
1279  typename std::enable_if<(
1281  build_connectivity() {
1282  // std::cerr << "build: " << DimensionToBuild
1283  // << " using " << UsingDimension << std::endl;
1284 
1285  // Sanity check
1286  static_assert(DimensionToBuild <= POLICY_TYPE::num_dimensions,
1287  "DimensionToBuild must be <= total number of dimensions");
1288  static_assert(UsingDimension <= POLICY_TYPE::num_dimensions,
1289  "UsingDimension must be <= total number of dimensions");
1290  static_assert(Domain < POLICY_TYPE::num_domains,
1291  "Domain must be < total number of domains");
1292 
1293  // Reference to storage from cells to the entity (to be created here).
1294  connectivity_t & cell_to_entity =
1295  get_connectivity_(Domain, UsingDimension, DimensionToBuild);
1296 
1297  // Storage for entity-to-vertex connectivity information.
1298  connection_vector_t entity_vertex_conn;
1299 
1300  // Helper variables
1301  size_t max_cell_entity_conns = 1;
1302 
1303  // keep track of the local ids, since they may be added out of order
1304  std::vector<size_t> entity_ids;
1305 
1307  base_t::ms_->topology[Domain][Domain];
1308 
1309  // Get connectivity for cells to vertices.
1310  connectivity_t & cell_to_vertex = dc.template get<UsingDimension>(0);
1311  flog_assert(!cell_to_vertex.empty(), "empty map");
1312 
1313  const size_t _num_cells = num_entities<UsingDimension, Domain>();
1314 
1315  // Storage for cell-to-entity connectivity information.
1316  connection_vector_t cell_entity_conn(_num_cells);
1317 
1318  // This map is primarily used to make sure that entities are not
1319  // created multiple times, i.e., that they are unique. The
1320  // emplace method of the map is used to only define a new entity
1321  // if it does not already exist in the map.
1322  id_vector_map_t entity_vertices_map;
1323 
1324  // This buffer should be large enough to hold all entities
1325  // vertices that potentially need to be created
1326  std::array<id_t, 4096> entity_vertices;
1327 
1328  using cell_type = entity_type<UsingDimension, Domain>;
1329  using entity_type = entity_type<DimensionToBuild, Domain>;
1330 
1331  auto & is = base_t::ms_->index_spaces[Domain][DimensionToBuild]
1332  .template cast<domain_entity<Domain, entity_type>>();
1333 
1334  auto & cis = base_t::ms_->index_spaces[Domain][UsingDimension]
1335  .template cast<domain_entity<Domain, cell_type>>();
1336 
1337  // Lookup the index space for the entity type being created.
1338  constexpr size_t cell_index_space = find_index_space_from_dimension<
1339  std::tuple_size<typename POLICY_TYPE::entity_types>::value,
1340  typename POLICY_TYPE::entity_types,
1341  UsingDimension,
1342  Domain>::find();
1343 
1344  // Lookup the index space for the vertices from the mesh
1345  // specialization.
1346  constexpr size_t vertex_index_space = find_index_space_from_dimension<
1347  std::tuple_size<typename POLICY_TYPE::entity_types>::value,
1348  typename POLICY_TYPE::entity_types,
1349  0,
1350  Domain>::find();
1351 
1352  // Lookup the index space for the entity type being created.
1353  constexpr size_t entity_index_space = find_index_space_from_dimension<
1354  std::tuple_size<typename POLICY_TYPE::entity_types>::value,
1355  typename POLICY_TYPE::entity_types,
1356  DimensionToBuild,
1357  Domain>::find();
1358 
1359  // get the global to local index space map
1360  auto & context_ = run::context::instance();
1361  size_t color = context_.color();
1362  auto & gis_to_cis = context_.reverse_index_map(cell_index_space);
1363 
1364  // Get the reverse map of the intermediate ids. This map takes
1365  // vertices defining an entity to the entity id in MIS.
1366  auto & reverse_intermediate_map =
1367  context_.reverse_intermediate_map(DimensionToBuild, Domain);
1368  auto has_intermediate_map = !reverse_intermediate_map.empty();
1369 
1370  // Get the index map for the entity.
1371  auto & entity_index_map = context_.reverse_index_map(entity_index_space);
1372 
1373  // Get the map of the vertex ids. This map takes
1374  // local compacted vertex ids to mesh index space ids.
1375  // CIS -> MIS.
1376  auto & vertex_map = context_.index_map(vertex_index_space);
1377 
1378  // a counter for added entityes
1379  size_t entity_counter{0};
1380 
1381  for(auto & citr : gis_to_cis) {
1382  size_t c = citr.second;
1383 
1384  // Get the cell object
1385  auto cell = static_cast<cell_type *>(cis[c]);
1386  id_t cell_id = cell->template global_id<Domain>();
1387 
1388  // Get storage reference.
1389  id_vector_t & conns = cell_entity_conn[c];
1390 
1391  // Try to optimize storage.
1392  conns.reserve(max_cell_entity_conns);
1393 
1394  // This call allows the users specialization to create
1395  // whatever entities are needed to complete the mesh.
1396  //
1397  // p.first: The number of entities per cell.
1398  // p.second: A std::vector of id_t containing the ids of the
1399  // vertices that define the entity.
1400  auto sv = cell->create_entities(
1401  cell_id, DimensionToBuild, dc, entity_vertices.data());
1402 
1403  size_t n = sv.size();
1404 
1405  // iterate over the newly-defined entities
1406  for(size_t i = 0, pos = 0; i < n; ++i) {
1407  size_t m = sv[i];
1408 
1409  // Get the vertices that define this entity by getting
1410  // a pointer to the vector-of-vector data and then constructing
1411  // a vector of ids for only this entity.
1412  id_t * a = &entity_vertices[pos];
1413  id_vector_t ev(a, a + m);
1414 
1415  // Sort the ids for the current entity so that they are
1416  // monotonically increasing. This ensures that entities are
1417  // created uniquely (using emplace_back below) because the ids
1418  // will always occur in the same order for the same entity.
1419  std::sort(ev.begin(), ev.end());
1420 
1421  //
1422  // The following set of steps use the vertices that define
1423  // the entity to be created to lookup the id so
1424  // that the topology creates it at the correct offset.
1425  // This requires:
1426  //
1427  // 1) lookup the MIS vertex ids
1428  // 2) create a vector of the MIS vertex ids
1429  // 3) lookup the MIS id of the entity
1430  // 4) lookup the CIS id of the entity
1431  //
1432  // The CIS id of the entity is passed to the create_entity
1433  // method. The specialization developer must pass this
1434  // information to 'make' so that the coloring id of the
1435  // entity is consitent with the id/offset of the entity
1436  // created by the topology.
1437  //
1438 
1439  size_t entity_id;
1440  if(has_intermediate_map) {
1441 
1442  std::vector<size_t> vertices_mis;
1443  vertices_mis.reserve(m);
1444 
1445  // Push the MIS vertex ids onto a vector to search for the
1446  // associated entity.
1447  for(id_t * aptr{a}; aptr < (a + m); ++aptr) {
1448  vertices_mis.push_back(vertex_map[aptr->entity()]);
1449  } // for
1450 
1451  // Lookup the MIS id of the entity.
1452  std::sort(vertices_mis.begin(), vertices_mis.end());
1453  const auto entity_id_mis = reverse_intermediate_map.at(vertices_mis);
1454 
1455  // Lookup the CIS id of the entity.
1456  entity_id = entity_index_map.at(entity_id_mis);
1457  }
1458  else {
1459 
1460  entity_id = entity_counter;
1461 
1462  } // intermediate_map
1463 
1464  id_t id = id_t::make<DimensionToBuild, Domain>(entity_id, color);
1465 
1466  // Emplace the sorted vertices into the entity map
1467  auto itr = entity_vertices_map.emplace(std::move(ev),
1468  id_t::make<DimensionToBuild, Domain>(entity_id, cell_id.partition()));
1469 
1470  // Add this id to the cell to entity connections
1471  conns.push_back(itr.first->second);
1472 
1473  // If the insertion took place
1474  if(itr.second) {
1475 
1476  // what does this do?
1477  id_vector_t ev2 = id_vector_t(a, a + m);
1478  entity_vertex_conn.emplace_back(std::move(ev2));
1479  entity_ids.emplace_back(entity_id);
1480 
1481  max_cell_entity_conns = std::max(max_cell_entity_conns, conns.size());
1482 
1483  auto ent =
1484  POLICY_TYPE::template create_entity<Domain, DimensionToBuild>(
1485  this, m, id);
1486 
1487  ++entity_counter;
1488 
1489  } // if
1490 
1491  // pos keeps track of the current array index when looping through
1492  // results of create_entities
1493  pos += m;
1494 
1495  } // for
1496  } // for
1497 
1498  // sort the entity connectivity. Entities may have been created out of
1499  // order. Sort them using the list of entity ids we kept track of
1500  if(has_intermediate_map)
1501  util::reorder_destructive(
1502  entity_ids.begin(), entity_ids.end(), entity_vertex_conn.begin());
1503 
1504  // Set the connectivity information from the created entities to
1505  // the vertices.
1506  connectivity_t & entity_to_vertex = dc.template get<DimensionToBuild>(0);
1507  entity_to_vertex.init(entity_vertex_conn);
1508  cell_to_entity.init(cell_entity_conn);
1509  } // build_connectivity
1510 
1522  template<size_t FROM_DOM, size_t TO_DOM, size_t FROM_DIM, size_t TO_DIM>
1523  void transpose() {
1524  // std::cout << "transpose: (" << FROM_DOM << ", " <<FROM_DIM
1525  // <<") -> (" << TO_DOM<<", "<<TO_DIM<<")" << std::endl;
1526 
1527  // The connectivity we will be populating
1528  auto & out_conn = get_connectivity_(FROM_DOM, TO_DOM, FROM_DIM, TO_DIM);
1529  if(!out_conn.empty()) {
1530  return;
1531  } // if
1532 
1533  // get the list of "to" entities
1534  const auto & to_entities = entities<TO_DIM, TO_DOM>();
1535 
1536  index_vector_t pos(num_entities_(FROM_DIM, FROM_DOM), 0);
1537 
1538  // Count how many connectivities go into each slot
1539  for(auto to_entity : to_entities) {
1540  for(id_t from_id : entity_ids<FROM_DIM, TO_DOM, FROM_DOM>(to_entity)) {
1541  ++pos[from_id.entity()];
1542  }
1543  }
1544 
1545  out_conn.resize(pos);
1546 
1547  std::fill(pos.begin(), pos.end(), 0);
1548 
1549  // now do the actual transpose
1550  for(auto to_entity : to_entities) {
1551  for(auto from_id : entity_ids<FROM_DIM, TO_DOM, FROM_DOM>(to_entity)) {
1552  auto from_lid = from_id.entity();
1553  out_conn.set(
1554  from_lid, to_entity->template global_id<TO_DOM>(), pos[from_lid]++);
1555  }
1556  }
1557 
1558  // now we need to sort the connecvtivity arrays:
1559  // .. we have to make sure the order of connectivity information apears in
1560  // in order of global id
1561 
1562  // we need the context to get the global-to-local mapping
1563  const auto & context_ = run::context::instance();
1564 
1565  // find the from index space and get the mapping from global to local
1566  constexpr size_t to_index_space = find_index_space_from_dimension<
1567  std::tuple_size<typename POLICY_TYPE::entity_types>::value,
1568  typename POLICY_TYPE::entity_types,
1569  TO_DIM,
1570  TO_DOM>::find();
1571 
1572  const auto & to_cis_to_gis = context_.index_map(to_index_space);
1573 
1574  // do the final sort of the connectivity arrays
1575  for(auto from_id : entity_ids<FROM_DIM, FROM_DOM>()) {
1576  // get the connectivity array
1577  size_t count;
1578  auto conn = out_conn.get_entities(from_id.entity(), count);
1579  // pack it into a list of id and global id pairs
1580  std::vector<std::pair<size_t, id_t>> gids(count);
1581  std::transform(conn, conn + count, gids.begin(), [&](auto id) {
1582  return std::make_pair(to_cis_to_gis.at(id.entity()), id);
1583  });
1584  // sort via global id
1585  std::sort(gids.begin(), gids.end(), [](auto a, auto b) {
1586  return a.first < b.first;
1587  });
1588  // upack the results
1589  std::transform(gids.begin(), gids.end(), conn, [](auto id_pair) {
1590  return id_pair.second;
1591  });
1592  }
1593  } // transpose
1594 
1608  template<size_t FROM_DOM,
1609  size_t TO_DOM,
1610  size_t FROM_DIM,
1611  size_t TO_DIM,
1612  size_t DIM>
1613  void intersect() {
1614  // std::cerr << "intersect: " << FROM_DIM << " -> " << TO_DIM << std::endl;
1615 
1616  // The connectivity we will be populating
1617  connectivity_t & out_conn =
1618  get_connectivity_(FROM_DOM, TO_DOM, FROM_DIM, TO_DIM);
1619  if(!out_conn.empty()) {
1620  return;
1621  } // if
1622 
1623  // the number of each entity type
1624  auto num_from_ent = num_entities_(FROM_DIM, FROM_DOM);
1625  auto num_to_ent = num_entities_(TO_DIM, FROM_DOM);
1626 
1627  // Temporary storage for connection id's
1628  connection_vector_t conns(num_from_ent);
1629 
1630  // Keep track of which to id's we have visited
1631  using visited_vec = std::vector<bool>;
1632  visited_vec visited(num_to_ent);
1633 
1634  size_t max_size = 1;
1635 
1636  // Read connectivities
1637  connectivity_t & c = get_connectivity_(FROM_DOM, FROM_DIM, DIM);
1638  flog_assert(!c.empty(), "empty map");
1639 
1640  connectivity_t & c2 = get_connectivity_(TO_DOM, TO_DIM, DIM);
1641  flog_assert(!c2.empty(), "empty map");
1642 
1643  // Iterate through entities in "from" topological dimension
1644  for(auto from_entity : entities<FROM_DIM, FROM_DOM>()) {
1645 
1646  id_t from_id = from_entity->template global_id<FROM_DOM>();
1647  id_vector_t & ents = conns[from_id.entity()];
1648  ents.reserve(max_size);
1649 
1650  size_t count;
1651  id_t * ep = c.get_entities(from_id.entity(), count);
1652 
1653  // Create a copy of to vertices so they can be sorted
1654  id_vector_t from_verts(ep, ep + count);
1655  // sort so we have a unique key for from vertices
1656  std::sort(from_verts.begin(), from_verts.end());
1657 
1658  // initially set all to id's to unvisited
1659  for(auto from_ent2 : entities<DIM, FROM_DOM>(from_entity)) {
1660  for(id_t to_id : entity_ids<TO_DIM, TO_DOM>(from_ent2)) {
1661  visited[to_id.entity()] = false;
1662  }
1663  }
1664 
1665  // Loop through each from entity again
1666  for(auto from_ent2 : entities<DIM, FROM_DOM>(from_entity)) {
1667  for(id_t to_id : entity_ids<TO_DIM, TO_DOM>(from_ent2)) {
1668 
1669  // If we have already visited, skip
1670  if(visited[to_id.entity()]) {
1671  continue;
1672  } // if
1673 
1674  visited[to_id.entity()] = true;
1675 
1676  // If the topological dimensions are the same, always add to id
1677  if(FROM_DIM == TO_DIM) {
1678  if(from_id != to_id) {
1679  ents.push_back(to_id);
1680  } // if
1681  }
1682  else {
1683  size_t count;
1684  id_t * ep = c2.get_entities(to_id.entity(), count);
1685 
1686  // Create a copy of to vertices so they can be sorted
1687  id_vector_t to_verts(ep, ep + count);
1688  // Sort to verts so we can do an inclusion check
1689  std::sort(to_verts.begin(), to_verts.end());
1690 
1691  // If from vertices contains the to vertices add to id
1692  // to this connection set
1693  if(DIM < TO_DIM) {
1694  if(std::includes(from_verts.begin(),
1695  from_verts.end(),
1696  to_verts.begin(),
1697  to_verts.end()))
1698  ents.emplace_back(to_id);
1699  }
1700  // If we are going through a higher level, then set
1701  // intersection is sufficient. i.e. one set does not need to
1702  // be a subset of the other
1703  else {
1704  if(util::intersects(from_verts.begin(),
1705  from_verts.end(),
1706  to_verts.begin(),
1707  to_verts.end()))
1708  ents.emplace_back(to_id);
1709  } // if
1710 
1711  } // if
1712  } // for
1713  } // for
1714 
1715  max_size = std::max(ents.size(), max_size);
1716  } // for
1717 
1718  // Finally create the connection from the temporary conns
1719  out_conn.init(conns);
1720  } // intersect
1721 
1731  template<size_t DOM, size_t FROM_DIM, size_t TO_DIM>
1732  void compute_connectivity() {
1733  // std::cerr << "compute: " << FROM_DIM << " -> " << TO_DIM << std::endl;
1734 
1735  // Get the output connectivity
1736  connectivity_t & out_conn = get_connectivity_(DOM, FROM_DIM, TO_DIM);
1737 
1738  // Check if we have already computed it
1739  if(!out_conn.empty()) {
1740  return;
1741  } // if
1742 
1743  // if we don't have cell -> vertex connectivities, then
1744  // try building cell -> vertex connectivity through the
1745  // faces (3d) or edges(2d)
1746  static_assert(POLICY_TYPE::num_dimensions <= 3,
1747  "this needs to be re-thought for higher dimensions");
1748 
1749  if(get_connectivity_(DOM, POLICY_TYPE::num_dimensions, 0).empty()) {
1750  flog_assert(
1751  !get_connectivity_(DOM, POLICY_TYPE::num_dimensions - 1, 0).empty(),
1752  " need at least edges(2d)/faces(3) -> vertex connectivity");
1753  // assume we have cell -> faces, so invert it to get faces -> cells
1754  transpose<DOM,
1755  DOM,
1756  POLICY_TYPE::num_dimensions - 1,
1757  POLICY_TYPE::num_dimensions>();
1758  // invert faces -> vertices to get vertices -> faces
1759  transpose<DOM, DOM, 0, POLICY_TYPE::num_dimensions - 1>();
1760  // build cells -> vertices via intersections with faces
1761  intersect<DOM,
1762  DOM,
1763  POLICY_TYPE::num_dimensions,
1764  0,
1765  POLICY_TYPE::num_dimensions - 1>();
1766  }
1767 
1768  // Check if we need to build entities, e.g: edges or faces
1769  if(num_entities_(FROM_DIM, DOM) == 0) {
1770  if(get_connectivity_(DOM, FROM_DIM + 1, 0).empty())
1771  build_connectivity<DOM, FROM_DIM, POLICY_TYPE::num_dimensions>();
1772  else
1773  build_connectivity<DOM, FROM_DIM, FROM_DIM + 1>();
1774  } // if
1775 
1776  if(num_entities_(TO_DIM, DOM) == 0) {
1777  if(get_connectivity_(DOM, TO_DIM + 1, 0).empty())
1778  build_connectivity<DOM, TO_DIM, POLICY_TYPE::num_dimensions>();
1779  else
1780  build_connectivity<DOM, TO_DIM, TO_DIM + 1>();
1781  } // if
1782 
1783  if(num_entities_(FROM_DIM, DOM) == 0 && num_entities_(TO_DIM, DOM) == 0) {
1784  return;
1785  } // if
1786 
1787  // Depending on the corresponding topological dimensions, call transpose
1788  // or intersect as need
1789  if(FROM_DIM < TO_DIM) {
1791  transpose<DOM, DOM, FROM_DIM, TO_DIM>();
1792  }
1793  else {
1794  if(FROM_DIM == 0 && TO_DIM == 0) {
1795  // compute vertex to vertex connectivities through shared cells.
1798  intersect<DOM, DOM, FROM_DIM, TO_DIM, POLICY_TYPE::num_dimensions>();
1799  }
1800  else {
1801  // computer connectivities through shared vertices.
1804  intersect<DOM, DOM, FROM_DIM, TO_DIM, 0>();
1805  }
1806  } // if
1807  } // compute_connectivity
1808 
1819  template<size_t FROM_DOM,
1820  size_t TO_DOM,
1821  size_t FROM_DIM,
1822  size_t TO_DIM,
1823  typename std::enable_if<(FROM_DOM < TO_DOM)>::type * = nullptr>
1824  void compute_bindings_() {
1825 
1826  // if the connectivity for a transpose exists, do it
1827  if(!get_connectivity_(TO_DOM, FROM_DOM, TO_DIM, FROM_DIM).empty())
1828  transpose<FROM_DOM, TO_DOM, FROM_DIM, TO_DIM>();
1829 
1830  // otherwise try building the connectivity directly
1831  else if(num_entities_(TO_DIM, TO_DOM) == 0)
1832  build_bindings<FROM_DOM, TO_DOM, TO_DIM>();
1833 
1834  } // compute_bindings
1835 
1846  template<size_t FROM_DOM,
1847  size_t TO_DOM,
1848  size_t FROM_DIM,
1849  size_t TO_DIM,
1850  typename = typename std::enable_if<(FROM_DOM > TO_DOM)>::type>
1851  void compute_bindings_() {
1852 
1853  // build the opposite connectivity first
1854  compute_bindings_<TO_DOM, FROM_DOM, TO_DIM, FROM_DIM>();
1855 
1856  // now apply a transpose to get the requested connectivity
1857  transpose<FROM_DOM, TO_DOM, FROM_DIM, TO_DIM>();
1858 
1859  } // compute_bindings
1860 
1871  template<size_t FROM_DOM, size_t TO_DOM, size_t FROM_DIM, size_t TO_DIM>
1872  typename std::enable_if<(FROM_DOM == TO_DOM)>::type compute_bindings_() {
1873 
1874  // compute connectivities through shared vertices at the at the lowest
1875  // dimension (doesn't matter which one really)
1876  compute_bindings_<0, TO_DOM, 0, FROM_DIM>();
1877  compute_bindings_<0, TO_DOM, 0, TO_DIM>();
1878 
1879  // now try and transpose it
1880  auto & trans_conn = get_connectivity_(TO_DOM, FROM_DOM, TO_DIM, FROM_DIM);
1881  if(!trans_conn.empty())
1882  transpose<FROM_DOM, TO_DOM, FROM_DIM, TO_DIM>();
1883 
1884  } // compute_bindings
1885 
1895  template<size_t FROM_DOM, size_t TO_DOM, size_t FROM_DIM, size_t TO_DIM>
1896  void compute_bindings() {
1897  // std::cerr << "compute: , dom " << FROM_DOM << " -> " << TO_DOM
1898  // << ", dim " << FROM_DIM << " -> " << TO_DIM << std::endl;
1899 
1900  // check if requested connectivity is already there, nothing to do
1901  connectivity_t & out_conn =
1902  get_connectivity_(FROM_DOM, TO_DOM, FROM_DIM, TO_DIM);
1903 
1904  if(!out_conn.empty())
1905  return;
1906 
1907  compute_bindings_<FROM_DOM, TO_DOM, FROM_DIM, TO_DIM>();
1908  }
1909 
1920  template<size_t FROM_DOM, size_t TO_DOM, size_t TO_DIM>
1921  void build_bindings() {
1922 
1923  // std::cout << "build bindings: dom " << FROM_DOM << " -> " << TO_DOM
1924  // << " dim " << TO_DIM << std::endl;
1925 
1926  // Sanity check
1927  static_assert(TO_DIM <= POLICY_TYPE::num_dimensions, "invalid dimension");
1928 
1929  constexpr auto num_dims = POLICY_TYPE::num_dimensions;
1930  constexpr auto cell_dim = POLICY_TYPE::num_dimensions;
1931 
1932  // Get cell definitions from domain 0
1933  using cell_type = entity_type<cell_dim, FROM_DOM>;
1934  // alias the entity type we are building
1935  using binding_type = entity_type<TO_DIM, TO_DOM>;
1936 
1937  // get the cells from mesh storage
1938  auto & cell_storage =
1939  base_t::ms_->index_spaces[FROM_DOM][cell_dim]
1940  .template cast<domain_entity<FROM_DOM, cell_type>>();
1941 
1942  // get the entities from mesh storage
1943  auto & binding_storage =
1944  base_t::ms_->index_spaces[TO_DOM][TO_DIM]
1945  .template cast<domain_entity<TO_DOM, binding_type>>();
1946 
1947  // Lookup the index space for the cell type.
1948  constexpr auto cell_index_space = find_index_space_from_dimension<
1949  std::tuple_size<typename POLICY_TYPE::entity_types>::value,
1950  typename POLICY_TYPE::entity_types,
1951  cell_dim,
1952  FROM_DOM>::find();
1953 
1954  // lookup all primal index spaces in the FROM_DOM
1955  auto entity_index_spaces =
1956  find_all_index_spaces_in_domain<POLICY_TYPE, FROM_DOM>();
1957 
1958  // Lookup the index space for the entity type being created.
1959  constexpr auto binding_index_space = find_index_space_from_dimension<
1960  std::tuple_size<typename POLICY_TYPE::entity_types>::value,
1961  typename POLICY_TYPE::entity_types,
1962  TO_DIM,
1963  TO_DOM>::find();
1964 
1965  // get the primal mesh connectivity and the domain connectivity
1966  domain_connectivity<num_dims> & primal_conn =
1967  base_t::ms_->topology[FROM_DOM][FROM_DOM];
1968  domain_connectivity<num_dims> & domain_conn =
1969  base_t::ms_->topology[FROM_DOM][TO_DOM];
1970 
1971  // get the global to local index space map
1972  auto & context_ = run::context::instance();
1973  auto color = context_.color();
1974  const auto & cell_gis_to_cis = context_.reverse_index_map(cell_index_space);
1975  const auto & binding_gis_to_cis =
1976  context_.reverse_index_map(binding_index_space);
1977 
1978  // Get the map of the different entity ids. This map takes
1979  // local compacted vids to mesh index space ids.
1980  // CIS -> MIS.
1981  using entity_map_t = std::decay_t<decltype(context_.index_map(0))>;
1982  std::map<size_t, entity_map_t *> entity_cis_to_mis;
1983  for(int dim = 0; dim <= num_dims; ++dim) {
1984  entity_cis_to_mis[dim] = &context_.index_map(entity_index_spaces[dim]);
1985  }
1986 
1987  // Get the reverse map of the intermediate ids. This maps
1988  // connected entities to their id within the MIS.
1989  const auto & reverse_intermediate_map =
1990  context_.reverse_intermediate_binding_map(TO_DIM, TO_DOM);
1991  // stop if one of the mappings is empty
1992  auto has_intermediate_map = (!reverse_intermediate_map.empty());
1993  // the simplified id type used for searching
1994  using simple_id_vector_t =
1995  typename std::decay_t<decltype(reverse_intermediate_map)>::key_type;
1996 
1997  // This buffer should be large enough to hold all entities
1998  // that potentially need to be created
1999  std::array<id_t, 4096> new_binding_connection_ids;
2000 
2001  // Storage all connectivity information
2002  // - A binding is the higher domain elemeent we are trying to build.
2003  // - An entity is an vertex/edge/element from the primal mesh.
2004  std::map<size_t, connection_vector_t> binding_to_entity_conn;
2005  // make a hashing function to get a unique key
2006  auto key = [](auto dom, auto dim) {
2007  return POLICY_TYPE::num_dimensions * dom + dim;
2008  };
2009 
2010  // we know we need cell to entity connectivity
2011  const auto num_cells = num_entities<cell_dim, FROM_DOM>();
2012  connection_vector_t cell_to_binding_conn(num_cells);
2013 
2014  // a counter for added entities
2015  size_t binding_counter{0};
2016 
2017  // Iterate over cells (this lets us iterate in the order of the global
2018  // index space)
2019  for(auto & cell_itr : cell_gis_to_cis) {
2020 
2021  // Get the cell object
2022  auto c = cell_itr.second;
2023  auto cell = static_cast<cell_type *>(cell_storage[c]);
2024  auto cell_id = cell->template global_id<FROM_DOM>();
2025 
2026  // This call allows the users specialization to create
2027  // whatever entities are needed to complete the mesh.
2028  //
2029  // new_entity_connection_sizes: The number of entities per cell.
2030  // new_entity_connection_ids: A std::vector of id_t containing
2031  // the ids of the entities that define
2032  // the bound entity.
2033  auto new_binding_connection_sizes = cell->create_bound_entities(FROM_DOM,
2034  TO_DOM,
2035  TO_DIM,
2036  cell_id,
2037  primal_conn,
2038  domain_conn,
2039  new_binding_connection_ids.data());
2040 
2041  auto num_new_bindings = new_binding_connection_sizes.size();
2042 
2043  // pre-reserve storage for connected entities
2044  auto & this_cell_to_binding_conn = cell_to_binding_conn[c];
2045  this_cell_to_binding_conn.reserve(num_new_bindings);
2046 
2047  // Iterate over the newly-defined entities
2048  size_t new_binding_pos = 0;
2049  for(auto num_connections : new_binding_connection_sizes) {
2050 
2051  //---------------------------------------------------------------------
2052  // Loop over all the connections, and store both their mesh id (mis)
2053  // and compact id (cis)
2054 
2055  // loop over items connected to the new entity, and add them to the
2056  // connectivity lists. We have to do some extra work to keep track of
2057  // which dimension and domain connected items are a part of.
2058  // dim_flags and dom_flags are used to keep track of which connectivity
2059  // arrays were populated and need to be closed after.
2060  uint32_t dim_flags = 0;
2061  uint32_t dom_flags = 0;
2062  size_t num_new_binding_vertices = 0;
2063 
2064  // entities_mis is used to figure out what the binding id is supposed to
2065  // be (+1 for cell)
2066  simple_id_vector_t connected_entities_mis;
2067  connected_entities_mis.reserve(num_connections + 1);
2068  connected_entities_mis.emplace_back(
2069  0, cell_dim, entity_cis_to_mis[cell_dim]->at(cell_id.entity()));
2070 
2071  // entities_cis is used to store the original encodied binding
2072  // connections ( no cell in this one, its connectivitty will be sorted
2073  // out later )
2074  id_vector_t connected_entities;
2075  connected_entities.reserve(num_connections);
2076 
2077  for(size_t k = 0; k < num_connections; ++k) {
2078 
2079  // get the connected item id
2080  auto connection_id = new_binding_connection_ids[new_binding_pos + k];
2081  auto dim = connection_id.dimension();
2082  auto dom = connection_id.domain();
2083 
2084  // add it to the main list
2085  connected_entities.push_back(connection_id);
2086 
2087  // if domain is the same as from domain, the connected item is part
2088  // of the primal mesh
2089  if(dom == FROM_DOM) {
2090  dim_flags |= 1U << dim;
2091  num_new_binding_vertices += dim == 0 ? 1 : 0;
2092  // also add to entity search list
2093  auto entity_cis = connection_id.entity();
2094  auto entity_mis = entity_cis_to_mis[dim]->at(entity_cis);
2095  connected_entities_mis.emplace_back(dom, dim, entity_mis);
2096  }
2097  // else its part of the to domain
2098  else
2099  dom_flags |= 1U << dim;
2100 
2101  } // for connection
2102 
2103  //---------------------------------------------------------------------
2104  // Figure out the binding's id
2105 
2106  // If we have an intermediate mapping, map the connected enitities to
2107  // an binding id. This makes sure the created bound entity has the
2108  // the right id. Otherwise, it may not match the exclusive, shared,
2109  // ghost sets.
2110  size_t new_binding_id_cis;
2111  if(has_intermediate_map) {
2112  // sort for comparison
2113  std::sort(
2114  connected_entities_mis.begin(), connected_entities_mis.end());
2115  // map the connected entities to a global binding id
2116  auto new_binding_id_gis =
2117  reverse_intermediate_map.at(connected_entities_mis);
2118  // then get the new compact id
2119  new_binding_id_cis = binding_gis_to_cis.at(new_binding_id_gis);
2120  }
2121  // just use the counter since we dont have a
2122  else {
2123  new_binding_id_cis = binding_counter;
2124  }
2125 
2126  // now create the entity id, on the same partition as the connected
2127  // cell. this
2128  auto new_binding_id =
2129  id_t::make<TO_DIM, TO_DOM>(new_binding_id_cis, color);
2130 
2131  // Add this id to the cell entity connections
2132  this_cell_to_binding_conn.push_back(new_binding_id);
2133 
2134  // now buid the new entity
2135  auto ent = POLICY_TYPE::template create_entity<TO_DOM, TO_DIM>(
2136  this, num_new_binding_vertices, new_binding_id);
2137 
2138  //---------------------------------------------------------------------
2139  // Now add the connected entities to the connectivity table, now that
2140  // we know where it is going. Note: we could have appended them to
2141  // a list, and reordered it later, avoiding the dynamic resizing. But
2142  // this was WAAAAAYYYYY slower.
2143  for(auto connection_id : connected_entities) {
2144 
2145  // get domain and dimension again
2146  auto dim = connection_id.dimension();
2147  auto dom = connection_id.domain();
2148 
2149  // search the map for this particular connectivity info, if its
2150  // not found, create it
2151  auto map_key = key(dom, dim);
2152  auto bit = binding_to_entity_conn.find(map_key);
2153  if(bit == binding_to_entity_conn.end()) {
2154  bit = binding_to_entity_conn
2155  .emplace(std::make_pair(map_key, connection_vector_t{}))
2156  .first; // first is iterator, second is insertion flag
2157  }
2158 
2159  // resize it and add the connection to the new entities connectivity
2160  auto & this_binding_to_entities = bit->second;
2161  if(this_binding_to_entities.size() <= new_binding_id_cis)
2162  this_binding_to_entities.resize(new_binding_id_cis + 1);
2163  this_binding_to_entities[new_binding_id_cis].push_back(connection_id);
2164 
2165  } // for
2166 
2167  // Done building this entity
2168  //---------------------------------------------------------------------
2169 
2170  // bump the counters
2171  ++binding_counter;
2172  new_binding_pos += num_connections;
2173 
2174  } // for
2175  } // for
2176 
2177  // Reference to storage from cells to the entity (to be created here).
2178  get_connectivity_(FROM_DOM, TO_DOM, cell_dim, TO_DIM)
2179  .init(std::move(cell_to_binding_conn));
2180 
2181  // binding to entity conn is a little different.
2182  for(const auto & binding_pair : binding_to_entity_conn) {
2183  // first is the key, and second is the connectivity
2184  auto & binding_to_entity = binding_pair.second;
2185  // domain and dimension is encoded in the ids
2186  const auto & first = binding_to_entity.at(0).at(0);
2187  auto dom = first.domain();
2188  auto dim = first.dimension();
2189  // initialize the connectivity
2190  get_connectivity_(TO_DOM, dom, TO_DIM, dim)
2191  .init(std::move(binding_to_entity));
2192  }
2193 
2194  } // build_bindings
2195 
2201  const connectivity_t & get_connectivity_(size_t from_domain,
2202  size_t to_domain,
2203  size_t from_dim,
2204  size_t to_dim) const {
2205  flog_assert(from_domain < POLICY_TYPE::num_domains, "invalid from domain");
2206  flog_assert(to_domain < POLICY_TYPE::num_domains, "invalid to domain");
2207  return base_t::ms_->topology[from_domain][to_domain].get(from_dim, to_dim);
2208  } // get_connectivity
2209 
2215  connectivity_t & get_connectivity_(size_t from_domain,
2216  size_t to_domain,
2217  size_t from_dim,
2218  size_t to_dim) {
2219  flog_assert(from_domain < POLICY_TYPE::num_domains, "invalid from domain");
2220  flog_assert(to_domain < POLICY_TYPE::num_domains, "invalid to domain");
2221  return base_t::ms_->topology[from_domain][to_domain].get(from_dim, to_dim);
2222  } // get_connectivity
2223 
2233  template<size_t FROM_DOM, size_t TO_DOM, size_t FROM_DIM>
2234  connectivity_t & get_connectivity_(size_t to_dim) {
2235  return base_t::ms_->topology[FROM_DOM][TO_DOM].template get<FROM_DIM>(
2236  to_dim);
2237  } // get_connectivity
2238 
2249  template<size_t FROM_DOM, size_t TO_DOM, size_t FROM_DIM, size_t TO_DIM>
2250  connectivity_t & get_connectivity_() {
2251  return base_t::ms_->topology[FROM_DOM][TO_DOM]
2252  .template get<FROM_DIM, TO_DIM>();
2253  } // get_connectivity
2254 
2260  const connectivity_t &
2261  get_connectivity_(size_t domain, size_t from_dim, size_t to_dim) const {
2262  return get_connectivity_(domain, domain, from_dim, to_dim);
2263  } // get_connectivity
2264 
2270  connectivity_t &
2271  get_connectivity_(size_t domain, size_t from_dim, size_t to_dim) {
2272  return get_connectivity_(domain, domain, from_dim, to_dim);
2273  } // get_connectivity
2274 
2275 }; // class unstructured
2276 #endif
2277 
2278 } // namespace topo
2279 } // namespace flecsi
contains methods and data about the mesh topology that do not depend on type parameterization, e.g: entity types, domains, etc.
Definition: types.hh:43
Definition: types.hh:287
compute_connectivity provides static recursion to process connectivity computation of mesh entity typ...
Definition: utils.hh:358
Definition: id.hh:36
Definition: types.hh:173
Definition: typeify.hh:31
Definition: utils.hh:500
offset represents an offset range (a start index plus a count of elements) in a single uint64_t...
Definition: offset.hh:34
bool empty() const
True if the connectivity is empty (hasn&#39;t been populated).
Definition: connectivity.hh:220
#define flog_assert(test, message)
Definition: flog.hh:411
Definition: core.hh:40
std::string type()
Definition: demangle.hh:44
Definition: types.hh:473
void init(const connection_vector_t &cv)
Definition: connectivity.hh:81
compute_bindings provides static recursion to process binding computation of mesh entity types...
Definition: utils.hh:416
Definition: storage.hh:41
Definition: index.hh:64
domain_entity is a simple wrapper to mesh entity that associates with its a domain id ...
Definition: array_buffer.hh:24
const auto & get_entities() const
Get the to id&#39;s vector.
Definition: connectivity.hh:165
typename std::tuple_element< 2, pair_ >::type type
Definition: utils.hh:101
Definition: interface.hh:112
size_t color()
Definition: execution.hh:326
#define FLECSI_MEMBER_CHECKER(X)
Macro to check if the object has a member _*.
Definition: static_verify.hh:27
connectivity_t provides basic connectivity information in a compressed storage format.
Definition: connectivity.hh:41
Definition: interface.hh:154
Check if the object is a tuple.
Definition: static_verify.hh:52
Definition: control.hh:31