28 #ifndef _SF_MESH_UTILS_EMI_H
29 #define _SF_MESH_UTILS_EMI_H
41 const int MAX_INTERSECTIONS = 20;
49 const int EMI_MIN_MERGE_RANKS = 8;
50 const int EMI_MAX_MERGE_RANKS_PER_NODE = 2;
51 const unsigned long long EMI_TARGET_BYTES_PER_MERGE_RANK = 8ull * 1024ull * 1024ull;
64 inline int emi_node_aware_merge_rank_cap(MPI_Comm comm)
67 MPI_Comm_size(comm, &size);
70 MPI_Comm node_comm = MPI_COMM_NULL;
71 MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, 0, MPI_INFO_NULL, &node_comm);
75 MPI_Comm_rank(node_comm, &node_rank);
77 int local_leader = (node_rank == 0) ? 1 : 0;
80 MPI_Allreduce(&local_leader, &num_nodes, 1, MPI_INT, MPI_SUM, comm);
82 MPI_Comm_free(&node_comm);
85 return std::min(size,
std::max(EMI_MIN_MERGE_RANKS, num_nodes * EMI_MAX_MERGE_RANKS_PER_NODE));
106 template<
class K,
class TokenFn>
107 inline int emi_select_merge_destinations(
const vector<K>& key_vec,
109 size_t bytes_per_entry,
115 int size = 0, rank = 0;
116 MPI_Comm_size(comm, &size);
117 MPI_Comm_rank(comm, &rank);
120 const unsigned long long local_bytes =
121 static_cast<unsigned long long>(dsize) *
static_cast<unsigned long long>(bytes_per_entry);
122 unsigned long long global_bytes = 0;
123 MPI_Allreduce(&local_bytes, &global_bytes, 1, MPI_UNSIGNED_LONG_LONG, MPI_SUM, comm);
126 const int merge_rank_cap = emi_node_aware_merge_rank_cap(comm);
128 if (size > merge_rank_cap) {
130 const int nmerge_floor = EMI_MIN_MERGE_RANKS;
131 const int nmerge_cap = merge_rank_cap;
132 const unsigned long long nmerge_est_ull =
133 std::max(1ull, (global_bytes + EMI_TARGET_BYTES_PER_MERGE_RANK - 1ull) /
134 EMI_TARGET_BYTES_PER_MERGE_RANK);
135 const int nmerge_est =
static_cast<int>(std::min<unsigned long long>(nmerge_cap, nmerge_est_ull));
137 nmerge =
std::max(nmerge_floor, nmerge_est);
141 for (
size_t i = 0; i < dsize; ++i) {
142 if (nmerge == size) {
144 dest[i] =
static_cast<int>(token_fn(key_vec[i]) %
static_cast<size_t>(size));
147 const size_t bucket = token_fn(key_vec[i]) %
static_cast<size_t>(nmerge);
150 dest[i] =
static_cast<int>((bucket *
static_cast<size_t>(size)) /
static_cast<size_t>(nmerge));
154 if (rank == 0 && std::getenv(
"OPENCARP_EMI_LOG_MERGE_RANKS") != NULL) {
155 const char* mode = (nmerge == size) ?
"all-ranks" :
"limited";
157 "[EMI merge ranks] %s: size=%d dsize=%zu global_bytes=%llu cap=%d nmerge=%d mode=%s\n",
158 label, size, dsize, global_bytes, merge_rank_cap, nmerge, mode);
173 struct intersection_tags {
181 int tags[MAX_INTERSECTIONS];
182 intersection_tags() {
183 std::fill_n(tags, MAX_INTERSECTIONS, -1);
188 struct intersection_data {
189 int tags[MAX_INTERSECTIONS];
190 int data[MAX_INTERSECTIONS];
191 int ranks[MAX_INTERSECTIONS];
193 intersection_data() {
194 std::fill_n(tags, MAX_INTERSECTIONS, -1);
195 std::fill_n(data, MAX_INTERSECTIONS, -1);
196 std::fill_n(ranks, MAX_INTERSECTIONS, -1);
203 struct intersection_indices {
205 intersection_indices() {
206 std::fill_n(indices, MAX_INTERSECTIONS, -1);
221 template<
class K,
class V>
inline
224 size_t dsize = map.
size();
225 vector<K> key_vec (dsize);
226 vector<V> value_vec (dsize);
231 for(
const auto & v : map) {
232 if (v.second.second.eidx == -1){
233 key_vec[idx] = v.first;
234 value_vec[idx] = v.second;
239 key_vec.resize(dsize);
240 value_vec.resize(dsize);
242 vector<int> perm, dest;
243 emi_select_merge_destinations(key_vec, dsize,
sizeof(K) +
sizeof(V), dest, comm,
244 "assign_counter_face",
247 commgraph<size_t> grph;
248 grph.configure(dest, comm);
249 size_t nrecv =
sum(grph.rcnt);
255 vector<K> sbuff_key(dsize), rbuff_key(nrecv);
256 vector<V> sbuff_value(dsize), ibuff_value(dsize), rbuff_value(nrecv);
257 for(
size_t i=0; i<dsize; i++) {
258 sbuff_key[i] = key_vec[perm[i]];
259 sbuff_value[i] = value_vec[perm[i]];
269 for (
size_t i = 0; i < nrecv; i++) {
270 auto it = rmap.
find(rbuff_key[i]);
271 if(it != rmap.
end()) {
276 if (it->second.first.tag != rbuff_value[i].first.tag) {
277 it->second.second = rbuff_value[i].first;
280 rmap.
insert({rbuff_key[i], rbuff_value[i]});
284 for (
size_t i = 0; i < nrecv; i++ ) {
285 auto it = rmap.
find(rbuff_key[i]);
286 if(it != rmap.
end()) rbuff_value[i] = it->second;
293 for (
size_t i = 0; i < dsize; i++ ) {
294 auto it = map.find(sbuff_key[i]);
295 if (it != map.end()) it->second = ibuff_value[i];
311 template<
class K,
class V>
inline
323 size_t dsize = map.
size();
324 vector<K> key_vec (dsize);
325 vector<V> value_vec (dsize);
329 for(
const auto & v : map) {
330 if (v.second.second.index_unique == -1 && v.second.second.index_one == -1){
331 key_vec[idx] = v.first;
332 value_vec[idx] = v.second;
337 key_vec.resize(dsize);
338 value_vec.resize(dsize);
340 vector<int> perm, dest;
341 emi_select_merge_destinations(key_vec, dsize,
sizeof(K) +
sizeof(V), dest, comm,
342 "assign_unique_first_face",
345 commgraph<size_t> grph;
346 grph.configure(dest, comm);
347 size_t nrecv =
sum(grph.rcnt);
353 vector<K> sbuff_key(dsize), rbuff_key(nrecv);
354 vector<V> sbuff_value(dsize), ibuff_value(dsize), rbuff_value(nrecv);
355 for(
size_t i=0; i<dsize; i++) {
356 sbuff_key[i] = key_vec[perm[i]];
357 sbuff_value[i] = value_vec[perm[i]];
367 for (
size_t i = 0; i < nrecv; i++) {
368 auto it = rmap.
find(rbuff_key[i]);
369 if(it != rmap.
end()) {
371 auto& existing = it->second;
372 using Face = std::decay_t<decltype(existing.first)>;
374 auto update_slot = [&](Face& slot,
const Face& src) {
378 if (src.index_unique >= 0) {
379 slot.index_unique = src.index_unique;
380 slot.rank = src.rank;
382 if (slot.rank < 0) slot.rank = src.rank;
384 if (slot.index_one < 0 && src.index_one >= 0) slot.index_one = src.index_one;
387 auto same_face = [&](
const Face& a,
const Face& b) {
389 return (a.rank >= 0 && b.rank >= 0 &&
390 a.index_one >= 0 && b.index_one >= 0 &&
391 a.rank == b.rank && a.index_one == b.index_one);
394 auto ingest = [&](
const Face& incoming) {
396 if (incoming.index_one < 0 && incoming.index_unique < 0 && incoming.rank < 0)
return;
398 if (same_face(existing.first, incoming) || existing.first.rank == incoming.rank) {
399 update_slot(existing.first, incoming);
400 }
else if (same_face(existing.second, incoming) || existing.second.rank == incoming.rank) {
401 update_slot(existing.second, incoming);
402 }
else if (existing.second.index_one == -1 && existing.second.index_unique == -1) {
404 existing.second = incoming;
405 }
else if (existing.first.index_one == -1 && existing.first.index_unique == -1) {
407 existing.first = incoming;
411 if (existing.first.index_unique < 0 && incoming.index_unique >= 0) {
412 existing.first.index_unique = incoming.index_unique;
413 existing.first.rank = incoming.rank;
414 }
else if (existing.second.index_unique < 0 && incoming.index_unique >= 0) {
415 existing.second.index_unique = incoming.index_unique;
416 existing.second.rank = incoming.rank;
422 ingest(rbuff_value[i].first);
423 ingest(rbuff_value[i].second);
426 rmap.
insert({rbuff_key[i], rbuff_value[i]});
430 for (
size_t i = 0; i < nrecv; i++ ) {
431 auto it = rmap.
find(rbuff_key[i]);
432 if(it != rmap.
end()) rbuff_value[i] = it->second;
439 for (
size_t i = 0; i < dsize; i++ ) {
440 auto it = map.find(sbuff_key[i]);
441 if (it != map.end()) {
443 it->second = ibuff_value[i];
447 map.insert({sbuff_key[i], ibuff_value[i]});
462 template<
class K>
inline
465 size_t dsize = map.
size();
466 vector<K> key_vec(dsize);
467 vector<intersection_data> value_vec(dsize);
470 for (
const auto& v : map) {
471 key_vec[idx] = v.first;
472 value_vec[idx] = v.second;
476 vector<int> perm, dest;
477 emi_select_merge_destinations(key_vec, dsize,
sizeof(K) +
sizeof(intersection_data), dest, comm,
478 "assign_counter_vertices_tuple",
481 commgraph<size_t> grph;
482 grph.configure(dest, comm);
483 size_t nrecv =
sum(grph.rcnt);
489 vector<K> sbuff_key(dsize), rbuff_key(nrecv);
490 vector<intersection_data> sbuff_value(dsize), ibuff_value(dsize), rbuff_value(nrecv);
491 for (
size_t i = 0; i < dsize; i++) {
492 sbuff_key[i] = key_vec[perm[i]];
493 sbuff_value[i] = value_vec[perm[i]];
499 for (
size_t i = 0; i < nrecv; i++) {
500 auto it = rmap.
find(rbuff_key[i]);
501 if (it != rmap.
end()) {
502 intersection_data& map_val = it->second;
503 intersection_data& r_val = rbuff_value[i];
505 int first_index = -1;
506 for (
int j = 0; j < MAX_INTERSECTIONS; ++j) {
507 if (map_val.tags[j] == -1 && map_val.ranks[j] == -1) {
513 if (first_index == -1)
continue;
515 for (
int j = 0; j < MAX_INTERSECTIONS; ++j) {
516 if (r_val.tags[j] == -1)
continue;
518 int rtag = r_val.tags[j];
519 int rdata = r_val.data[j];
520 int rrank = r_val.ranks[j];
522 bool exist_rtag =
false;
523 for (
int k = 0; k < first_index; ++k) {
524 if (map_val.tags[k] == rtag && map_val.ranks[k] == rrank) {
530 if (!exist_rtag && first_index < MAX_INTERSECTIONS) {
531 map_val.tags[first_index] = rtag;
532 map_val.data[first_index] = rdata;
533 map_val.ranks[first_index] = rrank;
539 rmap.
insert({ rbuff_key[i], rbuff_value[i] });
543 for (
size_t i = 0; i < nrecv; i++) {
544 auto it = rmap.
find(rbuff_key[i]);
545 if (it != rmap.
end()) rbuff_value[i] = it->second;
552 for (
size_t i = 0; i < dsize; i++) {
553 auto it = map.find(sbuff_key[i]);
554 if (it != map.end()) it->second = ibuff_value[i];
569 template<
class K,
class V>
inline
572 size_t dsize = map.
size();
573 vector<K> key_vec (dsize);
574 vector<V> value_vec (dsize);
579 for(
const auto & v : map) {
580 key_vec[idx] = v.first;
581 value_vec[idx] = v.second;
585 key_vec.resize(dsize);
586 value_vec.resize(dsize);
588 vector<int> perm, dest;
589 emi_select_merge_destinations(key_vec, dsize,
sizeof(K) +
sizeof(V), dest, comm,
590 "assign_dof_on_counter_face",
591 [](
const K& key) {
return key.first; });
593 commgraph<size_t> grph;
594 grph.configure(dest, comm);
595 size_t nrecv =
sum(grph.rcnt);
601 vector<K> sbuff_key(dsize), rbuff_key(nrecv);
602 vector<V> sbuff_value(dsize), ibuff_value(dsize), rbuff_value(nrecv);
603 for(
size_t i=0; i<dsize; i++) {
604 sbuff_key[i] = key_vec[perm[i]];
605 sbuff_value[i] = value_vec[perm[i]];
612 for (
size_t i = 0; i < nrecv; i++) {
613 auto it = rmap.
find(rbuff_key[i]);
614 if(it != rmap.
end()) {
615 if(rbuff_value[i] != -1 and it->second == -1){
616 it->second = rbuff_value[i];
619 rmap.
insert({rbuff_key[i], rbuff_value[i]});
623 for (
size_t i = 0; i < nrecv; i++ ) {
624 auto it = rmap.
find(rbuff_key[i]);
625 if(it != rmap.
end()) {
626 if(rbuff_value[i] == -1)
627 rbuff_value[i] = it->second;
635 for (
size_t i = 0; i < dsize; i++ ) {
636 auto it = map.find(sbuff_key[i]);
637 if (it != map.end()) it->second = ibuff_value[i];
652 template<
class K,
class V>
inline
655 size_t dsize = map.
size();
656 vector<K> key_vec (dsize);
657 vector<V> value_vec (dsize);
662 for(
const auto & v : map) {
663 key_vec[idx] = v.first;
664 value_vec[idx] = v.second;
668 key_vec.resize(dsize);
669 value_vec.resize(dsize);
671 vector<int> perm, dest;
672 emi_select_merge_destinations(key_vec, dsize,
sizeof(K) +
sizeof(V), dest, comm,
673 "assign_petsc_on_counter_face",
674 [](
const K& key) {
return key.first; });
676 commgraph<size_t> grph;
677 grph.configure(dest, comm);
678 size_t nrecv =
sum(grph.rcnt);
684 vector<K> sbuff_key(dsize), rbuff_key(nrecv);
685 vector<V> sbuff_value(dsize), ibuff_value(dsize), rbuff_value(nrecv);
686 for(
size_t i=0; i<dsize; i++) {
687 sbuff_key[i] = key_vec[perm[i]];
688 sbuff_value[i] = value_vec[perm[i]];
695 for (
size_t i = 0; i < nrecv; i++) {
696 auto it = rmap.
find(rbuff_key[i]);
697 if(it != rmap.
end()) {
698 if(rbuff_value[i].second != -1 and it->second.second == -1){
699 it->second = rbuff_value[i];
702 rmap.
insert({rbuff_key[i], rbuff_value[i]});
706 for (
size_t i = 0; i < nrecv; i++ ) {
707 auto it = rmap.
find(rbuff_key[i]);
708 if(it != rmap.
end()) {
709 if(rbuff_value[i].second == -1)
710 rbuff_value[i].second = it->second.second;
718 for (
size_t i = 0; i < dsize; i++ ) {
719 auto it = map.find(sbuff_key[i]);
720 if (it != map.end()) it->second = ibuff_value[i];
732 void sort_surf_local_indices(tuple<T> & ref, tuple<T> & target)
736 buff[0] = ref.v1, buff[1] = ref.v2;
739 target.v1 = buff[0], target.v2 = buff[1];
750 void sort_surf_local_indices(triple<T> & ref, triple<T> & target)
754 buff[0] = ref.v1, buff[1] = ref.v2, buff[2] = ref.v3;
757 target.v1 = buff[0], target.v2 = buff[1], target.v3 = buff[2];
768 void sort_surf_local_indices(quadruple<T> & ref, quadruple<T> & target)
772 buff[0] = ref.v1, buff[1] = ref.v2, buff[2] = ref.v3, buff[3] = ref.v4;
775 target.v1 = buff[0], target.v2 = buff[1], target.v3 = buff[2], target.v4 = buff[3];
789 template<
class K,
class V>
inline
790 void insert_surf_based_Tag(V & ref,
795 sort_surf_local_indices(ref.points, surf);
797 auto it = surfmap.find(surf);
798 if (it != surfmap.end()) {
801 if ( it->second.first.tag != ref.tag )
802 it->second.second = ref;
804 std::pair<V, V> face;
806 surfmap.insert({surf,face});
829 template<
class T,
class W,
class V,
class U>
inline
830 void insert_surf_emi(
int rank,
833 const T eidx,
const T tag,
834 const std::vector<T> & line_con,
const std::vector<T> & surf_con,
const std::vector<T> & qsurf_con,
850 for (
size_t i = 0; i < line_con.size(); i += 2) {
851 if (ptsData[line_con[i ] - 1] > 0 &&
852 ptsData[line_con[i + 1] - 1] > 0 ) {
853 line.points.v1 = ref_con[line_con[i ] - 1];
854 line.points.v2 = ref_con[line_con[i + 1] - 1];
856 insert_surf_based_Tag(line, line_face);
860 for (
size_t i = 0; i < surf_con.size(); i += 3) {
861 if (ptsData[surf_con[i ] - 1] > 0 &&
862 ptsData[surf_con[i + 1] - 1] > 0 &&
863 ptsData[surf_con[i + 2] - 1] > 0 ) {
864 face.points.v1 = ref_con[surf_con[i ] - 1];
865 face.points.v2 = ref_con[surf_con[i + 1] - 1];
866 face.points.v3 = ref_con[surf_con[i + 2] - 1];
868 insert_surf_based_Tag(face, surfmap);
872 for (
size_t i = 0; i < qsurf_con.size(); i += 4) {
873 if (ptsData[qsurf_con[i ] - 1] > 0 &&
874 ptsData[qsurf_con[i + 1] - 1] > 0 &&
875 ptsData[qsurf_con[i + 2] - 1] > 0 &&
876 ptsData[qsurf_con[i + 3] - 1] > 0) {
877 qface.points.v1 = ref_con[qsurf_con[i ] - 1];
878 qface.points.v2 = ref_con[qsurf_con[i + 1] - 1];
879 qface.points.v3 = ref_con[qsurf_con[i + 2] - 1];
880 qface.points.v4 = ref_con[qsurf_con[i + 3] - 1];
882 insert_surf_based_Tag(qface, qsurfmap);
893 template<
class T,
class V>
900 bool mark_to_take =
false;
907 struct emi_unique_face {
940 struct emi_index_rank {
961 template<
class T,
class S>
inline
962 void compute_surface_with_tags(meshdata<T,S> & mesh,
967 std::pair<emi_face<T,tuple<T>>, emi_face<T,tuple<T>>>> & line_face,
969 std::pair<emi_face<T,triple<T>>, emi_face<T,triple<T>>>> & tri_surf,
971 std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>>> & quad_surf)
975 MPI_Comm_size(comm, &size);
976 MPI_Comm_rank(comm, &rank);
978 const T* con = mesh.con.data();
979 const T* nbr = mesh.get_numbering(numbering).data();
984 for(
size_t i=0; i<mesh.con.size(); i++){
985 g2ptsData[rnod[con[i]]] = vertex2ptsdata[rnod[con[i]]];
988 const vector<T> & ref_eidx = mesh.get_numbering(
NBR_ELEM_REF);
993 for(
size_t eidx = 0; eidx < mesh.l_numelem; eidx++) {
994 T tag = mesh.tag[eidx];
995 T size_elem = mesh.dsp[eidx+1]-mesh.dsp[eidx];
997 vector<T> dofvec(size_elem);
998 vector<T> ptsDatavec(size_elem);
1000 for (
int n = mesh.dsp[eidx], i = 0; n < mesh.dsp[eidx+1];n++,i++)
1002 dofvec[i] = rnod[con[n]];
1003 ptsDatavec[i] = g2ptsData[rnod[con[n]]];
1005 std::vector<T> surf_con ;
1006 std::vector<T> qsurf_con;
1007 std::vector<T> line_con;
1008 switch(mesh.type[eidx]) {
1049 qsurf_con = {1,2,3,4};
1057 qsurf_con = {1,2,6,4,
1066 qsurf_con = {1,2,3,4,
1075 fprintf(stderr,
"%s error: Unsupported element in surface computation!\n", __func__);
1078 insert_surf_emi(rank, dofvec, ptsDatavec, ref_eidx[eidx], mesh.tag[eidx], line_con, surf_con, qsurf_con, line_face, tri_surf, quad_surf);
1082 assign_counter_face(line_face, mesh.comm);
1083 assign_counter_face(tri_surf, mesh.comm);
1084 assign_counter_face(quad_surf, mesh.comm);
1088 for(
auto it = line_face.begin(); it != line_face.end(); ) {
1089 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()))
1090 it = line_face.erase(it);
1095 for(
auto it = tri_surf.begin(); it != tri_surf.end(); ) {
1096 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()))
1097 it = tri_surf.erase(it);
1102 for(
auto it = quad_surf.begin(); it != quad_surf.end(); ) {
1103 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()))
1104 it = quad_surf.erase(it);
1123 inline bool should_take_first(
int tag1,
int tag2,
1127 bool tag1_is_intra = (intra_tags.
find(tag1) != intra_tags.
end());
1128 bool tag2_is_intra = (intra_tags.
find(tag2) != intra_tags.
end());
1129 bool tag1_is_extra = (extra_tags.
find(tag1) != extra_tags.
end());
1130 bool tag2_is_extra = (extra_tags.
find(tag2) != extra_tags.
end());
1133 if(tag1_is_intra && tag2_is_intra) {
1138 if(tag1_is_intra && tag2_is_extra) {
1141 if(tag2_is_intra && tag1_is_extra) {
1171 void assign_map_between_elem_oneface_and_elem_uniqueFace(
int rank,
1172 emi_unique_face <mesh_int_t> first,
1173 emi_unique_face <mesh_int_t> second,
1178 if(second.index_one==-1 && second.index_unique==-1){
1179 second.index_one = first.index_one;
1180 second.index_unique = first.index_unique;
1183 else if(first.rank != second.rank) {
1185 int our_index_one = (first.rank == rank) ? first.index_one :
1186 (second.rank == rank) ? second.index_one : -1;
1188 int owner_index_unique = (first.index_unique >= 0) ? first.index_unique :
1189 (second.index_unique >= 0) ? second.index_unique : -1;
1190 int owner_rank = (first.index_unique >= 0) ? first.rank :
1191 (second.index_unique >= 0) ? second.rank : -1;
1194 if(our_index_one >= 0 && owner_index_unique >= 0 && owner_rank >= 0 && owner_rank != rank) {
1195 map_elem_oneface_to_elem_uniqueFace[our_index_one].index = owner_index_unique;
1196 map_elem_oneface_to_elem_uniqueFace[our_index_one].rank = owner_rank;
1203 int local_index_unique = -1;
1204 emi_index_rank<mesh_int_t> value1, value2;
1206 if (first.index_unique >= 0 && first.rank == rank) {
1208 local_index_unique = first.index_unique;
1209 value1.index = first.index_one;
1210 value1.rank = first.rank;
1211 value2.index = second.index_one;
1212 value2.rank = second.rank;
1213 }
else if (second.index_unique >= 0 && second.rank == rank) {
1215 local_index_unique = second.index_unique;
1216 value1.index = second.index_one;
1217 value1.rank = second.rank;
1218 value2.index = first.index_one;
1219 value2.rank = first.rank;
1222 if (local_index_unique >= 0) {
1223 auto itr = map_elem_uniqueFace_to_elem_oneface.find(local_index_unique);
1224 if (itr == map_elem_uniqueFace_to_elem_oneface.end()) {
1225 std::pair <emi_index_rank<mesh_int_t>,emi_index_rank<mesh_int_t>> value;
1226 value = std::make_pair(value1, value2);
1227 map_elem_uniqueFace_to_elem_oneface.insert({local_index_unique, value});
1254 template <
class T,
class Key,
class Po
intsKey>
1255 inline void assign_ownership_rank_on_faces(
const Key& key,
1256 std::pair<emi_face<T, PointsKey>, emi_face<T, PointsKey>>& v,
1262 hashmap::unordered_map<Key,std::pair<emi_unique_face<mesh_int_t>, emi_unique_face<mesh_int_t>>>& unique_face_to_elements,
1265 const bool same_rank = (v.first.rank == v.second.rank);
1271 const bool first_intra = (intra_tags.
find(v.first.tag) != intra_tags.
end());
1272 const bool second_intra = (intra_tags.
find(v.second.tag) != intra_tags.
end());
1275 bool take_first_by_tags =
true;
1276 if (first_intra != second_intra) {
1277 take_first_by_tags = first_intra;
1278 }
else if (v.first.tag != v.second.tag) {
1279 take_first_by_tags = (v.first.tag < v.second.tag);
1282 take_first_by_tags = (v.first.rank <= v.second.rank);
1285 int owner_rank = take_first_by_tags ? v.first.rank : v.second.rank;
1287 const bool i_am_owner = (rank == owner_rank);
1291 auto& chosen = take_first_by_tags ? v.first : v.second;
1293 chosen.mark_to_take =
true;
1294 chosen.index_unique = lsize_unique;
1295 chosen.index_one = idx_oneface;
1297 map_elem_oneface_to_elem_uniqueFace[idx_oneface].index = lsize_unique;
1298 map_elem_oneface_to_elem_uniqueFace[idx_oneface].rank = rank;
1304 auto it = unique_face_to_elements.find(key);
1305 if (it == unique_face_to_elements.end()) {
1306 emi_unique_face<mesh_int_t> first;
1307 emi_unique_face<mesh_int_t> second;
1311 first.index_unique = lsize_unique;
1312 first.index_one = idx_oneface;
1316 second.index_unique = -1;
1317 second.index_one = -1;
1318 second.rank = same_rank ? rank : (rank == v.first.rank ? v.second.rank : v.first.rank);
1321 first.index_unique = -1;
1322 first.index_one = idx_oneface;
1325 second.index_unique = -1;
1326 second.index_one = -1;
1327 second.rank = owner_rank;
1330 unique_face_to_elements.insert({ key, std::make_pair(first, second) });
1333 auto& existing = it->second;
1336 emi_unique_face<mesh_int_t>* slot =
nullptr;
1337 if (existing.first.rank == rank || existing.first.rank < 0) {
1338 slot = &existing.first;
1339 }
else if (existing.second.rank == rank || existing.second.rank < 0) {
1340 slot = &existing.second;
1341 }
else if (existing.first.index_one == idx_oneface) {
1342 slot = &existing.first;
1343 }
else if (existing.second.index_one == idx_oneface) {
1344 slot = &existing.second;
1345 }
else if (existing.first.index_unique < 0) {
1346 slot = &existing.first;
1347 }
else if (existing.second.index_unique < 0) {
1348 slot = &existing.second;
1352 if (slot->rank < 0) slot->rank = rank;
1353 if (slot->index_one < 0) slot->index_one = idx_oneface;
1354 if (i_am_owner && slot->index_unique < 0) {
1355 slot->index_unique = lsize_unique;
1425 template<
class T,
class S>
inline
1426 void extract_face_based_tags(meshdata<T,S> & mesh,
1430 std::pair<emi_face<T,tuple<T>>, emi_face<T,tuple<T>>>> & line_face,
1432 std::pair<emi_face<T,triple<T>>, emi_face<T,triple<T>>>> & tri_face,
1434 std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>>> & quad_face,
1437 meshdata<T,S> & surfmesh,
1438 meshdata<T,S> & surfmesh_w_counter,
1439 meshdata<T,S> & surfmesh_unique_face,
1447 surfmesh_w_counter.register_numbering(
SF::NBR_REF);
1448 surfmesh_unique_face.register_numbering(
SF::NBR_REF);
1452 compute_surface_with_tags(mesh, numbering, vertex2ptsdata, extra_tags, line_face, tri_face, quad_face);
1455 MPI_Comm_size(mesh.comm, &size);
1456 MPI_Comm_rank(mesh.comm, &rank);
1458 long int g_num_line = line_face.size();
1459 long int g_num_tri = tri_face.size();
1460 long int g_num_quad = quad_face.size();
1461 MPI_Allreduce(MPI_IN_PLACE, &g_num_line, 1, MPI_LONG, MPI_SUM, mesh.comm);
1462 MPI_Allreduce(MPI_IN_PLACE, &g_num_tri, 1, MPI_LONG, MPI_SUM, mesh.comm);
1463 MPI_Allreduce(MPI_IN_PLACE, &g_num_quad, 1, MPI_LONG, MPI_SUM, mesh.comm);
1467 long int local_extra_extra = 0;
1468 for (
const auto& [key, v] : line_face) {
1469 if (extra_tags.
find(v.first.tag) != extra_tags.
end() &&
1470 extra_tags.
find(v.second.tag) != extra_tags.
end()) {
1471 local_extra_extra++;
1474 for (
const auto& [key, v] : tri_face) {
1475 if (extra_tags.
find(v.first.tag) != extra_tags.
end() &&
1476 extra_tags.
find(v.second.tag) != extra_tags.
end()) {
1477 local_extra_extra++;
1480 for (
const auto& [key, v] : quad_face) {
1481 if (extra_tags.
find(v.first.tag) != extra_tags.
end() &&
1482 extra_tags.
find(v.second.tag) != extra_tags.
end()) {
1483 local_extra_extra++;
1486 long int global_extra_extra = 0;
1487 MPI_Allreduce(&local_extra_extra, &global_extra_extra, 1, MPI_LONG, MPI_SUM, mesh.comm);
1488 if (global_extra_extra > 0 && rank == 0) {
1489 fprintf(stderr,
"WARN: extra-extra faces detected before filtering: %ld\n", global_extra_extra);
1493 surfmesh.g_numelem = g_num_line + g_num_tri + g_num_quad;
1494 surfmesh.l_numelem = line_face.size() + tri_face.size() + quad_face.size();
1496 vector<T> cnt(surfmesh.l_numelem, 0);
1497 surfmesh.tag.resize(surfmesh.l_numelem);
1498 surfmesh.type.resize(surfmesh.l_numelem);
1499 surfmesh.con.resize(line_face.size() * 2 + tri_face.size() * 3 + quad_face.size() * 4);
1506 vector<tuple<T>> line_keys;
1507 for(
auto const& [key, val] : line_face) line_keys.push_back(key);
1508 std::sort(line_keys.begin(), line_keys.end());
1510 vector<triple<T>> tri_keys;
1511 for(
auto const& [key, val] : tri_face) tri_keys.push_back(key);
1512 std::sort(tri_keys.begin(), tri_keys.end());
1514 vector<quadruple<T>> quad_keys;
1515 for(
auto const& [key, val] : quad_face) quad_keys.push_back(key);
1516 std::sort(quad_keys.begin(), quad_keys.end());
1541 for(
auto const& key : line_keys) {
1542 auto& v = line_face.
at(key);
1543 const bool local_involved = (v.first.rank == rank) || (v.second.rank == rank);
1544 if (!local_involved) {
1550 if ((intra_tags.
find(v.first.tag) != intra_tags.
end()) && (intra_tags.
find(v.second.tag) != intra_tags.
end())) {
1556 emi_face<T,tuple<T>> surf_neighbor =
1557 (v.first.rank == rank) ? v.first : v.second;
1559 surfmesh.type[idx] =
Line;
1560 surfmesh.tag[idx] = surf_neighbor.tag;
1561 surfmesh.con[cidx + 0] = surf_neighbor.points.v1;
1562 surfmesh.con[cidx + 1] = surf_neighbor.points.v2;
1565 if(v.first.rank == v.second.rank)
1570 assign_ownership_rank_on_faces<T, tuple<T>, tuple<T>>( key, v, rank,
1573 extra_tags, intra_tags,
1574 line_unique_face_to_elements,
1575 map_elem_oneface_to_elem_uniqueFace);
1580 for(
auto const& key : tri_keys) {
1581 auto& v = tri_face.at(key);
1582 const bool local_involved = (v.first.rank == rank) || (v.second.rank == rank);
1583 if (!local_involved) {
1588 if ((intra_tags.
find(v.first.tag) != intra_tags.
end()) && (intra_tags.
find(v.second.tag) != intra_tags.
end())) {
1594 emi_face<T,triple<T>> surf_neighbor =
1595 (v.first.rank == rank) ? v.first : v.second;
1597 surfmesh.type[idx] =
Tri;
1598 surfmesh.tag[idx] = surf_neighbor.tag;
1599 surfmesh.con[cidx + 0] = surf_neighbor.points.v1;
1600 surfmesh.con[cidx + 1] = surf_neighbor.points.v2;
1601 surfmesh.con[cidx + 2] = surf_neighbor.points.v3;
1604 if(v.first.rank == v.second.rank)
1609 assign_ownership_rank_on_faces<T, triple<T>, triple<T>>( key, v, rank,
1612 extra_tags, intra_tags,
1613 tri_unique_face_to_elements,
1614 map_elem_oneface_to_elem_uniqueFace);
1619 for(
auto const& key : quad_keys) {
1620 auto& v = quad_face.at(key);
1621 const bool local_involved = (v.first.rank == rank) || (v.second.rank == rank);
1622 if (!local_involved) {
1627 if ((intra_tags.
find(v.first.tag) != intra_tags.
end()) && (intra_tags.
find(v.second.tag) != intra_tags.
end())) {
1633 emi_face<T,quadruple<T>> qsurf_neighbor =
1634 (v.first.rank == rank) ? v.first : v.second;
1636 surfmesh.type[idx] =
Quad;
1637 surfmesh.tag[idx] = qsurf_neighbor.tag;
1638 surfmesh.con[cidx + 0] = qsurf_neighbor.points.v1;
1639 surfmesh.con[cidx + 1] = qsurf_neighbor.points.v2;
1640 surfmesh.con[cidx + 2] = qsurf_neighbor.points.v3;
1641 surfmesh.con[cidx + 3] = qsurf_neighbor.points.v4;
1644 if(v.first.rank == v.second.rank)
1649 assign_ownership_rank_on_faces<T, quadruple<T>, quadruple<T>>( key, v, rank,
1652 extra_tags, intra_tags,
1653 quad_unique_face_to_elements,
1654 map_elem_oneface_to_elem_uniqueFace);
1659 surfmesh.l_numelem = idx;
1660 surfmesh.tag.resize(idx);
1661 surfmesh.type.resize(idx);
1664 surfmesh.con.resize(cidx);
1666 long int g_num_surf = surfmesh.l_numelem;
1667 MPI_Allreduce(MPI_IN_PLACE, &g_num_surf, 1, MPI_LONG, MPI_SUM, mesh.comm);
1668 surfmesh.g_numelem = g_num_surf;
1671 std::cout <<
"surfmesh.g_numelem: " << surfmesh.g_numelem <<std::endl;
1672 std::cout <<
"surfmesh.l_numelem: " << surfmesh.l_numelem <<std::endl;
1676 long int g_num_w_counter_line = lsize_line;
1677 long int g_num_w_counter_tri = lsize_tri;
1678 long int g_num_w_counter_quad = lsize_quad;
1680 MPI_Allreduce(MPI_IN_PLACE, &g_num_w_counter_line, 1, MPI_LONG, MPI_SUM,
SF_COMM);
1681 MPI_Allreduce(MPI_IN_PLACE, &g_num_w_counter_tri, 1, MPI_LONG, MPI_SUM,
SF_COMM);
1682 MPI_Allreduce(MPI_IN_PLACE, &g_num_w_counter_quad, 1, MPI_LONG, MPI_SUM,
SF_COMM);
1685 surfmesh_w_counter.g_numelem = g_num_w_counter_line+g_num_w_counter_tri+g_num_w_counter_quad;
1686 surfmesh_w_counter.l_numelem = lsize_line + lsize_tri + lsize_quad;
1688 surfmesh_w_counter.tag.resize(surfmesh_w_counter.l_numelem);
1689 surfmesh_w_counter.type.resize(surfmesh_w_counter.l_numelem);
1690 surfmesh_w_counter.con.resize(lsize_line * 2 + lsize_tri * 3 + lsize_quad * 4);
1693 std::cout <<
"surfmesh_w_counter.g_numelem: " << surfmesh_w_counter.g_numelem <<std::endl;
1694 std::cout <<
"surfmesh_w_counter.l_numelem: " << surfmesh_w_counter.l_numelem <<std::endl;
1699 long int g_num_w_unique_line = lsize_unique_line;
1700 long int g_num_w_unique_tri = lsize_unique_tri;
1701 long int g_num_w_unique_quad = lsize_unique_quad;
1703 MPI_Allreduce(MPI_IN_PLACE, &g_num_w_unique_line, 1, MPI_LONG, MPI_SUM,
SF_COMM);
1704 MPI_Allreduce(MPI_IN_PLACE, &g_num_w_unique_tri, 1, MPI_LONG, MPI_SUM,
SF_COMM);
1705 MPI_Allreduce(MPI_IN_PLACE, &g_num_w_unique_quad, 1, MPI_LONG, MPI_SUM,
SF_COMM);
1708 surfmesh_unique_face.g_numelem = g_num_w_unique_line+g_num_w_unique_tri+g_num_w_unique_quad;
1709 surfmesh_unique_face.l_numelem = lsize_unique_line + lsize_unique_tri + lsize_unique_quad;
1711 surfmesh_unique_face.tag.resize(surfmesh_unique_face.l_numelem);
1712 surfmesh_unique_face.type.resize(surfmesh_unique_face.l_numelem);
1713 surfmesh_unique_face.con.resize(lsize_unique_line * 2 + lsize_unique_tri * 3 + lsize_unique_quad * 4);
1716 std::cout <<
"surfmesh_unique_face.g_numelem: " << surfmesh_unique_face.g_numelem <<std::endl;
1717 std::cout <<
"surfmesh_unique_face.l_numelem: " << surfmesh_unique_face.l_numelem <<std::endl;
1729 #ifdef EMI_DEBUG_MESH
1731 fprintf(stderr,
"RANK %d BEFORE exchange: line_hash=%zu, tri_hash=%zu, quad_hash=%zu (expected unique total=%ld)\n",
1732 rank, line_unique_face_to_elements.
size(), tri_unique_face_to_elements.
size(),
1733 quad_unique_face_to_elements.
size(), lsize_unique_line + lsize_unique_tri + lsize_unique_quad);
1741 assign_unique_first_face(line_unique_face_to_elements, mesh.comm);
1742 assign_unique_first_face(tri_unique_face_to_elements, mesh.comm);
1743 assign_unique_first_face(quad_unique_face_to_elements, mesh.comm);
1747 #ifdef EMI_DEBUG_MESH
1749 int valid_line = 0, valid_tri = 0, valid_quad = 0;
1750 for (
const auto& [key, val] : line_unique_face_to_elements) {
1751 if (val.first.index_unique >= 0 || val.second.index_unique >= 0) valid_line++;
1753 for (
const auto& [key, val] : tri_unique_face_to_elements) {
1754 if (val.first.index_unique >= 0 || val.second.index_unique >= 0) valid_tri++;
1756 for (
const auto& [key, val] : quad_unique_face_to_elements) {
1757 if (val.first.index_unique >= 0 || val.second.index_unique >= 0) valid_quad++;
1759 fprintf(stderr,
"RANK %d AFTER exchange: line_hash=%zu, tri_hash=%zu, quad_hash=%zu\n",
1760 rank, line_unique_face_to_elements.size(), tri_unique_face_to_elements.size(),
1761 quad_unique_face_to_elements.size());
1762 fprintf(stderr,
"RANK %d VALID entries (index_unique>=0): line=%d, tri=%d, quad=%d\n",
1763 rank, valid_line, valid_tri, valid_quad);
1771 for(
auto it = line_unique_face_to_elements.begin(); it != line_unique_face_to_elements.end(); ++it) {
1773 auto& first = it->second.first;
1774 auto& second = it->second.second;
1776 assign_map_between_elem_oneface_and_elem_uniqueFace(rank, first, second, map_elem_uniqueFace_to_elem_oneface, map_elem_oneface_to_elem_uniqueFace);
1779 for(
auto it = tri_unique_face_to_elements.begin(); it != tri_unique_face_to_elements.end(); ++it) {
1780 auto& first = it->second.first;
1781 auto& second = it->second.second;
1783 assign_map_between_elem_oneface_and_elem_uniqueFace(rank, first, second, map_elem_uniqueFace_to_elem_oneface, map_elem_oneface_to_elem_uniqueFace);
1786 for(
auto it = quad_unique_face_to_elements.begin(); it != quad_unique_face_to_elements.end(); ++it) {
1787 auto& first = it->second.first;
1788 auto& second = it->second.second;
1790 assign_map_between_elem_oneface_and_elem_uniqueFace(rank, first, second, map_elem_uniqueFace_to_elem_oneface, map_elem_oneface_to_elem_uniqueFace);
1803 template<
class T>
inline
1805 std::pair<emi_face<T,tuple<T>>, emi_face<T,tuple<T>>>> & line_face,
1807 std::pair<emi_face<T,triple<T>>, emi_face<T,triple<T>>>> & tri_face,
1809 std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>>> & quad_face,
1815 MPI_Comm_size(comm, &size);
1816 MPI_Comm_rank(comm, &rank);
1819 for(
const auto & v : line_face) {
1822 if(v.second.first.rank == v.second.second.rank){
1826 emi_face<T,tuple<T>> surf_neighbor =
1827 (v.second.first.rank != rank) ? v.second.first : v.second.second;
1830 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1831 Index_tag_old = std::make_pair(surf_neighbor.points.v1,surf_neighbor.tag);
1832 map_vertex_tag_to_dof.insert({Index_tag_old,-1});
1836 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1837 Index_tag_old = std::make_pair(surf_neighbor.points.v2,surf_neighbor.tag);
1838 map_vertex_tag_to_dof.insert({Index_tag_old,-1});
1843 for(
const auto & v : tri_face) {
1846 if(v.second.first.rank == v.second.second.rank){
1850 emi_face<T,triple<T>> surf_neighbor =
1851 (v.second.first.rank != rank) ? v.second.first : v.second.second;
1854 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1855 Index_tag_old = std::make_pair(surf_neighbor.points.v1,surf_neighbor.tag);
1856 map_vertex_tag_to_dof.insert({Index_tag_old,-1});
1860 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1861 Index_tag_old = std::make_pair(surf_neighbor.points.v2,surf_neighbor.tag);
1862 map_vertex_tag_to_dof.insert({Index_tag_old,-1});
1866 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1867 Index_tag_old = std::make_pair(surf_neighbor.points.v3,surf_neighbor.tag);
1868 map_vertex_tag_to_dof.insert({Index_tag_old,-1});
1873 for(
const auto & v : quad_face) {
1876 if(v.second.first.rank == v.second.second.rank){
1880 emi_face<T,quadruple<T>> qsurf_neighbor =
1881 (v.second.first.rank != rank) ? v.second.first : v.second.second;
1884 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1885 Index_tag_old = std::make_pair(qsurf_neighbor.points.v1,qsurf_neighbor.tag);
1886 map_vertex_tag_to_dof.insert({Index_tag_old,-1});
1890 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1891 Index_tag_old = std::make_pair(qsurf_neighbor.points.v2,qsurf_neighbor.tag);
1892 map_vertex_tag_to_dof.insert({Index_tag_old,-1});
1896 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1897 Index_tag_old = std::make_pair(qsurf_neighbor.points.v3,qsurf_neighbor.tag);
1898 map_vertex_tag_to_dof.insert({Index_tag_old,-1});
1902 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1903 Index_tag_old = std::make_pair(qsurf_neighbor.points.v4,qsurf_neighbor.tag);
1904 map_vertex_tag_to_dof.insert({Index_tag_old,-1});
1909 assign_dof_on_counter_face(map_vertex_tag_to_dof,comm);
1941 template<
class T,
class S>
inline
1942 void compute_map_vertex_to_dof(meshdata<T,S> & mesh,
1949 MPI_Comm comm = mesh.comm;
1951 MPI_Comm_size(comm, &size);
1952 MPI_Comm_rank(comm, &rank);
1956 const T* con = mesh.con.data();
1957 const T* nbr = mesh.get_numbering(numbering).data();
1962 for(
size_t i=0; i<mesh.con.size(); i++)
1964 g2ptsData[rnod[con[i]]] = vertex2ptsdata[rnod[con[i]]];
1976 for(
size_t eidx = 0; eidx < mesh.l_numelem; eidx++)
1978 T tag = mesh.tag[eidx];
1979 auto pos_extra = extra_tags.
find(tag);
1980 for (
int n = mesh.dsp[eidx]; n < mesh.dsp[eidx+1];n++)
1982 T gIndex = rnod[con[n]];
1983 T data_on_gIndex = g2ptsData[rnod[con[n]]];
1987 if((pos_extra != extra_tags.
end()) || data_on_gIndex==0){
1988 std::pair <mesh_int_t,mesh_int_t> Index_tag_old = std::make_pair(gIndex,tag);
1989 if (map_vertex_tag_to_dof.find(Index_tag_old) == map_vertex_tag_to_dof.end() )
1991 map_vertex_tag_to_dof.insert({Index_tag_old,gIndex});
1996 auto it = map_vertex_to_tags_data_ranks.
find(gIndex);
1997 if (it != map_vertex_to_tags_data_ranks.
end() )
1999 intersection_data& value = it->second;
2000 bool check_tag_rank =
true;
2001 for(
int i=0; i<MAX_INTERSECTIONS; ++i) {
2002 if(value.tags[i] == tag && value.ranks[i] == rank) {
2003 check_tag_rank =
false;
2010 for(
int i=0; i<MAX_INTERSECTIONS; ++i) {
2011 if(value.tags[i] == -1 && value.ranks[i] == -1) {
2012 value.tags[i] = tag;
2013 value.data[i] = data_on_gIndex;
2014 value.ranks[i] = rank;
2023 intersection_data value;
2024 value.tags[0] = tag;
2025 value.data[0] = data_on_gIndex;
2026 value.ranks[0] = rank;
2027 map_vertex_to_tags_data_ranks.
insert({gIndex,value});
2043 assign_counter_vertices_tuple(map_vertex_to_tags_data_ranks, comm);
2060 for(
const auto & key : map_vertex_to_tags_data_ranks)
2062 T gIndex = key.first;
2063 const intersection_data& value = key.second;
2064 T data_on_gIndex = g2ptsData[gIndex];
2067 int first_index = 0;
2068 for (
int i = 0; i < MAX_INTERSECTIONS; ++i) {
2069 if(value.tags[i] == -1 && value.ranks[i] == -1) {
2074 if(value.data[i]!=data_on_gIndex)
2078 "WARN: Due to an inconsistency in ptsData computation at gIndex %lld with tag %lld, "
2079 "the program is stopped while preparing the data structure to introduce DOFs.\n",
2080 static_cast<long long>(gIndex),
static_cast<long long>(value.tags[i]));
2081 fprintf(stderr,
"\n");
2085 if (i == MAX_INTERSECTIONS -1) first_index = MAX_INTERSECTIONS;
2088 if(data_on_gIndex==1){
2090 int count_intra_tags = 0;
2091 int count_extra_tags = 0;
2092 for (
int i = 0; i < first_index; ++i) {
2093 if(value.tags[i]!=-1 && extra_tags.
find(value.tags[i])==extra_tags.
end()){
2094 count_intra_tags += 1;
2095 }
else if(value.tags[i]!=-1 && extra_tags.
find(value.tags[i])!=extra_tags.
end()){
2096 count_extra_tags += 1;
2102 if(count_intra_tags>1 || count_extra_tags == 0)
2106 "WARN: Due to an issue in defining ptsData for gIndex %lld, , on the membrane"
2107 "the program is stopped while preparing the data structure to introduce DOFs.\n",
2108 static_cast<long long>(gIndex));
2109 fprintf(stderr,
"\n");
2113 int index_intra = -1;
2115 for (
int i = 0; i < first_index; ++i) {
2116 if(value.tags[i]!=-1 && extra_tags.
find(value.tags[i])==extra_tags.
end()){
2121 if(index_intra == -1) {
2122 fprintf(stderr,
"WARN: unhandled case in membrane while decoupling: gIndex %lld",
2123 static_cast<long long>(gIndex));
2124 fprintf(stderr,
"\n");
2127 if(index_intra != -1) {
2128 T tag_myocyte = value.tags[index_intra];
2129 T rank_myocyte = value.ranks[index_intra];
2131 if(rank_myocyte == rank) {
2132 std::pair <mesh_int_t,mesh_int_t> Index_tag_next = std::make_pair(gIndex,tag_myocyte);
2133 if (map_mark_new_dofs.
find(Index_tag_next) == map_mark_new_dofs.
end()) {
2134 map_mark_new_dofs.
insert({Index_tag_next,
true});
2140 else if(data_on_gIndex==2){
2142 int count_intra_tags = 0;
2143 int count_extra_tags = 0;
2144 for (
int i = 0; i < first_index; ++i) {
2145 if(value.tags[i]!=-1 && extra_tags.
find(value.tags[i])==extra_tags.
end()){
2146 count_intra_tags += 1;
2147 }
else if(value.tags[i]!=-1 && extra_tags.
find(value.tags[i])!=extra_tags.
end()){
2148 count_extra_tags += 1;
2151 if(count_intra_tags!=2 || count_extra_tags != 0){
2154 "WARN: Due to an issue in defining ptsData for gIndex %lld, on the gapjunction"
2155 "the program is stopped while preparing the data structure to introduce DOFs.\n",
2156 static_cast<long long>(gIndex));
2157 fprintf(stderr,
"\n");
2165 bool tag1_checked =
false;
2166 bool tag2_checked =
false;
2168 for (
int i = 0; i < first_index; ++i)
2170 auto pos_extra = extra_tags.
find(value.tags[i]);
2171 if(pos_extra == extra_tags.
end()) {
2173 tag1 = value.tags[i];
2174 rank1 = value.ranks[i];
2175 tag1_checked =
true;
2177 tag2 = value.tags[i];
2178 rank2 = value.ranks[i];
2179 tag2_checked =
true;
2185 if(!tag1_checked && !tag2_checked || (rank1==rank2 && rank1!=rank) ) {
2187 "WARN: unhandled case in gap junction while decoupling: gIndex %lld with tags %lld:%lld ",
2188 static_cast<long long>(gIndex),
2189 static_cast<long long>(tag1),
2190 static_cast<long long>(tag2));
2191 fprintf(stderr,
"\n");
2195 if(rank1==rank2 && (rank1 == rank)){
2196 T smallest_tag = tag1 < tag2? tag1:tag2;
2197 std::pair <mesh_int_t,mesh_int_t> Index_tag_old = std::make_pair(gIndex,smallest_tag);
2198 if (map_vertex_tag_to_dof.find(Index_tag_old) == map_vertex_tag_to_dof.end() ) {
2199 map_vertex_tag_to_dof.insert({Index_tag_old,gIndex});
2202 T bigger_tag = tag1 < tag2? tag2:tag1;
2203 std::pair <mesh_int_t,mesh_int_t> Index_tag_new = std::make_pair(gIndex,bigger_tag);
2204 if (map_mark_new_dofs.
find(Index_tag_new) == map_mark_new_dofs.
end() ) {
2205 map_mark_new_dofs.
insert({Index_tag_new,
true});
2209 else if(rank1!=rank2 && (rank1 == rank)) {
2211 std::pair <mesh_int_t,mesh_int_t> Index_tag_old = std::make_pair(gIndex,tag1);
2212 if (map_vertex_tag_to_dof.find(Index_tag_old) == map_vertex_tag_to_dof.end() ) {
2213 map_vertex_tag_to_dof.insert({Index_tag_old,gIndex});
2216 std::pair <mesh_int_t,mesh_int_t> Index_tag_new = std::make_pair(gIndex,tag1);
2217 if (map_mark_new_dofs.
find(Index_tag_new) == map_mark_new_dofs.
end() ) {
2218 map_mark_new_dofs.
insert({Index_tag_new,
true});
2223 else if(rank1!=rank2 && (rank2 == rank)) {
2225 std::pair <mesh_int_t,mesh_int_t> Index_tag_old = std::make_pair(gIndex,tag2);
2226 if (map_vertex_tag_to_dof.find(Index_tag_old) == map_vertex_tag_to_dof.end() ) {
2227 map_vertex_tag_to_dof.insert({Index_tag_old,gIndex});
2230 std::pair <mesh_int_t,mesh_int_t> Index_tag_new = std::make_pair(gIndex,tag2);
2231 if (map_mark_new_dofs.
find(Index_tag_new) == map_mark_new_dofs.
end() ) {
2232 map_mark_new_dofs.
insert({Index_tag_new,
true});
2238 else if(data_on_gIndex==3)
2241 int count_intra_tags = 0;
2242 int count_extra_tags = 0;
2243 for (
int i = 0; i < first_index; ++i) {
2244 if(value.tags[i]!=-1 && extra_tags.
find(value.tags[i])==extra_tags.
end()){
2245 count_intra_tags += 1;
2246 }
else if(value.tags[i]!=-1 && extra_tags.
find(value.tags[i])!=extra_tags.
end()){
2247 count_extra_tags += 1;
2250 if(count_intra_tags!=2 || count_extra_tags == 0){
2253 "WARN: Due to an issue in defining ptsData for gIndex %lld, on intersection between membrane and gapjunction"
2254 "the program is stopped while preparing the data structure to introduce DOFs.\n",
2255 static_cast<long long>(gIndex));
2256 fprintf(stderr,
"\n");
2262 for (
int i = 0; i < first_index; ++i) {
2264 auto pos_extra = extra_tags.
find(value.tags[i]);
2265 if(value.tags[i]!=-1 && value.ranks[i] == rank && pos_extra == extra_tags.
end()) {
2266 std::pair <mesh_int_t,mesh_int_t> Index_tag_new = std::make_pair(gIndex,value.tags[i]);
2267 if (map_mark_new_dofs.
find(Index_tag_new) == map_mark_new_dofs.
end() )
2269 map_mark_new_dofs.
insert({Index_tag_new,
true});
2277 vector<T> dsp_dof(size);
2278 MPI_Allgather(&shift,
sizeof(T), MPI_BYTE, dsp_dof.data(),
sizeof(T), MPI_BYTE, comm);
2293 start = mesh.g_numpts;
2297 start = mesh.g_numpts;
2298 for (
int r = 0; r < rank; ++r)
2305 auto lexicographic_comp_pair = [](
const std::pair<mesh_int_t,mesh_int_t> & a,
const std::pair<mesh_int_t,mesh_int_t> & b)
2307 if (a.second == b.second)
return a.first < b.first;
2308 return a.second < b.second;
2311 map_mark_new_dofs.
sort(lexicographic_comp_pair);
2313 for(
const auto & entry : map_mark_new_dofs)
2315 T newIndex = start+
count;
2316 map_vertex_tag_to_dof.insert({entry.first,newIndex});
2332 template<
class K,
class IntersectionIndices>
inline
2335 size_t dsize = map.
size();
2336 vector<K> key_vec(dsize);
2337 vector<IntersectionIndices> value_vec(dsize);
2338 IntersectionIndices indices;
2340 for (
const auto& v : map) {
2341 key_vec[idx] = v.first;
2342 value_vec[idx] = v.second;
2346 vector<int> perm, dest;
2347 emi_select_merge_destinations(key_vec, dsize,
sizeof(K) +
sizeof(intersection_indices), dest, comm,
2348 "assign_counter_dofs",
2351 commgraph<size_t> grph;
2352 grph.configure(dest, comm);
2353 size_t nrecv =
sum(grph.rcnt);
2359 vector<K> sbuff_key(dsize), rbuff_key(nrecv);
2360 vector<IntersectionIndices> sbuff_value(dsize), ibuff_value(dsize), rbuff_value(nrecv);
2361 for (
size_t i = 0; i < dsize; i++) {
2362 sbuff_key[i] = key_vec[perm[i]];
2363 sbuff_value[i] = value_vec[perm[i]];
2369 for (
size_t i = 0; i < nrecv; i++)
2371 auto it = rmap.
find(rbuff_key[i]);
2372 if (it != rmap.
end())
2374 IntersectionIndices& map_indices = it->second;
2375 IntersectionIndices& received_indices = rbuff_value[i];
2377 for (
mesh_int_t received_index : received_indices.indices)
2379 if (received_index == -1)
continue;
2381 for (
mesh_int_t map_index : map_indices.indices)
2383 if (map_index == received_index) {
2390 for (
size_t k = 0; k < MAX_INTERSECTIONS; ++k) {
2391 if (map_indices.indices[k] == -1) {
2392 map_indices.indices[k] = received_index;
2401 rmap.
insert({ rbuff_key[i], rbuff_value[i] });
2405 for (
size_t i = 0; i < nrecv; i++) {
2406 auto it = rmap.
find(rbuff_key[i]);
2407 if (it != rmap.
end()) rbuff_value[i] = it->second;
2414 for (
size_t i = 0; i < dsize; i++) {
2415 auto it = map.find(sbuff_key[i]);
2416 if (it != map.end()) it->second = ibuff_value[i];
2429 template<
class T,
class S>
inline
2430 void update_emi_mesh_with_dofs(meshdata<T,S> & mesh,
2438 MPI_Comm comm = mesh.comm;
2439 mesh.globalize(numbering);
2440 for(
size_t eidx = 0; eidx < mesh.l_numelem; eidx++) {
2441 T tag = mesh.tag[eidx];
2442 T size_elem = mesh.dsp[eidx+1]-mesh.dsp[eidx];
2444 for (
int n = mesh.dsp[eidx]; n < mesh.dsp[eidx+1];n++)
2446 T gIndex = mesh.con[n];
2448 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2449 Index_tag_old = std::make_pair(gIndex,tag);
2451 auto it_new = map_vertex_tag_to_dof.find(Index_tag_old);
2452 if (it_new != map_vertex_tag_to_dof.end() )
2455 dof2vertex.
insert({dof_new, gIndex});
2456 mesh.con[n] = dof_new;
2458 auto it = vertex2dof.
find(gIndex);
2459 if (it != vertex2dof.
end())
2461 intersection_indices& indices = it->second;
2463 for(T t : indices.indices) {
2471 for(
size_t i=0; i<MAX_INTERSECTIONS; ++i) {
2472 if(indices.indices[i] == -1) {
2473 indices.indices[i] = dof_new;
2479 intersection_indices indices;
2480 indices.indices[0] = dof_new;
2481 vertex2dof.
insert({gIndex,indices});
2487 assign_counter_dofs(vertex2dof, comm);
2490 for (
const auto& [old_idx, indices] : vertex2dof) {
2492 if (new_idx != -1) {
2494 if (dof2vertex.
find(new_idx) == dof2vertex.
end()) {
2495 dof2vertex.
insert({new_idx, old_idx});
2501 mesh.localize(numbering);
2517 template<
class T,
class S>
inline
2518 void update_map_indices_to_petsc(meshdata<T,S> & mesh,
2519 const SF_nbr numbering_ref,
const SF_nbr numbering_petsc,
2522 std::pair<mesh_int_t,mesh_int_t>> & map_vertex_tag_to_dof_petsc,
2526 const SF::vector<T> & ref_nbr = mesh.get_numbering(numbering_ref);
2527 const SF::vector<T> & petsc_nbr = mesh.get_numbering(numbering_petsc);
2529 elemTag_emi_mesh.
resize(mesh.l_numelem);
2530 for(
size_t eidx = 0; eidx < mesh.l_numelem; eidx++) {
2531 T tag = mesh.tag[eidx];
2532 elemTag_emi_mesh[eidx] = 1;
2533 if(extra_tags.
find(tag) == extra_tags.
end())
2534 elemTag_emi_mesh[eidx] = 2;
2535 for (
int n = mesh.dsp[eidx]; n < mesh.dsp[eidx+1];n++)
2537 T l_Indx = mesh.con[n];
2538 T petsc_Idx = petsc_nbr[l_Indx];
2539 T n_Indx = ref_nbr[l_Indx];
2540 T o_Indx = dof2vertex[n_Indx];
2542 std::pair <mesh_int_t,mesh_int_t> oIndx_tag;
2543 oIndx_tag = std::make_pair(o_Indx,tag);
2545 auto it_new = map_vertex_tag_to_dof_petsc.find(oIndx_tag);
2546 if (it_new != map_vertex_tag_to_dof_petsc.end() )
2548 std::pair <mesh_int_t,mesh_int_t> nIndx_petsc;
2549 nIndx_petsc = std::make_pair(n_Indx,petsc_Idx);
2551 (*it_new).second = nIndx_petsc;
2568 template<
class T,
class S>
2569 inline void update_faces_on_surface_mesh_after_decoupling_with_dofs(meshdata<T, S> & mesh,
2573 std::pair<emi_face<T,tuple<T>>, emi_face<T,tuple<T>>>> & line_face,
2575 std::pair<emi_face<T,triple<T>>, emi_face<T,triple<T>>>> & tri_face,
2577 std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>>> & quad_face)
2581 MPI_Comm_size(comm, &size); MPI_Comm_rank(comm, &rank);
2588 for(
size_t i=0; i<idxbuff.size(); i++){
2589 g2l[idxbuff[i]] = i;
2590 l2g[i] = idxbuff[i];
2593 for(
size_t eidx = 0; eidx < mesh.l_numelem; eidx++) {
2594 T tag = mesh.tag[eidx];
2595 T size_elem = mesh.dsp[eidx+1]-mesh.dsp[eidx];
2596 std::vector<mesh_int_t> elem_nodes;
2597 for (
int n = mesh.dsp[eidx]; n < mesh.dsp[eidx+1];n++)
2599 T gIndex = mesh.con[n];
2600 elem_nodes.push_back(gIndex);
2602 std::sort(elem_nodes.begin(),elem_nodes.end());
2603 if(elem_nodes.size()==2){
2605 key.v1 = elem_nodes[0];
2606 key.v2 = elem_nodes[1];
2607 std::pair<emi_face<T,tuple<T>>, emi_face<T,tuple<T>>> value = line_face[key];
2609 line_face.erase(key);
2610 std::vector<mesh_int_t> new_nodes(2);
2612 auto tag_key = (value.first.rank == rank) ? value.first.tag : value.second.tag;
2614 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2615 Index_tag_old = std::make_pair(elem_nodes[0],tag_key);
2616 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2617 new_nodes[0] = Index_new;
2620 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2621 Index_tag_old = std::make_pair(elem_nodes[1],tag_key);
2622 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2623 new_nodes[1] = Index_new;
2625 std::sort(new_nodes.begin(),new_nodes.end());
2628 new_key.v1 = new_nodes[0];
2629 new_key.v2 = new_nodes[1];
2633 mesh_int_t Index_new1 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v1, value.first.tag)];
2634 mesh_int_t Index_new2 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v2, value.first.tag)];
2635 value.first.points.v1 = Index_new1;
2636 value.first.points.v2 = Index_new2;
2640 mesh_int_t Index_new1 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v1, value.second.tag)];
2641 mesh_int_t Index_new2 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v2, value.second.tag)];
2642 value.second.points.v1 = Index_new1;
2643 value.second.points.v2 = Index_new2;
2645 line_face.insert({new_key,value});
2647 if(elem_nodes.size()==3){
2649 key.v1 = elem_nodes[0];
2650 key.v2 = elem_nodes[1];
2651 key.v3 = elem_nodes[2];
2652 std::pair<emi_face<T,triple<T>>, emi_face<T,triple<T>>> value = tri_face[key];
2653 tri_face.erase(key);
2654 std::vector<mesh_int_t> new_nodes(3);
2656 auto tag_key = (value.first.rank == rank) ? value.first.tag : value.second.tag;
2658 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2659 Index_tag_old = std::make_pair(elem_nodes[0],tag_key);
2660 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2661 new_nodes[0] = Index_new;
2664 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2665 Index_tag_old = std::make_pair(elem_nodes[1],tag_key);
2666 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2667 new_nodes[1] = Index_new;
2670 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2671 Index_tag_old = std::make_pair(elem_nodes[2],tag_key);
2672 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2673 new_nodes[2] = Index_new;
2675 std::sort(new_nodes.begin(),new_nodes.end());
2678 new_key.v1 = new_nodes[0];
2679 new_key.v2 = new_nodes[1];
2680 new_key.v3 = new_nodes[2];
2684 mesh_int_t Index_new1 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v1, value.first.tag)];
2685 mesh_int_t Index_new2 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v2, value.first.tag)];
2686 mesh_int_t Index_new3 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v3, value.first.tag)];
2687 value.first.points.v1 = Index_new1;
2688 value.first.points.v2 = Index_new2;
2689 value.first.points.v3 = Index_new3;
2693 mesh_int_t Index_new1 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v1, value.second.tag)];
2694 mesh_int_t Index_new2 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v2, value.second.tag)];
2695 mesh_int_t Index_new3 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v3, value.second.tag)];
2696 value.second.points.v1 = Index_new1;
2697 value.second.points.v2 = Index_new2;
2698 value.second.points.v3 = Index_new3;
2700 tri_face.insert({new_key,value});
2702 if(elem_nodes.size()==4){
2704 key.v1 = elem_nodes[0];
2705 key.v2 = elem_nodes[1];
2706 key.v3 = elem_nodes[2];
2707 key.v4 = elem_nodes[3];
2708 std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>> value = quad_face[key];
2709 quad_face.erase(key);
2710 std::vector<mesh_int_t> new_nodes(4);
2712 auto tag_key = (value.first.rank == rank) ? value.first.tag : value.second.tag;
2714 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2715 Index_tag_old = std::make_pair(elem_nodes[0],tag_key);
2716 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2717 new_nodes[0] = Index_new;
2720 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2721 Index_tag_old = std::make_pair(elem_nodes[1],tag_key);
2722 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2723 new_nodes[1] = Index_new;
2726 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2727 Index_tag_old = std::make_pair(elem_nodes[2],tag_key);
2728 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2729 new_nodes[2] = Index_new;
2732 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2733 Index_tag_old = std::make_pair(elem_nodes[3],tag_key);
2734 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2735 new_nodes[3] = Index_new;
2737 std::sort(new_nodes.begin(),new_nodes.end());
2739 quadruple<T> new_key;
2740 new_key.v1 = new_nodes[0];
2741 new_key.v2 = new_nodes[1];
2742 new_key.v3 = new_nodes[2];
2743 new_key.v4 = new_nodes[3];
2747 mesh_int_t Index_new1 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v1, value.first.tag)];
2748 mesh_int_t Index_new2 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v2, value.first.tag)];
2749 mesh_int_t Index_new3 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v3, value.first.tag)];
2750 mesh_int_t Index_new4 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v4, value.first.tag)];
2751 value.first.points.v1 = Index_new1;
2752 value.first.points.v2 = Index_new2;
2753 value.first.points.v3 = Index_new3;
2754 value.first.points.v4 = Index_new4;
2758 mesh_int_t Index_new1 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v1, value.second.tag)];
2759 mesh_int_t Index_new2 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v2, value.second.tag)];
2760 mesh_int_t Index_new3 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v3, value.second.tag)];
2761 mesh_int_t Index_new4 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v4, value.second.tag)];
2762 value.second.points.v1 = Index_new1;
2763 value.second.points.v2 = Index_new2;
2764 value.second.points.v3 = Index_new3;
2765 value.second.points.v4 = Index_new4;
2767 quad_face.insert({new_key,value});
2783 template<
class T,
class S>
inline
2784 void compute_surface_mesh_with_counter_face(meshdata<T, S> & mesh,
const SF_nbr numbering,
2786 std::pair<emi_face<T,tuple<T>>, emi_face<T,tuple<T>>>> & line_face,
2788 std::pair<emi_face<T,triple<T>>, emi_face<T,triple<T>>>> & tri_face,
2790 std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>>> & quad_face)
2792 mesh.register_numbering(numbering);
2796 MPI_Comm_size(comm, &size);
2797 MPI_Comm_rank(comm, &rank);
2800 vector<tuple<T>> line_keys;
2801 for(
auto const& [key, val] : line_face) line_keys.push_back(key);
2802 std::sort(line_keys.begin(), line_keys.end());
2804 vector<triple<T>> tri_keys;
2805 for(
auto const& [key, val] : tri_face) tri_keys.push_back(key);
2806 std::sort(tri_keys.begin(), tri_keys.end());
2808 vector<quadruple<T>> quad_keys;
2809 for(
auto const& [key, val] : quad_face) quad_keys.push_back(key);
2810 std::sort(quad_keys.begin(), quad_keys.end());
2812 vector<T> cnt(mesh.l_numelem);
2813 size_t idx = 0, cidx = 0;
2818 for(
const auto & key : line_keys) {
2819 const auto & v = line_face.at(key);
2820 bool both_faces = (v.first.rank == v.second.rank) ?
true:
false;
2824 emi_face<T,tuple<T>> surf_first;
2825 emi_face<T,tuple<T>> surf_second;
2826 if(v.first.rank == rank)
2828 surf_first = v.first;
2829 surf_second = v.second;
2833 surf_first = v.second;
2834 surf_second = v.first;
2837 mesh.type[idx] =
Line;
2838 mesh.tag[idx] = surf_first.tag;
2839 mesh.con[cidx + 0] = surf_first.points.v1;
2840 mesh.con[cidx + 1] = surf_first.points.v2;
2847 mesh.type[idx] =
Line;
2848 mesh.tag[idx] = surf_second.tag;
2849 mesh.con[cidx + 0] = surf_second.points.v1;
2850 mesh.con[cidx + 1] = surf_second.points.v2;
2857 for(
const auto & key : tri_keys) {
2858 const auto & v = tri_face.at(key);
2859 bool both_faces = (v.first.rank == v.second.rank) ?
true:
false;
2863 emi_face<T,triple<T>> surf_first;
2864 emi_face<T,triple<T>> surf_second;
2865 if(v.first.rank == rank)
2867 surf_first = v.first;
2868 surf_second = v.second;
2872 surf_first = v.second;
2873 surf_second = v.first;
2876 mesh.type[idx] =
Tri;
2877 mesh.tag[idx] = surf_first.tag;
2878 mesh.con[cidx + 0] = surf_first.points.v1;
2879 mesh.con[cidx + 1] = surf_first.points.v2;
2880 mesh.con[cidx + 2] = surf_first.points.v3;
2889 mesh.type[idx] =
Tri;
2890 mesh.tag[idx] = surf_second.tag;
2891 mesh.con[cidx + 0] = surf_second.points.v1;
2892 mesh.con[cidx + 1] = surf_second.points.v2;
2893 mesh.con[cidx + 2] = surf_second.points.v3;
2900 for(
const auto & key : quad_keys) {
2901 const auto & v = quad_face.at(key);
2902 bool both_faces = (v.first.rank == v.second.rank) ?
true:
false;
2905 emi_face<T,quadruple<T>> surf_first;
2906 emi_face<T,quadruple<T>> surf_second;
2907 if(v.first.rank == rank)
2909 surf_first = v.first;
2910 surf_second = v.second;
2914 surf_first = v.second;
2915 surf_second = v.first;
2918 mesh.type[idx] =
Quad;
2919 mesh.tag[idx] = surf_first.tag;
2920 mesh.con[cidx + 0] = surf_first.points.v1;
2921 mesh.con[cidx + 1] = surf_first.points.v2;
2922 mesh.con[cidx + 2] = surf_first.points.v3;
2923 mesh.con[cidx + 3] = surf_first.points.v4;
2932 mesh.type[idx] =
Quad;
2933 mesh.tag[idx] = surf_second.tag;
2934 mesh.con[cidx + 0] = surf_second.points.v1;
2935 mesh.con[cidx + 1] = surf_second.points.v2;
2936 mesh.con[cidx + 2] = surf_second.points.v3;
2937 mesh.con[cidx + 3] = surf_second.points.v4;
2977 template<
class T,
class S>
inline
2978 void compute_surface_mesh_with_unique_face(meshdata<T, S> & mesh,
const SF_nbr numbering,
2980 std::pair<emi_face<T,tuple<T>>, emi_face<T,tuple<T>>>> & line_face,
2982 std::pair<emi_face<T,triple<T>>, emi_face<T,triple<T>>>> & tri_face,
2984 std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>>> & quad_face,
2987 mesh.register_numbering(numbering);
2991 MPI_Comm_size(comm, &size);
2992 MPI_Comm_rank(comm, &rank);
2995 vector<tuple<T>> line_keys;
2996 for(
auto const& [key, val] : line_face) line_keys.push_back(key);
2997 std::sort(line_keys.begin(), line_keys.end());
2999 vector<triple<T>> tri_keys;
3000 for(
auto const& [key, val] : tri_face) tri_keys.push_back(key);
3001 std::sort(tri_keys.begin(), tri_keys.end());
3003 vector<quadruple<T>> quad_keys;
3004 for(
auto const& [key, val] : quad_face) quad_keys.push_back(key);
3005 std::sort(quad_keys.begin(), quad_keys.end());
3007 vector<T> cnt(mesh.l_numelem);
3008 size_t idx = 0, cidx = 0;
3013 for(
const auto & key : line_keys) {
3014 const auto & v = line_face.at(key);
3016 bool to_take_face =
false;
3018 emi_face<T,tuple<T>> surf_take;
3019 std::pair <mesh_int_t,mesh_int_t> tag_pairs_take;
3021 if(v.first.rank == rank && v.first.mark_to_take ==
true)
3023 surf_take = v.first;
3024 to_take_face =
true;
3025 tag_pairs_take = std::make_pair(v.first.tag,v.second.tag);
3027 else if(v.second.rank == rank && v.second.mark_to_take ==
true)
3029 surf_take = v.second;
3030 to_take_face =
true;
3031 tag_pairs_take = std::make_pair(v.second.tag,v.first.tag);
3036 map_elem_uniqueFace_to_tags.insert({idx,tag_pairs_take});
3038 mesh.type[idx] =
Line;
3039 mesh.tag[idx] = surf_take.tag;
3040 mesh.con[cidx + 0] = surf_take.points.v1;
3041 mesh.con[cidx + 1] = surf_take.points.v2;
3048 for(
const auto & key : tri_keys) {
3049 const auto & v = tri_face.at(key);
3051 bool to_take_face =
false;
3053 emi_face<T,triple<T>> surf_take;
3054 std::pair <mesh_int_t,mesh_int_t> tag_pairs_take;
3056 if(v.first.rank == rank && v.first.mark_to_take ==
true)
3058 surf_take = v.first;
3059 to_take_face =
true;
3060 tag_pairs_take = std::make_pair(v.first.tag,v.second.tag);
3062 else if(v.second.rank == rank && v.second.mark_to_take ==
true)
3064 surf_take = v.second;
3065 to_take_face =
true;
3066 tag_pairs_take = std::make_pair(v.second.tag,v.first.tag);
3071 map_elem_uniqueFace_to_tags.insert({idx,tag_pairs_take});
3073 mesh.type[idx] =
Tri;
3074 mesh.tag[idx] = surf_take.tag;
3075 mesh.con[cidx + 0] = surf_take.points.v1;
3076 mesh.con[cidx + 1] = surf_take.points.v2;
3077 mesh.con[cidx + 2] = surf_take.points.v3;
3085 for(
const auto & key : quad_keys) {
3086 const auto & v = quad_face.at(key);
3088 bool to_take_face =
false;
3090 emi_face<T,quadruple<T>> surf_take;
3091 std::pair <mesh_int_t,mesh_int_t> tag_pairs_take;
3093 if(v.first.rank == rank && v.first.mark_to_take ==
true)
3095 surf_take = v.first;
3096 to_take_face =
true;
3097 tag_pairs_take = std::make_pair(v.first.tag,v.second.tag);
3099 else if(v.second.rank == rank && v.second.mark_to_take ==
true)
3101 surf_take = v.second;
3102 to_take_face =
true;
3103 tag_pairs_take = std::make_pair(v.second.tag,v.first.tag);
3108 map_elem_uniqueFace_to_tags.insert({idx,tag_pairs_take});
3110 mesh.type[idx] =
Quad;
3111 mesh.tag[idx] = surf_take.tag;
3112 mesh.con[cidx + 0] = surf_take.points.v1;
3113 mesh.con[cidx + 1] = surf_take.points.v2;
3114 mesh.con[cidx + 2] = surf_take.points.v3;
3115 mesh.con[cidx + 3] = surf_take.points.v4;
3144 template<
class T>
inline
3145 void create_reverse_elem_mapping_between_surface_meshes(
3148 hashmap::unordered_map<quadruple<T>, std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>>>& quad_face,
3153 MPI_Comm_rank(comm, &rank);
3156 vector<tuple<T>> line_keys;
3157 for(
auto const& [key, val] : line_face) line_keys.push_back(key);
3158 std::sort(line_keys.begin(), line_keys.end());
3160 vector<triple<T>> tri_keys;
3161 for(
auto const& [key, val] : tri_face) tri_keys.push_back(key);
3162 std::sort(tri_keys.begin(), tri_keys.end());
3164 vector<quadruple<T>> quad_keys;
3165 for(
auto const& [key, val] : quad_face) quad_keys.push_back(key);
3166 std::sort(quad_keys.begin(), quad_keys.end());
3168 size_t surf_elem_idx = 0;
3169 size_t w_counter_elem_idx = 0;
3171 size_t lsize_line = 0;
3172 size_t lsize_tri = 0;
3173 size_t lsize_quad = 0;
3177 for(
const auto& key : line_keys) {
3178 const auto& v = line_face.at(key);
3179 const bool local_involved = (v.first.rank == rank) || (v.second.rank == rank);
3180 if (!local_involved) {
3183 if(v.first.rank == v.second.rank) lsize_line+=2;
3186 for(
const auto& key : tri_keys) {
3187 const auto& v = tri_face.at(key);
3188 const bool local_involved = (v.first.rank == rank) || (v.second.rank == rank);
3189 if (!local_involved) {
3192 if(v.first.rank == v.second.rank) lsize_tri+=2;
3195 for(
const auto& key : quad_keys) {
3196 const auto& v = quad_face.at(key);
3197 const bool local_involved = (v.first.rank == rank) || (v.second.rank == rank);
3198 if (!local_involved) {
3201 if(v.first.rank == v.second.rank) lsize_quad+=2;
3205 vec_one_to_both_face.
resize(lsize_line + lsize_tri + lsize_quad);
3209 for (
const auto& key : line_keys) {
3210 const auto& v = line_face.at(key);
3211 const bool local_involved = (v.first.rank == rank) || (v.second.rank == rank);
3212 if (!local_involved) {
3215 vec_one_to_both_face[w_counter_elem_idx++] = surf_elem_idx;
3216 if (v.first.rank == v.second.rank) {
3217 vec_one_to_both_face[w_counter_elem_idx++] = surf_elem_idx;
3222 for (
const auto& key : tri_keys) {
3223 const auto& v = tri_face.at(key);
3224 const bool local_involved = (v.first.rank == rank) || (v.second.rank == rank);
3225 if (!local_involved) {
3228 vec_one_to_both_face[w_counter_elem_idx++] = surf_elem_idx;
3229 if (v.first.rank == v.second.rank) {
3230 vec_one_to_both_face[w_counter_elem_idx++] = surf_elem_idx;
3235 for (
const auto& key : quad_keys) {
3236 const auto& v = quad_face.at(key);
3237 const bool local_involved = (v.first.rank == rank) || (v.second.rank == rank);
3238 if (!local_involved) {
3241 vec_one_to_both_face[w_counter_elem_idx++] = surf_elem_idx;
3242 if (v.first.rank == v.second.rank) {
3243 vec_one_to_both_face[w_counter_elem_idx++] = surf_elem_idx;
3257 template<
class T>
inline
3259 std::pair<emi_face<T,tuple<T>>, emi_face<T,tuple<T>>>> & line_face,
3261 std::pair<emi_face<T,triple<T>>, emi_face<T,triple<T>>>> & tri_face,
3263 std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>>> & quad_face)
3266 std::vector<std::pair<tuple<T>, std::pair<emi_face<T,tuple<T>>, emi_face<T,tuple<T>>>>> line_inserts;
3267 for(
const auto & v : line_face) {
3268 SF::emi_face<mesh_int_t,SF::tuple<mesh_int_t>> surf_first = v.second.first;
3269 SF::emi_face<mesh_int_t,SF::tuple<mesh_int_t>> surf_second = v.second.second;
3271 std::vector<mesh_int_t> elem_nodes_first; elem_nodes_first.
resize(2);
3272 std::vector<mesh_int_t> elem_nodes_second; elem_nodes_second.resize(2);
3275 elem_nodes_first[0] = surf_first.points.
v1;
3276 elem_nodes_first[1] = surf_first.points.v2;
3277 std::sort(elem_nodes_first.begin(),elem_nodes_first.end());
3278 key_first.
v1 = elem_nodes_first[0];
3279 key_first.
v2 = elem_nodes_first[1];
3282 elem_nodes_second[0] = surf_second.points.
v1;
3283 elem_nodes_second[1] = surf_second.points.v2;
3284 std::sort(elem_nodes_second.begin(),elem_nodes_second.end());
3285 key_second.
v1 = elem_nodes_second[0];
3286 key_second.
v2 = elem_nodes_second[1];
3288 const bool same_key_first = (v.first.v1 == key_first.
v1 && v.first.v2 == key_first.
v2);
3289 if (!same_key_first && line_face.find(key_first) == line_face.end()) {
3290 line_inserts.push_back({key_first, v.second});
3292 const bool same_key_second = (v.first.v1 == key_second.
v1 && v.first.v2 == key_second.
v2);
3293 if (!same_key_second && line_face.find(key_second) == line_face.end()) {
3294 line_inserts.push_back({key_second, v.second});
3297 for (
const auto & entry : line_inserts) line_face.insert(entry);
3299 std::vector<std::pair<triple<T>, std::pair<emi_face<T,triple<T>>, emi_face<T,triple<T>>>>> tri_inserts;
3300 for(
const auto & v : tri_face) {
3301 SF::emi_face<mesh_int_t,SF::triple<mesh_int_t>> surf_first = v.second.first;
3302 SF::emi_face<mesh_int_t,SF::triple<mesh_int_t>> surf_second = v.second.second;
3304 std::vector<mesh_int_t> elem_nodes_first; elem_nodes_first.resize(3);
3305 std::vector<mesh_int_t> elem_nodes_second; elem_nodes_second.resize(3);
3308 elem_nodes_first[0] = surf_first.points.
v1;
3309 elem_nodes_first[1] = surf_first.points.v2;
3310 elem_nodes_first[2] = surf_first.points.v3;
3311 std::sort(elem_nodes_first.begin(),elem_nodes_first.end());
3312 key_first.
v1 = elem_nodes_first[0];
3313 key_first.
v2 = elem_nodes_first[1];
3314 key_first.
v3 = elem_nodes_first[2];
3317 elem_nodes_second[0] = surf_second.points.
v1;
3318 elem_nodes_second[1] = surf_second.points.v2;
3319 elem_nodes_second[2] = surf_second.points.v3;
3320 std::sort(elem_nodes_second.begin(),elem_nodes_second.end());
3321 key_second.
v1 = elem_nodes_second[0];
3322 key_second.
v2 = elem_nodes_second[1];
3323 key_second.
v3 = elem_nodes_second[2];
3325 const bool same_key_first = (v.first.v1 == key_first.
v1 &&
3326 v.first.v2 == key_first.
v2 &&
3327 v.first.v3 == key_first.
v3);
3328 if (!same_key_first && tri_face.find(key_first) == tri_face.end()) {
3329 tri_inserts.push_back({key_first, v.second});
3331 const bool same_key_second = (v.first.v1 == key_second.
v1 &&
3332 v.first.v2 == key_second.
v2 &&
3333 v.first.v3 == key_second.
v3);
3334 if (!same_key_second && tri_face.find(key_second) == tri_face.end()) {
3335 tri_inserts.push_back({key_second, v.second});
3338 for (
const auto & entry : tri_inserts) tri_face.insert(entry);
3340 std::vector<std::pair<quadruple<T>, std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>>>> quad_inserts;
3341 for(
const auto & v : quad_face) {
3342 SF::emi_face<mesh_int_t,SF::quadruple<mesh_int_t>> surf_first = v.second.first;
3343 SF::emi_face<mesh_int_t,SF::quadruple<mesh_int_t>> surf_second = v.second.second;
3345 std::vector<mesh_int_t> elem_nodes_first; elem_nodes_first.resize(4);
3346 std::vector<mesh_int_t> elem_nodes_second; elem_nodes_second.resize(4);
3349 elem_nodes_first[0] = surf_first.points.
v1;
3350 elem_nodes_first[1] = surf_first.points.v2;
3351 elem_nodes_first[2] = surf_first.points.v3;
3352 elem_nodes_first[3] = surf_first.points.v4;
3353 std::sort(elem_nodes_first.begin(),elem_nodes_first.end());
3354 key_first.
v1 = elem_nodes_first[0];
3355 key_first.
v2 = elem_nodes_first[1];
3356 key_first.
v3 = elem_nodes_first[2];
3357 key_first.
v4 = elem_nodes_first[3];
3360 elem_nodes_second[0] = surf_second.points.
v1;
3361 elem_nodes_second[1] = surf_second.points.v2;
3362 elem_nodes_second[2] = surf_second.points.v3;
3363 elem_nodes_second[3] = surf_second.points.v4;
3364 std::sort(elem_nodes_second.begin(),elem_nodes_second.end());
3365 key_second.
v1 = elem_nodes_second[0];
3366 key_second.
v2 = elem_nodes_second[1];
3367 key_second.
v3 = elem_nodes_second[2];
3368 key_second.
v4 = elem_nodes_second[3];
3370 const bool same_key_first = (v.first.v1 == key_first.
v1 &&
3371 v.first.v2 == key_first.
v2 &&
3372 v.first.v3 == key_first.
v3 &&
3373 v.first.v4 == key_first.
v4);
3374 if (!same_key_first && quad_face.find(key_first) == quad_face.end()) {
3375 quad_inserts.push_back({key_first, v.second});
3377 const bool same_key_second = (v.first.v1 == key_second.
v1 &&
3378 v.first.v2 == key_second.
v2 &&
3379 v.first.v3 == key_second.
v3 &&
3380 v.first.v4 == key_second.
v4);
3381 if (!same_key_second && quad_face.find(key_second) == quad_face.end()) {
3382 quad_inserts.push_back({key_second, v.second});
3385 for (
const auto & entry : quad_inserts) quad_face.insert(entry);
3395 template<
class K>
inline
3398 size_t dsize = map.
size();
3399 vector<K> key_vec(dsize);
3400 vector<intersection_tags> value_vec(dsize);
3403 for (
const auto& v : map) {
3404 key_vec[idx] = v.first;
3405 value_vec[idx] = v.second;
3409 vector<int> perm, dest;
3410 emi_select_merge_destinations(key_vec, dsize,
sizeof(K) +
sizeof(intersection_tags), dest, comm,
3411 "assign_counter_tags",
3414 commgraph<size_t> grph;
3415 grph.configure(dest, comm);
3416 size_t nrecv =
sum(grph.rcnt);
3422 vector<K> sbuff_key(dsize), rbuff_key(nrecv);
3423 vector<intersection_tags> sbuff_value(dsize), ibuff_value(dsize), rbuff_value(nrecv);
3424 for (
size_t i = 0; i < dsize; i++) {
3425 sbuff_key[i] = key_vec[perm[i]];
3426 sbuff_value[i] = value_vec[perm[i]];
3432 for (
size_t i = 0; i < nrecv; i++)
3434 auto it = rmap.
find(rbuff_key[i]);
3435 if (it != rmap.
end())
3437 intersection_tags& map_tags = it->second;
3438 intersection_tags& r_tags = rbuff_value[i];
3440 for (
int r_tag : r_tags.tags)
3442 if (r_tag == -1)
continue;
3444 for (
int m_tag : map_tags.tags)
3446 if (m_tag == r_tag) {
3453 for (
size_t k = 0; k < MAX_INTERSECTIONS; ++k) {
3454 if (map_tags.tags[k] == -1) {
3455 map_tags.tags[k] = r_tag;
3464 rmap.
insert({ rbuff_key[i], rbuff_value[i] });
3468 for (
size_t i = 0; i < nrecv; i++) {
3469 auto it = rmap.
find(rbuff_key[i]);
3470 if (it != rmap.
end()) rbuff_value[i] = it->second;
3477 for (
size_t i = 0; i < dsize; i++) {
3478 auto it = map.find(sbuff_key[i]);
3479 if (it != map.end()) it->second = ibuff_value[i];
3504 template<
class T,
class S>
inline
3505 void compute_ptsdata_from_original_mesh(meshdata<T,S> & mesh,
3511 MPI_Comm comm = mesh.comm;
3513 MPI_Comm_size(comm, &size);
3514 MPI_Comm_rank(comm, &rank);
3516 const T* con = mesh.con.data();
3523 for(
size_t eidx = 0; eidx < mesh.l_numelem; eidx++)
3525 T tag = mesh.tag[eidx];
3526 for (
int n = mesh.dsp[eidx]; n < mesh.dsp[eidx+1];n++)
3528 T gIndex = rnod[con[n]];
3530 auto it_new = map_index_to_tags.
find(gIndex);
3531 if (it_new != map_index_to_tags.
end())
3534 intersection_tags& tags = it_new->second;
3536 for(T t : tags.tags) {
3544 for(
int i=0; i <MAX_INTERSECTIONS; ++i) {
3545 if (tags.tags[i] == -1) {
3554 intersection_tags tags;
3556 map_index_to_tags.
insert({gIndex,tags});
3564 assign_counter_tags(map_index_to_tags, comm);
3567 for(
size_t eidx = 0; eidx < mesh.l_numelem; eidx++)
3569 for (
int n = mesh.dsp[eidx]; n < mesh.dsp[eidx+1];n++)
3571 T gIndex = rnod[con[n]];
3572 intersection_tags& vec_tags = map_index_to_tags[gIndex];
3573 int count_intra_tags = 0;
3574 int count_extra_tags = 0;
3578 for(T t : vec_tags.tags) {
3579 if(intra_tags.
count(t)) count_intra_tags++;
3580 if(extra_tags.
count(t)) count_extra_tags++;
3584 if(count_extra_tags>=1 && count_intra_tags==0){
3585 vertex2ptsdata[gIndex] = 0;
3586 }
else if(count_extra_tags==0 && count_intra_tags==1){
3587 vertex2ptsdata[gIndex] = 0;
3588 }
else if(count_extra_tags>=1 && count_intra_tags==1){
3589 vertex2ptsdata[gIndex] = 1;
3590 }
else if(count_extra_tags==0 && count_intra_tags==2){
3591 vertex2ptsdata[gIndex] = 2;
3592 }
else if(count_extra_tags>=1 && count_intra_tags==2){
3593 vertex2ptsdata[gIndex] = 3;
3595 else if(count_intra_tags>2){
3597 fprintf(stderr,
"More than two intracellular are connected %lld. Tags:",
3598 static_cast<long long>(gIndex));
3599 for(T tag : vec_tags.tags)
if(tag != -1) fprintf(stderr,
" %lld",
static_cast<long long>(tag));
3600 fprintf(stderr,
"\n");
3605 fprintf(stderr,
"WARN: unhandled case in ptsData computation for gIndex %lld. Tags:",
3606 static_cast<long long>(gIndex));
3607 for(T tag : vec_tags.tags)
if(tag != -1) fprintf(stderr,
" %lld",
static_cast<long long>(tag));
3608 fprintf(stderr,
"\n");
3631 template <
class T,
class S,
class V,
class emi_index_rank>
3634 std::pair<emi_index_rank, emi_index_rank>>& map,
3641 MPI_Comm_rank(both_mesh.
comm, &rank);
3644 SF::layout_from_count<long int>(both_mesh.
l_numelem, layout_both, both_mesh.
comm);
3647 SF::layout_from_count<long int>(unique_mesh.
l_numelem, layout_unique, unique_mesh.
comm);
3653 for (
const auto& [local_unique_idx, both_pair] : map) {
3654 const auto& first_both = both_pair.first;
3655 const auto& second_both = both_pair.second;
3659 T global_unique_row = layout_unique[rank] + local_unique_idx;
3660 row_idx[0] = global_unique_row;
3663 bool first_valid = (first_both.index >= 0 && first_both.rank >= 0);
3664 bool second_valid = (second_both.index >= 0 && second_both.rank >= 0);
3666 T global_both_col_first = -1;
3667 T global_both_col_second = -1;
3669 global_both_col_first = layout_both[first_both.rank] + first_both.index;
3672 global_both_col_second = layout_both[second_both.rank] + second_both.index;
3677 if (first_valid && second_valid && global_both_col_first == global_both_col_second) {
3678 second_valid =
false;
3683 if (first_valid)
count++;
3684 if (second_valid)
count++;
3686 if (
count == 0)
continue;
3690 double weight = 0.5;
3691 if (
count == 1) weight = 1.0;
3693 ebuff.assign(1, 1, weight);
3697 col_idx[0] = global_both_col_first;
3698 op.
set_values(row_idx, col_idx, ebuff.data(),
false);
3703 col_idx[0] = global_both_col_second;
3704 op.
set_values(row_idx, col_idx, ebuff.data(),
false);
3728 inline void restrict_to_membrane(vector<T> & v,
3730 const meshdata<mesh_int_t, mesh_real_t> & mesh)
3735 for(
size_t i=0; i<rnod.
size(); i++){
3742 for(
size_t i=0; i<v.size(); i++){
3745 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)