13 #ifndef _SF_MESH_UTILS_EMI_H
14 #define _SF_MESH_UTILS_EMI_H
26 const int MAX_INTERSECTIONS = 20;
34 const int EMI_MIN_MERGE_RANKS = 8;
35 const int EMI_MAX_MERGE_RANKS_PER_NODE = 2;
36 const unsigned long long EMI_TARGET_BYTES_PER_MERGE_RANK = 8ull * 1024ull * 1024ull;
49 inline int emi_node_aware_merge_rank_cap(MPI_Comm comm)
52 MPI_Comm_size(comm, &size);
55 MPI_Comm node_comm = MPI_COMM_NULL;
56 MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, 0, MPI_INFO_NULL, &node_comm);
60 MPI_Comm_rank(node_comm, &node_rank);
62 int local_leader = (node_rank == 0) ? 1 : 0;
65 MPI_Allreduce(&local_leader, &num_nodes, 1, MPI_INT, MPI_SUM, comm);
67 MPI_Comm_free(&node_comm);
70 return std::min(size,
std::max(EMI_MIN_MERGE_RANKS, num_nodes * EMI_MAX_MERGE_RANKS_PER_NODE));
91 template<
class K,
class TokenFn>
92 inline int emi_select_merge_destinations(
const vector<K>& key_vec,
94 size_t bytes_per_entry,
100 int size = 0, rank = 0;
101 MPI_Comm_size(comm, &size);
102 MPI_Comm_rank(comm, &rank);
105 const unsigned long long local_bytes =
106 static_cast<unsigned long long>(dsize) *
static_cast<unsigned long long>(bytes_per_entry);
107 unsigned long long global_bytes = 0;
108 MPI_Allreduce(&local_bytes, &global_bytes, 1, MPI_UNSIGNED_LONG_LONG, MPI_SUM, comm);
111 const int merge_rank_cap = emi_node_aware_merge_rank_cap(comm);
113 if (size > merge_rank_cap) {
115 const int nmerge_floor = EMI_MIN_MERGE_RANKS;
116 const int nmerge_cap = merge_rank_cap;
117 const unsigned long long nmerge_est_ull =
118 std::max(1ull, (global_bytes + EMI_TARGET_BYTES_PER_MERGE_RANK - 1ull) /
119 EMI_TARGET_BYTES_PER_MERGE_RANK);
120 const int nmerge_est =
static_cast<int>(std::min<unsigned long long>(nmerge_cap, nmerge_est_ull));
122 nmerge =
std::max(nmerge_floor, nmerge_est);
126 for (
size_t i = 0; i < dsize; ++i) {
127 if (nmerge == size) {
129 dest[i] =
static_cast<int>(token_fn(key_vec[i]) %
static_cast<size_t>(size));
132 const size_t bucket = token_fn(key_vec[i]) %
static_cast<size_t>(nmerge);
135 dest[i] =
static_cast<int>((bucket *
static_cast<size_t>(size)) /
static_cast<size_t>(nmerge));
139 if (rank == 0 && std::getenv(
"OPENCARP_EMI_LOG_MERGE_RANKS") != NULL) {
140 const char* mode = (nmerge == size) ?
"all-ranks" :
"limited";
142 "[EMI merge ranks] %s: size=%d dsize=%zu global_bytes=%llu cap=%d nmerge=%d mode=%s\n",
143 label, size, dsize, global_bytes, merge_rank_cap, nmerge, mode);
158 struct intersection_tags {
166 int tags[MAX_INTERSECTIONS];
167 intersection_tags() {
168 std::fill_n(tags, MAX_INTERSECTIONS, -1);
173 struct intersection_data {
174 int tags[MAX_INTERSECTIONS];
175 int data[MAX_INTERSECTIONS];
176 int ranks[MAX_INTERSECTIONS];
178 intersection_data() {
179 std::fill_n(tags, MAX_INTERSECTIONS, -1);
180 std::fill_n(data, MAX_INTERSECTIONS, -1);
181 std::fill_n(ranks, MAX_INTERSECTIONS, -1);
188 struct intersection_indices {
190 intersection_indices() {
191 std::fill_n(indices, MAX_INTERSECTIONS, -1);
206 template<
class K,
class V>
inline
209 size_t dsize = map.
size();
210 vector<K> key_vec (dsize);
211 vector<V> value_vec (dsize);
216 for(
const auto & v : map) {
217 if (v.second.second.eidx == -1){
218 key_vec[idx] = v.first;
219 value_vec[idx] = v.second;
224 key_vec.resize(dsize);
225 value_vec.resize(dsize);
227 vector<int> perm, dest;
228 emi_select_merge_destinations(key_vec, dsize,
sizeof(K) +
sizeof(V), dest, comm,
229 "assign_counter_face",
232 commgraph<size_t> grph;
233 grph.configure(dest, comm);
234 size_t nrecv =
sum(grph.rcnt);
240 vector<K> sbuff_key(dsize), rbuff_key(nrecv);
241 vector<V> sbuff_value(dsize), ibuff_value(dsize), rbuff_value(nrecv);
242 for(
size_t i=0; i<dsize; i++) {
243 sbuff_key[i] = key_vec[perm[i]];
244 sbuff_value[i] = value_vec[perm[i]];
254 for (
size_t i = 0; i < nrecv; i++) {
255 auto it = rmap.
find(rbuff_key[i]);
256 if(it != rmap.
end()) {
261 if (it->second.first.tag != rbuff_value[i].first.tag) {
262 it->second.second = rbuff_value[i].first;
265 rmap.
insert({rbuff_key[i], rbuff_value[i]});
269 for (
size_t i = 0; i < nrecv; i++ ) {
270 auto it = rmap.
find(rbuff_key[i]);
271 if(it != rmap.
end()) rbuff_value[i] = it->second;
278 for (
size_t i = 0; i < dsize; i++ ) {
279 auto it = map.find(sbuff_key[i]);
280 if (it != map.end()) it->second = ibuff_value[i];
296 template<
class K,
class V>
inline
308 size_t dsize = map.
size();
309 vector<K> key_vec (dsize);
310 vector<V> value_vec (dsize);
314 for(
const auto & v : map) {
315 if (v.second.second.index_unique == -1 && v.second.second.index_one == -1){
316 key_vec[idx] = v.first;
317 value_vec[idx] = v.second;
322 key_vec.resize(dsize);
323 value_vec.resize(dsize);
325 vector<int> perm, dest;
326 emi_select_merge_destinations(key_vec, dsize,
sizeof(K) +
sizeof(V), dest, comm,
327 "assign_unique_first_face",
330 commgraph<size_t> grph;
331 grph.configure(dest, comm);
332 size_t nrecv =
sum(grph.rcnt);
338 vector<K> sbuff_key(dsize), rbuff_key(nrecv);
339 vector<V> sbuff_value(dsize), ibuff_value(dsize), rbuff_value(nrecv);
340 for(
size_t i=0; i<dsize; i++) {
341 sbuff_key[i] = key_vec[perm[i]];
342 sbuff_value[i] = value_vec[perm[i]];
352 for (
size_t i = 0; i < nrecv; i++) {
353 auto it = rmap.
find(rbuff_key[i]);
354 if(it != rmap.
end()) {
356 auto& existing = it->second;
357 using Face = std::decay_t<decltype(existing.first)>;
359 auto update_slot = [&](Face& slot,
const Face& src) {
363 if (src.index_unique >= 0) {
364 slot.index_unique = src.index_unique;
365 slot.rank = src.rank;
367 if (slot.rank < 0) slot.rank = src.rank;
369 if (slot.index_one < 0 && src.index_one >= 0) slot.index_one = src.index_one;
372 auto same_face = [&](
const Face& a,
const Face& b) {
374 return (a.rank >= 0 && b.rank >= 0 &&
375 a.index_one >= 0 && b.index_one >= 0 &&
376 a.rank == b.rank && a.index_one == b.index_one);
379 auto ingest = [&](
const Face& incoming) {
381 if (incoming.index_one < 0 && incoming.index_unique < 0 && incoming.rank < 0)
return;
383 if (same_face(existing.first, incoming) || existing.first.rank == incoming.rank) {
384 update_slot(existing.first, incoming);
385 }
else if (same_face(existing.second, incoming) || existing.second.rank == incoming.rank) {
386 update_slot(existing.second, incoming);
387 }
else if (existing.second.index_one == -1 && existing.second.index_unique == -1) {
389 existing.second = incoming;
390 }
else if (existing.first.index_one == -1 && existing.first.index_unique == -1) {
392 existing.first = incoming;
396 if (existing.first.index_unique < 0 && incoming.index_unique >= 0) {
397 existing.first.index_unique = incoming.index_unique;
398 existing.first.rank = incoming.rank;
399 }
else if (existing.second.index_unique < 0 && incoming.index_unique >= 0) {
400 existing.second.index_unique = incoming.index_unique;
401 existing.second.rank = incoming.rank;
407 ingest(rbuff_value[i].first);
408 ingest(rbuff_value[i].second);
411 rmap.
insert({rbuff_key[i], rbuff_value[i]});
415 for (
size_t i = 0; i < nrecv; i++ ) {
416 auto it = rmap.
find(rbuff_key[i]);
417 if(it != rmap.
end()) rbuff_value[i] = it->second;
424 for (
size_t i = 0; i < dsize; i++ ) {
425 auto it = map.find(sbuff_key[i]);
426 if (it != map.end()) {
428 it->second = ibuff_value[i];
432 map.insert({sbuff_key[i], ibuff_value[i]});
447 template<
class K>
inline
450 size_t dsize = map.
size();
451 vector<K> key_vec(dsize);
452 vector<intersection_data> value_vec(dsize);
455 for (
const auto& v : map) {
456 key_vec[idx] = v.first;
457 value_vec[idx] = v.second;
461 vector<int> perm, dest;
462 emi_select_merge_destinations(key_vec, dsize,
sizeof(K) +
sizeof(intersection_data), dest, comm,
463 "assign_counter_vertices_tuple",
466 commgraph<size_t> grph;
467 grph.configure(dest, comm);
468 size_t nrecv =
sum(grph.rcnt);
474 vector<K> sbuff_key(dsize), rbuff_key(nrecv);
475 vector<intersection_data> sbuff_value(dsize), ibuff_value(dsize), rbuff_value(nrecv);
476 for (
size_t i = 0; i < dsize; i++) {
477 sbuff_key[i] = key_vec[perm[i]];
478 sbuff_value[i] = value_vec[perm[i]];
484 for (
size_t i = 0; i < nrecv; i++) {
485 auto it = rmap.
find(rbuff_key[i]);
486 if (it != rmap.
end()) {
487 intersection_data& map_val = it->second;
488 intersection_data& r_val = rbuff_value[i];
490 int first_index = -1;
491 for (
int j = 0; j < MAX_INTERSECTIONS; ++j) {
492 if (map_val.tags[j] == -1 && map_val.ranks[j] == -1) {
498 if (first_index == -1)
continue;
500 for (
int j = 0; j < MAX_INTERSECTIONS; ++j) {
501 if (r_val.tags[j] == -1)
continue;
503 int rtag = r_val.tags[j];
504 int rdata = r_val.data[j];
505 int rrank = r_val.ranks[j];
507 bool exist_rtag =
false;
508 for (
int k = 0; k < first_index; ++k) {
509 if (map_val.tags[k] == rtag && map_val.ranks[k] == rrank) {
515 if (!exist_rtag && first_index < MAX_INTERSECTIONS) {
516 map_val.tags[first_index] = rtag;
517 map_val.data[first_index] = rdata;
518 map_val.ranks[first_index] = rrank;
524 rmap.
insert({ rbuff_key[i], rbuff_value[i] });
528 for (
size_t i = 0; i < nrecv; i++) {
529 auto it = rmap.
find(rbuff_key[i]);
530 if (it != rmap.
end()) rbuff_value[i] = it->second;
537 for (
size_t i = 0; i < dsize; i++) {
538 auto it = map.find(sbuff_key[i]);
539 if (it != map.end()) it->second = ibuff_value[i];
554 template<
class K,
class V>
inline
557 size_t dsize = map.
size();
558 vector<K> key_vec (dsize);
559 vector<V> value_vec (dsize);
564 for(
const auto & v : map) {
565 key_vec[idx] = v.first;
566 value_vec[idx] = v.second;
570 key_vec.resize(dsize);
571 value_vec.resize(dsize);
573 vector<int> perm, dest;
574 emi_select_merge_destinations(key_vec, dsize,
sizeof(K) +
sizeof(V), dest, comm,
575 "assign_dof_on_counter_face",
576 [](
const K& key) {
return key.first; });
578 commgraph<size_t> grph;
579 grph.configure(dest, comm);
580 size_t nrecv =
sum(grph.rcnt);
586 vector<K> sbuff_key(dsize), rbuff_key(nrecv);
587 vector<V> sbuff_value(dsize), ibuff_value(dsize), rbuff_value(nrecv);
588 for(
size_t i=0; i<dsize; i++) {
589 sbuff_key[i] = key_vec[perm[i]];
590 sbuff_value[i] = value_vec[perm[i]];
597 for (
size_t i = 0; i < nrecv; i++) {
598 auto it = rmap.
find(rbuff_key[i]);
599 if(it != rmap.
end()) {
600 if(rbuff_value[i] != -1 and it->second == -1){
601 it->second = rbuff_value[i];
604 rmap.
insert({rbuff_key[i], rbuff_value[i]});
608 for (
size_t i = 0; i < nrecv; i++ ) {
609 auto it = rmap.
find(rbuff_key[i]);
610 if(it != rmap.
end()) {
611 if(rbuff_value[i] == -1)
612 rbuff_value[i] = it->second;
620 for (
size_t i = 0; i < dsize; i++ ) {
621 auto it = map.find(sbuff_key[i]);
622 if (it != map.end()) it->second = ibuff_value[i];
637 template<
class K,
class V>
inline
640 size_t dsize = map.
size();
641 vector<K> key_vec (dsize);
642 vector<V> value_vec (dsize);
647 for(
const auto & v : map) {
648 key_vec[idx] = v.first;
649 value_vec[idx] = v.second;
653 key_vec.resize(dsize);
654 value_vec.resize(dsize);
656 vector<int> perm, dest;
657 emi_select_merge_destinations(key_vec, dsize,
sizeof(K) +
sizeof(V), dest, comm,
658 "assign_petsc_on_counter_face",
659 [](
const K& key) {
return key.first; });
661 commgraph<size_t> grph;
662 grph.configure(dest, comm);
663 size_t nrecv =
sum(grph.rcnt);
669 vector<K> sbuff_key(dsize), rbuff_key(nrecv);
670 vector<V> sbuff_value(dsize), ibuff_value(dsize), rbuff_value(nrecv);
671 for(
size_t i=0; i<dsize; i++) {
672 sbuff_key[i] = key_vec[perm[i]];
673 sbuff_value[i] = value_vec[perm[i]];
680 for (
size_t i = 0; i < nrecv; i++) {
681 auto it = rmap.
find(rbuff_key[i]);
682 if(it != rmap.
end()) {
683 if(rbuff_value[i].second != -1 and it->second.second == -1){
684 it->second = rbuff_value[i];
687 rmap.
insert({rbuff_key[i], rbuff_value[i]});
691 for (
size_t i = 0; i < nrecv; i++ ) {
692 auto it = rmap.
find(rbuff_key[i]);
693 if(it != rmap.
end()) {
694 if(rbuff_value[i].second == -1)
695 rbuff_value[i].second = it->second.second;
703 for (
size_t i = 0; i < dsize; i++ ) {
704 auto it = map.find(sbuff_key[i]);
705 if (it != map.end()) it->second = ibuff_value[i];
717 void sort_surf_local_indices(tuple<T> & ref, tuple<T> & target)
721 buff[0] = ref.v1, buff[1] = ref.v2;
724 target.v1 = buff[0], target.v2 = buff[1];
735 void sort_surf_local_indices(triple<T> & ref, triple<T> & target)
739 buff[0] = ref.v1, buff[1] = ref.v2, buff[2] = ref.v3;
742 target.v1 = buff[0], target.v2 = buff[1], target.v3 = buff[2];
753 void sort_surf_local_indices(quadruple<T> & ref, quadruple<T> & target)
757 buff[0] = ref.v1, buff[1] = ref.v2, buff[2] = ref.v3, buff[3] = ref.v4;
760 target.v1 = buff[0], target.v2 = buff[1], target.v3 = buff[2], target.v4 = buff[3];
774 template<
class K,
class V>
inline
775 void insert_surf_based_Tag(V & ref,
780 sort_surf_local_indices(ref.points, surf);
782 auto it = surfmap.find(surf);
783 if (it != surfmap.end()) {
786 if ( it->second.first.tag != ref.tag )
787 it->second.second = ref;
789 std::pair<V, V> face;
791 surfmap.insert({surf,face});
814 template<
class T,
class W,
class V,
class U>
inline
815 void insert_surf_emi(
int rank,
818 const T eidx,
const T tag,
819 const std::vector<T> & line_con,
const std::vector<T> & surf_con,
const std::vector<T> & qsurf_con,
835 for (
size_t i = 0; i < line_con.size(); i += 2) {
836 if (ptsData[line_con[i ] - 1] > 0 &&
837 ptsData[line_con[i + 1] - 1] > 0 ) {
838 line.points.v1 = ref_con[line_con[i ] - 1];
839 line.points.v2 = ref_con[line_con[i + 1] - 1];
841 insert_surf_based_Tag(line, line_face);
845 for (
size_t i = 0; i < surf_con.size(); i += 3) {
846 if (ptsData[surf_con[i ] - 1] > 0 &&
847 ptsData[surf_con[i + 1] - 1] > 0 &&
848 ptsData[surf_con[i + 2] - 1] > 0 ) {
849 face.points.v1 = ref_con[surf_con[i ] - 1];
850 face.points.v2 = ref_con[surf_con[i + 1] - 1];
851 face.points.v3 = ref_con[surf_con[i + 2] - 1];
853 insert_surf_based_Tag(face, surfmap);
857 for (
size_t i = 0; i < qsurf_con.size(); i += 4) {
858 if (ptsData[qsurf_con[i ] - 1] > 0 &&
859 ptsData[qsurf_con[i + 1] - 1] > 0 &&
860 ptsData[qsurf_con[i + 2] - 1] > 0 &&
861 ptsData[qsurf_con[i + 3] - 1] > 0) {
862 qface.points.v1 = ref_con[qsurf_con[i ] - 1];
863 qface.points.v2 = ref_con[qsurf_con[i + 1] - 1];
864 qface.points.v3 = ref_con[qsurf_con[i + 2] - 1];
865 qface.points.v4 = ref_con[qsurf_con[i + 3] - 1];
867 insert_surf_based_Tag(qface, qsurfmap);
878 template<
class T,
class V>
885 bool mark_to_take =
false;
892 struct emi_unique_face {
925 struct emi_index_rank {
946 template<
class T,
class S>
inline
947 void compute_surface_with_tags(meshdata<T,S> & mesh,
952 std::pair<emi_face<T,tuple<T>>, emi_face<T,tuple<T>>>> & line_face,
954 std::pair<emi_face<T,triple<T>>, emi_face<T,triple<T>>>> & tri_surf,
956 std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>>> & quad_surf)
960 MPI_Comm_size(comm, &size);
961 MPI_Comm_rank(comm, &rank);
963 const T* con = mesh.con.data();
964 const T* nbr = mesh.get_numbering(numbering).data();
969 for(
size_t i=0; i<mesh.con.size(); i++){
970 g2ptsData[rnod[con[i]]] = vertex2ptsdata[rnod[con[i]]];
973 const vector<T> & ref_eidx = mesh.get_numbering(
NBR_ELEM_REF);
978 for(
size_t eidx = 0; eidx < mesh.l_numelem; eidx++) {
979 T tag = mesh.tag[eidx];
980 T size_elem = mesh.dsp[eidx+1]-mesh.dsp[eidx];
982 vector<T> dofvec(size_elem);
983 vector<T> ptsDatavec(size_elem);
985 for (
int n = mesh.dsp[eidx], i = 0; n < mesh.dsp[eidx+1];n++,i++)
987 dofvec[i] = rnod[con[n]];
988 ptsDatavec[i] = g2ptsData[rnod[con[n]]];
990 std::vector<T> surf_con ;
991 std::vector<T> qsurf_con;
992 std::vector<T> line_con;
993 switch(mesh.type[eidx]) {
1034 qsurf_con = {1,2,3,4};
1042 qsurf_con = {1,2,6,4,
1051 qsurf_con = {1,2,3,4,
1060 fprintf(stderr,
"%s error: Unsupported element in surface computation!\n", __func__);
1063 insert_surf_emi(rank, dofvec, ptsDatavec, ref_eidx[eidx], mesh.tag[eidx], line_con, surf_con, qsurf_con, line_face, tri_surf, quad_surf);
1067 assign_counter_face(line_face, mesh.comm);
1068 assign_counter_face(tri_surf, mesh.comm);
1069 assign_counter_face(quad_surf, mesh.comm);
1073 for(
auto it = line_face.begin(); it != line_face.end(); ) {
1074 if( it->second.second.eidx == -1 ||(extra_tags.
find(it->second.first.tag) != extra_tags.
end() && extra_tags.
find(it->second.second.tag) != extra_tags.
end()))
1075 it = line_face.erase(it);
1080 for(
auto it = tri_surf.begin(); it != tri_surf.end(); ) {
1081 if( it->second.second.eidx == -1 ||(extra_tags.
find(it->second.first.tag) != extra_tags.
end() && extra_tags.
find(it->second.second.tag) != extra_tags.
end()))
1082 it = tri_surf.erase(it);
1087 for(
auto it = quad_surf.begin(); it != quad_surf.end(); ) {
1088 if( it->second.second.eidx == -1 ||(extra_tags.
find(it->second.first.tag) != extra_tags.
end() && extra_tags.
find(it->second.second.tag) != extra_tags.
end()))
1089 it = quad_surf.erase(it);
1108 inline bool should_take_first(
int tag1,
int tag2,
1112 bool tag1_is_intra = (intra_tags.
find(tag1) != intra_tags.
end());
1113 bool tag2_is_intra = (intra_tags.
find(tag2) != intra_tags.
end());
1114 bool tag1_is_extra = (extra_tags.
find(tag1) != extra_tags.
end());
1115 bool tag2_is_extra = (extra_tags.
find(tag2) != extra_tags.
end());
1118 if(tag1_is_intra && tag2_is_intra) {
1123 if(tag1_is_intra && tag2_is_extra) {
1126 if(tag2_is_intra && tag1_is_extra) {
1156 void assign_map_between_elem_oneface_and_elem_uniqueFace(
int rank,
1157 emi_unique_face <mesh_int_t> first,
1158 emi_unique_face <mesh_int_t> second,
1163 if(second.index_one==-1 && second.index_unique==-1){
1164 second.index_one = first.index_one;
1165 second.index_unique = first.index_unique;
1168 else if(first.rank != second.rank) {
1170 int our_index_one = (first.rank == rank) ? first.index_one :
1171 (second.rank == rank) ? second.index_one : -1;
1173 int owner_index_unique = (first.index_unique >= 0) ? first.index_unique :
1174 (second.index_unique >= 0) ? second.index_unique : -1;
1175 int owner_rank = (first.index_unique >= 0) ? first.rank :
1176 (second.index_unique >= 0) ? second.rank : -1;
1179 if(our_index_one >= 0 && owner_index_unique >= 0 && owner_rank >= 0 && owner_rank != rank) {
1180 map_elem_oneface_to_elem_uniqueFace[our_index_one].index = owner_index_unique;
1181 map_elem_oneface_to_elem_uniqueFace[our_index_one].rank = owner_rank;
1188 int local_index_unique = -1;
1189 emi_index_rank<mesh_int_t> value1, value2;
1191 if (first.index_unique >= 0 && first.rank == rank) {
1193 local_index_unique = first.index_unique;
1194 value1.index = first.index_one;
1195 value1.rank = first.rank;
1196 value2.index = second.index_one;
1197 value2.rank = second.rank;
1198 }
else if (second.index_unique >= 0 && second.rank == rank) {
1200 local_index_unique = second.index_unique;
1201 value1.index = second.index_one;
1202 value1.rank = second.rank;
1203 value2.index = first.index_one;
1204 value2.rank = first.rank;
1207 if (local_index_unique >= 0) {
1208 auto itr = map_elem_uniqueFace_to_elem_oneface.find(local_index_unique);
1209 if (itr == map_elem_uniqueFace_to_elem_oneface.end()) {
1210 std::pair <emi_index_rank<mesh_int_t>,emi_index_rank<mesh_int_t>> value;
1211 value = std::make_pair(value1, value2);
1212 map_elem_uniqueFace_to_elem_oneface.insert({local_index_unique, value});
1239 template <
class T,
class Key,
class Po
intsKey>
1240 inline void assign_ownership_rank_on_faces(
const Key& key,
1241 std::pair<emi_face<T, PointsKey>, emi_face<T, PointsKey>>& v,
1247 hashmap::unordered_map<Key,std::pair<emi_unique_face<mesh_int_t>, emi_unique_face<mesh_int_t>>>& unique_face_to_elements,
1250 const bool same_rank = (v.first.rank == v.second.rank);
1256 const bool first_intra = (intra_tags.
find(v.first.tag) != intra_tags.
end());
1257 const bool second_intra = (intra_tags.
find(v.second.tag) != intra_tags.
end());
1260 bool take_first_by_tags =
true;
1261 if (first_intra != second_intra) {
1262 take_first_by_tags = first_intra;
1263 }
else if (v.first.tag != v.second.tag) {
1264 take_first_by_tags = (v.first.tag < v.second.tag);
1267 take_first_by_tags = (v.first.rank <= v.second.rank);
1270 int owner_rank = take_first_by_tags ? v.first.rank : v.second.rank;
1272 const bool i_am_owner = (rank == owner_rank);
1276 auto& chosen = take_first_by_tags ? v.first : v.second;
1278 chosen.mark_to_take =
true;
1279 chosen.index_unique = lsize_unique;
1280 chosen.index_one = idx_oneface;
1282 map_elem_oneface_to_elem_uniqueFace[idx_oneface].index = lsize_unique;
1283 map_elem_oneface_to_elem_uniqueFace[idx_oneface].rank = rank;
1289 auto it = unique_face_to_elements.find(key);
1290 if (it == unique_face_to_elements.end()) {
1291 emi_unique_face<mesh_int_t> first;
1292 emi_unique_face<mesh_int_t> second;
1296 first.index_unique = lsize_unique;
1297 first.index_one = idx_oneface;
1301 second.index_unique = -1;
1302 second.index_one = -1;
1303 second.rank = same_rank ? rank : (rank == v.first.rank ? v.second.rank : v.first.rank);
1306 first.index_unique = -1;
1307 first.index_one = idx_oneface;
1310 second.index_unique = -1;
1311 second.index_one = -1;
1312 second.rank = owner_rank;
1315 unique_face_to_elements.insert({ key, std::make_pair(first, second) });
1318 auto& existing = it->second;
1321 emi_unique_face<mesh_int_t>* slot =
nullptr;
1322 if (existing.first.rank == rank || existing.first.rank < 0) {
1323 slot = &existing.first;
1324 }
else if (existing.second.rank == rank || existing.second.rank < 0) {
1325 slot = &existing.second;
1326 }
else if (existing.first.index_one == idx_oneface) {
1327 slot = &existing.first;
1328 }
else if (existing.second.index_one == idx_oneface) {
1329 slot = &existing.second;
1330 }
else if (existing.first.index_unique < 0) {
1331 slot = &existing.first;
1332 }
else if (existing.second.index_unique < 0) {
1333 slot = &existing.second;
1337 if (slot->rank < 0) slot->rank = rank;
1338 if (slot->index_one < 0) slot->index_one = idx_oneface;
1339 if (i_am_owner && slot->index_unique < 0) {
1340 slot->index_unique = lsize_unique;
1410 template<
class T,
class S>
inline
1411 void extract_face_based_tags(meshdata<T,S> & mesh,
1415 std::pair<emi_face<T,tuple<T>>, emi_face<T,tuple<T>>>> & line_face,
1417 std::pair<emi_face<T,triple<T>>, emi_face<T,triple<T>>>> & tri_face,
1419 std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>>> & quad_face,
1422 meshdata<T,S> & surfmesh,
1423 meshdata<T,S> & surfmesh_w_counter,
1424 meshdata<T,S> & surfmesh_unique_face,
1432 surfmesh_w_counter.register_numbering(
SF::NBR_REF);
1433 surfmesh_unique_face.register_numbering(
SF::NBR_REF);
1437 compute_surface_with_tags(mesh, numbering, vertex2ptsdata, extra_tags, line_face, tri_face, quad_face);
1440 MPI_Comm_size(mesh.comm, &size);
1441 MPI_Comm_rank(mesh.comm, &rank);
1443 long int g_num_line = line_face.size();
1444 long int g_num_tri = tri_face.size();
1445 long int g_num_quad = quad_face.size();
1446 MPI_Allreduce(MPI_IN_PLACE, &g_num_line, 1, MPI_LONG, MPI_SUM, mesh.comm);
1447 MPI_Allreduce(MPI_IN_PLACE, &g_num_tri, 1, MPI_LONG, MPI_SUM, mesh.comm);
1448 MPI_Allreduce(MPI_IN_PLACE, &g_num_quad, 1, MPI_LONG, MPI_SUM, mesh.comm);
1452 long int local_extra_extra = 0;
1453 for (
const auto& [key, v] : line_face) {
1454 if (extra_tags.
find(v.first.tag) != extra_tags.
end() &&
1455 extra_tags.
find(v.second.tag) != extra_tags.
end()) {
1456 local_extra_extra++;
1459 for (
const auto& [key, v] : tri_face) {
1460 if (extra_tags.
find(v.first.tag) != extra_tags.
end() &&
1461 extra_tags.
find(v.second.tag) != extra_tags.
end()) {
1462 local_extra_extra++;
1465 for (
const auto& [key, v] : quad_face) {
1466 if (extra_tags.
find(v.first.tag) != extra_tags.
end() &&
1467 extra_tags.
find(v.second.tag) != extra_tags.
end()) {
1468 local_extra_extra++;
1471 long int global_extra_extra = 0;
1472 MPI_Allreduce(&local_extra_extra, &global_extra_extra, 1, MPI_LONG, MPI_SUM, mesh.comm);
1473 if (global_extra_extra > 0 && rank == 0) {
1474 fprintf(stderr,
"WARN: extra-extra faces detected before filtering: %ld\n", global_extra_extra);
1478 surfmesh.g_numelem = g_num_line + g_num_tri + g_num_quad;
1479 surfmesh.l_numelem = line_face.size() + tri_face.size() + quad_face.size();
1481 vector<T> cnt(surfmesh.l_numelem, 0);
1482 surfmesh.tag.resize(surfmesh.l_numelem);
1483 surfmesh.type.resize(surfmesh.l_numelem);
1484 surfmesh.con.resize(line_face.size() * 2 + tri_face.size() * 3 + quad_face.size() * 4);
1491 vector<tuple<T>> line_keys;
1492 for(
auto const& [key, val] : line_face) line_keys.push_back(key);
1493 std::sort(line_keys.begin(), line_keys.end());
1495 vector<triple<T>> tri_keys;
1496 for(
auto const& [key, val] : tri_face) tri_keys.push_back(key);
1497 std::sort(tri_keys.begin(), tri_keys.end());
1499 vector<quadruple<T>> quad_keys;
1500 for(
auto const& [key, val] : quad_face) quad_keys.push_back(key);
1501 std::sort(quad_keys.begin(), quad_keys.end());
1526 for(
auto const& key : line_keys) {
1527 auto& v = line_face.
at(key);
1528 const bool local_involved = (v.first.rank == rank) || (v.second.rank == rank);
1529 if (!local_involved) {
1535 if ((intra_tags.
find(v.first.tag) != intra_tags.
end()) && (intra_tags.
find(v.second.tag) != intra_tags.
end())) {
1541 emi_face<T,tuple<T>> surf_neighbor =
1542 (v.first.rank == rank) ? v.first : v.second;
1544 surfmesh.type[idx] =
Line;
1545 surfmesh.tag[idx] = surf_neighbor.tag;
1546 surfmesh.con[cidx + 0] = surf_neighbor.points.v1;
1547 surfmesh.con[cidx + 1] = surf_neighbor.points.v2;
1550 if(v.first.rank == v.second.rank)
1555 assign_ownership_rank_on_faces<T, tuple<T>, tuple<T>>( key, v, rank,
1558 extra_tags, intra_tags,
1559 line_unique_face_to_elements,
1560 map_elem_oneface_to_elem_uniqueFace);
1565 for(
auto const& key : tri_keys) {
1566 auto& v = tri_face.at(key);
1567 const bool local_involved = (v.first.rank == rank) || (v.second.rank == rank);
1568 if (!local_involved) {
1573 if ((intra_tags.
find(v.first.tag) != intra_tags.
end()) && (intra_tags.
find(v.second.tag) != intra_tags.
end())) {
1579 emi_face<T,triple<T>> surf_neighbor =
1580 (v.first.rank == rank) ? v.first : v.second;
1582 surfmesh.type[idx] =
Tri;
1583 surfmesh.tag[idx] = surf_neighbor.tag;
1584 surfmesh.con[cidx + 0] = surf_neighbor.points.v1;
1585 surfmesh.con[cidx + 1] = surf_neighbor.points.v2;
1586 surfmesh.con[cidx + 2] = surf_neighbor.points.v3;
1589 if(v.first.rank == v.second.rank)
1594 assign_ownership_rank_on_faces<T, triple<T>, triple<T>>( key, v, rank,
1597 extra_tags, intra_tags,
1598 tri_unique_face_to_elements,
1599 map_elem_oneface_to_elem_uniqueFace);
1604 for(
auto const& key : quad_keys) {
1605 auto& v = quad_face.at(key);
1606 const bool local_involved = (v.first.rank == rank) || (v.second.rank == rank);
1607 if (!local_involved) {
1612 if ((intra_tags.
find(v.first.tag) != intra_tags.
end()) && (intra_tags.
find(v.second.tag) != intra_tags.
end())) {
1618 emi_face<T,quadruple<T>> qsurf_neighbor =
1619 (v.first.rank == rank) ? v.first : v.second;
1621 surfmesh.type[idx] =
Quad;
1622 surfmesh.tag[idx] = qsurf_neighbor.tag;
1623 surfmesh.con[cidx + 0] = qsurf_neighbor.points.v1;
1624 surfmesh.con[cidx + 1] = qsurf_neighbor.points.v2;
1625 surfmesh.con[cidx + 2] = qsurf_neighbor.points.v3;
1626 surfmesh.con[cidx + 3] = qsurf_neighbor.points.v4;
1629 if(v.first.rank == v.second.rank)
1634 assign_ownership_rank_on_faces<T, quadruple<T>, quadruple<T>>( key, v, rank,
1637 extra_tags, intra_tags,
1638 quad_unique_face_to_elements,
1639 map_elem_oneface_to_elem_uniqueFace);
1644 surfmesh.l_numelem = idx;
1645 surfmesh.tag.resize(idx);
1646 surfmesh.type.resize(idx);
1649 surfmesh.con.resize(cidx);
1651 long int g_num_surf = surfmesh.l_numelem;
1652 MPI_Allreduce(MPI_IN_PLACE, &g_num_surf, 1, MPI_LONG, MPI_SUM, mesh.comm);
1653 surfmesh.g_numelem = g_num_surf;
1656 std::cout <<
"surfmesh.g_numelem: " << surfmesh.g_numelem <<std::endl;
1657 std::cout <<
"surfmesh.l_numelem: " << surfmesh.l_numelem <<std::endl;
1661 long int g_num_w_counter_line = lsize_line;
1662 long int g_num_w_counter_tri = lsize_tri;
1663 long int g_num_w_counter_quad = lsize_quad;
1665 MPI_Allreduce(MPI_IN_PLACE, &g_num_w_counter_line, 1, MPI_LONG, MPI_SUM,
SF_COMM);
1666 MPI_Allreduce(MPI_IN_PLACE, &g_num_w_counter_tri, 1, MPI_LONG, MPI_SUM,
SF_COMM);
1667 MPI_Allreduce(MPI_IN_PLACE, &g_num_w_counter_quad, 1, MPI_LONG, MPI_SUM,
SF_COMM);
1670 surfmesh_w_counter.g_numelem = g_num_w_counter_line+g_num_w_counter_tri+g_num_w_counter_quad;
1671 surfmesh_w_counter.l_numelem = lsize_line + lsize_tri + lsize_quad;
1673 surfmesh_w_counter.tag.resize(surfmesh_w_counter.l_numelem);
1674 surfmesh_w_counter.type.resize(surfmesh_w_counter.l_numelem);
1675 surfmesh_w_counter.con.resize(lsize_line * 2 + lsize_tri * 3 + lsize_quad * 4);
1678 std::cout <<
"surfmesh_w_counter.g_numelem: " << surfmesh_w_counter.g_numelem <<std::endl;
1679 std::cout <<
"surfmesh_w_counter.l_numelem: " << surfmesh_w_counter.l_numelem <<std::endl;
1684 long int g_num_w_unique_line = lsize_unique_line;
1685 long int g_num_w_unique_tri = lsize_unique_tri;
1686 long int g_num_w_unique_quad = lsize_unique_quad;
1688 MPI_Allreduce(MPI_IN_PLACE, &g_num_w_unique_line, 1, MPI_LONG, MPI_SUM,
SF_COMM);
1689 MPI_Allreduce(MPI_IN_PLACE, &g_num_w_unique_tri, 1, MPI_LONG, MPI_SUM,
SF_COMM);
1690 MPI_Allreduce(MPI_IN_PLACE, &g_num_w_unique_quad, 1, MPI_LONG, MPI_SUM,
SF_COMM);
1693 surfmesh_unique_face.g_numelem = g_num_w_unique_line+g_num_w_unique_tri+g_num_w_unique_quad;
1694 surfmesh_unique_face.l_numelem = lsize_unique_line + lsize_unique_tri + lsize_unique_quad;
1696 surfmesh_unique_face.tag.resize(surfmesh_unique_face.l_numelem);
1697 surfmesh_unique_face.type.resize(surfmesh_unique_face.l_numelem);
1698 surfmesh_unique_face.con.resize(lsize_unique_line * 2 + lsize_unique_tri * 3 + lsize_unique_quad * 4);
1701 std::cout <<
"surfmesh_unique_face.g_numelem: " << surfmesh_unique_face.g_numelem <<std::endl;
1702 std::cout <<
"surfmesh_unique_face.l_numelem: " << surfmesh_unique_face.l_numelem <<std::endl;
1714 #ifdef EMI_DEBUG_MESH
1716 fprintf(stderr,
"RANK %d BEFORE exchange: line_hash=%zu, tri_hash=%zu, quad_hash=%zu (expected unique total=%ld)\n",
1717 rank, line_unique_face_to_elements.
size(), tri_unique_face_to_elements.
size(),
1718 quad_unique_face_to_elements.
size(), lsize_unique_line + lsize_unique_tri + lsize_unique_quad);
1726 assign_unique_first_face(line_unique_face_to_elements, mesh.comm);
1727 assign_unique_first_face(tri_unique_face_to_elements, mesh.comm);
1728 assign_unique_first_face(quad_unique_face_to_elements, mesh.comm);
1732 #ifdef EMI_DEBUG_MESH
1734 int valid_line = 0, valid_tri = 0, valid_quad = 0;
1735 for (
const auto& [key, val] : line_unique_face_to_elements) {
1736 if (val.first.index_unique >= 0 || val.second.index_unique >= 0) valid_line++;
1738 for (
const auto& [key, val] : tri_unique_face_to_elements) {
1739 if (val.first.index_unique >= 0 || val.second.index_unique >= 0) valid_tri++;
1741 for (
const auto& [key, val] : quad_unique_face_to_elements) {
1742 if (val.first.index_unique >= 0 || val.second.index_unique >= 0) valid_quad++;
1744 fprintf(stderr,
"RANK %d AFTER exchange: line_hash=%zu, tri_hash=%zu, quad_hash=%zu\n",
1745 rank, line_unique_face_to_elements.size(), tri_unique_face_to_elements.size(),
1746 quad_unique_face_to_elements.size());
1747 fprintf(stderr,
"RANK %d VALID entries (index_unique>=0): line=%d, tri=%d, quad=%d\n",
1748 rank, valid_line, valid_tri, valid_quad);
1756 for(
auto it = line_unique_face_to_elements.begin(); it != line_unique_face_to_elements.end(); ++it) {
1758 auto& first = it->second.first;
1759 auto& second = it->second.second;
1761 assign_map_between_elem_oneface_and_elem_uniqueFace(rank, first, second, map_elem_uniqueFace_to_elem_oneface, map_elem_oneface_to_elem_uniqueFace);
1764 for(
auto it = tri_unique_face_to_elements.begin(); it != tri_unique_face_to_elements.end(); ++it) {
1765 auto& first = it->second.first;
1766 auto& second = it->second.second;
1768 assign_map_between_elem_oneface_and_elem_uniqueFace(rank, first, second, map_elem_uniqueFace_to_elem_oneface, map_elem_oneface_to_elem_uniqueFace);
1771 for(
auto it = quad_unique_face_to_elements.begin(); it != quad_unique_face_to_elements.end(); ++it) {
1772 auto& first = it->second.first;
1773 auto& second = it->second.second;
1775 assign_map_between_elem_oneface_and_elem_uniqueFace(rank, first, second, map_elem_uniqueFace_to_elem_oneface, map_elem_oneface_to_elem_uniqueFace);
1788 template<
class T>
inline
1790 std::pair<emi_face<T,tuple<T>>, emi_face<T,tuple<T>>>> & line_face,
1792 std::pair<emi_face<T,triple<T>>, emi_face<T,triple<T>>>> & tri_face,
1794 std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>>> & quad_face,
1800 MPI_Comm_size(comm, &size);
1801 MPI_Comm_rank(comm, &rank);
1804 for(
const auto & v : line_face) {
1807 if(v.second.first.rank == v.second.second.rank){
1811 emi_face<T,tuple<T>> surf_neighbor =
1812 (v.second.first.rank != rank) ? v.second.first : v.second.second;
1815 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1816 Index_tag_old = std::make_pair(surf_neighbor.points.v1,surf_neighbor.tag);
1817 map_vertex_tag_to_dof.insert({Index_tag_old,-1});
1821 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1822 Index_tag_old = std::make_pair(surf_neighbor.points.v2,surf_neighbor.tag);
1823 map_vertex_tag_to_dof.insert({Index_tag_old,-1});
1828 for(
const auto & v : tri_face) {
1831 if(v.second.first.rank == v.second.second.rank){
1835 emi_face<T,triple<T>> surf_neighbor =
1836 (v.second.first.rank != rank) ? v.second.first : v.second.second;
1839 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1840 Index_tag_old = std::make_pair(surf_neighbor.points.v1,surf_neighbor.tag);
1841 map_vertex_tag_to_dof.insert({Index_tag_old,-1});
1845 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1846 Index_tag_old = std::make_pair(surf_neighbor.points.v2,surf_neighbor.tag);
1847 map_vertex_tag_to_dof.insert({Index_tag_old,-1});
1851 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1852 Index_tag_old = std::make_pair(surf_neighbor.points.v3,surf_neighbor.tag);
1853 map_vertex_tag_to_dof.insert({Index_tag_old,-1});
1858 for(
const auto & v : quad_face) {
1861 if(v.second.first.rank == v.second.second.rank){
1865 emi_face<T,quadruple<T>> qsurf_neighbor =
1866 (v.second.first.rank != rank) ? v.second.first : v.second.second;
1869 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1870 Index_tag_old = std::make_pair(qsurf_neighbor.points.v1,qsurf_neighbor.tag);
1871 map_vertex_tag_to_dof.insert({Index_tag_old,-1});
1875 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1876 Index_tag_old = std::make_pair(qsurf_neighbor.points.v2,qsurf_neighbor.tag);
1877 map_vertex_tag_to_dof.insert({Index_tag_old,-1});
1881 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1882 Index_tag_old = std::make_pair(qsurf_neighbor.points.v3,qsurf_neighbor.tag);
1883 map_vertex_tag_to_dof.insert({Index_tag_old,-1});
1887 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1888 Index_tag_old = std::make_pair(qsurf_neighbor.points.v4,qsurf_neighbor.tag);
1889 map_vertex_tag_to_dof.insert({Index_tag_old,-1});
1894 assign_dof_on_counter_face(map_vertex_tag_to_dof,comm);
1926 template<
class T,
class S>
inline
1927 void compute_map_vertex_to_dof(meshdata<T,S> & mesh,
1934 MPI_Comm comm = mesh.comm;
1936 MPI_Comm_size(comm, &size);
1937 MPI_Comm_rank(comm, &rank);
1941 const T* con = mesh.con.data();
1942 const T* nbr = mesh.get_numbering(numbering).data();
1947 for(
size_t i=0; i<mesh.con.size(); i++)
1949 g2ptsData[rnod[con[i]]] = vertex2ptsdata[rnod[con[i]]];
1961 for(
size_t eidx = 0; eidx < mesh.l_numelem; eidx++)
1963 T tag = mesh.tag[eidx];
1964 auto pos_extra = extra_tags.
find(tag);
1965 for (
int n = mesh.dsp[eidx]; n < mesh.dsp[eidx+1];n++)
1967 T gIndex = rnod[con[n]];
1968 T data_on_gIndex = g2ptsData[rnod[con[n]]];
1972 if((pos_extra != extra_tags.
end()) || data_on_gIndex==0){
1973 std::pair <mesh_int_t,mesh_int_t> Index_tag_old = std::make_pair(gIndex,tag);
1974 if (map_vertex_tag_to_dof.find(Index_tag_old) == map_vertex_tag_to_dof.end() )
1976 map_vertex_tag_to_dof.insert({Index_tag_old,gIndex});
1981 auto it = map_vertex_to_tags_data_ranks.
find(gIndex);
1982 if (it != map_vertex_to_tags_data_ranks.
end() )
1984 intersection_data& value = it->second;
1985 bool check_tag_rank =
true;
1986 for(
int i=0; i<MAX_INTERSECTIONS; ++i) {
1987 if(value.tags[i] == tag && value.ranks[i] == rank) {
1988 check_tag_rank =
false;
1995 for(
int i=0; i<MAX_INTERSECTIONS; ++i) {
1996 if(value.tags[i] == -1 && value.ranks[i] == -1) {
1997 value.tags[i] = tag;
1998 value.data[i] = data_on_gIndex;
1999 value.ranks[i] = rank;
2008 intersection_data value;
2009 value.tags[0] = tag;
2010 value.data[0] = data_on_gIndex;
2011 value.ranks[0] = rank;
2012 map_vertex_to_tags_data_ranks.
insert({gIndex,value});
2028 assign_counter_vertices_tuple(map_vertex_to_tags_data_ranks, comm);
2045 for(
const auto & key : map_vertex_to_tags_data_ranks)
2047 T gIndex = key.first;
2048 const intersection_data& value = key.second;
2049 T data_on_gIndex = g2ptsData[gIndex];
2052 int first_index = 0;
2053 for (
int i = 0; i < MAX_INTERSECTIONS; ++i) {
2054 if(value.tags[i] == -1 && value.ranks[i] == -1) {
2059 if(value.data[i]!=data_on_gIndex)
2063 "WARN: Due to an inconsistency in ptsData computation at gIndex %lld with tag %lld, "
2064 "the program is stopped while preparing the data structure to introduce DOFs.\n",
2065 static_cast<long long>(gIndex),
static_cast<long long>(value.tags[i]));
2066 fprintf(stderr,
"\n");
2070 if (i == MAX_INTERSECTIONS -1) first_index = MAX_INTERSECTIONS;
2073 if(data_on_gIndex==1){
2075 int count_intra_tags = 0;
2076 int count_extra_tags = 0;
2077 for (
int i = 0; i < first_index; ++i) {
2078 if(value.tags[i]!=-1 && extra_tags.
find(value.tags[i])==extra_tags.
end()){
2079 count_intra_tags += 1;
2080 }
else if(value.tags[i]!=-1 && extra_tags.
find(value.tags[i])!=extra_tags.
end()){
2081 count_extra_tags += 1;
2087 if(count_intra_tags>1 || count_extra_tags == 0)
2091 "WARN: Due to an issue in defining ptsData for gIndex %lld, , on the membrane"
2092 "the program is stopped while preparing the data structure to introduce DOFs.\n",
2093 static_cast<long long>(gIndex));
2094 fprintf(stderr,
"\n");
2098 int index_intra = -1;
2100 for (
int i = 0; i < first_index; ++i) {
2101 if(value.tags[i]!=-1 && extra_tags.
find(value.tags[i])==extra_tags.
end()){
2106 if(index_intra == -1) {
2107 fprintf(stderr,
"WARN: unhandled case in membrane while decoupling: gIndex %lld",
2108 static_cast<long long>(gIndex));
2109 fprintf(stderr,
"\n");
2112 if(index_intra != -1) {
2113 T tag_myocyte = value.tags[index_intra];
2114 T rank_myocyte = value.ranks[index_intra];
2116 if(rank_myocyte == rank) {
2117 std::pair <mesh_int_t,mesh_int_t> Index_tag_next = std::make_pair(gIndex,tag_myocyte);
2118 if (map_mark_new_dofs.
find(Index_tag_next) == map_mark_new_dofs.
end()) {
2119 map_mark_new_dofs.
insert({Index_tag_next,
true});
2125 else if(data_on_gIndex==2){
2127 int count_intra_tags = 0;
2128 int count_extra_tags = 0;
2129 for (
int i = 0; i < first_index; ++i) {
2130 if(value.tags[i]!=-1 && extra_tags.
find(value.tags[i])==extra_tags.
end()){
2131 count_intra_tags += 1;
2132 }
else if(value.tags[i]!=-1 && extra_tags.
find(value.tags[i])!=extra_tags.
end()){
2133 count_extra_tags += 1;
2136 if(count_intra_tags!=2 || count_extra_tags != 0){
2139 "WARN: Due to an issue in defining ptsData for gIndex %lld, on the gapjunction"
2140 "the program is stopped while preparing the data structure to introduce DOFs.\n",
2141 static_cast<long long>(gIndex));
2142 fprintf(stderr,
"\n");
2150 bool tag1_checked =
false;
2151 bool tag2_checked =
false;
2153 for (
int i = 0; i < first_index; ++i)
2155 auto pos_extra = extra_tags.
find(value.tags[i]);
2156 if(pos_extra == extra_tags.
end()) {
2158 tag1 = value.tags[i];
2159 rank1 = value.ranks[i];
2160 tag1_checked =
true;
2162 tag2 = value.tags[i];
2163 rank2 = value.ranks[i];
2164 tag2_checked =
true;
2170 if(!tag1_checked && !tag2_checked || (rank1==rank2 && rank1!=rank) ) {
2172 "WARN: unhandled case in gap junction while decoupling: gIndex %lld with tags %lld:%lld ",
2173 static_cast<long long>(gIndex),
2174 static_cast<long long>(tag1),
2175 static_cast<long long>(tag2));
2176 fprintf(stderr,
"\n");
2180 if(rank1==rank2 && (rank1 == rank)){
2181 T smallest_tag = tag1 < tag2? tag1:tag2;
2182 std::pair <mesh_int_t,mesh_int_t> Index_tag_old = std::make_pair(gIndex,smallest_tag);
2183 if (map_vertex_tag_to_dof.find(Index_tag_old) == map_vertex_tag_to_dof.end() ) {
2184 map_vertex_tag_to_dof.insert({Index_tag_old,gIndex});
2187 T bigger_tag = tag1 < tag2? tag2:tag1;
2188 std::pair <mesh_int_t,mesh_int_t> Index_tag_new = std::make_pair(gIndex,bigger_tag);
2189 if (map_mark_new_dofs.
find(Index_tag_new) == map_mark_new_dofs.
end() ) {
2190 map_mark_new_dofs.
insert({Index_tag_new,
true});
2194 else if(rank1!=rank2 && (rank1 == rank)) {
2196 std::pair <mesh_int_t,mesh_int_t> Index_tag_old = std::make_pair(gIndex,tag1);
2197 if (map_vertex_tag_to_dof.find(Index_tag_old) == map_vertex_tag_to_dof.end() ) {
2198 map_vertex_tag_to_dof.insert({Index_tag_old,gIndex});
2201 std::pair <mesh_int_t,mesh_int_t> Index_tag_new = std::make_pair(gIndex,tag1);
2202 if (map_mark_new_dofs.
find(Index_tag_new) == map_mark_new_dofs.
end() ) {
2203 map_mark_new_dofs.
insert({Index_tag_new,
true});
2208 else if(rank1!=rank2 && (rank2 == rank)) {
2210 std::pair <mesh_int_t,mesh_int_t> Index_tag_old = std::make_pair(gIndex,tag2);
2211 if (map_vertex_tag_to_dof.find(Index_tag_old) == map_vertex_tag_to_dof.end() ) {
2212 map_vertex_tag_to_dof.insert({Index_tag_old,gIndex});
2215 std::pair <mesh_int_t,mesh_int_t> Index_tag_new = std::make_pair(gIndex,tag2);
2216 if (map_mark_new_dofs.
find(Index_tag_new) == map_mark_new_dofs.
end() ) {
2217 map_mark_new_dofs.
insert({Index_tag_new,
true});
2223 else if(data_on_gIndex==3)
2226 int count_intra_tags = 0;
2227 int count_extra_tags = 0;
2228 for (
int i = 0; i < first_index; ++i) {
2229 if(value.tags[i]!=-1 && extra_tags.
find(value.tags[i])==extra_tags.
end()){
2230 count_intra_tags += 1;
2231 }
else if(value.tags[i]!=-1 && extra_tags.
find(value.tags[i])!=extra_tags.
end()){
2232 count_extra_tags += 1;
2235 if(count_intra_tags!=2 || count_extra_tags == 0){
2238 "WARN: Due to an issue in defining ptsData for gIndex %lld, on intersection between membrane and gapjunction"
2239 "the program is stopped while preparing the data structure to introduce DOFs.\n",
2240 static_cast<long long>(gIndex));
2241 fprintf(stderr,
"\n");
2247 for (
int i = 0; i < first_index; ++i) {
2249 auto pos_extra = extra_tags.
find(value.tags[i]);
2250 if(value.tags[i]!=-1 && value.ranks[i] == rank && pos_extra == extra_tags.
end()) {
2251 std::pair <mesh_int_t,mesh_int_t> Index_tag_new = std::make_pair(gIndex,value.tags[i]);
2252 if (map_mark_new_dofs.
find(Index_tag_new) == map_mark_new_dofs.
end() )
2254 map_mark_new_dofs.
insert({Index_tag_new,
true});
2262 vector<T> dsp_dof(size);
2263 MPI_Allgather(&shift,
sizeof(T), MPI_BYTE, dsp_dof.data(),
sizeof(T), MPI_BYTE, comm);
2279 for (
int r = 0; r < rank; ++r)
2280 start += dsp_dof[r];
2283 auto lexicographic_comp_pair = [](
const std::pair<mesh_int_t,mesh_int_t> & a,
const std::pair<mesh_int_t,mesh_int_t> & b)
2285 if (a.second == b.second)
return a.first < b.first;
2286 return a.second < b.second;
2289 map_mark_new_dofs.
sort(lexicographic_comp_pair);
2291 for(
const auto & entry : map_mark_new_dofs)
2293 T newIndex = start+
count;
2294 map_vertex_tag_to_dof.insert({entry.first,newIndex});
2310 template<
class K,
class IntersectionIndices>
inline
2313 size_t dsize = map.
size();
2314 vector<K> key_vec(dsize);
2315 vector<IntersectionIndices> value_vec(dsize);
2316 IntersectionIndices indices;
2318 for (
const auto& v : map) {
2319 key_vec[idx] = v.first;
2320 value_vec[idx] = v.second;
2324 vector<int> perm, dest;
2325 emi_select_merge_destinations(key_vec, dsize,
sizeof(K) +
sizeof(intersection_indices), dest, comm,
2326 "assign_counter_dofs",
2329 commgraph<size_t> grph;
2330 grph.configure(dest, comm);
2331 size_t nrecv =
sum(grph.rcnt);
2337 vector<K> sbuff_key(dsize), rbuff_key(nrecv);
2338 vector<IntersectionIndices> sbuff_value(dsize), ibuff_value(dsize), rbuff_value(nrecv);
2339 for (
size_t i = 0; i < dsize; i++) {
2340 sbuff_key[i] = key_vec[perm[i]];
2341 sbuff_value[i] = value_vec[perm[i]];
2347 for (
size_t i = 0; i < nrecv; i++)
2349 auto it = rmap.
find(rbuff_key[i]);
2350 if (it != rmap.
end())
2352 IntersectionIndices& map_indices = it->second;
2353 IntersectionIndices& received_indices = rbuff_value[i];
2355 for (
mesh_int_t received_index : received_indices.indices)
2357 if (received_index == -1)
continue;
2359 for (
mesh_int_t map_index : map_indices.indices)
2361 if (map_index == received_index) {
2368 for (
size_t k = 0; k < MAX_INTERSECTIONS; ++k) {
2369 if (map_indices.indices[k] == -1) {
2370 map_indices.indices[k] = received_index;
2379 rmap.
insert({ rbuff_key[i], rbuff_value[i] });
2383 for (
size_t i = 0; i < nrecv; i++) {
2384 auto it = rmap.
find(rbuff_key[i]);
2385 if (it != rmap.
end()) rbuff_value[i] = it->second;
2392 for (
size_t i = 0; i < dsize; i++) {
2393 auto it = map.find(sbuff_key[i]);
2394 if (it != map.end()) it->second = ibuff_value[i];
2407 template<
class T,
class S>
inline
2408 void update_emi_mesh_with_dofs(meshdata<T,S> & mesh,
2416 MPI_Comm comm = mesh.comm;
2417 mesh.globalize(numbering);
2418 for(
size_t eidx = 0; eidx < mesh.l_numelem; eidx++) {
2419 T tag = mesh.tag[eidx];
2420 T size_elem = mesh.dsp[eidx+1]-mesh.dsp[eidx];
2422 for (
int n = mesh.dsp[eidx]; n < mesh.dsp[eidx+1];n++)
2424 T gIndex = mesh.con[n];
2426 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2427 Index_tag_old = std::make_pair(gIndex,tag);
2429 auto it_new = map_vertex_tag_to_dof.find(Index_tag_old);
2430 if (it_new != map_vertex_tag_to_dof.end() )
2433 dof2vertex.
insert({dof_new, gIndex});
2434 mesh.con[n] = dof_new;
2436 auto it = vertex2dof.
find(gIndex);
2437 if (it != vertex2dof.
end())
2439 intersection_indices& indices = it->second;
2441 for(T t : indices.indices) {
2449 for(
size_t i=0; i<MAX_INTERSECTIONS; ++i) {
2450 if(indices.indices[i] == -1) {
2451 indices.indices[i] = dof_new;
2457 intersection_indices indices;
2458 indices.indices[0] = dof_new;
2459 vertex2dof.
insert({gIndex,indices});
2465 assign_counter_dofs(vertex2dof, comm);
2468 for (
const auto& [old_idx, indices] : vertex2dof) {
2470 if (new_idx != -1) {
2472 if (dof2vertex.
find(new_idx) == dof2vertex.
end()) {
2473 dof2vertex.
insert({new_idx, old_idx});
2479 mesh.localize(numbering);
2495 template<
class T,
class S>
inline
2496 void update_map_indices_to_petsc(meshdata<T,S> & mesh,
2497 const SF_nbr numbering_ref,
const SF_nbr numbering_petsc,
2500 std::pair<mesh_int_t,mesh_int_t>> & map_vertex_tag_to_dof_petsc,
2504 const SF::vector<T> & ref_nbr = mesh.get_numbering(numbering_ref);
2505 const SF::vector<T> & petsc_nbr = mesh.get_numbering(numbering_petsc);
2507 elemTag_emi_mesh.
resize(mesh.l_numelem);
2508 for(
size_t eidx = 0; eidx < mesh.l_numelem; eidx++) {
2509 T tag = mesh.tag[eidx];
2510 elemTag_emi_mesh[eidx] = 1;
2511 if(extra_tags.
find(tag) == extra_tags.
end())
2512 elemTag_emi_mesh[eidx] = 2;
2513 for (
int n = mesh.dsp[eidx]; n < mesh.dsp[eidx+1];n++)
2515 T l_Indx = mesh.con[n];
2516 T petsc_Idx = petsc_nbr[l_Indx];
2517 T n_Indx = ref_nbr[l_Indx];
2518 T o_Indx = dof2vertex[n_Indx];
2520 std::pair <mesh_int_t,mesh_int_t> oIndx_tag;
2521 oIndx_tag = std::make_pair(o_Indx,tag);
2523 auto it_new = map_vertex_tag_to_dof_petsc.find(oIndx_tag);
2524 if (it_new != map_vertex_tag_to_dof_petsc.end() )
2526 std::pair <mesh_int_t,mesh_int_t> nIndx_petsc;
2527 nIndx_petsc = std::make_pair(n_Indx,petsc_Idx);
2529 (*it_new).second = nIndx_petsc;
2546 template<
class T,
class S>
2547 inline void update_faces_on_surface_mesh_after_decoupling_with_dofs(meshdata<T, S> & mesh,
2551 std::pair<emi_face<T,tuple<T>>, emi_face<T,tuple<T>>>> & line_face,
2553 std::pair<emi_face<T,triple<T>>, emi_face<T,triple<T>>>> & tri_face,
2555 std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>>> & quad_face)
2559 MPI_Comm_size(comm, &size); MPI_Comm_rank(comm, &rank);
2566 for(
size_t i=0; i<idxbuff.size(); i++){
2567 g2l[idxbuff[i]] = i;
2568 l2g[i] = idxbuff[i];
2571 for(
size_t eidx = 0; eidx < mesh.l_numelem; eidx++) {
2572 T tag = mesh.tag[eidx];
2573 T size_elem = mesh.dsp[eidx+1]-mesh.dsp[eidx];
2574 std::vector<mesh_int_t> elem_nodes;
2575 for (
int n = mesh.dsp[eidx]; n < mesh.dsp[eidx+1];n++)
2577 T gIndex = mesh.con[n];
2578 elem_nodes.push_back(gIndex);
2580 std::sort(elem_nodes.begin(),elem_nodes.end());
2581 if(elem_nodes.size()==2){
2583 key.v1 = elem_nodes[0];
2584 key.v2 = elem_nodes[1];
2585 std::pair<emi_face<T,tuple<T>>, emi_face<T,tuple<T>>> value = line_face[key];
2587 line_face.erase(key);
2588 std::vector<mesh_int_t> new_nodes(2);
2590 auto tag_key = (value.first.rank == rank) ? value.first.tag : value.second.tag;
2592 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2593 Index_tag_old = std::make_pair(elem_nodes[0],tag_key);
2594 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2595 new_nodes[0] = Index_new;
2598 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2599 Index_tag_old = std::make_pair(elem_nodes[1],tag_key);
2600 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2601 new_nodes[1] = Index_new;
2603 std::sort(new_nodes.begin(),new_nodes.end());
2606 new_key.v1 = new_nodes[0];
2607 new_key.v2 = new_nodes[1];
2611 mesh_int_t Index_new1 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v1, value.first.tag)];
2612 mesh_int_t Index_new2 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v2, value.first.tag)];
2613 value.first.points.v1 = Index_new1;
2614 value.first.points.v2 = Index_new2;
2618 mesh_int_t Index_new1 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v1, value.second.tag)];
2619 mesh_int_t Index_new2 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v2, value.second.tag)];
2620 value.second.points.v1 = Index_new1;
2621 value.second.points.v2 = Index_new2;
2623 line_face.insert({new_key,value});
2625 if(elem_nodes.size()==3){
2627 key.v1 = elem_nodes[0];
2628 key.v2 = elem_nodes[1];
2629 key.v3 = elem_nodes[2];
2630 std::pair<emi_face<T,triple<T>>, emi_face<T,triple<T>>> value = tri_face[key];
2631 tri_face.erase(key);
2632 std::vector<mesh_int_t> new_nodes(3);
2634 auto tag_key = (value.first.rank == rank) ? value.first.tag : value.second.tag;
2636 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2637 Index_tag_old = std::make_pair(elem_nodes[0],tag_key);
2638 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2639 new_nodes[0] = Index_new;
2642 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2643 Index_tag_old = std::make_pair(elem_nodes[1],tag_key);
2644 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2645 new_nodes[1] = Index_new;
2648 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2649 Index_tag_old = std::make_pair(elem_nodes[2],tag_key);
2650 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2651 new_nodes[2] = Index_new;
2653 std::sort(new_nodes.begin(),new_nodes.end());
2656 new_key.v1 = new_nodes[0];
2657 new_key.v2 = new_nodes[1];
2658 new_key.v3 = new_nodes[2];
2662 mesh_int_t Index_new1 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v1, value.first.tag)];
2663 mesh_int_t Index_new2 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v2, value.first.tag)];
2664 mesh_int_t Index_new3 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v3, value.first.tag)];
2665 value.first.points.v1 = Index_new1;
2666 value.first.points.v2 = Index_new2;
2667 value.first.points.v3 = Index_new3;
2671 mesh_int_t Index_new1 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v1, value.second.tag)];
2672 mesh_int_t Index_new2 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v2, value.second.tag)];
2673 mesh_int_t Index_new3 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v3, value.second.tag)];
2674 value.second.points.v1 = Index_new1;
2675 value.second.points.v2 = Index_new2;
2676 value.second.points.v3 = Index_new3;
2678 tri_face.insert({new_key,value});
2680 if(elem_nodes.size()==4){
2682 key.v1 = elem_nodes[0];
2683 key.v2 = elem_nodes[1];
2684 key.v3 = elem_nodes[2];
2685 key.v4 = elem_nodes[3];
2686 std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>> value = quad_face[key];
2687 quad_face.erase(key);
2688 std::vector<mesh_int_t> new_nodes(4);
2690 auto tag_key = (value.first.rank == rank) ? value.first.tag : value.second.tag;
2692 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2693 Index_tag_old = std::make_pair(elem_nodes[0],tag_key);
2694 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2695 new_nodes[0] = Index_new;
2698 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2699 Index_tag_old = std::make_pair(elem_nodes[1],tag_key);
2700 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2701 new_nodes[1] = Index_new;
2704 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2705 Index_tag_old = std::make_pair(elem_nodes[2],tag_key);
2706 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2707 new_nodes[2] = Index_new;
2710 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2711 Index_tag_old = std::make_pair(elem_nodes[3],tag_key);
2712 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2713 new_nodes[3] = Index_new;
2715 std::sort(new_nodes.begin(),new_nodes.end());
2717 quadruple<T> new_key;
2718 new_key.v1 = new_nodes[0];
2719 new_key.v2 = new_nodes[1];
2720 new_key.v3 = new_nodes[2];
2721 new_key.v4 = new_nodes[3];
2725 mesh_int_t Index_new1 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v1, value.first.tag)];
2726 mesh_int_t Index_new2 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v2, value.first.tag)];
2727 mesh_int_t Index_new3 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v3, value.first.tag)];
2728 mesh_int_t Index_new4 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v4, value.first.tag)];
2729 value.first.points.v1 = Index_new1;
2730 value.first.points.v2 = Index_new2;
2731 value.first.points.v3 = Index_new3;
2732 value.first.points.v4 = Index_new4;
2736 mesh_int_t Index_new1 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v1, value.second.tag)];
2737 mesh_int_t Index_new2 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v2, value.second.tag)];
2738 mesh_int_t Index_new3 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v3, value.second.tag)];
2739 mesh_int_t Index_new4 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v4, value.second.tag)];
2740 value.second.points.v1 = Index_new1;
2741 value.second.points.v2 = Index_new2;
2742 value.second.points.v3 = Index_new3;
2743 value.second.points.v4 = Index_new4;
2745 quad_face.insert({new_key,value});
2761 template<
class T,
class S>
inline
2762 void compute_surface_mesh_with_counter_face(meshdata<T, S> & mesh,
const SF_nbr numbering,
2764 std::pair<emi_face<T,tuple<T>>, emi_face<T,tuple<T>>>> & line_face,
2766 std::pair<emi_face<T,triple<T>>, emi_face<T,triple<T>>>> & tri_face,
2768 std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>>> & quad_face)
2770 mesh.register_numbering(numbering);
2774 MPI_Comm_size(comm, &size);
2775 MPI_Comm_rank(comm, &rank);
2778 vector<tuple<T>> line_keys;
2779 for(
auto const& [key, val] : line_face) line_keys.push_back(key);
2780 std::sort(line_keys.begin(), line_keys.end());
2782 vector<triple<T>> tri_keys;
2783 for(
auto const& [key, val] : tri_face) tri_keys.push_back(key);
2784 std::sort(tri_keys.begin(), tri_keys.end());
2786 vector<quadruple<T>> quad_keys;
2787 for(
auto const& [key, val] : quad_face) quad_keys.push_back(key);
2788 std::sort(quad_keys.begin(), quad_keys.end());
2790 vector<T> cnt(mesh.l_numelem);
2791 size_t idx = 0, cidx = 0;
2796 for(
const auto & key : line_keys) {
2797 const auto & v = line_face.at(key);
2798 bool both_faces = (v.first.rank == v.second.rank) ?
true:
false;
2802 emi_face<T,tuple<T>> surf_first;
2803 emi_face<T,tuple<T>> surf_second;
2804 if(v.first.rank == rank)
2806 surf_first = v.first;
2807 surf_second = v.second;
2811 surf_first = v.second;
2812 surf_second = v.first;
2815 mesh.type[idx] =
Line;
2816 mesh.tag[idx] = surf_first.tag;
2817 mesh.con[cidx + 0] = surf_first.points.v1;
2818 mesh.con[cidx + 1] = surf_first.points.v2;
2825 mesh.type[idx] =
Line;
2826 mesh.tag[idx] = surf_second.tag;
2827 mesh.con[cidx + 0] = surf_second.points.v1;
2828 mesh.con[cidx + 1] = surf_second.points.v2;
2835 for(
const auto & key : tri_keys) {
2836 const auto & v = tri_face.at(key);
2837 bool both_faces = (v.first.rank == v.second.rank) ?
true:
false;
2841 emi_face<T,triple<T>> surf_first;
2842 emi_face<T,triple<T>> surf_second;
2843 if(v.first.rank == rank)
2845 surf_first = v.first;
2846 surf_second = v.second;
2850 surf_first = v.second;
2851 surf_second = v.first;
2854 mesh.type[idx] =
Tri;
2855 mesh.tag[idx] = surf_first.tag;
2856 mesh.con[cidx + 0] = surf_first.points.v1;
2857 mesh.con[cidx + 1] = surf_first.points.v2;
2858 mesh.con[cidx + 2] = surf_first.points.v3;
2867 mesh.type[idx] =
Tri;
2868 mesh.tag[idx] = surf_second.tag;
2869 mesh.con[cidx + 0] = surf_second.points.v1;
2870 mesh.con[cidx + 1] = surf_second.points.v2;
2871 mesh.con[cidx + 2] = surf_second.points.v3;
2878 for(
const auto & key : quad_keys) {
2879 const auto & v = quad_face.at(key);
2880 bool both_faces = (v.first.rank == v.second.rank) ?
true:
false;
2883 emi_face<T,quadruple<T>> surf_first;
2884 emi_face<T,quadruple<T>> surf_second;
2885 if(v.first.rank == rank)
2887 surf_first = v.first;
2888 surf_second = v.second;
2892 surf_first = v.second;
2893 surf_second = v.first;
2896 mesh.type[idx] =
Quad;
2897 mesh.tag[idx] = surf_first.tag;
2898 mesh.con[cidx + 0] = surf_first.points.v1;
2899 mesh.con[cidx + 1] = surf_first.points.v2;
2900 mesh.con[cidx + 2] = surf_first.points.v3;
2901 mesh.con[cidx + 3] = surf_first.points.v4;
2910 mesh.type[idx] =
Quad;
2911 mesh.tag[idx] = surf_second.tag;
2912 mesh.con[cidx + 0] = surf_second.points.v1;
2913 mesh.con[cidx + 1] = surf_second.points.v2;
2914 mesh.con[cidx + 2] = surf_second.points.v3;
2915 mesh.con[cidx + 3] = surf_second.points.v4;
2955 template<
class T,
class S>
inline
2956 void compute_surface_mesh_with_unique_face(meshdata<T, S> & mesh,
const SF_nbr numbering,
2958 std::pair<emi_face<T,tuple<T>>, emi_face<T,tuple<T>>>> & line_face,
2960 std::pair<emi_face<T,triple<T>>, emi_face<T,triple<T>>>> & tri_face,
2962 std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>>> & quad_face,
2965 mesh.register_numbering(numbering);
2969 MPI_Comm_size(comm, &size);
2970 MPI_Comm_rank(comm, &rank);
2973 vector<tuple<T>> line_keys;
2974 for(
auto const& [key, val] : line_face) line_keys.push_back(key);
2975 std::sort(line_keys.begin(), line_keys.end());
2977 vector<triple<T>> tri_keys;
2978 for(
auto const& [key, val] : tri_face) tri_keys.push_back(key);
2979 std::sort(tri_keys.begin(), tri_keys.end());
2981 vector<quadruple<T>> quad_keys;
2982 for(
auto const& [key, val] : quad_face) quad_keys.push_back(key);
2983 std::sort(quad_keys.begin(), quad_keys.end());
2985 vector<T> cnt(mesh.l_numelem);
2986 size_t idx = 0, cidx = 0;
2991 for(
const auto & key : line_keys) {
2992 const auto & v = line_face.at(key);
2994 bool to_take_face =
false;
2996 emi_face<T,tuple<T>> surf_take;
2997 std::pair <mesh_int_t,mesh_int_t> tag_pairs_take;
2999 if(v.first.rank == rank && v.first.mark_to_take ==
true)
3001 surf_take = v.first;
3002 to_take_face =
true;
3003 tag_pairs_take = std::make_pair(v.first.tag,v.second.tag);
3005 else if(v.second.rank == rank && v.second.mark_to_take ==
true)
3007 surf_take = v.second;
3008 to_take_face =
true;
3009 tag_pairs_take = std::make_pair(v.second.tag,v.first.tag);
3014 map_elem_uniqueFace_to_tags.insert({idx,tag_pairs_take});
3016 mesh.type[idx] =
Line;
3017 mesh.tag[idx] = surf_take.tag;
3018 mesh.con[cidx + 0] = surf_take.points.v1;
3019 mesh.con[cidx + 1] = surf_take.points.v2;
3026 for(
const auto & key : tri_keys) {
3027 const auto & v = tri_face.at(key);
3029 bool to_take_face =
false;
3031 emi_face<T,triple<T>> surf_take;
3032 std::pair <mesh_int_t,mesh_int_t> tag_pairs_take;
3034 if(v.first.rank == rank && v.first.mark_to_take ==
true)
3036 surf_take = v.first;
3037 to_take_face =
true;
3038 tag_pairs_take = std::make_pair(v.first.tag,v.second.tag);
3040 else if(v.second.rank == rank && v.second.mark_to_take ==
true)
3042 surf_take = v.second;
3043 to_take_face =
true;
3044 tag_pairs_take = std::make_pair(v.second.tag,v.first.tag);
3049 map_elem_uniqueFace_to_tags.insert({idx,tag_pairs_take});
3051 mesh.type[idx] =
Tri;
3052 mesh.tag[idx] = surf_take.tag;
3053 mesh.con[cidx + 0] = surf_take.points.v1;
3054 mesh.con[cidx + 1] = surf_take.points.v2;
3055 mesh.con[cidx + 2] = surf_take.points.v3;
3063 for(
const auto & key : quad_keys) {
3064 const auto & v = quad_face.at(key);
3066 bool to_take_face =
false;
3068 emi_face<T,quadruple<T>> surf_take;
3069 std::pair <mesh_int_t,mesh_int_t> tag_pairs_take;
3071 if(v.first.rank == rank && v.first.mark_to_take ==
true)
3073 surf_take = v.first;
3074 to_take_face =
true;
3075 tag_pairs_take = std::make_pair(v.first.tag,v.second.tag);
3077 else if(v.second.rank == rank && v.second.mark_to_take ==
true)
3079 surf_take = v.second;
3080 to_take_face =
true;
3081 tag_pairs_take = std::make_pair(v.second.tag,v.first.tag);
3086 map_elem_uniqueFace_to_tags.insert({idx,tag_pairs_take});
3088 mesh.type[idx] =
Quad;
3089 mesh.tag[idx] = surf_take.tag;
3090 mesh.con[cidx + 0] = surf_take.points.v1;
3091 mesh.con[cidx + 1] = surf_take.points.v2;
3092 mesh.con[cidx + 2] = surf_take.points.v3;
3093 mesh.con[cidx + 3] = surf_take.points.v4;
3122 template<
class T>
inline
3123 void create_reverse_elem_mapping_between_surface_meshes(
3126 hashmap::unordered_map<quadruple<T>, std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>>>& quad_face,
3131 MPI_Comm_rank(comm, &rank);
3134 vector<tuple<T>> line_keys;
3135 for(
auto const& [key, val] : line_face) line_keys.push_back(key);
3136 std::sort(line_keys.begin(), line_keys.end());
3138 vector<triple<T>> tri_keys;
3139 for(
auto const& [key, val] : tri_face) tri_keys.push_back(key);
3140 std::sort(tri_keys.begin(), tri_keys.end());
3142 vector<quadruple<T>> quad_keys;
3143 for(
auto const& [key, val] : quad_face) quad_keys.push_back(key);
3144 std::sort(quad_keys.begin(), quad_keys.end());
3146 size_t surf_elem_idx = 0;
3147 size_t w_counter_elem_idx = 0;
3149 size_t lsize_line = 0;
3150 size_t lsize_tri = 0;
3151 size_t lsize_quad = 0;
3155 for(
const auto& key : line_keys) {
3156 const auto& v = line_face.at(key);
3157 const bool local_involved = (v.first.rank == rank) || (v.second.rank == rank);
3158 if (!local_involved) {
3161 if(v.first.rank == v.second.rank) lsize_line+=2;
3164 for(
const auto& key : tri_keys) {
3165 const auto& v = tri_face.at(key);
3166 const bool local_involved = (v.first.rank == rank) || (v.second.rank == rank);
3167 if (!local_involved) {
3170 if(v.first.rank == v.second.rank) lsize_tri+=2;
3173 for(
const auto& key : quad_keys) {
3174 const auto& v = quad_face.at(key);
3175 const bool local_involved = (v.first.rank == rank) || (v.second.rank == rank);
3176 if (!local_involved) {
3179 if(v.first.rank == v.second.rank) lsize_quad+=2;
3183 vec_one_to_both_face.
resize(lsize_line + lsize_tri + lsize_quad);
3187 for (
const auto& key : line_keys) {
3188 const auto& v = line_face.at(key);
3189 const bool local_involved = (v.first.rank == rank) || (v.second.rank == rank);
3190 if (!local_involved) {
3193 vec_one_to_both_face[w_counter_elem_idx++] = surf_elem_idx;
3194 if (v.first.rank == v.second.rank) {
3195 vec_one_to_both_face[w_counter_elem_idx++] = surf_elem_idx;
3200 for (
const auto& key : tri_keys) {
3201 const auto& v = tri_face.at(key);
3202 const bool local_involved = (v.first.rank == rank) || (v.second.rank == rank);
3203 if (!local_involved) {
3206 vec_one_to_both_face[w_counter_elem_idx++] = surf_elem_idx;
3207 if (v.first.rank == v.second.rank) {
3208 vec_one_to_both_face[w_counter_elem_idx++] = surf_elem_idx;
3213 for (
const auto& key : quad_keys) {
3214 const auto& v = quad_face.at(key);
3215 const bool local_involved = (v.first.rank == rank) || (v.second.rank == rank);
3216 if (!local_involved) {
3219 vec_one_to_both_face[w_counter_elem_idx++] = surf_elem_idx;
3220 if (v.first.rank == v.second.rank) {
3221 vec_one_to_both_face[w_counter_elem_idx++] = surf_elem_idx;
3235 template<
class T>
inline
3237 std::pair<emi_face<T,tuple<T>>, emi_face<T,tuple<T>>>> & line_face,
3239 std::pair<emi_face<T,triple<T>>, emi_face<T,triple<T>>>> & tri_face,
3241 std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>>> & quad_face)
3244 std::vector<std::pair<tuple<T>, std::pair<emi_face<T,tuple<T>>, emi_face<T,tuple<T>>>>> line_inserts;
3245 for(
const auto & v : line_face) {
3246 SF::emi_face<mesh_int_t,SF::tuple<mesh_int_t>> surf_first = v.second.first;
3247 SF::emi_face<mesh_int_t,SF::tuple<mesh_int_t>> surf_second = v.second.second;
3249 std::vector<mesh_int_t> elem_nodes_first; elem_nodes_first.
resize(2);
3250 std::vector<mesh_int_t> elem_nodes_second; elem_nodes_second.resize(2);
3253 elem_nodes_first[0] = surf_first.points.
v1;
3254 elem_nodes_first[1] = surf_first.points.v2;
3255 std::sort(elem_nodes_first.begin(),elem_nodes_first.end());
3256 key_first.
v1 = elem_nodes_first[0];
3257 key_first.
v2 = elem_nodes_first[1];
3260 elem_nodes_second[0] = surf_second.points.
v1;
3261 elem_nodes_second[1] = surf_second.points.v2;
3262 std::sort(elem_nodes_second.begin(),elem_nodes_second.end());
3263 key_second.
v1 = elem_nodes_second[0];
3264 key_second.
v2 = elem_nodes_second[1];
3266 const bool same_key_first = (v.first.v1 == key_first.
v1 && v.first.v2 == key_first.
v2);
3267 if (!same_key_first && line_face.find(key_first) == line_face.end()) {
3268 line_inserts.push_back({key_first, v.second});
3270 const bool same_key_second = (v.first.v1 == key_second.
v1 && v.first.v2 == key_second.
v2);
3271 if (!same_key_second && line_face.find(key_second) == line_face.end()) {
3272 line_inserts.push_back({key_second, v.second});
3275 for (
const auto & entry : line_inserts) line_face.insert(entry);
3277 std::vector<std::pair<triple<T>, std::pair<emi_face<T,triple<T>>, emi_face<T,triple<T>>>>> tri_inserts;
3278 for(
const auto & v : tri_face) {
3279 SF::emi_face<mesh_int_t,SF::triple<mesh_int_t>> surf_first = v.second.first;
3280 SF::emi_face<mesh_int_t,SF::triple<mesh_int_t>> surf_second = v.second.second;
3282 std::vector<mesh_int_t> elem_nodes_first; elem_nodes_first.resize(3);
3283 std::vector<mesh_int_t> elem_nodes_second; elem_nodes_second.resize(3);
3286 elem_nodes_first[0] = surf_first.points.
v1;
3287 elem_nodes_first[1] = surf_first.points.v2;
3288 elem_nodes_first[2] = surf_first.points.v3;
3289 std::sort(elem_nodes_first.begin(),elem_nodes_first.end());
3290 key_first.
v1 = elem_nodes_first[0];
3291 key_first.
v2 = elem_nodes_first[1];
3292 key_first.
v3 = elem_nodes_first[2];
3295 elem_nodes_second[0] = surf_second.points.
v1;
3296 elem_nodes_second[1] = surf_second.points.v2;
3297 elem_nodes_second[2] = surf_second.points.v3;
3298 std::sort(elem_nodes_second.begin(),elem_nodes_second.end());
3299 key_second.
v1 = elem_nodes_second[0];
3300 key_second.
v2 = elem_nodes_second[1];
3301 key_second.
v3 = elem_nodes_second[2];
3303 const bool same_key_first = (v.first.v1 == key_first.
v1 &&
3304 v.first.v2 == key_first.
v2 &&
3305 v.first.v3 == key_first.
v3);
3306 if (!same_key_first && tri_face.find(key_first) == tri_face.end()) {
3307 tri_inserts.push_back({key_first, v.second});
3309 const bool same_key_second = (v.first.v1 == key_second.
v1 &&
3310 v.first.v2 == key_second.
v2 &&
3311 v.first.v3 == key_second.
v3);
3312 if (!same_key_second && tri_face.find(key_second) == tri_face.end()) {
3313 tri_inserts.push_back({key_second, v.second});
3316 for (
const auto & entry : tri_inserts) tri_face.insert(entry);
3318 std::vector<std::pair<quadruple<T>, std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>>>> quad_inserts;
3319 for(
const auto & v : quad_face) {
3320 SF::emi_face<mesh_int_t,SF::quadruple<mesh_int_t>> surf_first = v.second.first;
3321 SF::emi_face<mesh_int_t,SF::quadruple<mesh_int_t>> surf_second = v.second.second;
3323 std::vector<mesh_int_t> elem_nodes_first; elem_nodes_first.resize(4);
3324 std::vector<mesh_int_t> elem_nodes_second; elem_nodes_second.resize(4);
3327 elem_nodes_first[0] = surf_first.points.
v1;
3328 elem_nodes_first[1] = surf_first.points.v2;
3329 elem_nodes_first[2] = surf_first.points.v3;
3330 elem_nodes_first[3] = surf_first.points.v4;
3331 std::sort(elem_nodes_first.begin(),elem_nodes_first.end());
3332 key_first.
v1 = elem_nodes_first[0];
3333 key_first.
v2 = elem_nodes_first[1];
3334 key_first.
v3 = elem_nodes_first[2];
3335 key_first.
v4 = elem_nodes_first[3];
3338 elem_nodes_second[0] = surf_second.points.
v1;
3339 elem_nodes_second[1] = surf_second.points.v2;
3340 elem_nodes_second[2] = surf_second.points.v3;
3341 elem_nodes_second[3] = surf_second.points.v4;
3342 std::sort(elem_nodes_second.begin(),elem_nodes_second.end());
3343 key_second.
v1 = elem_nodes_second[0];
3344 key_second.
v2 = elem_nodes_second[1];
3345 key_second.
v3 = elem_nodes_second[2];
3346 key_second.
v4 = elem_nodes_second[3];
3348 const bool same_key_first = (v.first.v1 == key_first.
v1 &&
3349 v.first.v2 == key_first.
v2 &&
3350 v.first.v3 == key_first.
v3 &&
3351 v.first.v4 == key_first.
v4);
3352 if (!same_key_first && quad_face.find(key_first) == quad_face.end()) {
3353 quad_inserts.push_back({key_first, v.second});
3355 const bool same_key_second = (v.first.v1 == key_second.
v1 &&
3356 v.first.v2 == key_second.
v2 &&
3357 v.first.v3 == key_second.
v3 &&
3358 v.first.v4 == key_second.
v4);
3359 if (!same_key_second && quad_face.find(key_second) == quad_face.end()) {
3360 quad_inserts.push_back({key_second, v.second});
3363 for (
const auto & entry : quad_inserts) quad_face.insert(entry);
3373 template<
class K>
inline
3376 size_t dsize = map.
size();
3377 vector<K> key_vec(dsize);
3378 vector<intersection_tags> value_vec(dsize);
3381 for (
const auto& v : map) {
3382 key_vec[idx] = v.first;
3383 value_vec[idx] = v.second;
3387 vector<int> perm, dest;
3388 emi_select_merge_destinations(key_vec, dsize,
sizeof(K) +
sizeof(intersection_tags), dest, comm,
3389 "assign_counter_tags",
3392 commgraph<size_t> grph;
3393 grph.configure(dest, comm);
3394 size_t nrecv =
sum(grph.rcnt);
3400 vector<K> sbuff_key(dsize), rbuff_key(nrecv);
3401 vector<intersection_tags> sbuff_value(dsize), ibuff_value(dsize), rbuff_value(nrecv);
3402 for (
size_t i = 0; i < dsize; i++) {
3403 sbuff_key[i] = key_vec[perm[i]];
3404 sbuff_value[i] = value_vec[perm[i]];
3410 for (
size_t i = 0; i < nrecv; i++)
3412 auto it = rmap.
find(rbuff_key[i]);
3413 if (it != rmap.
end())
3415 intersection_tags& map_tags = it->second;
3416 intersection_tags& r_tags = rbuff_value[i];
3418 for (
int r_tag : r_tags.tags)
3420 if (r_tag == -1)
continue;
3422 for (
int m_tag : map_tags.tags)
3424 if (m_tag == r_tag) {
3431 for (
size_t k = 0; k < MAX_INTERSECTIONS; ++k) {
3432 if (map_tags.tags[k] == -1) {
3433 map_tags.tags[k] = r_tag;
3442 rmap.
insert({ rbuff_key[i], rbuff_value[i] });
3446 for (
size_t i = 0; i < nrecv; i++) {
3447 auto it = rmap.
find(rbuff_key[i]);
3448 if (it != rmap.
end()) rbuff_value[i] = it->second;
3455 for (
size_t i = 0; i < dsize; i++) {
3456 auto it = map.find(sbuff_key[i]);
3457 if (it != map.end()) it->second = ibuff_value[i];
3482 template<
class T,
class S>
inline
3483 void compute_ptsdata_from_original_mesh(meshdata<T,S> & mesh,
3489 MPI_Comm comm = mesh.comm;
3491 MPI_Comm_size(comm, &size);
3492 MPI_Comm_rank(comm, &rank);
3494 const T* con = mesh.con.data();
3501 for(
size_t eidx = 0; eidx < mesh.l_numelem; eidx++)
3503 T tag = mesh.tag[eidx];
3504 for (
int n = mesh.dsp[eidx]; n < mesh.dsp[eidx+1];n++)
3506 T gIndex = rnod[con[n]];
3508 auto it_new = map_index_to_tags.
find(gIndex);
3509 if (it_new != map_index_to_tags.
end())
3512 intersection_tags& tags = it_new->second;
3514 for(T t : tags.tags) {
3522 for(
int i=0; i <MAX_INTERSECTIONS; ++i) {
3523 if (tags.tags[i] == -1) {
3532 intersection_tags tags;
3534 map_index_to_tags.
insert({gIndex,tags});
3542 assign_counter_tags(map_index_to_tags, comm);
3545 for(
size_t eidx = 0; eidx < mesh.l_numelem; eidx++)
3547 for (
int n = mesh.dsp[eidx]; n < mesh.dsp[eidx+1];n++)
3549 T gIndex = rnod[con[n]];
3550 intersection_tags& vec_tags = map_index_to_tags[gIndex];
3551 int count_intra_tags = 0;
3552 int count_extra_tags = 0;
3556 for(T t : vec_tags.tags) {
3557 if(intra_tags.
count(t)) count_intra_tags++;
3558 if(extra_tags.
count(t)) count_extra_tags++;
3562 if(count_extra_tags>=1 && count_intra_tags==0){
3563 vertex2ptsdata[gIndex] = 0;
3564 }
else if(count_extra_tags==0 && count_intra_tags==1){
3565 vertex2ptsdata[gIndex] = 0;
3566 }
else if(count_extra_tags>=1 && count_intra_tags==1){
3567 vertex2ptsdata[gIndex] = 1;
3568 }
else if(count_extra_tags==0 && count_intra_tags==2){
3569 vertex2ptsdata[gIndex] = 2;
3570 }
else if(count_extra_tags>=1 && count_intra_tags==2){
3571 vertex2ptsdata[gIndex] = 3;
3573 else if(count_intra_tags>2){
3575 fprintf(stderr,
"More than two intracellular are connected %lld. Tags:",
3576 static_cast<long long>(gIndex));
3577 for(T tag : vec_tags.tags)
if(tag != -1) fprintf(stderr,
" %lld",
static_cast<long long>(tag));
3578 fprintf(stderr,
"\n");
3583 fprintf(stderr,
"WARN: unhandled case in ptsData computation for gIndex %lld. Tags:",
3584 static_cast<long long>(gIndex));
3585 for(T tag : vec_tags.tags)
if(tag != -1) fprintf(stderr,
" %lld",
static_cast<long long>(tag));
3586 fprintf(stderr,
"\n");
3609 template <
class T,
class S,
class V,
class emi_index_rank>
3612 std::pair<emi_index_rank, emi_index_rank>>& map,
3619 MPI_Comm_rank(both_mesh.
comm, &rank);
3622 SF::layout_from_count<long int>(both_mesh.
l_numelem, layout_both, both_mesh.
comm);
3625 SF::layout_from_count<long int>(unique_mesh.
l_numelem, layout_unique, unique_mesh.
comm);
3631 for (
const auto& [local_unique_idx, both_pair] : map) {
3632 const auto& first_both = both_pair.first;
3633 const auto& second_both = both_pair.second;
3637 T global_unique_row = layout_unique[rank] + local_unique_idx;
3638 row_idx[0] = global_unique_row;
3641 bool first_valid = (first_both.index >= 0 && first_both.rank >= 0);
3642 bool second_valid = (second_both.index >= 0 && second_both.rank >= 0);
3644 T global_both_col_first = -1;
3645 T global_both_col_second = -1;
3647 global_both_col_first = layout_both[first_both.rank] + first_both.index;
3650 global_both_col_second = layout_both[second_both.rank] + second_both.index;
3655 if (first_valid && second_valid && global_both_col_first == global_both_col_second) {
3656 second_valid =
false;
3661 if (first_valid)
count++;
3662 if (second_valid)
count++;
3664 if (
count == 0)
continue;
3668 double weight = 0.5;
3669 if (
count == 1) weight = 1.0;
3671 ebuff.assign(1, 1, weight);
3675 col_idx[0] = global_both_col_first;
3676 op.
set_values(row_idx, col_idx, ebuff.data(),
false);
3681 col_idx[0] = global_both_col_second;
3682 op.
set_values(row_idx, col_idx, ebuff.data(),
false);
3706 inline void restrict_to_membrane(vector<T> & v,
3708 const meshdata<mesh_int_t, mesh_real_t> & mesh)
3713 for(
size_t i=0; i<rnod.
size(); i++){
3720 for(
size_t i=0; i<v.size(); i++){
3723 if (dof2ptsData[g] > 0) {
opencarp::local_index_t mesh_int_t
#define SF_COMM
the default SlimFem MPI communicator
Functions related to EMI mesh IO.
Functions handling a distributed mesh.
#define EXIT(A)
finalize the backend, if it runs, and exit
virtual void finish_assembly()=0
virtual void set_values(const vector< T > &row_idx, const vector< T > &col_idx, const vector< S > &vals, bool add)=0
The mesh storage class. It contains both element and vertex data.
size_t l_numelem
local number of elements
MPI_Comm comm
the parallel mesh is defined on a MPI world
A vector storing arbitrary data.
size_t size() const
The current size of the vector.
void resize(size_t n)
Resize a vector.
iterator find(const K &key)
Search for key. Return iterator.
void sort(Compare comp=Compare())
Sort data entries.
void insert(InputIterator first, InputIterator last)
Insert Iterator range.
T & at(const K &key)
Data access by key.
iterator find(const K &key)
hm_int count(const K &key) const
void dsp_from_cnt(const vector< T > &cnt, vector< T > &dsp)
Compute displacements from counts.
void interval(vector< T > &vec, size_t start, size_t end)
Create an integer interval between start and end.
void binary_sort_copy(vector< T > &_V, vector< S > &_W)
T sum(const vector< T > &vec)
Compute sum of a vector's entries.
void unique_resize(vector< T > &_P)
void count(const vector< T > &data, vector< S > &cnt)
Count number of occurrences of indices.
void MPI_Exchange(commgraph< T > &grph, vector< S > &send, vector< S > &recv, MPI_Comm comm)
Exchange data in parallel over MPI.
void binary_sort(vector< T > &_V)
T global_max(const vector< T > &vec, MPI_Comm comm)
Compute the global maximum of a distributed vector.
SF_nbr
Enumeration encoding the different supported numberings.
@ NBR_ELEM_REF
The element numbering of the reference mesh (the one stored on HD).
@ NBR_REF
The nodal numbering of the reference mesh (the one stored on HD).
void dsp_from_cnt(const std::vector< T > &cnt, std::vector< T > &dsp)
Compute displacements from counts.
constexpr T min(T a, T b)
constexpr T max(T a, T b)
static hm_uint hash(const T &a)