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);
2278 start = mesh.g_numpts;
2282 start = mesh.g_numpts;
2283 for (
int r = 0; r < rank; ++r)
2290 auto lexicographic_comp_pair = [](
const std::pair<mesh_int_t,mesh_int_t> & a,
const std::pair<mesh_int_t,mesh_int_t> & b)
2292 if (a.second == b.second)
return a.first < b.first;
2293 return a.second < b.second;
2296 map_mark_new_dofs.
sort(lexicographic_comp_pair);
2298 for(
const auto & entry : map_mark_new_dofs)
2300 T newIndex = start+
count;
2301 map_vertex_tag_to_dof.insert({entry.first,newIndex});
2317 template<
class K,
class IntersectionIndices>
inline
2320 size_t dsize = map.
size();
2321 vector<K> key_vec(dsize);
2322 vector<IntersectionIndices> value_vec(dsize);
2323 IntersectionIndices indices;
2325 for (
const auto& v : map) {
2326 key_vec[idx] = v.first;
2327 value_vec[idx] = v.second;
2331 vector<int> perm, dest;
2332 emi_select_merge_destinations(key_vec, dsize,
sizeof(K) +
sizeof(intersection_indices), dest, comm,
2333 "assign_counter_dofs",
2336 commgraph<size_t> grph;
2337 grph.configure(dest, comm);
2338 size_t nrecv =
sum(grph.rcnt);
2344 vector<K> sbuff_key(dsize), rbuff_key(nrecv);
2345 vector<IntersectionIndices> sbuff_value(dsize), ibuff_value(dsize), rbuff_value(nrecv);
2346 for (
size_t i = 0; i < dsize; i++) {
2347 sbuff_key[i] = key_vec[perm[i]];
2348 sbuff_value[i] = value_vec[perm[i]];
2354 for (
size_t i = 0; i < nrecv; i++)
2356 auto it = rmap.
find(rbuff_key[i]);
2357 if (it != rmap.
end())
2359 IntersectionIndices& map_indices = it->second;
2360 IntersectionIndices& received_indices = rbuff_value[i];
2362 for (
mesh_int_t received_index : received_indices.indices)
2364 if (received_index == -1)
continue;
2366 for (
mesh_int_t map_index : map_indices.indices)
2368 if (map_index == received_index) {
2375 for (
size_t k = 0; k < MAX_INTERSECTIONS; ++k) {
2376 if (map_indices.indices[k] == -1) {
2377 map_indices.indices[k] = received_index;
2386 rmap.
insert({ rbuff_key[i], rbuff_value[i] });
2390 for (
size_t i = 0; i < nrecv; i++) {
2391 auto it = rmap.
find(rbuff_key[i]);
2392 if (it != rmap.
end()) rbuff_value[i] = it->second;
2399 for (
size_t i = 0; i < dsize; i++) {
2400 auto it = map.find(sbuff_key[i]);
2401 if (it != map.end()) it->second = ibuff_value[i];
2414 template<
class T,
class S>
inline
2415 void update_emi_mesh_with_dofs(meshdata<T,S> & mesh,
2423 MPI_Comm comm = mesh.comm;
2424 mesh.globalize(numbering);
2425 for(
size_t eidx = 0; eidx < mesh.l_numelem; eidx++) {
2426 T tag = mesh.tag[eidx];
2427 T size_elem = mesh.dsp[eidx+1]-mesh.dsp[eidx];
2429 for (
int n = mesh.dsp[eidx]; n < mesh.dsp[eidx+1];n++)
2431 T gIndex = mesh.con[n];
2433 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2434 Index_tag_old = std::make_pair(gIndex,tag);
2436 auto it_new = map_vertex_tag_to_dof.find(Index_tag_old);
2437 if (it_new != map_vertex_tag_to_dof.end() )
2440 dof2vertex.
insert({dof_new, gIndex});
2441 mesh.con[n] = dof_new;
2443 auto it = vertex2dof.
find(gIndex);
2444 if (it != vertex2dof.
end())
2446 intersection_indices& indices = it->second;
2448 for(T t : indices.indices) {
2456 for(
size_t i=0; i<MAX_INTERSECTIONS; ++i) {
2457 if(indices.indices[i] == -1) {
2458 indices.indices[i] = dof_new;
2464 intersection_indices indices;
2465 indices.indices[0] = dof_new;
2466 vertex2dof.
insert({gIndex,indices});
2472 assign_counter_dofs(vertex2dof, comm);
2475 for (
const auto& [old_idx, indices] : vertex2dof) {
2477 if (new_idx != -1) {
2479 if (dof2vertex.
find(new_idx) == dof2vertex.
end()) {
2480 dof2vertex.
insert({new_idx, old_idx});
2486 mesh.localize(numbering);
2502 template<
class T,
class S>
inline
2503 void update_map_indices_to_petsc(meshdata<T,S> & mesh,
2504 const SF_nbr numbering_ref,
const SF_nbr numbering_petsc,
2507 std::pair<mesh_int_t,mesh_int_t>> & map_vertex_tag_to_dof_petsc,
2511 const SF::vector<T> & ref_nbr = mesh.get_numbering(numbering_ref);
2512 const SF::vector<T> & petsc_nbr = mesh.get_numbering(numbering_petsc);
2514 elemTag_emi_mesh.
resize(mesh.l_numelem);
2515 for(
size_t eidx = 0; eidx < mesh.l_numelem; eidx++) {
2516 T tag = mesh.tag[eidx];
2517 elemTag_emi_mesh[eidx] = 1;
2518 if(extra_tags.
find(tag) == extra_tags.
end())
2519 elemTag_emi_mesh[eidx] = 2;
2520 for (
int n = mesh.dsp[eidx]; n < mesh.dsp[eidx+1];n++)
2522 T l_Indx = mesh.con[n];
2523 T petsc_Idx = petsc_nbr[l_Indx];
2524 T n_Indx = ref_nbr[l_Indx];
2525 T o_Indx = dof2vertex[n_Indx];
2527 std::pair <mesh_int_t,mesh_int_t> oIndx_tag;
2528 oIndx_tag = std::make_pair(o_Indx,tag);
2530 auto it_new = map_vertex_tag_to_dof_petsc.find(oIndx_tag);
2531 if (it_new != map_vertex_tag_to_dof_petsc.end() )
2533 std::pair <mesh_int_t,mesh_int_t> nIndx_petsc;
2534 nIndx_petsc = std::make_pair(n_Indx,petsc_Idx);
2536 (*it_new).second = nIndx_petsc;
2553 template<
class T,
class S>
2554 inline void update_faces_on_surface_mesh_after_decoupling_with_dofs(meshdata<T, S> & mesh,
2558 std::pair<emi_face<T,tuple<T>>, emi_face<T,tuple<T>>>> & line_face,
2560 std::pair<emi_face<T,triple<T>>, emi_face<T,triple<T>>>> & tri_face,
2562 std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>>> & quad_face)
2566 MPI_Comm_size(comm, &size); MPI_Comm_rank(comm, &rank);
2573 for(
size_t i=0; i<idxbuff.size(); i++){
2574 g2l[idxbuff[i]] = i;
2575 l2g[i] = idxbuff[i];
2578 for(
size_t eidx = 0; eidx < mesh.l_numelem; eidx++) {
2579 T tag = mesh.tag[eidx];
2580 T size_elem = mesh.dsp[eidx+1]-mesh.dsp[eidx];
2581 std::vector<mesh_int_t> elem_nodes;
2582 for (
int n = mesh.dsp[eidx]; n < mesh.dsp[eidx+1];n++)
2584 T gIndex = mesh.con[n];
2585 elem_nodes.push_back(gIndex);
2587 std::sort(elem_nodes.begin(),elem_nodes.end());
2588 if(elem_nodes.size()==2){
2590 key.v1 = elem_nodes[0];
2591 key.v2 = elem_nodes[1];
2592 std::pair<emi_face<T,tuple<T>>, emi_face<T,tuple<T>>> value = line_face[key];
2594 line_face.erase(key);
2595 std::vector<mesh_int_t> new_nodes(2);
2597 auto tag_key = (value.first.rank == rank) ? value.first.tag : value.second.tag;
2599 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2600 Index_tag_old = std::make_pair(elem_nodes[0],tag_key);
2601 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2602 new_nodes[0] = Index_new;
2605 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2606 Index_tag_old = std::make_pair(elem_nodes[1],tag_key);
2607 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2608 new_nodes[1] = Index_new;
2610 std::sort(new_nodes.begin(),new_nodes.end());
2613 new_key.v1 = new_nodes[0];
2614 new_key.v2 = new_nodes[1];
2618 mesh_int_t Index_new1 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v1, value.first.tag)];
2619 mesh_int_t Index_new2 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v2, value.first.tag)];
2620 value.first.points.v1 = Index_new1;
2621 value.first.points.v2 = Index_new2;
2625 mesh_int_t Index_new1 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v1, value.second.tag)];
2626 mesh_int_t Index_new2 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v2, value.second.tag)];
2627 value.second.points.v1 = Index_new1;
2628 value.second.points.v2 = Index_new2;
2630 line_face.insert({new_key,value});
2632 if(elem_nodes.size()==3){
2634 key.v1 = elem_nodes[0];
2635 key.v2 = elem_nodes[1];
2636 key.v3 = elem_nodes[2];
2637 std::pair<emi_face<T,triple<T>>, emi_face<T,triple<T>>> value = tri_face[key];
2638 tri_face.erase(key);
2639 std::vector<mesh_int_t> new_nodes(3);
2641 auto tag_key = (value.first.rank == rank) ? value.first.tag : value.second.tag;
2643 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2644 Index_tag_old = std::make_pair(elem_nodes[0],tag_key);
2645 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2646 new_nodes[0] = Index_new;
2649 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2650 Index_tag_old = std::make_pair(elem_nodes[1],tag_key);
2651 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2652 new_nodes[1] = Index_new;
2655 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2656 Index_tag_old = std::make_pair(elem_nodes[2],tag_key);
2657 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2658 new_nodes[2] = Index_new;
2660 std::sort(new_nodes.begin(),new_nodes.end());
2663 new_key.v1 = new_nodes[0];
2664 new_key.v2 = new_nodes[1];
2665 new_key.v3 = new_nodes[2];
2669 mesh_int_t Index_new1 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v1, value.first.tag)];
2670 mesh_int_t Index_new2 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v2, value.first.tag)];
2671 mesh_int_t Index_new3 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v3, value.first.tag)];
2672 value.first.points.v1 = Index_new1;
2673 value.first.points.v2 = Index_new2;
2674 value.first.points.v3 = Index_new3;
2678 mesh_int_t Index_new1 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v1, value.second.tag)];
2679 mesh_int_t Index_new2 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v2, value.second.tag)];
2680 mesh_int_t Index_new3 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v3, value.second.tag)];
2681 value.second.points.v1 = Index_new1;
2682 value.second.points.v2 = Index_new2;
2683 value.second.points.v3 = Index_new3;
2685 tri_face.insert({new_key,value});
2687 if(elem_nodes.size()==4){
2689 key.v1 = elem_nodes[0];
2690 key.v2 = elem_nodes[1];
2691 key.v3 = elem_nodes[2];
2692 key.v4 = elem_nodes[3];
2693 std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>> value = quad_face[key];
2694 quad_face.erase(key);
2695 std::vector<mesh_int_t> new_nodes(4);
2697 auto tag_key = (value.first.rank == rank) ? value.first.tag : value.second.tag;
2699 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2700 Index_tag_old = std::make_pair(elem_nodes[0],tag_key);
2701 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2702 new_nodes[0] = Index_new;
2705 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2706 Index_tag_old = std::make_pair(elem_nodes[1],tag_key);
2707 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2708 new_nodes[1] = Index_new;
2711 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2712 Index_tag_old = std::make_pair(elem_nodes[2],tag_key);
2713 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2714 new_nodes[2] = Index_new;
2717 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2718 Index_tag_old = std::make_pair(elem_nodes[3],tag_key);
2719 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2720 new_nodes[3] = Index_new;
2722 std::sort(new_nodes.begin(),new_nodes.end());
2724 quadruple<T> new_key;
2725 new_key.v1 = new_nodes[0];
2726 new_key.v2 = new_nodes[1];
2727 new_key.v3 = new_nodes[2];
2728 new_key.v4 = new_nodes[3];
2732 mesh_int_t Index_new1 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v1, value.first.tag)];
2733 mesh_int_t Index_new2 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v2, value.first.tag)];
2734 mesh_int_t Index_new3 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v3, value.first.tag)];
2735 mesh_int_t Index_new4 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v4, value.first.tag)];
2736 value.first.points.v1 = Index_new1;
2737 value.first.points.v2 = Index_new2;
2738 value.first.points.v3 = Index_new3;
2739 value.first.points.v4 = Index_new4;
2743 mesh_int_t Index_new1 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v1, value.second.tag)];
2744 mesh_int_t Index_new2 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v2, value.second.tag)];
2745 mesh_int_t Index_new3 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v3, value.second.tag)];
2746 mesh_int_t Index_new4 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v4, value.second.tag)];
2747 value.second.points.v1 = Index_new1;
2748 value.second.points.v2 = Index_new2;
2749 value.second.points.v3 = Index_new3;
2750 value.second.points.v4 = Index_new4;
2752 quad_face.insert({new_key,value});
2768 template<
class T,
class S>
inline
2769 void compute_surface_mesh_with_counter_face(meshdata<T, S> & mesh,
const SF_nbr numbering,
2771 std::pair<emi_face<T,tuple<T>>, emi_face<T,tuple<T>>>> & line_face,
2773 std::pair<emi_face<T,triple<T>>, emi_face<T,triple<T>>>> & tri_face,
2775 std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>>> & quad_face)
2777 mesh.register_numbering(numbering);
2781 MPI_Comm_size(comm, &size);
2782 MPI_Comm_rank(comm, &rank);
2785 vector<tuple<T>> line_keys;
2786 for(
auto const& [key, val] : line_face) line_keys.push_back(key);
2787 std::sort(line_keys.begin(), line_keys.end());
2789 vector<triple<T>> tri_keys;
2790 for(
auto const& [key, val] : tri_face) tri_keys.push_back(key);
2791 std::sort(tri_keys.begin(), tri_keys.end());
2793 vector<quadruple<T>> quad_keys;
2794 for(
auto const& [key, val] : quad_face) quad_keys.push_back(key);
2795 std::sort(quad_keys.begin(), quad_keys.end());
2797 vector<T> cnt(mesh.l_numelem);
2798 size_t idx = 0, cidx = 0;
2803 for(
const auto & key : line_keys) {
2804 const auto & v = line_face.at(key);
2805 bool both_faces = (v.first.rank == v.second.rank) ?
true:
false;
2809 emi_face<T,tuple<T>> surf_first;
2810 emi_face<T,tuple<T>> surf_second;
2811 if(v.first.rank == rank)
2813 surf_first = v.first;
2814 surf_second = v.second;
2818 surf_first = v.second;
2819 surf_second = v.first;
2822 mesh.type[idx] =
Line;
2823 mesh.tag[idx] = surf_first.tag;
2824 mesh.con[cidx + 0] = surf_first.points.v1;
2825 mesh.con[cidx + 1] = surf_first.points.v2;
2832 mesh.type[idx] =
Line;
2833 mesh.tag[idx] = surf_second.tag;
2834 mesh.con[cidx + 0] = surf_second.points.v1;
2835 mesh.con[cidx + 1] = surf_second.points.v2;
2842 for(
const auto & key : tri_keys) {
2843 const auto & v = tri_face.at(key);
2844 bool both_faces = (v.first.rank == v.second.rank) ?
true:
false;
2848 emi_face<T,triple<T>> surf_first;
2849 emi_face<T,triple<T>> surf_second;
2850 if(v.first.rank == rank)
2852 surf_first = v.first;
2853 surf_second = v.second;
2857 surf_first = v.second;
2858 surf_second = v.first;
2861 mesh.type[idx] =
Tri;
2862 mesh.tag[idx] = surf_first.tag;
2863 mesh.con[cidx + 0] = surf_first.points.v1;
2864 mesh.con[cidx + 1] = surf_first.points.v2;
2865 mesh.con[cidx + 2] = surf_first.points.v3;
2874 mesh.type[idx] =
Tri;
2875 mesh.tag[idx] = surf_second.tag;
2876 mesh.con[cidx + 0] = surf_second.points.v1;
2877 mesh.con[cidx + 1] = surf_second.points.v2;
2878 mesh.con[cidx + 2] = surf_second.points.v3;
2885 for(
const auto & key : quad_keys) {
2886 const auto & v = quad_face.at(key);
2887 bool both_faces = (v.first.rank == v.second.rank) ?
true:
false;
2890 emi_face<T,quadruple<T>> surf_first;
2891 emi_face<T,quadruple<T>> surf_second;
2892 if(v.first.rank == rank)
2894 surf_first = v.first;
2895 surf_second = v.second;
2899 surf_first = v.second;
2900 surf_second = v.first;
2903 mesh.type[idx] =
Quad;
2904 mesh.tag[idx] = surf_first.tag;
2905 mesh.con[cidx + 0] = surf_first.points.v1;
2906 mesh.con[cidx + 1] = surf_first.points.v2;
2907 mesh.con[cidx + 2] = surf_first.points.v3;
2908 mesh.con[cidx + 3] = surf_first.points.v4;
2917 mesh.type[idx] =
Quad;
2918 mesh.tag[idx] = surf_second.tag;
2919 mesh.con[cidx + 0] = surf_second.points.v1;
2920 mesh.con[cidx + 1] = surf_second.points.v2;
2921 mesh.con[cidx + 2] = surf_second.points.v3;
2922 mesh.con[cidx + 3] = surf_second.points.v4;
2962 template<
class T,
class S>
inline
2963 void compute_surface_mesh_with_unique_face(meshdata<T, S> & mesh,
const SF_nbr numbering,
2965 std::pair<emi_face<T,tuple<T>>, emi_face<T,tuple<T>>>> & line_face,
2967 std::pair<emi_face<T,triple<T>>, emi_face<T,triple<T>>>> & tri_face,
2969 std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>>> & quad_face,
2972 mesh.register_numbering(numbering);
2976 MPI_Comm_size(comm, &size);
2977 MPI_Comm_rank(comm, &rank);
2980 vector<tuple<T>> line_keys;
2981 for(
auto const& [key, val] : line_face) line_keys.push_back(key);
2982 std::sort(line_keys.begin(), line_keys.end());
2984 vector<triple<T>> tri_keys;
2985 for(
auto const& [key, val] : tri_face) tri_keys.push_back(key);
2986 std::sort(tri_keys.begin(), tri_keys.end());
2988 vector<quadruple<T>> quad_keys;
2989 for(
auto const& [key, val] : quad_face) quad_keys.push_back(key);
2990 std::sort(quad_keys.begin(), quad_keys.end());
2992 vector<T> cnt(mesh.l_numelem);
2993 size_t idx = 0, cidx = 0;
2998 for(
const auto & key : line_keys) {
2999 const auto & v = line_face.at(key);
3001 bool to_take_face =
false;
3003 emi_face<T,tuple<T>> surf_take;
3004 std::pair <mesh_int_t,mesh_int_t> tag_pairs_take;
3006 if(v.first.rank == rank && v.first.mark_to_take ==
true)
3008 surf_take = v.first;
3009 to_take_face =
true;
3010 tag_pairs_take = std::make_pair(v.first.tag,v.second.tag);
3012 else if(v.second.rank == rank && v.second.mark_to_take ==
true)
3014 surf_take = v.second;
3015 to_take_face =
true;
3016 tag_pairs_take = std::make_pair(v.second.tag,v.first.tag);
3021 map_elem_uniqueFace_to_tags.insert({idx,tag_pairs_take});
3023 mesh.type[idx] =
Line;
3024 mesh.tag[idx] = surf_take.tag;
3025 mesh.con[cidx + 0] = surf_take.points.v1;
3026 mesh.con[cidx + 1] = surf_take.points.v2;
3033 for(
const auto & key : tri_keys) {
3034 const auto & v = tri_face.at(key);
3036 bool to_take_face =
false;
3038 emi_face<T,triple<T>> surf_take;
3039 std::pair <mesh_int_t,mesh_int_t> tag_pairs_take;
3041 if(v.first.rank == rank && v.first.mark_to_take ==
true)
3043 surf_take = v.first;
3044 to_take_face =
true;
3045 tag_pairs_take = std::make_pair(v.first.tag,v.second.tag);
3047 else if(v.second.rank == rank && v.second.mark_to_take ==
true)
3049 surf_take = v.second;
3050 to_take_face =
true;
3051 tag_pairs_take = std::make_pair(v.second.tag,v.first.tag);
3056 map_elem_uniqueFace_to_tags.insert({idx,tag_pairs_take});
3058 mesh.type[idx] =
Tri;
3059 mesh.tag[idx] = surf_take.tag;
3060 mesh.con[cidx + 0] = surf_take.points.v1;
3061 mesh.con[cidx + 1] = surf_take.points.v2;
3062 mesh.con[cidx + 2] = surf_take.points.v3;
3070 for(
const auto & key : quad_keys) {
3071 const auto & v = quad_face.at(key);
3073 bool to_take_face =
false;
3075 emi_face<T,quadruple<T>> surf_take;
3076 std::pair <mesh_int_t,mesh_int_t> tag_pairs_take;
3078 if(v.first.rank == rank && v.first.mark_to_take ==
true)
3080 surf_take = v.first;
3081 to_take_face =
true;
3082 tag_pairs_take = std::make_pair(v.first.tag,v.second.tag);
3084 else if(v.second.rank == rank && v.second.mark_to_take ==
true)
3086 surf_take = v.second;
3087 to_take_face =
true;
3088 tag_pairs_take = std::make_pair(v.second.tag,v.first.tag);
3093 map_elem_uniqueFace_to_tags.insert({idx,tag_pairs_take});
3095 mesh.type[idx] =
Quad;
3096 mesh.tag[idx] = surf_take.tag;
3097 mesh.con[cidx + 0] = surf_take.points.v1;
3098 mesh.con[cidx + 1] = surf_take.points.v2;
3099 mesh.con[cidx + 2] = surf_take.points.v3;
3100 mesh.con[cidx + 3] = surf_take.points.v4;
3129 template<
class T>
inline
3130 void create_reverse_elem_mapping_between_surface_meshes(
3133 hashmap::unordered_map<quadruple<T>, std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>>>& quad_face,
3138 MPI_Comm_rank(comm, &rank);
3141 vector<tuple<T>> line_keys;
3142 for(
auto const& [key, val] : line_face) line_keys.push_back(key);
3143 std::sort(line_keys.begin(), line_keys.end());
3145 vector<triple<T>> tri_keys;
3146 for(
auto const& [key, val] : tri_face) tri_keys.push_back(key);
3147 std::sort(tri_keys.begin(), tri_keys.end());
3149 vector<quadruple<T>> quad_keys;
3150 for(
auto const& [key, val] : quad_face) quad_keys.push_back(key);
3151 std::sort(quad_keys.begin(), quad_keys.end());
3153 size_t surf_elem_idx = 0;
3154 size_t w_counter_elem_idx = 0;
3156 size_t lsize_line = 0;
3157 size_t lsize_tri = 0;
3158 size_t lsize_quad = 0;
3162 for(
const auto& key : line_keys) {
3163 const auto& v = line_face.at(key);
3164 const bool local_involved = (v.first.rank == rank) || (v.second.rank == rank);
3165 if (!local_involved) {
3168 if(v.first.rank == v.second.rank) lsize_line+=2;
3171 for(
const auto& key : tri_keys) {
3172 const auto& v = tri_face.at(key);
3173 const bool local_involved = (v.first.rank == rank) || (v.second.rank == rank);
3174 if (!local_involved) {
3177 if(v.first.rank == v.second.rank) lsize_tri+=2;
3180 for(
const auto& key : quad_keys) {
3181 const auto& v = quad_face.at(key);
3182 const bool local_involved = (v.first.rank == rank) || (v.second.rank == rank);
3183 if (!local_involved) {
3186 if(v.first.rank == v.second.rank) lsize_quad+=2;
3190 vec_one_to_both_face.
resize(lsize_line + lsize_tri + lsize_quad);
3194 for (
const auto& key : line_keys) {
3195 const auto& v = line_face.at(key);
3196 const bool local_involved = (v.first.rank == rank) || (v.second.rank == rank);
3197 if (!local_involved) {
3200 vec_one_to_both_face[w_counter_elem_idx++] = surf_elem_idx;
3201 if (v.first.rank == v.second.rank) {
3202 vec_one_to_both_face[w_counter_elem_idx++] = surf_elem_idx;
3207 for (
const auto& key : tri_keys) {
3208 const auto& v = tri_face.at(key);
3209 const bool local_involved = (v.first.rank == rank) || (v.second.rank == rank);
3210 if (!local_involved) {
3213 vec_one_to_both_face[w_counter_elem_idx++] = surf_elem_idx;
3214 if (v.first.rank == v.second.rank) {
3215 vec_one_to_both_face[w_counter_elem_idx++] = surf_elem_idx;
3220 for (
const auto& key : quad_keys) {
3221 const auto& v = quad_face.at(key);
3222 const bool local_involved = (v.first.rank == rank) || (v.second.rank == rank);
3223 if (!local_involved) {
3226 vec_one_to_both_face[w_counter_elem_idx++] = surf_elem_idx;
3227 if (v.first.rank == v.second.rank) {
3228 vec_one_to_both_face[w_counter_elem_idx++] = surf_elem_idx;
3242 template<
class T>
inline
3244 std::pair<emi_face<T,tuple<T>>, emi_face<T,tuple<T>>>> & line_face,
3246 std::pair<emi_face<T,triple<T>>, emi_face<T,triple<T>>>> & tri_face,
3248 std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>>> & quad_face)
3251 std::vector<std::pair<tuple<T>, std::pair<emi_face<T,tuple<T>>, emi_face<T,tuple<T>>>>> line_inserts;
3252 for(
const auto & v : line_face) {
3253 SF::emi_face<mesh_int_t,SF::tuple<mesh_int_t>> surf_first = v.second.first;
3254 SF::emi_face<mesh_int_t,SF::tuple<mesh_int_t>> surf_second = v.second.second;
3256 std::vector<mesh_int_t> elem_nodes_first; elem_nodes_first.
resize(2);
3257 std::vector<mesh_int_t> elem_nodes_second; elem_nodes_second.resize(2);
3260 elem_nodes_first[0] = surf_first.points.
v1;
3261 elem_nodes_first[1] = surf_first.points.v2;
3262 std::sort(elem_nodes_first.begin(),elem_nodes_first.end());
3263 key_first.
v1 = elem_nodes_first[0];
3264 key_first.
v2 = elem_nodes_first[1];
3267 elem_nodes_second[0] = surf_second.points.
v1;
3268 elem_nodes_second[1] = surf_second.points.v2;
3269 std::sort(elem_nodes_second.begin(),elem_nodes_second.end());
3270 key_second.
v1 = elem_nodes_second[0];
3271 key_second.
v2 = elem_nodes_second[1];
3273 const bool same_key_first = (v.first.v1 == key_first.
v1 && v.first.v2 == key_first.
v2);
3274 if (!same_key_first && line_face.find(key_first) == line_face.end()) {
3275 line_inserts.push_back({key_first, v.second});
3277 const bool same_key_second = (v.first.v1 == key_second.
v1 && v.first.v2 == key_second.
v2);
3278 if (!same_key_second && line_face.find(key_second) == line_face.end()) {
3279 line_inserts.push_back({key_second, v.second});
3282 for (
const auto & entry : line_inserts) line_face.insert(entry);
3284 std::vector<std::pair<triple<T>, std::pair<emi_face<T,triple<T>>, emi_face<T,triple<T>>>>> tri_inserts;
3285 for(
const auto & v : tri_face) {
3286 SF::emi_face<mesh_int_t,SF::triple<mesh_int_t>> surf_first = v.second.first;
3287 SF::emi_face<mesh_int_t,SF::triple<mesh_int_t>> surf_second = v.second.second;
3289 std::vector<mesh_int_t> elem_nodes_first; elem_nodes_first.resize(3);
3290 std::vector<mesh_int_t> elem_nodes_second; elem_nodes_second.resize(3);
3293 elem_nodes_first[0] = surf_first.points.
v1;
3294 elem_nodes_first[1] = surf_first.points.v2;
3295 elem_nodes_first[2] = surf_first.points.v3;
3296 std::sort(elem_nodes_first.begin(),elem_nodes_first.end());
3297 key_first.
v1 = elem_nodes_first[0];
3298 key_first.
v2 = elem_nodes_first[1];
3299 key_first.
v3 = elem_nodes_first[2];
3302 elem_nodes_second[0] = surf_second.points.
v1;
3303 elem_nodes_second[1] = surf_second.points.v2;
3304 elem_nodes_second[2] = surf_second.points.v3;
3305 std::sort(elem_nodes_second.begin(),elem_nodes_second.end());
3306 key_second.
v1 = elem_nodes_second[0];
3307 key_second.
v2 = elem_nodes_second[1];
3308 key_second.
v3 = elem_nodes_second[2];
3310 const bool same_key_first = (v.first.v1 == key_first.
v1 &&
3311 v.first.v2 == key_first.
v2 &&
3312 v.first.v3 == key_first.
v3);
3313 if (!same_key_first && tri_face.find(key_first) == tri_face.end()) {
3314 tri_inserts.push_back({key_first, v.second});
3316 const bool same_key_second = (v.first.v1 == key_second.
v1 &&
3317 v.first.v2 == key_second.
v2 &&
3318 v.first.v3 == key_second.
v3);
3319 if (!same_key_second && tri_face.find(key_second) == tri_face.end()) {
3320 tri_inserts.push_back({key_second, v.second});
3323 for (
const auto & entry : tri_inserts) tri_face.insert(entry);
3325 std::vector<std::pair<quadruple<T>, std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>>>> quad_inserts;
3326 for(
const auto & v : quad_face) {
3327 SF::emi_face<mesh_int_t,SF::quadruple<mesh_int_t>> surf_first = v.second.first;
3328 SF::emi_face<mesh_int_t,SF::quadruple<mesh_int_t>> surf_second = v.second.second;
3330 std::vector<mesh_int_t> elem_nodes_first; elem_nodes_first.resize(4);
3331 std::vector<mesh_int_t> elem_nodes_second; elem_nodes_second.resize(4);
3334 elem_nodes_first[0] = surf_first.points.
v1;
3335 elem_nodes_first[1] = surf_first.points.v2;
3336 elem_nodes_first[2] = surf_first.points.v3;
3337 elem_nodes_first[3] = surf_first.points.v4;
3338 std::sort(elem_nodes_first.begin(),elem_nodes_first.end());
3339 key_first.
v1 = elem_nodes_first[0];
3340 key_first.
v2 = elem_nodes_first[1];
3341 key_first.
v3 = elem_nodes_first[2];
3342 key_first.
v4 = elem_nodes_first[3];
3345 elem_nodes_second[0] = surf_second.points.
v1;
3346 elem_nodes_second[1] = surf_second.points.v2;
3347 elem_nodes_second[2] = surf_second.points.v3;
3348 elem_nodes_second[3] = surf_second.points.v4;
3349 std::sort(elem_nodes_second.begin(),elem_nodes_second.end());
3350 key_second.
v1 = elem_nodes_second[0];
3351 key_second.
v2 = elem_nodes_second[1];
3352 key_second.
v3 = elem_nodes_second[2];
3353 key_second.
v4 = elem_nodes_second[3];
3355 const bool same_key_first = (v.first.v1 == key_first.
v1 &&
3356 v.first.v2 == key_first.
v2 &&
3357 v.first.v3 == key_first.
v3 &&
3358 v.first.v4 == key_first.
v4);
3359 if (!same_key_first && quad_face.find(key_first) == quad_face.end()) {
3360 quad_inserts.push_back({key_first, v.second});
3362 const bool same_key_second = (v.first.v1 == key_second.
v1 &&
3363 v.first.v2 == key_second.
v2 &&
3364 v.first.v3 == key_second.
v3 &&
3365 v.first.v4 == key_second.
v4);
3366 if (!same_key_second && quad_face.find(key_second) == quad_face.end()) {
3367 quad_inserts.push_back({key_second, v.second});
3370 for (
const auto & entry : quad_inserts) quad_face.insert(entry);
3380 template<
class K>
inline
3383 size_t dsize = map.
size();
3384 vector<K> key_vec(dsize);
3385 vector<intersection_tags> value_vec(dsize);
3388 for (
const auto& v : map) {
3389 key_vec[idx] = v.first;
3390 value_vec[idx] = v.second;
3394 vector<int> perm, dest;
3395 emi_select_merge_destinations(key_vec, dsize,
sizeof(K) +
sizeof(intersection_tags), dest, comm,
3396 "assign_counter_tags",
3399 commgraph<size_t> grph;
3400 grph.configure(dest, comm);
3401 size_t nrecv =
sum(grph.rcnt);
3407 vector<K> sbuff_key(dsize), rbuff_key(nrecv);
3408 vector<intersection_tags> sbuff_value(dsize), ibuff_value(dsize), rbuff_value(nrecv);
3409 for (
size_t i = 0; i < dsize; i++) {
3410 sbuff_key[i] = key_vec[perm[i]];
3411 sbuff_value[i] = value_vec[perm[i]];
3417 for (
size_t i = 0; i < nrecv; i++)
3419 auto it = rmap.
find(rbuff_key[i]);
3420 if (it != rmap.
end())
3422 intersection_tags& map_tags = it->second;
3423 intersection_tags& r_tags = rbuff_value[i];
3425 for (
int r_tag : r_tags.tags)
3427 if (r_tag == -1)
continue;
3429 for (
int m_tag : map_tags.tags)
3431 if (m_tag == r_tag) {
3438 for (
size_t k = 0; k < MAX_INTERSECTIONS; ++k) {
3439 if (map_tags.tags[k] == -1) {
3440 map_tags.tags[k] = r_tag;
3449 rmap.
insert({ rbuff_key[i], rbuff_value[i] });
3453 for (
size_t i = 0; i < nrecv; i++) {
3454 auto it = rmap.
find(rbuff_key[i]);
3455 if (it != rmap.
end()) rbuff_value[i] = it->second;
3462 for (
size_t i = 0; i < dsize; i++) {
3463 auto it = map.find(sbuff_key[i]);
3464 if (it != map.end()) it->second = ibuff_value[i];
3489 template<
class T,
class S>
inline
3490 void compute_ptsdata_from_original_mesh(meshdata<T,S> & mesh,
3496 MPI_Comm comm = mesh.comm;
3498 MPI_Comm_size(comm, &size);
3499 MPI_Comm_rank(comm, &rank);
3501 const T* con = mesh.con.data();
3508 for(
size_t eidx = 0; eidx < mesh.l_numelem; eidx++)
3510 T tag = mesh.tag[eidx];
3511 for (
int n = mesh.dsp[eidx]; n < mesh.dsp[eidx+1];n++)
3513 T gIndex = rnod[con[n]];
3515 auto it_new = map_index_to_tags.
find(gIndex);
3516 if (it_new != map_index_to_tags.
end())
3519 intersection_tags& tags = it_new->second;
3521 for(T t : tags.tags) {
3529 for(
int i=0; i <MAX_INTERSECTIONS; ++i) {
3530 if (tags.tags[i] == -1) {
3539 intersection_tags tags;
3541 map_index_to_tags.
insert({gIndex,tags});
3549 assign_counter_tags(map_index_to_tags, comm);
3552 for(
size_t eidx = 0; eidx < mesh.l_numelem; eidx++)
3554 for (
int n = mesh.dsp[eidx]; n < mesh.dsp[eidx+1];n++)
3556 T gIndex = rnod[con[n]];
3557 intersection_tags& vec_tags = map_index_to_tags[gIndex];
3558 int count_intra_tags = 0;
3559 int count_extra_tags = 0;
3563 for(T t : vec_tags.tags) {
3564 if(intra_tags.
count(t)) count_intra_tags++;
3565 if(extra_tags.
count(t)) count_extra_tags++;
3569 if(count_extra_tags>=1 && count_intra_tags==0){
3570 vertex2ptsdata[gIndex] = 0;
3571 }
else if(count_extra_tags==0 && count_intra_tags==1){
3572 vertex2ptsdata[gIndex] = 0;
3573 }
else if(count_extra_tags>=1 && count_intra_tags==1){
3574 vertex2ptsdata[gIndex] = 1;
3575 }
else if(count_extra_tags==0 && count_intra_tags==2){
3576 vertex2ptsdata[gIndex] = 2;
3577 }
else if(count_extra_tags>=1 && count_intra_tags==2){
3578 vertex2ptsdata[gIndex] = 3;
3580 else if(count_intra_tags>2){
3582 fprintf(stderr,
"More than two intracellular are connected %lld. Tags:",
3583 static_cast<long long>(gIndex));
3584 for(T tag : vec_tags.tags)
if(tag != -1) fprintf(stderr,
" %lld",
static_cast<long long>(tag));
3585 fprintf(stderr,
"\n");
3590 fprintf(stderr,
"WARN: unhandled case in ptsData computation for gIndex %lld. Tags:",
3591 static_cast<long long>(gIndex));
3592 for(T tag : vec_tags.tags)
if(tag != -1) fprintf(stderr,
" %lld",
static_cast<long long>(tag));
3593 fprintf(stderr,
"\n");
3616 template <
class T,
class S,
class V,
class emi_index_rank>
3619 std::pair<emi_index_rank, emi_index_rank>>& map,
3626 MPI_Comm_rank(both_mesh.
comm, &rank);
3629 SF::layout_from_count<long int>(both_mesh.
l_numelem, layout_both, both_mesh.
comm);
3632 SF::layout_from_count<long int>(unique_mesh.
l_numelem, layout_unique, unique_mesh.
comm);
3638 for (
const auto& [local_unique_idx, both_pair] : map) {
3639 const auto& first_both = both_pair.first;
3640 const auto& second_both = both_pair.second;
3644 T global_unique_row = layout_unique[rank] + local_unique_idx;
3645 row_idx[0] = global_unique_row;
3648 bool first_valid = (first_both.index >= 0 && first_both.rank >= 0);
3649 bool second_valid = (second_both.index >= 0 && second_both.rank >= 0);
3651 T global_both_col_first = -1;
3652 T global_both_col_second = -1;
3654 global_both_col_first = layout_both[first_both.rank] + first_both.index;
3657 global_both_col_second = layout_both[second_both.rank] + second_both.index;
3662 if (first_valid && second_valid && global_both_col_first == global_both_col_second) {
3663 second_valid =
false;
3668 if (first_valid)
count++;
3669 if (second_valid)
count++;
3671 if (
count == 0)
continue;
3675 double weight = 0.5;
3676 if (
count == 1) weight = 1.0;
3678 ebuff.assign(1, 1, weight);
3682 col_idx[0] = global_both_col_first;
3683 op.
set_values(row_idx, col_idx, ebuff.data(),
false);
3688 col_idx[0] = global_both_col_second;
3689 op.
set_values(row_idx, col_idx, ebuff.data(),
false);
3713 inline void restrict_to_membrane(vector<T> & v,
3715 const meshdata<mesh_int_t, mesh_real_t> & mesh)
3720 for(
size_t i=0; i<rnod.
size(); i++){
3727 for(
size_t i=0; i<v.size(); i++){
3730 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.
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)
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)