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;
57 inline int emi_node_aware_merge_rank_cap(MPI_Comm comm)
60 MPI_Comm_size(comm, &size);
63 MPI_Comm node_comm = MPI_COMM_NULL;
64 MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, 0, MPI_INFO_NULL, &node_comm);
68 MPI_Comm_rank(node_comm, &node_rank);
70 int local_leader = (node_rank == 0) ? 1 : 0;
73 MPI_Allreduce(&local_leader, &num_nodes, 1, MPI_INT, MPI_SUM, comm);
75 MPI_Comm_free(&node_comm);
78 return std::min(size,
std::max(EMI_MIN_MERGE_RANKS, num_nodes * EMI_MAX_MERGE_RANKS_PER_NODE));
88 template<
class K,
class TokenFn>
89 inline int emi_select_merge_destinations(
const vector<K>& key_vec,
91 size_t bytes_per_entry,
97 int size = 0, rank = 0;
98 MPI_Comm_size(comm, &size);
99 MPI_Comm_rank(comm, &rank);
102 const unsigned long long local_bytes =
103 static_cast<unsigned long long>(dsize) *
static_cast<unsigned long long>(bytes_per_entry);
104 unsigned long long global_bytes = 0;
105 MPI_Allreduce(&local_bytes, &global_bytes, 1, MPI_UNSIGNED_LONG_LONG, MPI_SUM, comm);
108 const int merge_rank_cap = emi_node_aware_merge_rank_cap(comm);
110 if (size > merge_rank_cap) {
112 const int nmerge_floor = EMI_MIN_MERGE_RANKS;
113 const int nmerge_cap = merge_rank_cap;
114 const unsigned long long nmerge_est_ull =
115 std::max(1ull, (global_bytes + EMI_TARGET_BYTES_PER_MERGE_RANK - 1ull) /
116 EMI_TARGET_BYTES_PER_MERGE_RANK);
117 const int nmerge_est =
static_cast<int>(std::min<unsigned long long>(nmerge_cap, nmerge_est_ull));
119 nmerge =
std::max(nmerge_floor, nmerge_est);
123 for (
size_t i = 0; i < dsize; ++i) {
124 if (nmerge == size) {
126 dest[i] =
static_cast<int>(token_fn(key_vec[i]) %
static_cast<size_t>(size));
129 const size_t bucket = token_fn(key_vec[i]) %
static_cast<size_t>(nmerge);
132 dest[i] =
static_cast<int>((bucket *
static_cast<size_t>(size)) /
static_cast<size_t>(nmerge));
136 if (rank == 0 && std::getenv(
"OPENCARP_EMI_LOG_MERGE_RANKS") != NULL) {
137 const char* mode = (nmerge == size) ?
"all-ranks" :
"limited";
139 "[EMI merge ranks] %s: size=%d dsize=%zu global_bytes=%llu cap=%d nmerge=%d mode=%s\n",
140 label, size, dsize, global_bytes, merge_rank_cap, nmerge, mode);
155 struct intersection_tags {
163 int tags[MAX_INTERSECTIONS];
164 intersection_tags() {
165 std::fill_n(tags, MAX_INTERSECTIONS, -1);
170 struct intersection_data {
171 int tags[MAX_INTERSECTIONS];
172 int data[MAX_INTERSECTIONS];
173 int ranks[MAX_INTERSECTIONS];
175 intersection_data() {
176 std::fill_n(tags, MAX_INTERSECTIONS, -1);
177 std::fill_n(data, MAX_INTERSECTIONS, -1);
178 std::fill_n(ranks, MAX_INTERSECTIONS, -1);
182 struct intersection_indices {
183 int indices[MAX_INTERSECTIONS];
184 intersection_indices() {
185 std::fill_n(indices, MAX_INTERSECTIONS, -1);
196 template<
class K,
class V>
inline
199 size_t dsize = map.
size();
200 vector<K> key_vec (dsize);
201 vector<V> value_vec (dsize);
206 for(
const auto & v : map) {
207 if (v.second.second.eidx == -1){
208 key_vec[idx] = v.first;
209 value_vec[idx] = v.second;
214 key_vec.resize(dsize);
215 value_vec.resize(dsize);
217 vector<int> perm, dest;
218 emi_select_merge_destinations(key_vec, dsize,
sizeof(K) +
sizeof(V), dest, comm,
219 "assign_counter_face",
222 commgraph<size_t> grph;
223 grph.configure(dest, comm);
224 size_t nrecv =
sum(grph.rcnt);
230 vector<K> sbuff_key(dsize), rbuff_key(nrecv);
231 vector<V> sbuff_value(dsize), ibuff_value(dsize), rbuff_value(nrecv);
232 for(
size_t i=0; i<dsize; i++) {
233 sbuff_key[i] = key_vec[perm[i]];
234 sbuff_value[i] = value_vec[perm[i]];
244 for (
size_t i = 0; i < nrecv; i++) {
245 auto it = rmap.
find(rbuff_key[i]);
246 if(it != rmap.
end()) {
251 if (it->second.first.tag != rbuff_value[i].first.tag) {
252 it->second.second = rbuff_value[i].first;
255 rmap.
insert({rbuff_key[i], rbuff_value[i]});
259 for (
size_t i = 0; i < nrecv; i++ ) {
260 auto it = rmap.
find(rbuff_key[i]);
261 if(it != rmap.
end()) rbuff_value[i] = it->second;
268 for (
size_t i = 0; i < dsize; i++ ) {
269 auto it = map.find(sbuff_key[i]);
270 if (it != map.end()) it->second = ibuff_value[i];
282 template<
class K,
class V>
inline
294 size_t dsize = map.
size();
295 vector<K> key_vec (dsize);
296 vector<V> value_vec (dsize);
300 for(
const auto & v : map) {
301 if (v.second.second.index_unique == -1 && v.second.second.index_one == -1){
302 key_vec[idx] = v.first;
303 value_vec[idx] = v.second;
308 key_vec.resize(dsize);
309 value_vec.resize(dsize);
311 vector<int> perm, dest;
312 emi_select_merge_destinations(key_vec, dsize,
sizeof(K) +
sizeof(V), dest, comm,
313 "assign_unique_first_face",
316 commgraph<size_t> grph;
317 grph.configure(dest, comm);
318 size_t nrecv =
sum(grph.rcnt);
324 vector<K> sbuff_key(dsize), rbuff_key(nrecv);
325 vector<V> sbuff_value(dsize), ibuff_value(dsize), rbuff_value(nrecv);
326 for(
size_t i=0; i<dsize; i++) {
327 sbuff_key[i] = key_vec[perm[i]];
328 sbuff_value[i] = value_vec[perm[i]];
338 for (
size_t i = 0; i < nrecv; i++) {
339 auto it = rmap.
find(rbuff_key[i]);
340 if(it != rmap.
end()) {
342 auto& existing = it->second;
343 using Face = std::decay_t<decltype(existing.first)>;
345 auto update_slot = [&](Face& slot,
const Face& src) {
349 if (src.index_unique >= 0) {
350 slot.index_unique = src.index_unique;
351 slot.rank = src.rank;
353 if (slot.rank < 0) slot.rank = src.rank;
355 if (slot.index_one < 0 && src.index_one >= 0) slot.index_one = src.index_one;
358 auto same_face = [&](
const Face& a,
const Face& b) {
360 return (a.rank >= 0 && b.rank >= 0 &&
361 a.index_one >= 0 && b.index_one >= 0 &&
362 a.rank == b.rank && a.index_one == b.index_one);
365 auto ingest = [&](
const Face& incoming) {
367 if (incoming.index_one < 0 && incoming.index_unique < 0 && incoming.rank < 0)
return;
369 if (same_face(existing.first, incoming) || existing.first.rank == incoming.rank) {
370 update_slot(existing.first, incoming);
371 }
else if (same_face(existing.second, incoming) || existing.second.rank == incoming.rank) {
372 update_slot(existing.second, incoming);
373 }
else if (existing.second.index_one == -1 && existing.second.index_unique == -1) {
375 existing.second = incoming;
376 }
else if (existing.first.index_one == -1 && existing.first.index_unique == -1) {
378 existing.first = incoming;
382 if (existing.first.index_unique < 0 && incoming.index_unique >= 0) {
383 existing.first.index_unique = incoming.index_unique;
384 existing.first.rank = incoming.rank;
385 }
else if (existing.second.index_unique < 0 && incoming.index_unique >= 0) {
386 existing.second.index_unique = incoming.index_unique;
387 existing.second.rank = incoming.rank;
393 ingest(rbuff_value[i].first);
394 ingest(rbuff_value[i].second);
397 rmap.
insert({rbuff_key[i], rbuff_value[i]});
401 for (
size_t i = 0; i < nrecv; i++ ) {
402 auto it = rmap.
find(rbuff_key[i]);
403 if(it != rmap.
end()) rbuff_value[i] = it->second;
410 for (
size_t i = 0; i < dsize; i++ ) {
411 auto it = map.find(sbuff_key[i]);
412 if (it != map.end()) {
414 it->second = ibuff_value[i];
418 map.insert({sbuff_key[i], ibuff_value[i]});
430 template<
class K>
inline
433 size_t dsize = map.
size();
434 vector<K> key_vec(dsize);
435 vector<intersection_data> value_vec(dsize);
438 for (
const auto& v : map) {
439 key_vec[idx] = v.first;
440 value_vec[idx] = v.second;
444 vector<int> perm, dest;
445 emi_select_merge_destinations(key_vec, dsize,
sizeof(K) +
sizeof(intersection_data), dest, comm,
446 "assign_counter_vertices_tuple",
449 commgraph<size_t> grph;
450 grph.configure(dest, comm);
451 size_t nrecv =
sum(grph.rcnt);
457 vector<K> sbuff_key(dsize), rbuff_key(nrecv);
458 vector<intersection_data> sbuff_value(dsize), ibuff_value(dsize), rbuff_value(nrecv);
459 for (
size_t i = 0; i < dsize; i++) {
460 sbuff_key[i] = key_vec[perm[i]];
461 sbuff_value[i] = value_vec[perm[i]];
467 for (
size_t i = 0; i < nrecv; i++) {
468 auto it = rmap.
find(rbuff_key[i]);
469 if (it != rmap.
end()) {
470 intersection_data& map_val = it->second;
471 intersection_data& r_val = rbuff_value[i];
473 int first_index = -1;
474 for (
int j = 0; j < MAX_INTERSECTIONS; ++j) {
475 if (map_val.tags[j] == -1 && map_val.ranks[j] == -1) {
481 if (first_index == -1)
continue;
483 for (
int j = 0; j < MAX_INTERSECTIONS; ++j) {
484 if (r_val.tags[j] == -1)
continue;
486 int rtag = r_val.tags[j];
487 int rdata = r_val.data[j];
488 int rrank = r_val.ranks[j];
490 bool exist_rtag =
false;
491 for (
int k = 0; k < first_index; ++k) {
492 if (map_val.tags[k] == rtag && map_val.ranks[k] == rrank) {
498 if (!exist_rtag && first_index < MAX_INTERSECTIONS) {
499 map_val.tags[first_index] = rtag;
500 map_val.data[first_index] = rdata;
501 map_val.ranks[first_index] = rrank;
507 rmap.
insert({ rbuff_key[i], rbuff_value[i] });
511 for (
size_t i = 0; i < nrecv; i++) {
512 auto it = rmap.
find(rbuff_key[i]);
513 if (it != rmap.
end()) rbuff_value[i] = it->second;
520 for (
size_t i = 0; i < dsize; i++) {
521 auto it = map.find(sbuff_key[i]);
522 if (it != map.end()) it->second = ibuff_value[i];
533 template<
class K,
class V>
inline
536 size_t dsize = map.
size();
537 vector<K> key_vec (dsize);
538 vector<V> value_vec (dsize);
543 for(
const auto & v : map) {
544 key_vec[idx] = v.first;
545 value_vec[idx] = v.second;
549 key_vec.resize(dsize);
550 value_vec.resize(dsize);
552 vector<int> perm, dest;
553 emi_select_merge_destinations(key_vec, dsize,
sizeof(K) +
sizeof(V), dest, comm,
554 "assign_dof_on_counter_face",
555 [](
const K& key) {
return key.first; });
557 commgraph<size_t> grph;
558 grph.configure(dest, comm);
559 size_t nrecv =
sum(grph.rcnt);
565 vector<K> sbuff_key(dsize), rbuff_key(nrecv);
566 vector<V> sbuff_value(dsize), ibuff_value(dsize), rbuff_value(nrecv);
567 for(
size_t i=0; i<dsize; i++) {
568 sbuff_key[i] = key_vec[perm[i]];
569 sbuff_value[i] = value_vec[perm[i]];
576 for (
size_t i = 0; i < nrecv; i++) {
577 auto it = rmap.
find(rbuff_key[i]);
578 if(it != rmap.
end()) {
579 if(rbuff_value[i] != -1 and it->second == -1){
580 it->second = rbuff_value[i];
583 rmap.
insert({rbuff_key[i], rbuff_value[i]});
587 for (
size_t i = 0; i < nrecv; i++ ) {
588 auto it = rmap.
find(rbuff_key[i]);
589 if(it != rmap.
end()) {
590 if(rbuff_value[i] == -1)
591 rbuff_value[i] = it->second;
599 for (
size_t i = 0; i < dsize; i++ ) {
600 auto it = map.find(sbuff_key[i]);
601 if (it != map.end()) it->second = ibuff_value[i];
613 template<
class K,
class V>
inline
616 size_t dsize = map.
size();
617 vector<K> key_vec (dsize);
618 vector<V> value_vec (dsize);
623 for(
const auto & v : map) {
624 key_vec[idx] = v.first;
625 value_vec[idx] = v.second;
629 key_vec.resize(dsize);
630 value_vec.resize(dsize);
632 vector<int> perm, dest;
633 emi_select_merge_destinations(key_vec, dsize,
sizeof(K) +
sizeof(V), dest, comm,
634 "assign_petsc_on_counter_face",
635 [](
const K& key) {
return key.first; });
637 commgraph<size_t> grph;
638 grph.configure(dest, comm);
639 size_t nrecv =
sum(grph.rcnt);
645 vector<K> sbuff_key(dsize), rbuff_key(nrecv);
646 vector<V> sbuff_value(dsize), ibuff_value(dsize), rbuff_value(nrecv);
647 for(
size_t i=0; i<dsize; i++) {
648 sbuff_key[i] = key_vec[perm[i]];
649 sbuff_value[i] = value_vec[perm[i]];
656 for (
size_t i = 0; i < nrecv; i++) {
657 auto it = rmap.
find(rbuff_key[i]);
658 if(it != rmap.
end()) {
659 if(rbuff_value[i].second != -1 and it->second.second == -1){
660 it->second = rbuff_value[i];
663 rmap.
insert({rbuff_key[i], rbuff_value[i]});
667 for (
size_t i = 0; i < nrecv; i++ ) {
668 auto it = rmap.
find(rbuff_key[i]);
669 if(it != rmap.
end()) {
670 if(rbuff_value[i].second == -1)
671 rbuff_value[i].second = it->second.second;
679 for (
size_t i = 0; i < dsize; i++ ) {
680 auto it = map.find(sbuff_key[i]);
681 if (it != map.end()) it->second = ibuff_value[i];
693 void sort_surf_local_indices(tuple<T> & ref, tuple<T> & target)
697 buff[0] = ref.v1, buff[1] = ref.v2;
700 target.v1 = buff[0], target.v2 = buff[1];
711 void sort_surf_local_indices(triple<T> & ref, triple<T> & target)
715 buff[0] = ref.v1, buff[1] = ref.v2, buff[2] = ref.v3;
718 target.v1 = buff[0], target.v2 = buff[1], target.v3 = buff[2];
729 void sort_surf_local_indices(quadruple<T> & ref, quadruple<T> & target)
733 buff[0] = ref.v1, buff[1] = ref.v2, buff[2] = ref.v3, buff[3] = ref.v4;
736 target.v1 = buff[0], target.v2 = buff[1], target.v3 = buff[2], target.v4 = buff[3];
746 template<
class K,
class V>
inline
747 void insert_surf_based_Tag(V & ref,
752 sort_surf_local_indices(ref.points, surf);
754 auto it = surfmap.find(surf);
755 if (it != surfmap.end()) {
758 if ( it->second.first.tag != ref.tag )
759 it->second.second = ref;
761 std::pair<V, V> face;
763 surfmap.insert({surf,face});
786 template<
class T,
class W,
class V,
class U>
inline
787 void insert_surf_emi(
int rank,
790 const T eidx,
const T tag,
791 const std::vector<T> & line_con,
const std::vector<T> & surf_con,
const std::vector<T> & qsurf_con,
807 for (
size_t i = 0; i < line_con.size(); i += 2) {
808 if (ptsData[line_con[i ] - 1] > 0 &&
809 ptsData[line_con[i + 1] - 1] > 0 ) {
810 line.points.v1 = ref_con[line_con[i ] - 1];
811 line.points.v2 = ref_con[line_con[i + 1] - 1];
813 insert_surf_based_Tag(line, line_face);
817 for (
size_t i = 0; i < surf_con.size(); i += 3) {
818 if (ptsData[surf_con[i ] - 1] > 0 &&
819 ptsData[surf_con[i + 1] - 1] > 0 &&
820 ptsData[surf_con[i + 2] - 1] > 0 ) {
821 face.points.v1 = ref_con[surf_con[i ] - 1];
822 face.points.v2 = ref_con[surf_con[i + 1] - 1];
823 face.points.v3 = ref_con[surf_con[i + 2] - 1];
825 insert_surf_based_Tag(face, surfmap);
829 for (
size_t i = 0; i < qsurf_con.size(); i += 4) {
830 if (ptsData[qsurf_con[i ] - 1] > 0 &&
831 ptsData[qsurf_con[i + 1] - 1] > 0 &&
832 ptsData[qsurf_con[i + 2] - 1] > 0 &&
833 ptsData[qsurf_con[i + 3] - 1] > 0) {
834 qface.points.v1 = ref_con[qsurf_con[i ] - 1];
835 qface.points.v2 = ref_con[qsurf_con[i + 1] - 1];
836 qface.points.v3 = ref_con[qsurf_con[i + 2] - 1];
837 qface.points.v4 = ref_con[qsurf_con[i + 3] - 1];
839 insert_surf_based_Tag(qface, qsurfmap);
850 template<
class T,
class V>
857 bool mark_to_take =
false;
864 struct emi_unique_face {
897 struct emi_index_rank {
913 template<
class T,
class S>
inline
914 void compute_surface_with_tags(meshdata<T,S> & mesh,
919 std::pair<emi_face<T,tuple<T>>, emi_face<T,tuple<T>>>> & line_face,
921 std::pair<emi_face<T,triple<T>>, emi_face<T,triple<T>>>> & tri_surf,
923 std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>>> & quad_surf)
927 MPI_Comm_size(comm, &size);
928 MPI_Comm_rank(comm, &rank);
930 const T* con = mesh.con.data();
931 const T* nbr = mesh.get_numbering(numbering).data();
936 for(
size_t i=0; i<mesh.con.size(); i++){
937 g2ptsData[rnod[con[i]]] = vertex2ptsdata[rnod[con[i]]];
940 const vector<T> & ref_eidx = mesh.get_numbering(
NBR_ELEM_REF);
945 for(
size_t eidx = 0; eidx < mesh.l_numelem; eidx++) {
946 T tag = mesh.tag[eidx];
947 T size_elem = mesh.dsp[eidx+1]-mesh.dsp[eidx];
949 vector<T> dofvec(size_elem);
950 vector<T> ptsDatavec(size_elem);
952 for (
int n = mesh.dsp[eidx], i = 0; n < mesh.dsp[eidx+1];n++,i++)
954 dofvec[i] = rnod[con[n]];
955 ptsDatavec[i] = g2ptsData[rnod[con[n]]];
957 std::vector<T> surf_con ;
958 std::vector<T> qsurf_con;
959 std::vector<T> line_con;
960 switch(mesh.type[eidx]) {
1001 qsurf_con = {1,2,3,4};
1009 qsurf_con = {1,2,6,4,
1018 qsurf_con = {1,2,3,4,
1027 fprintf(stderr,
"%s error: Unsupported element in surface computation!\n", __func__);
1030 insert_surf_emi(rank, dofvec, ptsDatavec, ref_eidx[eidx], mesh.tag[eidx], line_con, surf_con, qsurf_con, line_face, tri_surf, quad_surf);
1034 assign_counter_face(line_face, mesh.comm);
1035 assign_counter_face(tri_surf, mesh.comm);
1036 assign_counter_face(quad_surf, mesh.comm);
1040 for(
auto it = line_face.begin(); it != line_face.end(); ) {
1041 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()))
1042 it = line_face.erase(it);
1047 for(
auto it = tri_surf.begin(); it != tri_surf.end(); ) {
1048 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()))
1049 it = tri_surf.erase(it);
1054 for(
auto it = quad_surf.begin(); it != quad_surf.end(); ) {
1055 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()))
1056 it = quad_surf.erase(it);
1075 inline bool should_take_first(
int tag1,
int tag2,
1079 bool tag1_is_intra = (intra_tags.
find(tag1) != intra_tags.
end());
1080 bool tag2_is_intra = (intra_tags.
find(tag2) != intra_tags.
end());
1081 bool tag1_is_extra = (extra_tags.
find(tag1) != extra_tags.
end());
1082 bool tag2_is_extra = (extra_tags.
find(tag2) != extra_tags.
end());
1085 if(tag1_is_intra && tag2_is_intra) {
1090 if(tag1_is_intra && tag2_is_extra) {
1093 if(tag2_is_intra && tag1_is_extra) {
1123 void assign_map_between_elem_oneface_and_elem_uniqueFace(
int rank,
1124 emi_unique_face <mesh_int_t> first,
1125 emi_unique_face <mesh_int_t> second,
1130 if(second.index_one==-1 && second.index_unique==-1){
1131 second.index_one = first.index_one;
1132 second.index_unique = first.index_unique;
1135 else if(first.rank != second.rank) {
1137 int our_index_one = (first.rank == rank) ? first.index_one :
1138 (second.rank == rank) ? second.index_one : -1;
1140 int owner_index_unique = (first.index_unique >= 0) ? first.index_unique :
1141 (second.index_unique >= 0) ? second.index_unique : -1;
1142 int owner_rank = (first.index_unique >= 0) ? first.rank :
1143 (second.index_unique >= 0) ? second.rank : -1;
1146 if(our_index_one >= 0 && owner_index_unique >= 0 && owner_rank >= 0 && owner_rank != rank) {
1147 map_elem_oneface_to_elem_uniqueFace[our_index_one].index = owner_index_unique;
1148 map_elem_oneface_to_elem_uniqueFace[our_index_one].rank = owner_rank;
1155 int local_index_unique = -1;
1156 emi_index_rank<mesh_int_t> value1, value2;
1158 if (first.index_unique >= 0 && first.rank == rank) {
1160 local_index_unique = first.index_unique;
1161 value1.index = first.index_one;
1162 value1.rank = first.rank;
1163 value2.index = second.index_one;
1164 value2.rank = second.rank;
1165 }
else if (second.index_unique >= 0 && second.rank == rank) {
1167 local_index_unique = second.index_unique;
1168 value1.index = second.index_one;
1169 value1.rank = second.rank;
1170 value2.index = first.index_one;
1171 value2.rank = first.rank;
1174 if (local_index_unique >= 0) {
1175 auto itr = map_elem_uniqueFace_to_elem_oneface.find(local_index_unique);
1176 if (itr == map_elem_uniqueFace_to_elem_oneface.end()) {
1177 std::pair <emi_index_rank<mesh_int_t>,emi_index_rank<mesh_int_t>> value;
1178 value = std::make_pair(value1, value2);
1179 map_elem_uniqueFace_to_elem_oneface.insert({local_index_unique, value});
1206 template <
class T,
class Key,
class Po
intsKey>
1207 inline void assign_ownership_rank_on_faces(
const Key& key,
1208 std::pair<emi_face<T, PointsKey>, emi_face<T, PointsKey>>& v,
1214 hashmap::unordered_map<Key,std::pair<emi_unique_face<mesh_int_t>, emi_unique_face<mesh_int_t>>>& unique_face_to_elements,
1217 const bool same_rank = (v.first.rank == v.second.rank);
1223 const bool first_intra = (intra_tags.
find(v.first.tag) != intra_tags.
end());
1224 const bool second_intra = (intra_tags.
find(v.second.tag) != intra_tags.
end());
1227 bool take_first_by_tags =
true;
1228 if (first_intra != second_intra) {
1229 take_first_by_tags = first_intra;
1230 }
else if (v.first.tag != v.second.tag) {
1231 take_first_by_tags = (v.first.tag < v.second.tag);
1234 take_first_by_tags = (v.first.rank <= v.second.rank);
1237 int owner_rank = take_first_by_tags ? v.first.rank : v.second.rank;
1239 const bool i_am_owner = (rank == owner_rank);
1243 auto& chosen = take_first_by_tags ? v.first : v.second;
1245 chosen.mark_to_take =
true;
1246 chosen.index_unique = lsize_unique;
1247 chosen.index_one = idx_oneface;
1249 map_elem_oneface_to_elem_uniqueFace[idx_oneface].index = lsize_unique;
1250 map_elem_oneface_to_elem_uniqueFace[idx_oneface].rank = rank;
1256 auto it = unique_face_to_elements.find(key);
1257 if (it == unique_face_to_elements.end()) {
1258 emi_unique_face<mesh_int_t> first;
1259 emi_unique_face<mesh_int_t> second;
1263 first.index_unique = lsize_unique;
1264 first.index_one = idx_oneface;
1268 second.index_unique = -1;
1269 second.index_one = -1;
1270 second.rank = same_rank ? rank : (rank == v.first.rank ? v.second.rank : v.first.rank);
1273 first.index_unique = -1;
1274 first.index_one = idx_oneface;
1277 second.index_unique = -1;
1278 second.index_one = -1;
1279 second.rank = owner_rank;
1282 unique_face_to_elements.insert({ key, std::make_pair(first, second) });
1285 auto& existing = it->second;
1288 emi_unique_face<mesh_int_t>* slot =
nullptr;
1289 if (existing.first.rank == rank || existing.first.rank < 0) {
1290 slot = &existing.first;
1291 }
else if (existing.second.rank == rank || existing.second.rank < 0) {
1292 slot = &existing.second;
1293 }
else if (existing.first.index_one == idx_oneface) {
1294 slot = &existing.first;
1295 }
else if (existing.second.index_one == idx_oneface) {
1296 slot = &existing.second;
1297 }
else if (existing.first.index_unique < 0) {
1298 slot = &existing.first;
1299 }
else if (existing.second.index_unique < 0) {
1300 slot = &existing.second;
1304 if (slot->rank < 0) slot->rank = rank;
1305 if (slot->index_one < 0) slot->index_one = idx_oneface;
1306 if (i_am_owner && slot->index_unique < 0) {
1307 slot->index_unique = lsize_unique;
1377 template<
class T,
class S>
inline
1378 void extract_face_based_tags(meshdata<T,S> & mesh,
1382 std::pair<emi_face<T,tuple<T>>, emi_face<T,tuple<T>>>> & line_face,
1384 std::pair<emi_face<T,triple<T>>, emi_face<T,triple<T>>>> & tri_face,
1386 std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>>> & quad_face,
1389 meshdata<T,S> & surfmesh,
1390 meshdata<T,S> & surfmesh_w_counter,
1391 meshdata<T,S> & surfmesh_unique_face,
1399 surfmesh_w_counter.register_numbering(
SF::NBR_REF);
1400 surfmesh_unique_face.register_numbering(
SF::NBR_REF);
1404 compute_surface_with_tags(mesh, numbering, vertex2ptsdata, extra_tags, line_face, tri_face, quad_face);
1407 MPI_Comm_size(mesh.comm, &size);
1408 MPI_Comm_rank(mesh.comm, &rank);
1410 long int g_num_line = line_face.size();
1411 long int g_num_tri = tri_face.size();
1412 long int g_num_quad = quad_face.size();
1413 MPI_Allreduce(MPI_IN_PLACE, &g_num_line, 1, MPI_LONG, MPI_SUM, mesh.comm);
1414 MPI_Allreduce(MPI_IN_PLACE, &g_num_tri, 1, MPI_LONG, MPI_SUM, mesh.comm);
1415 MPI_Allreduce(MPI_IN_PLACE, &g_num_quad, 1, MPI_LONG, MPI_SUM, mesh.comm);
1419 long int local_extra_extra = 0;
1420 for (
const auto& [key, v] : line_face) {
1421 if (extra_tags.
find(v.first.tag) != extra_tags.
end() &&
1422 extra_tags.
find(v.second.tag) != extra_tags.
end()) {
1423 local_extra_extra++;
1426 for (
const auto& [key, v] : tri_face) {
1427 if (extra_tags.
find(v.first.tag) != extra_tags.
end() &&
1428 extra_tags.
find(v.second.tag) != extra_tags.
end()) {
1429 local_extra_extra++;
1432 for (
const auto& [key, v] : quad_face) {
1433 if (extra_tags.
find(v.first.tag) != extra_tags.
end() &&
1434 extra_tags.
find(v.second.tag) != extra_tags.
end()) {
1435 local_extra_extra++;
1438 long int global_extra_extra = 0;
1439 MPI_Allreduce(&local_extra_extra, &global_extra_extra, 1, MPI_LONG, MPI_SUM, mesh.comm);
1440 if (global_extra_extra > 0 && rank == 0) {
1441 fprintf(stderr,
"WARN: extra-extra faces detected before filtering: %ld\n", global_extra_extra);
1445 surfmesh.g_numelem = g_num_line + g_num_tri + g_num_quad;
1446 surfmesh.l_numelem = line_face.size() + tri_face.size() + quad_face.size();
1448 vector<T> cnt(surfmesh.l_numelem, 0);
1449 surfmesh.tag.resize(surfmesh.l_numelem);
1450 surfmesh.type.resize(surfmesh.l_numelem);
1451 surfmesh.con.resize(line_face.size() * 2 + tri_face.size() * 3 + quad_face.size() * 4);
1458 vector<tuple<T>> line_keys;
1459 for(
auto const& [key, val] : line_face) line_keys.push_back(key);
1460 std::sort(line_keys.begin(), line_keys.end());
1462 vector<triple<T>> tri_keys;
1463 for(
auto const& [key, val] : tri_face) tri_keys.push_back(key);
1464 std::sort(tri_keys.begin(), tri_keys.end());
1466 vector<quadruple<T>> quad_keys;
1467 for(
auto const& [key, val] : quad_face) quad_keys.push_back(key);
1468 std::sort(quad_keys.begin(), quad_keys.end());
1493 for(
auto const& key : line_keys) {
1494 auto& v = line_face.
at(key);
1495 const bool local_involved = (v.first.rank == rank) || (v.second.rank == rank);
1496 if (!local_involved) {
1502 if ((intra_tags.
find(v.first.tag) != intra_tags.
end()) && (intra_tags.
find(v.second.tag) != intra_tags.
end())) {
1508 emi_face<T,tuple<T>> surf_neighbor =
1509 (v.first.rank == rank) ? v.first : v.second;
1511 surfmesh.type[idx] =
Line;
1512 surfmesh.tag[idx] = surf_neighbor.tag;
1513 surfmesh.con[cidx + 0] = surf_neighbor.points.v1;
1514 surfmesh.con[cidx + 1] = surf_neighbor.points.v2;
1517 if(v.first.rank == v.second.rank)
1522 assign_ownership_rank_on_faces<T, tuple<T>, tuple<T>>( key, v, rank,
1525 extra_tags, intra_tags,
1526 line_unique_face_to_elements,
1527 map_elem_oneface_to_elem_uniqueFace);
1532 for(
auto const& key : tri_keys) {
1533 auto& v = tri_face.at(key);
1534 const bool local_involved = (v.first.rank == rank) || (v.second.rank == rank);
1535 if (!local_involved) {
1540 if ((intra_tags.
find(v.first.tag) != intra_tags.
end()) && (intra_tags.
find(v.second.tag) != intra_tags.
end())) {
1546 emi_face<T,triple<T>> surf_neighbor =
1547 (v.first.rank == rank) ? v.first : v.second;
1549 surfmesh.type[idx] =
Tri;
1550 surfmesh.tag[idx] = surf_neighbor.tag;
1551 surfmesh.con[cidx + 0] = surf_neighbor.points.v1;
1552 surfmesh.con[cidx + 1] = surf_neighbor.points.v2;
1553 surfmesh.con[cidx + 2] = surf_neighbor.points.v3;
1556 if(v.first.rank == v.second.rank)
1561 assign_ownership_rank_on_faces<T, triple<T>, triple<T>>( key, v, rank,
1564 extra_tags, intra_tags,
1565 tri_unique_face_to_elements,
1566 map_elem_oneface_to_elem_uniqueFace);
1571 for(
auto const& key : quad_keys) {
1572 auto& v = quad_face.at(key);
1573 const bool local_involved = (v.first.rank == rank) || (v.second.rank == rank);
1574 if (!local_involved) {
1579 if ((intra_tags.
find(v.first.tag) != intra_tags.
end()) && (intra_tags.
find(v.second.tag) != intra_tags.
end())) {
1585 emi_face<T,quadruple<T>> qsurf_neighbor =
1586 (v.first.rank == rank) ? v.first : v.second;
1588 surfmesh.type[idx] =
Quad;
1589 surfmesh.tag[idx] = qsurf_neighbor.tag;
1590 surfmesh.con[cidx + 0] = qsurf_neighbor.points.v1;
1591 surfmesh.con[cidx + 1] = qsurf_neighbor.points.v2;
1592 surfmesh.con[cidx + 2] = qsurf_neighbor.points.v3;
1593 surfmesh.con[cidx + 3] = qsurf_neighbor.points.v4;
1596 if(v.first.rank == v.second.rank)
1601 assign_ownership_rank_on_faces<T, quadruple<T>, quadruple<T>>( key, v, rank,
1604 extra_tags, intra_tags,
1605 quad_unique_face_to_elements,
1606 map_elem_oneface_to_elem_uniqueFace);
1611 surfmesh.l_numelem = idx;
1612 surfmesh.tag.resize(idx);
1613 surfmesh.type.resize(idx);
1616 surfmesh.con.resize(cidx);
1618 long int g_num_surf = surfmesh.l_numelem;
1619 MPI_Allreduce(MPI_IN_PLACE, &g_num_surf, 1, MPI_LONG, MPI_SUM, mesh.comm);
1620 surfmesh.g_numelem = g_num_surf;
1623 std::cout <<
"surfmesh.g_numelem: " << surfmesh.g_numelem <<std::endl;
1624 std::cout <<
"surfmesh.l_numelem: " << surfmesh.l_numelem <<std::endl;
1628 long int g_num_w_counter_line = lsize_line;
1629 long int g_num_w_counter_tri = lsize_tri;
1630 long int g_num_w_counter_quad = lsize_quad;
1632 MPI_Allreduce(MPI_IN_PLACE, &g_num_w_counter_line, 1, MPI_LONG, MPI_SUM,
SF_COMM);
1633 MPI_Allreduce(MPI_IN_PLACE, &g_num_w_counter_tri, 1, MPI_LONG, MPI_SUM,
SF_COMM);
1634 MPI_Allreduce(MPI_IN_PLACE, &g_num_w_counter_quad, 1, MPI_LONG, MPI_SUM,
SF_COMM);
1637 surfmesh_w_counter.g_numelem = g_num_w_counter_line+g_num_w_counter_tri+g_num_w_counter_quad;
1638 surfmesh_w_counter.l_numelem = lsize_line + lsize_tri + lsize_quad;
1640 surfmesh_w_counter.tag.resize(surfmesh_w_counter.l_numelem);
1641 surfmesh_w_counter.type.resize(surfmesh_w_counter.l_numelem);
1642 surfmesh_w_counter.con.resize(lsize_line * 2 + lsize_tri * 3 + lsize_quad * 4);
1645 std::cout <<
"surfmesh_w_counter.g_numelem: " << surfmesh_w_counter.g_numelem <<std::endl;
1646 std::cout <<
"surfmesh_w_counter.l_numelem: " << surfmesh_w_counter.l_numelem <<std::endl;
1651 long int g_num_w_unique_line = lsize_unique_line;
1652 long int g_num_w_unique_tri = lsize_unique_tri;
1653 long int g_num_w_unique_quad = lsize_unique_quad;
1655 MPI_Allreduce(MPI_IN_PLACE, &g_num_w_unique_line, 1, MPI_LONG, MPI_SUM,
SF_COMM);
1656 MPI_Allreduce(MPI_IN_PLACE, &g_num_w_unique_tri, 1, MPI_LONG, MPI_SUM,
SF_COMM);
1657 MPI_Allreduce(MPI_IN_PLACE, &g_num_w_unique_quad, 1, MPI_LONG, MPI_SUM,
SF_COMM);
1660 surfmesh_unique_face.g_numelem = g_num_w_unique_line+g_num_w_unique_tri+g_num_w_unique_quad;
1661 surfmesh_unique_face.l_numelem = lsize_unique_line + lsize_unique_tri + lsize_unique_quad;
1663 surfmesh_unique_face.tag.resize(surfmesh_unique_face.l_numelem);
1664 surfmesh_unique_face.type.resize(surfmesh_unique_face.l_numelem);
1665 surfmesh_unique_face.con.resize(lsize_unique_line * 2 + lsize_unique_tri * 3 + lsize_unique_quad * 4);
1668 std::cout <<
"surfmesh_unique_face.g_numelem: " << surfmesh_unique_face.g_numelem <<std::endl;
1669 std::cout <<
"surfmesh_unique_face.l_numelem: " << surfmesh_unique_face.l_numelem <<std::endl;
1681 #ifdef EMI_DEBUG_MESH
1683 fprintf(stderr,
"RANK %d BEFORE exchange: line_hash=%zu, tri_hash=%zu, quad_hash=%zu (expected unique total=%ld)\n",
1684 rank, line_unique_face_to_elements.
size(), tri_unique_face_to_elements.
size(),
1685 quad_unique_face_to_elements.
size(), lsize_unique_line + lsize_unique_tri + lsize_unique_quad);
1693 assign_unique_first_face(line_unique_face_to_elements, mesh.comm);
1694 assign_unique_first_face(tri_unique_face_to_elements, mesh.comm);
1695 assign_unique_first_face(quad_unique_face_to_elements, mesh.comm);
1699 #ifdef EMI_DEBUG_MESH
1701 int valid_line = 0, valid_tri = 0, valid_quad = 0;
1702 for (
const auto& [key, val] : line_unique_face_to_elements) {
1703 if (val.first.index_unique >= 0 || val.second.index_unique >= 0) valid_line++;
1705 for (
const auto& [key, val] : tri_unique_face_to_elements) {
1706 if (val.first.index_unique >= 0 || val.second.index_unique >= 0) valid_tri++;
1708 for (
const auto& [key, val] : quad_unique_face_to_elements) {
1709 if (val.first.index_unique >= 0 || val.second.index_unique >= 0) valid_quad++;
1711 fprintf(stderr,
"RANK %d AFTER exchange: line_hash=%zu, tri_hash=%zu, quad_hash=%zu\n",
1712 rank, line_unique_face_to_elements.size(), tri_unique_face_to_elements.size(),
1713 quad_unique_face_to_elements.size());
1714 fprintf(stderr,
"RANK %d VALID entries (index_unique>=0): line=%d, tri=%d, quad=%d\n",
1715 rank, valid_line, valid_tri, valid_quad);
1723 for(
auto it = line_unique_face_to_elements.begin(); it != line_unique_face_to_elements.end(); ++it) {
1725 auto& first = it->second.first;
1726 auto& second = it->second.second;
1728 assign_map_between_elem_oneface_and_elem_uniqueFace(rank, first, second, map_elem_uniqueFace_to_elem_oneface, map_elem_oneface_to_elem_uniqueFace);
1731 for(
auto it = tri_unique_face_to_elements.begin(); it != tri_unique_face_to_elements.end(); ++it) {
1732 auto& first = it->second.first;
1733 auto& second = it->second.second;
1735 assign_map_between_elem_oneface_and_elem_uniqueFace(rank, first, second, map_elem_uniqueFace_to_elem_oneface, map_elem_oneface_to_elem_uniqueFace);
1738 for(
auto it = quad_unique_face_to_elements.begin(); it != quad_unique_face_to_elements.end(); ++it) {
1739 auto& first = it->second.first;
1740 auto& second = it->second.second;
1742 assign_map_between_elem_oneface_and_elem_uniqueFace(rank, first, second, map_elem_uniqueFace_to_elem_oneface, map_elem_oneface_to_elem_uniqueFace);
1755 template<
class T>
inline
1757 std::pair<emi_face<T,tuple<T>>, emi_face<T,tuple<T>>>> & line_face,
1759 std::pair<emi_face<T,triple<T>>, emi_face<T,triple<T>>>> & tri_face,
1761 std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>>> & quad_face,
1767 MPI_Comm_size(comm, &size);
1768 MPI_Comm_rank(comm, &rank);
1771 for(
const auto & v : line_face) {
1774 if(v.second.first.rank == v.second.second.rank){
1778 emi_face<T,tuple<T>> surf_neighbor =
1779 (v.second.first.rank != rank) ? v.second.first : v.second.second;
1782 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1783 Index_tag_old = std::make_pair(surf_neighbor.points.v1,surf_neighbor.tag);
1784 map_vertex_tag_to_dof.insert({Index_tag_old,-1});
1788 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1789 Index_tag_old = std::make_pair(surf_neighbor.points.v2,surf_neighbor.tag);
1790 map_vertex_tag_to_dof.insert({Index_tag_old,-1});
1795 for(
const auto & v : tri_face) {
1798 if(v.second.first.rank == v.second.second.rank){
1802 emi_face<T,triple<T>> surf_neighbor =
1803 (v.second.first.rank != rank) ? v.second.first : v.second.second;
1806 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1807 Index_tag_old = std::make_pair(surf_neighbor.points.v1,surf_neighbor.tag);
1808 map_vertex_tag_to_dof.insert({Index_tag_old,-1});
1812 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1813 Index_tag_old = std::make_pair(surf_neighbor.points.v2,surf_neighbor.tag);
1814 map_vertex_tag_to_dof.insert({Index_tag_old,-1});
1818 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1819 Index_tag_old = std::make_pair(surf_neighbor.points.v3,surf_neighbor.tag);
1820 map_vertex_tag_to_dof.insert({Index_tag_old,-1});
1825 for(
const auto & v : quad_face) {
1828 if(v.second.first.rank == v.second.second.rank){
1832 emi_face<T,quadruple<T>> qsurf_neighbor =
1833 (v.second.first.rank != rank) ? v.second.first : v.second.second;
1836 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1837 Index_tag_old = std::make_pair(qsurf_neighbor.points.v1,qsurf_neighbor.tag);
1838 map_vertex_tag_to_dof.insert({Index_tag_old,-1});
1842 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1843 Index_tag_old = std::make_pair(qsurf_neighbor.points.v2,qsurf_neighbor.tag);
1844 map_vertex_tag_to_dof.insert({Index_tag_old,-1});
1848 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1849 Index_tag_old = std::make_pair(qsurf_neighbor.points.v3,qsurf_neighbor.tag);
1850 map_vertex_tag_to_dof.insert({Index_tag_old,-1});
1854 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1855 Index_tag_old = std::make_pair(qsurf_neighbor.points.v4,qsurf_neighbor.tag);
1856 map_vertex_tag_to_dof.insert({Index_tag_old,-1});
1861 assign_dof_on_counter_face(map_vertex_tag_to_dof,comm);
1893 template<
class T,
class S>
inline
1894 void compute_map_vertex_to_dof(meshdata<T,S> & mesh,
1901 MPI_Comm comm = mesh.comm;
1903 MPI_Comm_size(comm, &size);
1904 MPI_Comm_rank(comm, &rank);
1908 const T* con = mesh.con.data();
1909 const T* nbr = mesh.get_numbering(numbering).data();
1914 for(
size_t i=0; i<mesh.con.size(); i++)
1916 g2ptsData[rnod[con[i]]] = vertex2ptsdata[rnod[con[i]]];
1928 for(
size_t eidx = 0; eidx < mesh.l_numelem; eidx++)
1930 T tag = mesh.tag[eidx];
1931 auto pos_extra = extra_tags.
find(tag);
1932 for (
int n = mesh.dsp[eidx]; n < mesh.dsp[eidx+1];n++)
1934 T gIndex = rnod[con[n]];
1935 T data_on_gIndex = g2ptsData[rnod[con[n]]];
1939 if((pos_extra != extra_tags.
end()) || data_on_gIndex==0){
1940 std::pair <mesh_int_t,mesh_int_t> Index_tag_old = std::make_pair(gIndex,tag);
1941 if (map_vertex_tag_to_dof.find(Index_tag_old) == map_vertex_tag_to_dof.end() )
1943 map_vertex_tag_to_dof.insert({Index_tag_old,gIndex});
1948 auto it = map_vertex_to_tags_data_ranks.
find(gIndex);
1949 if (it != map_vertex_to_tags_data_ranks.
end() )
1951 intersection_data& value = it->second;
1952 bool check_tag_rank =
true;
1953 for(
int i=0; i<MAX_INTERSECTIONS; ++i) {
1954 if(value.tags[i] == tag && value.ranks[i] == rank) {
1955 check_tag_rank =
false;
1962 for(
int i=0; i<MAX_INTERSECTIONS; ++i) {
1963 if(value.tags[i] == -1 && value.ranks[i] == -1) {
1964 value.tags[i] = tag;
1965 value.data[i] = data_on_gIndex;
1966 value.ranks[i] = rank;
1975 intersection_data value;
1976 value.tags[0] = tag;
1977 value.data[0] = data_on_gIndex;
1978 value.ranks[0] = rank;
1979 map_vertex_to_tags_data_ranks.
insert({gIndex,value});
1995 assign_counter_vertices_tuple(map_vertex_to_tags_data_ranks, comm);
2012 for(
const auto & key : map_vertex_to_tags_data_ranks)
2014 T gIndex = key.first;
2015 const intersection_data& value = key.second;
2016 T data_on_gIndex = g2ptsData[gIndex];
2019 int first_index = 0;
2020 for (
int i = 0; i < MAX_INTERSECTIONS; ++i) {
2021 if(value.tags[i] == -1 && value.ranks[i] == -1) {
2026 if(value.data[i]!=data_on_gIndex)
2030 "WARN: Due to an inconsistency in ptsData computation at gIndex %d with tag %d, "
2031 "the program is stopped while preparing the data structure to introduce DOFs.\n",
2032 gIndex, value.tags[i]);
2033 fprintf(stderr,
"\n");
2037 if (i == MAX_INTERSECTIONS -1) first_index = MAX_INTERSECTIONS;
2040 if(data_on_gIndex==1){
2042 int count_intra_tags = 0;
2043 int count_extra_tags = 0;
2044 for (
int i = 0; i < first_index; ++i) {
2045 if(value.tags[i]!=-1 && extra_tags.
find(value.tags[i])==extra_tags.
end()){
2046 count_intra_tags += 1;
2047 }
else if(value.tags[i]!=-1 && extra_tags.
find(value.tags[i])!=extra_tags.
end()){
2048 count_extra_tags += 1;
2054 if(count_intra_tags>1 || count_extra_tags == 0)
2058 "WARN: Due to an issue in defining ptsData for gIndex %d, , on the membrane"
2059 "the program is stopped while preparing the data structure to introduce DOFs.\n",
2061 fprintf(stderr,
"\n");
2065 int index_intra = -1;
2067 for (
int i = 0; i < first_index; ++i) {
2068 if(value.tags[i]!=-1 && extra_tags.
find(value.tags[i])==extra_tags.
end()){
2073 if(index_intra == -1) {
2074 fprintf(stderr,
"WARN: unhandled case in membrane while decoupling: gIndex %d", gIndex);
2075 fprintf(stderr,
"\n");
2078 if(index_intra != -1) {
2079 T tag_myocyte = value.tags[index_intra];
2080 T rank_myocyte = value.ranks[index_intra];
2082 if(rank_myocyte == rank) {
2083 std::pair <mesh_int_t,mesh_int_t> Index_tag_next = std::make_pair(gIndex,tag_myocyte);
2084 if (map_mark_new_dofs.
find(Index_tag_next) == map_mark_new_dofs.
end()) {
2085 map_mark_new_dofs.
insert({Index_tag_next,
true});
2091 else if(data_on_gIndex==2){
2093 int count_intra_tags = 0;
2094 int count_extra_tags = 0;
2095 for (
int i = 0; i < first_index; ++i) {
2096 if(value.tags[i]!=-1 && extra_tags.
find(value.tags[i])==extra_tags.
end()){
2097 count_intra_tags += 1;
2098 }
else if(value.tags[i]!=-1 && extra_tags.
find(value.tags[i])!=extra_tags.
end()){
2099 count_extra_tags += 1;
2102 if(count_intra_tags!=2 || count_extra_tags != 0){
2105 "WARN: Due to an issue in defining ptsData for gIndex %d, on the gapjunction"
2106 "the program is stopped while preparing the data structure to introduce DOFs.\n",
2108 fprintf(stderr,
"\n");
2116 bool tag1_checked =
false;
2117 bool tag2_checked =
false;
2119 for (
int i = 0; i < first_index; ++i)
2121 auto pos_extra = extra_tags.
find(value.tags[i]);
2122 if(pos_extra == extra_tags.
end()) {
2124 tag1 = value.tags[i];
2125 rank1 = value.ranks[i];
2126 tag1_checked =
true;
2128 tag2 = value.tags[i];
2129 rank2 = value.ranks[i];
2130 tag2_checked =
true;
2136 if(!tag1_checked && !tag2_checked || (rank1==rank2 && rank1!=rank) ) {
2137 fprintf(stderr,
"WARN: unhandled case in gap junction while decoupling: gIndex %d with tags %d:%d ", gIndex, tag1, tag2);
2138 fprintf(stderr,
"\n");
2142 if(rank1==rank2 && (rank1 == rank)){
2143 T smallest_tag = tag1 < tag2? tag1:tag2;
2144 std::pair <mesh_int_t,mesh_int_t> Index_tag_old = std::make_pair(gIndex,smallest_tag);
2145 if (map_vertex_tag_to_dof.find(Index_tag_old) == map_vertex_tag_to_dof.end() ) {
2146 map_vertex_tag_to_dof.insert({Index_tag_old,gIndex});
2149 T bigger_tag = tag1 < tag2? tag2:tag1;
2150 std::pair <mesh_int_t,mesh_int_t> Index_tag_new = std::make_pair(gIndex,bigger_tag);
2151 if (map_mark_new_dofs.
find(Index_tag_new) == map_mark_new_dofs.
end() ) {
2152 map_mark_new_dofs.
insert({Index_tag_new,
true});
2156 else if(rank1!=rank2 && (rank1 == rank)) {
2158 std::pair <mesh_int_t,mesh_int_t> Index_tag_old = std::make_pair(gIndex,tag1);
2159 if (map_vertex_tag_to_dof.find(Index_tag_old) == map_vertex_tag_to_dof.end() ) {
2160 map_vertex_tag_to_dof.insert({Index_tag_old,gIndex});
2163 std::pair <mesh_int_t,mesh_int_t> Index_tag_new = std::make_pair(gIndex,tag1);
2164 if (map_mark_new_dofs.
find(Index_tag_new) == map_mark_new_dofs.
end() ) {
2165 map_mark_new_dofs.
insert({Index_tag_new,
true});
2170 else if(rank1!=rank2 && (rank2 == rank)) {
2172 std::pair <mesh_int_t,mesh_int_t> Index_tag_old = std::make_pair(gIndex,tag2);
2173 if (map_vertex_tag_to_dof.find(Index_tag_old) == map_vertex_tag_to_dof.end() ) {
2174 map_vertex_tag_to_dof.insert({Index_tag_old,gIndex});
2177 std::pair <mesh_int_t,mesh_int_t> Index_tag_new = std::make_pair(gIndex,tag2);
2178 if (map_mark_new_dofs.
find(Index_tag_new) == map_mark_new_dofs.
end() ) {
2179 map_mark_new_dofs.
insert({Index_tag_new,
true});
2185 else if(data_on_gIndex==3)
2188 int count_intra_tags = 0;
2189 int count_extra_tags = 0;
2190 for (
int i = 0; i < first_index; ++i) {
2191 if(value.tags[i]!=-1 && extra_tags.
find(value.tags[i])==extra_tags.
end()){
2192 count_intra_tags += 1;
2193 }
else if(value.tags[i]!=-1 && extra_tags.
find(value.tags[i])!=extra_tags.
end()){
2194 count_extra_tags += 1;
2197 if(count_intra_tags!=2 || count_extra_tags == 0){
2200 "WARN: Due to an issue in defining ptsData for gIndex %d, on intersection between membrane and gapjunction"
2201 "the program is stopped while preparing the data structure to introduce DOFs.\n",
2203 fprintf(stderr,
"\n");
2209 for (
int i = 0; i < first_index; ++i) {
2211 auto pos_extra = extra_tags.
find(value.tags[i]);
2212 if(value.tags[i]!=-1 && value.ranks[i] == rank && pos_extra == extra_tags.
end()) {
2213 std::pair <mesh_int_t,mesh_int_t> Index_tag_new = std::make_pair(gIndex,value.tags[i]);
2214 if (map_mark_new_dofs.
find(Index_tag_new) == map_mark_new_dofs.
end() )
2216 map_mark_new_dofs.
insert({Index_tag_new,
true});
2224 vector<size_t> dsp_dof(size);
2225 MPI_Allgather(&shift,
sizeof(
size_t), MPI_BYTE, dsp_dof.data(),
sizeof(
size_t), MPI_BYTE, comm);
2240 start = mesh.g_numpts;
2244 start = mesh.g_numpts;
2245 for (
int r = 0; r < rank; ++r)
2252 auto lexicographic_comp_pair = [](
const std::pair<mesh_int_t,mesh_int_t> & a,
const std::pair<mesh_int_t,mesh_int_t> & b)
2254 if (a.second == b.second)
return a.first < b.first;
2255 return a.second < b.second;
2258 map_mark_new_dofs.
sort(lexicographic_comp_pair);
2260 for(
const auto & entry : map_mark_new_dofs)
2262 T newIndex = start+
count;
2263 map_vertex_tag_to_dof.insert({entry.first,newIndex});
2274 template<
class K,
class intersection_indices>
inline
2277 size_t dsize = map.
size();
2278 vector<K> key_vec(dsize);
2279 vector<intersection_indices> value_vec(dsize);
2280 intersection_indices indices;
2282 for (
const auto& v : map) {
2283 key_vec[idx] = v.first;
2284 value_vec[idx] = v.second;
2288 vector<int> perm, dest;
2289 emi_select_merge_destinations(key_vec, dsize,
sizeof(K) +
sizeof(intersection_indices), dest, comm,
2290 "assign_counter_dofs",
2293 commgraph<size_t> grph;
2294 grph.configure(dest, comm);
2295 size_t nrecv =
sum(grph.rcnt);
2301 vector<K> sbuff_key(dsize), rbuff_key(nrecv);
2302 vector<intersection_indices> sbuff_value(dsize), ibuff_value(dsize), rbuff_value(nrecv);
2303 for (
size_t i = 0; i < dsize; i++) {
2304 sbuff_key[i] = key_vec[perm[i]];
2305 sbuff_value[i] = value_vec[perm[i]];
2311 for (
size_t i = 0; i < nrecv; i++)
2313 auto it = rmap.
find(rbuff_key[i]);
2314 if (it != rmap.
end())
2316 intersection_indices& map_indices = it->second;
2317 intersection_indices& r_indices = rbuff_value[i];
2319 for (
int r_indices : r_indices.indices)
2321 if (r_indices == -1)
continue;
2323 for (
int m_index : map_indices.indices)
2325 if (m_index == r_indices) {
2332 for (
size_t k = 0; k < MAX_INTERSECTIONS; ++k) {
2333 if (map_indices.indices[k] == -1) {
2334 map_indices.indices[k] = r_indices;
2343 rmap.
insert({ rbuff_key[i], rbuff_value[i] });
2347 for (
size_t i = 0; i < nrecv; i++) {
2348 auto it = rmap.
find(rbuff_key[i]);
2349 if (it != rmap.
end()) rbuff_value[i] = it->second;
2356 for (
size_t i = 0; i < dsize; i++) {
2357 auto it = map.find(sbuff_key[i]);
2358 if (it != map.end()) it->second = ibuff_value[i];
2371 template<
class T,
class S>
inline
2372 void update_emi_mesh_with_dofs(meshdata<T,S> & mesh,
2380 MPI_Comm comm = mesh.comm;
2381 mesh.globalize(numbering);
2382 for(
size_t eidx = 0; eidx < mesh.l_numelem; eidx++) {
2383 T tag = mesh.tag[eidx];
2384 T size_elem = mesh.dsp[eidx+1]-mesh.dsp[eidx];
2386 for (
int n = mesh.dsp[eidx]; n < mesh.dsp[eidx+1];n++)
2388 T gIndex = mesh.con[n];
2390 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2391 Index_tag_old = std::make_pair(gIndex,tag);
2393 auto it_new = map_vertex_tag_to_dof.find(Index_tag_old);
2394 if (it_new != map_vertex_tag_to_dof.end() )
2397 dof2vertex.
insert({dof_new, gIndex});
2398 mesh.con[n] = dof_new;
2400 auto it = vertex2dof.
find(gIndex);
2401 if (it != vertex2dof.
end())
2403 intersection_indices& indices = it->second;
2405 for(T t : indices.indices) {
2413 for(
size_t i=0; i<MAX_INTERSECTIONS; ++i) {
2414 if(indices.indices[i] == -1) {
2415 indices.indices[i] = dof_new;
2421 intersection_indices indices;
2422 indices.indices[0] = dof_new;
2423 vertex2dof.
insert({gIndex,indices});
2429 assign_counter_dofs(vertex2dof, comm);
2432 for (
const auto& [old_idx, indices] : vertex2dof) {
2433 for (
int new_idx : indices.indices) {
2434 if (new_idx != -1) {
2436 if (dof2vertex.
find(new_idx) == dof2vertex.
end()) {
2437 dof2vertex.
insert({new_idx, old_idx});
2443 mesh.localize(numbering);
2457 template<
class T,
class S>
inline
2458 void update_map_indices_to_petsc(meshdata<T,S> & mesh,
2459 const SF_nbr numbering_ref,
const SF_nbr numbering_petsc,
2462 std::pair<mesh_int_t,mesh_int_t>> & map_vertex_tag_to_dof_petsc,
2469 elemTag_emi_mesh.
resize(mesh.l_numelem);
2470 for(
size_t eidx = 0; eidx < mesh.l_numelem; eidx++) {
2471 T tag = mesh.tag[eidx];
2472 elemTag_emi_mesh[eidx] = 1;
2473 if(extra_tags.
find(tag) == extra_tags.
end())
2474 elemTag_emi_mesh[eidx] = 2;
2475 for (
int n = mesh.dsp[eidx]; n < mesh.dsp[eidx+1];n++)
2477 T l_Indx = mesh.con[n];
2478 T petsc_Idx = petsc_nbr[l_Indx];
2479 T n_Indx = ref_nbr[l_Indx];
2480 T o_Indx = dof2vertex[n_Indx];
2482 std::pair <mesh_int_t,mesh_int_t> oIndx_tag;
2483 oIndx_tag = std::make_pair(o_Indx,tag);
2485 auto it_new = map_vertex_tag_to_dof_petsc.find(oIndx_tag);
2486 if (it_new != map_vertex_tag_to_dof_petsc.end() )
2488 std::pair <mesh_int_t,mesh_int_t> nIndx_petsc;
2489 nIndx_petsc = std::make_pair(n_Indx,petsc_Idx);
2491 (*it_new).second = nIndx_petsc;
2509 template<
class T,
class S>
2510 inline void update_faces_on_surface_mesh_after_decoupling_with_dofs(meshdata<T, S> & mesh,
2514 std::pair<emi_face<T,tuple<T>>, emi_face<T,tuple<T>>>> & line_face,
2516 std::pair<emi_face<T,triple<T>>, emi_face<T,triple<T>>>> & tri_face,
2518 std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>>> & quad_face)
2522 MPI_Comm_size(comm, &size); MPI_Comm_rank(comm, &rank);
2529 for(
size_t i=0; i<idxbuff.size(); i++){
2530 g2l[idxbuff[i]] = i;
2531 l2g[i] = idxbuff[i];
2534 for(
size_t eidx = 0; eidx < mesh.l_numelem; eidx++) {
2535 T tag = mesh.tag[eidx];
2536 T size_elem = mesh.dsp[eidx+1]-mesh.dsp[eidx];
2537 std::vector<int> elem_nodes;
2538 for (
int n = mesh.dsp[eidx]; n < mesh.dsp[eidx+1];n++)
2540 T gIndex = mesh.con[n];
2541 elem_nodes.push_back(gIndex);
2543 std::sort(elem_nodes.begin(),elem_nodes.end());
2544 if(elem_nodes.size()==2){
2546 key.v1 = elem_nodes[0];
2547 key.v2 = elem_nodes[1];
2548 std::pair<emi_face<T,tuple<T>>, emi_face<T,tuple<T>>> value = line_face[key];
2550 line_face.erase(key);
2551 std::vector<int> new_nodes(2);
2553 auto tag_key = (value.first.rank == rank) ? value.first.tag : value.second.tag;
2555 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2556 Index_tag_old = std::make_pair(elem_nodes[0],tag_key);
2557 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2558 new_nodes[0] = Index_new;
2561 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2562 Index_tag_old = std::make_pair(elem_nodes[1],tag_key);
2563 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2564 new_nodes[1] = Index_new;
2566 std::sort(new_nodes.begin(),new_nodes.end());
2569 new_key.v1 = new_nodes[0];
2570 new_key.v2 = new_nodes[1];
2574 mesh_int_t Index_new1 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v1, value.first.tag)];
2575 mesh_int_t Index_new2 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v2, value.first.tag)];
2576 value.first.points.v1 = Index_new1;
2577 value.first.points.v2 = Index_new2;
2581 mesh_int_t Index_new1 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v1, value.second.tag)];
2582 mesh_int_t Index_new2 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v2, value.second.tag)];
2583 value.second.points.v1 = Index_new1;
2584 value.second.points.v2 = Index_new2;
2586 line_face.insert({new_key,value});
2588 if(elem_nodes.size()==3){
2590 key.v1 = elem_nodes[0];
2591 key.v2 = elem_nodes[1];
2592 key.v3 = elem_nodes[2];
2593 std::pair<emi_face<T,triple<T>>, emi_face<T,triple<T>>> value = tri_face[key];
2594 tri_face.erase(key);
2595 std::vector<int> new_nodes(3);
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;
2611 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2612 Index_tag_old = std::make_pair(elem_nodes[2],tag_key);
2613 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2614 new_nodes[2] = Index_new;
2616 std::sort(new_nodes.begin(),new_nodes.end());
2619 new_key.v1 = new_nodes[0];
2620 new_key.v2 = new_nodes[1];
2621 new_key.v3 = new_nodes[2];
2625 mesh_int_t Index_new1 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v1, value.first.tag)];
2626 mesh_int_t Index_new2 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v2, value.first.tag)];
2627 mesh_int_t Index_new3 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v3, value.first.tag)];
2628 value.first.points.v1 = Index_new1;
2629 value.first.points.v2 = Index_new2;
2630 value.first.points.v3 = Index_new3;
2634 mesh_int_t Index_new1 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v1, value.second.tag)];
2635 mesh_int_t Index_new2 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v2, value.second.tag)];
2636 mesh_int_t Index_new3 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v3, value.second.tag)];
2637 value.second.points.v1 = Index_new1;
2638 value.second.points.v2 = Index_new2;
2639 value.second.points.v3 = Index_new3;
2641 tri_face.insert({new_key,value});
2643 if(elem_nodes.size()==4){
2645 key.v1 = elem_nodes[0];
2646 key.v2 = elem_nodes[1];
2647 key.v3 = elem_nodes[2];
2648 key.v4 = elem_nodes[3];
2649 std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>> value = quad_face[key];
2650 quad_face.erase(key);
2651 std::vector<int> new_nodes(4);
2653 auto tag_key = (value.first.rank == rank) ? value.first.tag : value.second.tag;
2655 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2656 Index_tag_old = std::make_pair(elem_nodes[0],tag_key);
2657 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2658 new_nodes[0] = Index_new;
2661 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2662 Index_tag_old = std::make_pair(elem_nodes[1],tag_key);
2663 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2664 new_nodes[1] = Index_new;
2667 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2668 Index_tag_old = std::make_pair(elem_nodes[2],tag_key);
2669 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2670 new_nodes[2] = Index_new;
2673 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
2674 Index_tag_old = std::make_pair(elem_nodes[3],tag_key);
2675 mesh_int_t Index_new = map_vertex_tag_to_dof[Index_tag_old];
2676 new_nodes[3] = Index_new;
2678 std::sort(new_nodes.begin(),new_nodes.end());
2680 quadruple<T> new_key;
2681 new_key.v1 = new_nodes[0];
2682 new_key.v2 = new_nodes[1];
2683 new_key.v3 = new_nodes[2];
2684 new_key.v4 = new_nodes[3];
2688 mesh_int_t Index_new1 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v1, value.first.tag)];
2689 mesh_int_t Index_new2 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v2, value.first.tag)];
2690 mesh_int_t Index_new3 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v3, value.first.tag)];
2691 mesh_int_t Index_new4 = map_vertex_tag_to_dof[std::make_pair(value.first.points.v4, value.first.tag)];
2692 value.first.points.v1 = Index_new1;
2693 value.first.points.v2 = Index_new2;
2694 value.first.points.v3 = Index_new3;
2695 value.first.points.v4 = Index_new4;
2699 mesh_int_t Index_new1 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v1, value.second.tag)];
2700 mesh_int_t Index_new2 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v2, value.second.tag)];
2701 mesh_int_t Index_new3 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v3, value.second.tag)];
2702 mesh_int_t Index_new4 = map_vertex_tag_to_dof[std::make_pair(value.second.points.v4, value.second.tag)];
2703 value.second.points.v1 = Index_new1;
2704 value.second.points.v2 = Index_new2;
2705 value.second.points.v3 = Index_new3;
2706 value.second.points.v4 = Index_new4;
2708 quad_face.insert({new_key,value});
2724 template<
class T,
class S>
inline
2725 void compute_surface_mesh_with_counter_face(meshdata<T, S> & mesh,
const SF_nbr numbering,
2727 std::pair<emi_face<T,tuple<T>>, emi_face<T,tuple<T>>>> & line_face,
2729 std::pair<emi_face<T,triple<T>>, emi_face<T,triple<T>>>> & tri_face,
2731 std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>>> & quad_face)
2733 mesh.register_numbering(numbering);
2737 MPI_Comm_size(comm, &size);
2738 MPI_Comm_rank(comm, &rank);
2741 vector<tuple<T>> line_keys;
2742 for(
auto const& [key, val] : line_face) line_keys.push_back(key);
2743 std::sort(line_keys.begin(), line_keys.end());
2745 vector<triple<T>> tri_keys;
2746 for(
auto const& [key, val] : tri_face) tri_keys.push_back(key);
2747 std::sort(tri_keys.begin(), tri_keys.end());
2749 vector<quadruple<T>> quad_keys;
2750 for(
auto const& [key, val] : quad_face) quad_keys.push_back(key);
2751 std::sort(quad_keys.begin(), quad_keys.end());
2753 vector<T> cnt(mesh.l_numelem);
2754 size_t idx = 0, cidx = 0;
2759 for(
const auto & key : line_keys) {
2760 const auto & v = line_face.at(key);
2761 bool both_faces = (v.first.rank == v.second.rank) ?
true:
false;
2765 emi_face<T,tuple<T>> surf_first;
2766 emi_face<T,tuple<T>> surf_second;
2767 if(v.first.rank == rank)
2769 surf_first = v.first;
2770 surf_second = v.second;
2774 surf_first = v.second;
2775 surf_second = v.first;
2778 mesh.type[idx] =
Line;
2779 mesh.tag[idx] = surf_first.tag;
2780 mesh.con[cidx + 0] = surf_first.points.v1;
2781 mesh.con[cidx + 1] = surf_first.points.v2;
2788 mesh.type[idx] =
Line;
2789 mesh.tag[idx] = surf_second.tag;
2790 mesh.con[cidx + 0] = surf_second.points.v1;
2791 mesh.con[cidx + 1] = surf_second.points.v2;
2798 for(
const auto & key : tri_keys) {
2799 const auto & v = tri_face.at(key);
2800 bool both_faces = (v.first.rank == v.second.rank) ?
true:
false;
2804 emi_face<T,triple<T>> surf_first;
2805 emi_face<T,triple<T>> surf_second;
2806 if(v.first.rank == rank)
2808 surf_first = v.first;
2809 surf_second = v.second;
2813 surf_first = v.second;
2814 surf_second = v.first;
2817 mesh.type[idx] =
Tri;
2818 mesh.tag[idx] = surf_first.tag;
2819 mesh.con[cidx + 0] = surf_first.points.v1;
2820 mesh.con[cidx + 1] = surf_first.points.v2;
2821 mesh.con[cidx + 2] = surf_first.points.v3;
2830 mesh.type[idx] =
Tri;
2831 mesh.tag[idx] = surf_second.tag;
2832 mesh.con[cidx + 0] = surf_second.points.v1;
2833 mesh.con[cidx + 1] = surf_second.points.v2;
2834 mesh.con[cidx + 2] = surf_second.points.v3;
2841 for(
const auto & key : quad_keys) {
2842 const auto & v = quad_face.at(key);
2843 bool both_faces = (v.first.rank == v.second.rank) ?
true:
false;
2846 emi_face<T,quadruple<T>> surf_first;
2847 emi_face<T,quadruple<T>> surf_second;
2848 if(v.first.rank == rank)
2850 surf_first = v.first;
2851 surf_second = v.second;
2855 surf_first = v.second;
2856 surf_second = v.first;
2859 mesh.type[idx] =
Quad;
2860 mesh.tag[idx] = surf_first.tag;
2861 mesh.con[cidx + 0] = surf_first.points.v1;
2862 mesh.con[cidx + 1] = surf_first.points.v2;
2863 mesh.con[cidx + 2] = surf_first.points.v3;
2864 mesh.con[cidx + 3] = surf_first.points.v4;
2873 mesh.type[idx] =
Quad;
2874 mesh.tag[idx] = surf_second.tag;
2875 mesh.con[cidx + 0] = surf_second.points.v1;
2876 mesh.con[cidx + 1] = surf_second.points.v2;
2877 mesh.con[cidx + 2] = surf_second.points.v3;
2878 mesh.con[cidx + 3] = surf_second.points.v4;
2917 template<
class T,
class S>
inline
2918 void compute_surface_mesh_with_unique_face(meshdata<T, S> & mesh,
const SF_nbr numbering,
2920 std::pair<emi_face<T,tuple<T>>, emi_face<T,tuple<T>>>> & line_face,
2922 std::pair<emi_face<T,triple<T>>, emi_face<T,triple<T>>>> & tri_face,
2924 std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>>> & quad_face,
2927 mesh.register_numbering(numbering);
2931 MPI_Comm_size(comm, &size);
2932 MPI_Comm_rank(comm, &rank);
2935 vector<tuple<T>> line_keys;
2936 for(
auto const& [key, val] : line_face) line_keys.push_back(key);
2937 std::sort(line_keys.begin(), line_keys.end());
2939 vector<triple<T>> tri_keys;
2940 for(
auto const& [key, val] : tri_face) tri_keys.push_back(key);
2941 std::sort(tri_keys.begin(), tri_keys.end());
2943 vector<quadruple<T>> quad_keys;
2944 for(
auto const& [key, val] : quad_face) quad_keys.push_back(key);
2945 std::sort(quad_keys.begin(), quad_keys.end());
2947 vector<T> cnt(mesh.l_numelem);
2948 size_t idx = 0, cidx = 0;
2953 for(
const auto & key : line_keys) {
2954 const auto & v = line_face.at(key);
2956 bool to_take_face =
false;
2958 emi_face<T,tuple<T>> surf_take;
2959 std::pair <mesh_int_t,mesh_int_t> tag_pairs_take;
2961 if(v.first.rank == rank && v.first.mark_to_take ==
true)
2963 surf_take = v.first;
2964 to_take_face =
true;
2965 tag_pairs_take = std::make_pair(v.first.tag,v.second.tag);
2967 else if(v.second.rank == rank && v.second.mark_to_take ==
true)
2969 surf_take = v.second;
2970 to_take_face =
true;
2971 tag_pairs_take = std::make_pair(v.second.tag,v.first.tag);
2976 map_elem_uniqueFace_to_tags.insert({idx,tag_pairs_take});
2978 mesh.type[idx] =
Line;
2979 mesh.tag[idx] = surf_take.tag;
2980 mesh.con[cidx + 0] = surf_take.points.v1;
2981 mesh.con[cidx + 1] = surf_take.points.v2;
2988 for(
const auto & key : tri_keys) {
2989 const auto & v = tri_face.at(key);
2991 bool to_take_face =
false;
2993 emi_face<T,triple<T>> surf_take;
2994 std::pair <mesh_int_t,mesh_int_t> tag_pairs_take;
2996 if(v.first.rank == rank && v.first.mark_to_take ==
true)
2998 surf_take = v.first;
2999 to_take_face =
true;
3000 tag_pairs_take = std::make_pair(v.first.tag,v.second.tag);
3002 else if(v.second.rank == rank && v.second.mark_to_take ==
true)
3004 surf_take = v.second;
3005 to_take_face =
true;
3006 tag_pairs_take = std::make_pair(v.second.tag,v.first.tag);
3011 map_elem_uniqueFace_to_tags.insert({idx,tag_pairs_take});
3013 mesh.type[idx] =
Tri;
3014 mesh.tag[idx] = surf_take.tag;
3015 mesh.con[cidx + 0] = surf_take.points.v1;
3016 mesh.con[cidx + 1] = surf_take.points.v2;
3017 mesh.con[cidx + 2] = surf_take.points.v3;
3025 for(
const auto & key : quad_keys) {
3026 const auto & v = quad_face.at(key);
3029 bool to_take_face =
false;
3031 emi_face<T,quadruple<T>> surf_take;
3032 std::pair <mesh_int_t,mesh_int_t> tag_pairs_take;
3034 if(v.first.rank == rank && v.first.mark_to_take ==
true)
3036 surf_take = v.first;
3037 to_take_face =
true;
3038 tag_pairs_take = std::make_pair(v.first.tag,v.second.tag);
3040 else if(v.second.rank == rank && v.second.mark_to_take ==
true)
3042 surf_take = v.second;
3043 to_take_face =
true;
3044 tag_pairs_take = std::make_pair(v.second.tag,v.first.tag);
3049 map_elem_uniqueFace_to_tags.insert({idx,tag_pairs_take});
3051 mesh.type[idx] =
Quad;
3052 mesh.tag[idx] = surf_take.tag;
3053 mesh.con[cidx + 0] = surf_take.points.v1;
3054 mesh.con[cidx + 1] = surf_take.points.v2;
3055 mesh.con[cidx + 2] = surf_take.points.v3;
3056 mesh.con[cidx + 3] = surf_take.points.v4;
3085 template<
class T>
inline
3086 void create_reverse_elem_mapping_between_surface_meshes(
3089 hashmap::unordered_map<quadruple<T>, std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>>>& quad_face,
3094 MPI_Comm_rank(comm, &rank);
3097 vector<tuple<T>> line_keys;
3098 for(
auto const& [key, val] : line_face) line_keys.push_back(key);
3099 std::sort(line_keys.begin(), line_keys.end());
3101 vector<triple<T>> tri_keys;
3102 for(
auto const& [key, val] : tri_face) tri_keys.push_back(key);
3103 std::sort(tri_keys.begin(), tri_keys.end());
3105 vector<quadruple<T>> quad_keys;
3106 for(
auto const& [key, val] : quad_face) quad_keys.push_back(key);
3107 std::sort(quad_keys.begin(), quad_keys.end());
3109 size_t surf_elem_idx = 0;
3110 size_t w_counter_elem_idx = 0;
3112 size_t lsize_line = 0;
3113 size_t lsize_tri = 0;
3114 size_t lsize_quad = 0;
3118 for(
const auto& key : line_keys) {
3119 const auto& v = line_face.at(key);
3120 const bool local_involved = (v.first.rank == rank) || (v.second.rank == rank);
3121 if (!local_involved) {
3124 if(v.first.rank == v.second.rank) lsize_line+=2;
3127 for(
const auto& key : tri_keys) {
3128 const auto& v = tri_face.at(key);
3129 const bool local_involved = (v.first.rank == rank) || (v.second.rank == rank);
3130 if (!local_involved) {
3133 if(v.first.rank == v.second.rank) lsize_tri+=2;
3136 for(
const auto& key : quad_keys) {
3137 const auto& v = quad_face.at(key);
3138 const bool local_involved = (v.first.rank == rank) || (v.second.rank == rank);
3139 if (!local_involved) {
3142 if(v.first.rank == v.second.rank) lsize_quad+=2;
3146 vec_one_to_both_face.
resize(lsize_line + lsize_tri + lsize_quad);
3150 for (
const auto& key : line_keys) {
3151 const auto& v = line_face.at(key);
3152 const bool local_involved = (v.first.rank == rank) || (v.second.rank == rank);
3153 if (!local_involved) {
3156 vec_one_to_both_face[w_counter_elem_idx++] = surf_elem_idx;
3157 if (v.first.rank == v.second.rank) {
3158 vec_one_to_both_face[w_counter_elem_idx++] = surf_elem_idx;
3163 for (
const auto& key : tri_keys) {
3164 const auto& v = tri_face.at(key);
3165 const bool local_involved = (v.first.rank == rank) || (v.second.rank == rank);
3166 if (!local_involved) {
3169 vec_one_to_both_face[w_counter_elem_idx++] = surf_elem_idx;
3170 if (v.first.rank == v.second.rank) {
3171 vec_one_to_both_face[w_counter_elem_idx++] = surf_elem_idx;
3176 for (
const auto& key : quad_keys) {
3177 const auto& v = quad_face.at(key);
3178 const bool local_involved = (v.first.rank == rank) || (v.second.rank == rank);
3179 if (!local_involved) {
3182 vec_one_to_both_face[w_counter_elem_idx++] = surf_elem_idx;
3183 if (v.first.rank == v.second.rank) {
3184 vec_one_to_both_face[w_counter_elem_idx++] = surf_elem_idx;
3198 template<
class T>
inline
3200 std::pair<emi_face<T,tuple<T>>, emi_face<T,tuple<T>>>> & line_face,
3202 std::pair<emi_face<T,triple<T>>, emi_face<T,triple<T>>>> & tri_face,
3204 std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>>> & quad_face)
3207 std::vector<std::pair<tuple<T>, std::pair<emi_face<T,tuple<T>>, emi_face<T,tuple<T>>>>> line_inserts;
3208 for(
const auto & v : line_face) {
3209 SF::emi_face<mesh_int_t,SF::tuple<mesh_int_t>> surf_first = v.second.first;
3210 SF::emi_face<mesh_int_t,SF::tuple<mesh_int_t>> surf_second = v.second.second;
3212 std::vector<mesh_int_t> elem_nodes_first; elem_nodes_first.
resize(2);
3213 std::vector<mesh_int_t> elem_nodes_second; elem_nodes_second.resize(2);
3216 elem_nodes_first[0] = surf_first.points.
v1;
3217 elem_nodes_first[1] = surf_first.points.v2;
3218 std::sort(elem_nodes_first.begin(),elem_nodes_first.end());
3219 key_first.
v1 = elem_nodes_first[0];
3220 key_first.
v2 = elem_nodes_first[1];
3223 elem_nodes_second[0] = surf_second.points.
v1;
3224 elem_nodes_second[1] = surf_second.points.v2;
3225 std::sort(elem_nodes_second.begin(),elem_nodes_second.end());
3226 key_second.
v1 = elem_nodes_second[0];
3227 key_second.
v2 = elem_nodes_second[1];
3229 const bool same_key_first = (v.first.v1 == key_first.
v1 && v.first.v2 == key_first.
v2);
3230 if (!same_key_first && line_face.find(key_first) == line_face.end()) {
3231 line_inserts.push_back({key_first, v.second});
3233 const bool same_key_second = (v.first.v1 == key_second.
v1 && v.first.v2 == key_second.
v2);
3234 if (!same_key_second && line_face.find(key_second) == line_face.end()) {
3235 line_inserts.push_back({key_second, v.second});
3238 for (
const auto & entry : line_inserts) line_face.insert(entry);
3240 std::vector<std::pair<triple<T>, std::pair<emi_face<T,triple<T>>, emi_face<T,triple<T>>>>> tri_inserts;
3241 for(
const auto & v : tri_face) {
3242 SF::emi_face<mesh_int_t,SF::triple<mesh_int_t>> surf_first = v.second.first;
3243 SF::emi_face<mesh_int_t,SF::triple<mesh_int_t>> surf_second = v.second.second;
3245 std::vector<mesh_int_t> elem_nodes_first; elem_nodes_first.resize(3);
3246 std::vector<mesh_int_t> elem_nodes_second; elem_nodes_second.resize(3);
3249 elem_nodes_first[0] = surf_first.points.
v1;
3250 elem_nodes_first[1] = surf_first.points.v2;
3251 elem_nodes_first[2] = surf_first.points.v3;
3252 std::sort(elem_nodes_first.begin(),elem_nodes_first.end());
3253 key_first.
v1 = elem_nodes_first[0];
3254 key_first.
v2 = elem_nodes_first[1];
3255 key_first.
v3 = elem_nodes_first[2];
3258 elem_nodes_second[0] = surf_second.points.
v1;
3259 elem_nodes_second[1] = surf_second.points.v2;
3260 elem_nodes_second[2] = surf_second.points.v3;
3261 std::sort(elem_nodes_second.begin(),elem_nodes_second.end());
3262 key_second.
v1 = elem_nodes_second[0];
3263 key_second.
v2 = elem_nodes_second[1];
3264 key_second.
v3 = elem_nodes_second[2];
3266 const bool same_key_first = (v.first.v1 == key_first.
v1 &&
3267 v.first.v2 == key_first.
v2 &&
3268 v.first.v3 == key_first.
v3);
3269 if (!same_key_first && tri_face.find(key_first) == tri_face.end()) {
3270 tri_inserts.push_back({key_first, v.second});
3272 const bool same_key_second = (v.first.v1 == key_second.
v1 &&
3273 v.first.v2 == key_second.
v2 &&
3274 v.first.v3 == key_second.
v3);
3275 if (!same_key_second && tri_face.find(key_second) == tri_face.end()) {
3276 tri_inserts.push_back({key_second, v.second});
3279 for (
const auto & entry : tri_inserts) tri_face.insert(entry);
3281 std::vector<std::pair<quadruple<T>, std::pair<emi_face<T,quadruple<T>>, emi_face<T,quadruple<T>>>>> quad_inserts;
3282 for(
const auto & v : quad_face) {
3283 SF::emi_face<mesh_int_t,SF::quadruple<mesh_int_t>> surf_first = v.second.first;
3284 SF::emi_face<mesh_int_t,SF::quadruple<mesh_int_t>> surf_second = v.second.second;
3286 std::vector<mesh_int_t> elem_nodes_first; elem_nodes_first.resize(4);
3287 std::vector<mesh_int_t> elem_nodes_second; elem_nodes_second.resize(4);
3290 elem_nodes_first[0] = surf_first.points.
v1;
3291 elem_nodes_first[1] = surf_first.points.v2;
3292 elem_nodes_first[2] = surf_first.points.v3;
3293 elem_nodes_first[3] = surf_first.points.v4;
3294 std::sort(elem_nodes_first.begin(),elem_nodes_first.end());
3295 key_first.
v1 = elem_nodes_first[0];
3296 key_first.
v2 = elem_nodes_first[1];
3297 key_first.
v3 = elem_nodes_first[2];
3298 key_first.
v4 = elem_nodes_first[3];
3301 elem_nodes_second[0] = surf_second.points.
v1;
3302 elem_nodes_second[1] = surf_second.points.v2;
3303 elem_nodes_second[2] = surf_second.points.v3;
3304 elem_nodes_second[3] = surf_second.points.v4;
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];
3309 key_second.
v4 = elem_nodes_second[3];
3311 const bool same_key_first = (v.first.v1 == key_first.
v1 &&
3312 v.first.v2 == key_first.
v2 &&
3313 v.first.v3 == key_first.
v3 &&
3314 v.first.v4 == key_first.
v4);
3315 if (!same_key_first && quad_face.find(key_first) == quad_face.end()) {
3316 quad_inserts.push_back({key_first, v.second});
3318 const bool same_key_second = (v.first.v1 == key_second.
v1 &&
3319 v.first.v2 == key_second.
v2 &&
3320 v.first.v3 == key_second.
v3 &&
3321 v.first.v4 == key_second.
v4);
3322 if (!same_key_second && quad_face.find(key_second) == quad_face.end()) {
3323 quad_inserts.push_back({key_second, v.second});
3326 for (
const auto & entry : quad_inserts) quad_face.insert(entry);
3335 template<
class K>
inline
3338 size_t dsize = map.
size();
3339 vector<K> key_vec(dsize);
3340 vector<intersection_tags> value_vec(dsize);
3343 for (
const auto& v : map) {
3344 key_vec[idx] = v.first;
3345 value_vec[idx] = v.second;
3349 vector<int> perm, dest;
3350 emi_select_merge_destinations(key_vec, dsize,
sizeof(K) +
sizeof(intersection_tags), dest, comm,
3351 "assign_counter_tags",
3354 commgraph<size_t> grph;
3355 grph.configure(dest, comm);
3356 size_t nrecv =
sum(grph.rcnt);
3362 vector<K> sbuff_key(dsize), rbuff_key(nrecv);
3363 vector<intersection_tags> sbuff_value(dsize), ibuff_value(dsize), rbuff_value(nrecv);
3364 for (
size_t i = 0; i < dsize; i++) {
3365 sbuff_key[i] = key_vec[perm[i]];
3366 sbuff_value[i] = value_vec[perm[i]];
3372 for (
size_t i = 0; i < nrecv; i++)
3374 auto it = rmap.
find(rbuff_key[i]);
3375 if (it != rmap.
end())
3377 intersection_tags& map_tags = it->second;
3378 intersection_tags& r_tags = rbuff_value[i];
3380 for (
int r_tag : r_tags.tags)
3382 if (r_tag == -1)
continue;
3384 for (
int m_tag : map_tags.tags)
3386 if (m_tag == r_tag) {
3393 for (
size_t k = 0; k < MAX_INTERSECTIONS; ++k) {
3394 if (map_tags.tags[k] == -1) {
3395 map_tags.tags[k] = r_tag;
3404 rmap.
insert({ rbuff_key[i], rbuff_value[i] });
3408 for (
size_t i = 0; i < nrecv; i++) {
3409 auto it = rmap.
find(rbuff_key[i]);
3410 if (it != rmap.
end()) rbuff_value[i] = it->second;
3417 for (
size_t i = 0; i < dsize; i++) {
3418 auto it = map.find(sbuff_key[i]);
3419 if (it != map.end()) it->second = ibuff_value[i];
3444 template<
class T,
class S>
inline
3445 void compute_ptsdata_from_original_mesh(meshdata<T,S> & mesh,
3451 MPI_Comm comm = mesh.comm;
3453 MPI_Comm_size(comm, &size);
3454 MPI_Comm_rank(comm, &rank);
3456 const T* con = mesh.con.data();
3463 for(
size_t eidx = 0; eidx < mesh.l_numelem; eidx++)
3465 T tag = mesh.tag[eidx];
3466 for (
int n = mesh.dsp[eidx]; n < mesh.dsp[eidx+1];n++)
3468 T gIndex = rnod[con[n]];
3470 auto it_new = map_index_to_tags.
find(gIndex);
3471 if (it_new != map_index_to_tags.
end())
3474 intersection_tags& tags = it_new->second;
3476 for(T t : tags.tags) {
3484 for(
int i=0; i <MAX_INTERSECTIONS; ++i) {
3485 if (tags.tags[i] == -1) {
3494 intersection_tags tags;
3496 map_index_to_tags.
insert({gIndex,tags});
3504 assign_counter_tags(map_index_to_tags, comm);
3507 for(
size_t eidx = 0; eidx < mesh.l_numelem; eidx++)
3509 for (
int n = mesh.dsp[eidx]; n < mesh.dsp[eidx+1];n++)
3511 T gIndex = rnod[con[n]];
3512 intersection_tags& vec_tags = map_index_to_tags[gIndex];
3513 int count_intra_tags = 0;
3514 int count_extra_tags = 0;
3518 for(T t : vec_tags.tags) {
3519 if(intra_tags.
count(t)) count_intra_tags++;
3520 if(extra_tags.
count(t)) count_extra_tags++;
3524 if(count_extra_tags>=1 && count_intra_tags==0){
3525 vertex2ptsdata[gIndex] = 0;
3526 }
else if(count_extra_tags==0 && count_intra_tags==1){
3527 vertex2ptsdata[gIndex] = 0;
3528 }
else if(count_extra_tags>=1 && count_intra_tags==1){
3529 vertex2ptsdata[gIndex] = 1;
3530 }
else if(count_extra_tags==0 && count_intra_tags==2){
3531 vertex2ptsdata[gIndex] = 2;
3532 }
else if(count_extra_tags>=1 && count_intra_tags==2){
3533 vertex2ptsdata[gIndex] = 3;
3535 else if(count_intra_tags>2){
3537 fprintf(stderr,
"More than two intracellular are connected %d. Tags:", gIndex);
3538 for(T tag : vec_tags.tags)
if(tag != -1) fprintf(stderr,
" %d", tag);
3539 fprintf(stderr,
"\n");
3544 fprintf(stderr,
"WARN: unhandled case in ptsData computation for gIndex %d. Tags:", gIndex);
3545 for(T tag : vec_tags.tags)
if(tag != -1) fprintf(stderr,
" %d", tag);
3546 fprintf(stderr,
"\n");
3569 template <
class T,
class S,
class V,
class emi_index_rank>
3572 std::pair<emi_index_rank, emi_index_rank>>& map,
3579 MPI_Comm_rank(both_mesh.
comm, &rank);
3582 SF::layout_from_count<long int>(both_mesh.
l_numelem, layout_both, both_mesh.
comm);
3585 SF::layout_from_count<long int>(unique_mesh.
l_numelem, layout_unique, unique_mesh.
comm);
3591 for (
const auto& [local_unique_idx, both_pair] : map) {
3592 const auto& first_both = both_pair.first;
3593 const auto& second_both = both_pair.second;
3597 T global_unique_row = layout_unique[rank] + local_unique_idx;
3598 row_idx[0] = global_unique_row;
3601 bool first_valid = (first_both.index >= 0 && first_both.rank >= 0);
3602 bool second_valid = (second_both.index >= 0 && second_both.rank >= 0);
3604 T global_both_col_first = -1;
3605 T global_both_col_second = -1;
3607 global_both_col_first = layout_both[first_both.rank] + first_both.index;
3610 global_both_col_second = layout_both[second_both.rank] + second_both.index;
3615 if (first_valid && second_valid && global_both_col_first == global_both_col_second) {
3616 second_valid =
false;
3621 if (first_valid)
count++;
3622 if (second_valid)
count++;
3624 if (
count == 0)
continue;
3628 double weight = 0.5;
3629 if (
count == 1) weight = 1.0;
3631 ebuff.assign(1, 1, weight);
3635 col_idx[0] = global_both_col_first;
3636 op.
set_values(row_idx, col_idx, ebuff.data(),
false);
3641 col_idx[0] = global_both_col_second;
3642 op.
set_values(row_idx, col_idx, ebuff.data(),
false);
3671 for(
size_t i=0; i<rnod.
size(); i++){
3678 for(
size_t i=0; i<v.size(); i++){
3681 if (dof2ptsData[g] > 0) {
#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)