52 Point edge1 = p2 - p1;
53 Point edge2 = p3 - p1;
59 double crossProductMagnitude =
mag(crossProduct);
61 return 0.5 * crossProductMagnitude;
74 inline void compute_barycentric_coordinates_coefficients(
const SF::Point& p1,
const SF::Point& p2,
const SF::Point& P, vector<double>& interpolationCoefficients,
double & lengthSquared)
80 double lambda2 =
inner_prod(v, d) / lengthSquared;
81 double lambda1 = 1.0 - lambda2;
83 interpolationCoefficients[0] = lambda1;
84 interpolationCoefficients[1] = lambda2;
98 inline void compute_barycentric_coordinates_coefficients(
const SF::Point& p1,
const SF::Point& p2,
const SF::Point& p3,
const SF::Point& P, vector<double>& interpolationCoefficients,
double & area)
101 area = computeTriangleArea(p1, p2, p3);
116 double denom = d00 * d11 - d01 * d01;
117 double beta = (d11 * d20 - d01 * d21) / denom;
118 double gamma = (d00 * d21 - d01 * d20) / denom;
119 double alpha = 1.0 - beta - gamma;
120 interpolationCoefficients[0] = alpha;
121 interpolationCoefficients[1] = beta;
122 interpolationCoefficients[2] = gamma;
141 double area1 = computeTriangleArea(p1, p2, p4);
142 double area2 = computeTriangleArea(p2, p3, p4);
143 area = area1 + area2;
160 interpolationCoefficients[0] = (1 - u) * (1 - v);
161 interpolationCoefficients[1] = u * (1 - v);
162 interpolationCoefficients[2] = u * v;
163 interpolationCoefficients[3] = (1 - u) * v;
177 inline void compute_integrate_matrix_barycentric(vector<SF::Point> face_coordinates,
SF_int nnodes, dmat<SF_real> & ebuff, dmat<SF_real> & ebuff_s, dmat<SF_real> & ebuff_counter, S mass_scale)
183 for (
int i = 0; i < nnodes; ++i)
185 x += face_coordinates[i].x;
186 y += face_coordinates[i].y;
187 z += face_coordinates[i].z;
189 SF::Point b; b.
x = x/nnodes; b.
y = y/nnodes; b.
z = z/nnodes;
191 vector<double> interpolationCoefficients(nnodes);
192 double area, weighted_area;
194 compute_barycentric_coordinates_coefficients(face_coordinates[0], face_coordinates[1], b, interpolationCoefficients, area);
198 compute_barycentric_coordinates_coefficients(face_coordinates[0], face_coordinates[1], face_coordinates[2], b, interpolationCoefficients, area);
201 compute_barycentric_coordinates_coefficients(face_coordinates[0], face_coordinates[1], face_coordinates[2], face_coordinates[3], b, interpolationCoefficients, area);
204 weighted_area = area/nnodes;
207 ebuff[0][0] = interpolationCoefficients[0];
208 ebuff[0][1] = interpolationCoefficients[1];
210 ebuff_counter[0][0] = interpolationCoefficients[0];
211 ebuff_counter[0][1] = interpolationCoefficients[1];
213 ebuff_s[0][0] = mass_scale*weighted_area;
214 ebuff_s[0][1] = mass_scale*weighted_area;
217 ebuff[0][0] = interpolationCoefficients[0];
218 ebuff[0][1] = interpolationCoefficients[1];
219 ebuff[0][2] = interpolationCoefficients[2];
221 ebuff_counter[0][0] = interpolationCoefficients[0];
222 ebuff_counter[0][1] = interpolationCoefficients[1];
223 ebuff_counter[0][2] = interpolationCoefficients[2];
225 ebuff_s[0][0] = mass_scale*weighted_area;
226 ebuff_s[0][1] = mass_scale*weighted_area;
227 ebuff_s[0][2] = mass_scale*weighted_area;
230 ebuff[0][0] = interpolationCoefficients[0];
231 ebuff[0][1] = interpolationCoefficients[1];
232 ebuff[0][2] = interpolationCoefficients[2];
233 ebuff[0][3] = interpolationCoefficients[3];
235 ebuff_counter[0][0] = interpolationCoefficients[0];
236 ebuff_counter[0][1] = interpolationCoefficients[1];
237 ebuff_counter[0][2] = interpolationCoefficients[2];
238 ebuff_counter[0][3] = interpolationCoefficients[3];
240 ebuff_s[0][0] = mass_scale*weighted_area;
241 ebuff_s[0][1] = mass_scale*weighted_area;
242 ebuff_s[0][2] = mass_scale*weighted_area;
243 ebuff_s[0][3] = mass_scale*weighted_area;
279 template<
class T,
class S,
class emi_index_rank>
280 inline void construct_direct_unique_both_operators(
288 int max_row_entries_emi,
293 T M = emi_surfmesh_w_counter_face.
g_numelem;
294 T m = emi_surfmesh_w_counter_face.
l_numelem;
295 T M_unique_face = emi_surfmesh_unique_face.
g_numelem;
296 T m_unique_face = emi_surfmesh_unique_face.
l_numelem;
300 MPI_Comm_rank(emi_surfmesh_w_counter_face.
comm, &rank);
301 MPI_Comm_size(emi_surfmesh_w_counter_face.
comm, &comm_size);
304 SF::layout_from_count<long int>(emi_surfmesh_w_counter_face.
l_numelem, layout, emi_surfmesh_w_counter_face.
comm);
305 T m_l = layout[rank];
308 SF::layout_from_count<long int>(emi_surfmesh_unique_face.
l_numelem, layout_unique_face, emi_surfmesh_unique_face.
comm);
309 T m_unique_face_l = layout_unique_face[rank];
312 map_elem_uniqueFace_to_elem_bothface.clear();
316 std::vector<int> both_counts(comm_size, 0), both_displs(comm_size, 0);
317 int local_both_count =
static_cast<int>(vec_both_to_one_face.
size());
318 MPI_Allgather(&local_both_count, 1, MPI_INT, both_counts.data(), 1, MPI_INT,
319 emi_surfmesh_w_counter_face.
comm);
321 int total_both_count = 0;
322 for (
int i = 0; i < comm_size; i++) {
323 both_displs[i] = total_both_count;
324 total_both_count += both_counts[i];
327 std::vector<mesh_int_t> all_both_to_one(total_both_count);
330 std::vector<int> both_byte_counts(comm_size, 0), both_byte_displs(comm_size, 0);
331 for (
int i = 0; i < comm_size; i++) {
332 both_byte_counts[i] = both_counts[i] *
static_cast<int>(
sizeof(
mesh_int_t));
333 both_byte_displs[i] = both_displs[i] *
static_cast<int>(
sizeof(
mesh_int_t));
335 const int local_both_bytes = local_both_count *
static_cast<int>(
sizeof(
mesh_int_t));
336 MPI_Allgatherv(
reinterpret_cast<const unsigned char*
>(vec_both_to_one_face.
data()),
337 local_both_bytes, MPI_BYTE,
338 reinterpret_cast<unsigned char*
>(all_both_to_one.data()),
339 both_byte_counts.data(), both_byte_displs.data(), MPI_BYTE,
340 emi_surfmesh_w_counter_face.
comm);
344 std::vector<std::vector<mesh_int_t>> one_to_both_first(comm_size);
345 std::vector<std::vector<mesh_int_t>> one_to_both_second(comm_size);
346 for (
int r = 0; r < comm_size; r++) {
348 for (
int i = 0; i < both_counts[r]; i++) {
349 mesh_int_t one_idx = all_both_to_one[both_displs[r] + i];
350 if (one_idx > max_one) max_one = one_idx;
352 if (max_one < 0)
continue;
354 one_to_both_first[r].assign(max_one + 1, -1);
355 one_to_both_second[r].assign(max_one + 1, -1);
356 for (
int i = 0; i < both_counts[r]; i++) {
357 mesh_int_t one_idx = all_both_to_one[both_displs[r] + i];
358 if (one_idx < 0)
continue;
359 if (one_to_both_first[r][one_idx] < 0) one_to_both_first[r][one_idx] = i;
360 else one_to_both_second[r][one_idx] = i;
365 for (
const auto& [unique_idx, one_face_pair] : map_elem_uniqueFace_to_elem_oneface) {
366 const auto& first_oneface = one_face_pair.first;
367 const auto& second_oneface = one_face_pair.second;
369 auto map_one_to_both = [&](
const emi_index_rank& one_face_idx,
bool use_second) {
370 emi_index_rank both_face_idx;
371 both_face_idx.index = -1;
372 both_face_idx.rank = -1;
374 if (one_face_idx.rank < 0 || one_face_idx.rank >= comm_size || one_face_idx.index < 0) {
375 return both_face_idx;
377 if (one_face_idx.index >=
static_cast<int>(one_to_both_first[one_face_idx.rank].size())) {
378 return both_face_idx;
381 mesh_int_t both_idx = one_to_both_first[one_face_idx.rank][one_face_idx.index];
383 one_face_idx.index <
static_cast<int>(one_to_both_second[one_face_idx.rank].size()) &&
384 one_to_both_second[one_face_idx.rank][one_face_idx.index] >= 0) {
385 both_idx = one_to_both_second[one_face_idx.rank][one_face_idx.index];
389 both_face_idx.index = both_idx;
390 both_face_idx.rank = one_face_idx.rank;
392 return both_face_idx;
395 const bool same_oneface =
396 (first_oneface.index >= 0 && second_oneface.index >= 0 &&
397 first_oneface.index == second_oneface.index &&
398 first_oneface.rank == second_oneface.rank);
400 map_elem_uniqueFace_to_elem_bothface[unique_idx] = std::make_pair(
401 map_one_to_both(first_oneface,
false),
402 map_one_to_both(second_oneface, same_oneface));
408 operator_unique_to_both_faces->
init(M, M_unique_face, m, m_unique_face, m_l, max_row_entries_emi*10);
409 operator_unique_to_both_faces->
zero();
413 const int M_unique_global =
static_cast<int>(emi_surfmesh_unique_face.
g_numelem);
414 std::vector<int> first_rank(M_unique_global, -1), first_idx(M_unique_global, -1);
415 std::vector<int> second_rank(M_unique_global, -1), second_idx(M_unique_global, -1);
417 for (
const auto& [local_unique_idx, both_pair] : map_elem_uniqueFace_to_elem_bothface) {
418 int global_unique =
static_cast<int>(layout_unique_face[rank] + local_unique_idx);
419 if (global_unique < 0 || global_unique >= M_unique_global)
continue;
421 first_rank[global_unique] =
static_cast<int>(both_pair.first.rank);
422 first_idx[global_unique] =
static_cast<int>(both_pair.first.index);
423 second_rank[global_unique] =
static_cast<int>(both_pair.second.rank);
424 second_idx[global_unique] =
static_cast<int>(both_pair.second.index);
427 MPI_Allreduce(MPI_IN_PLACE, first_rank.data(), M_unique_global, MPI_INT, MPI_MAX, emi_surfmesh_w_counter_face.
comm);
428 MPI_Allreduce(MPI_IN_PLACE, first_idx.data(), M_unique_global, MPI_INT, MPI_MAX, emi_surfmesh_w_counter_face.
comm);
429 MPI_Allreduce(MPI_IN_PLACE, second_rank.data(), M_unique_global, MPI_INT, MPI_MAX, emi_surfmesh_w_counter_face.
comm);
430 MPI_Allreduce(MPI_IN_PLACE, second_idx.data(), M_unique_global, MPI_INT, MPI_MAX, emi_surfmesh_w_counter_face.
comm);
434 ebuff.assign(1, 1, 1.0);
436 for (
int gid = 0; gid < M_unique_global; gid++) {
438 if (first_rank[gid] == rank && first_idx[gid] >= 0) {
439 row_idx[0] =
static_cast<SF_int>(layout[rank] + first_idx[gid]);
440 operator_unique_to_both_faces->
set_values(row_idx, col_idx, ebuff.data(),
false);
442 if (second_rank[gid] == rank && second_idx[gid] >= 0) {
443 row_idx[0] =
static_cast<SF_int>(layout[rank] + second_idx[gid]);
444 operator_unique_to_both_faces->
set_values(row_idx, col_idx, ebuff.data(),
false);
452 operator_both_to_unique_face->
init(M_unique_face, M, m_unique_face, m, m_unique_face_l, max_row_entries_emi*10);
453 operator_both_to_unique_face->
zero();
454 assemble_map_both_to_unique(*operator_both_to_unique_face,
455 map_elem_uniqueFace_to_elem_bothface,
456 emi_surfmesh_unique_face,
457 emi_surfmesh_w_counter_face);
459 #ifdef EMI_DEBUG_MESH
463 mesh_int_t local_valid_first = 0, local_valid_second = 0;
466 SF::layout_from_count<long int>(emi_surfmesh_w_counter_face.
l_numelem, layout_both_dbg, emi_surfmesh_w_counter_face.
comm);
468 SF::layout_from_count<long int>(emi_surfmesh_unique_face.
l_numelem, layout_unique_dbg, emi_surfmesh_unique_face.
comm);
470 for (
const auto& [uidx, both_pair] : map_elem_uniqueFace_to_elem_bothface) {
471 if (both_pair.first.index >= 0) local_valid_first++;
472 if (both_pair.second.index >= 0) local_valid_second++;
474 if (both_pair.first.index >= 0 && both_pair.second.index >= 0 &&
475 both_pair.first.rank >= 0 && both_pair.second.rank >= 0) {
476 mesh_int_t global_first = layout_both_dbg[both_pair.first.rank] + both_pair.first.index;
477 mesh_int_t global_second = layout_both_dbg[both_pair.second.rank] + both_pair.second.index;
478 if (global_first == global_second) local_same_column++;
481 mesh_int_t global_valid_first = 0, global_valid_second = 0;
483 unsigned long long local_valid_first_ull =
static_cast<unsigned long long>(local_valid_first);
484 unsigned long long local_valid_second_ull =
static_cast<unsigned long long>(local_valid_second);
485 unsigned long long local_same_column_ull =
static_cast<unsigned long long>(local_same_column);
486 unsigned long long global_valid_first_ull = 0;
487 unsigned long long global_valid_second_ull = 0;
488 unsigned long long global_same_column_ull = 0;
489 MPI_Allreduce(&local_valid_first_ull, &global_valid_first_ull, 1, MPI_UNSIGNED_LONG_LONG, MPI_SUM, emi_surfmesh_w_counter_face.
comm);
490 MPI_Allreduce(&local_valid_second_ull, &global_valid_second_ull, 1, MPI_UNSIGNED_LONG_LONG, MPI_SUM, emi_surfmesh_w_counter_face.
comm);
491 MPI_Allreduce(&local_same_column_ull, &global_same_column_ull, 1, MPI_UNSIGNED_LONG_LONG, MPI_SUM, emi_surfmesh_w_counter_face.
comm);
492 global_valid_first =
static_cast<mesh_int_t>(global_valid_first_ull);
493 global_valid_second =
static_cast<mesh_int_t>(global_valid_second_ull);
494 global_same_column =
static_cast<mesh_int_t>(global_same_column_ull);
497 MPI_Comm_rank(emi_surfmesh_w_counter_face.
comm, &dbg_rank);
499 log_msg(NULL, 0, 0,
"DEBUG map_unique_to_both: valid_first=%d valid_second=%d (global M=%zu, M_unique=%zu)",
500 (
int)global_valid_first, (
int)global_valid_second,
501 (
size_t)emi_surfmesh_w_counter_face.
g_numelem,
502 (
size_t)emi_surfmesh_unique_face.
g_numelem);
503 log_msg(NULL, 0, 0,
"DEBUG map_unique_to_both: same_column=%d", (
int)global_same_column);
507 std::vector<char> present(emi_surfmesh_unique_face.
l_numelem, 0);
508 for (
const auto& [uidx, both_pair] : map_elem_uniqueFace_to_elem_bothface) {
509 if (uidx >= 0 && uidx < (
mesh_int_t)present.size()) present[uidx] = 1;
511 std::vector<int> missing;
513 if (!present[i]) missing.push_back((
int)i);
515 int local_missing = (int)missing.size();
516 int comm_size_dbg = 0;
517 MPI_Comm_size(emi_surfmesh_w_counter_face.
comm, &comm_size_dbg);
518 std::vector<int> counts(comm_size_dbg, 0), displs(comm_size_dbg, 0);
519 MPI_Gather(&local_missing, 1, MPI_INT,
520 dbg_rank == 0 ? counts.data() :
nullptr, 1, MPI_INT,
521 0, emi_surfmesh_w_counter_face.
comm);
524 for (
int r = 0; r < comm_size_dbg; r++) {
528 std::vector<int> all_missing(total, -1);
529 MPI_Gatherv(missing.data(), local_missing, MPI_INT,
530 all_missing.data(), counts.data(), displs.data(), MPI_INT,
531 0, emi_surfmesh_w_counter_face.
comm);
534 for (
int r = 0; r < comm_size_dbg; r++) {
535 if (counts[r] == 0) {
540 log_msg(NULL, 0, 0,
"DEBUG unique missing: rank=%d count=%d", r, counts[r]);
541 int to_print = counts[r] < 10 ? counts[r] : 10;
542 for (
int i = 0; i < to_print; i++) {
543 log_msg(NULL, 0, 0,
"DEBUG unique missing: rank=%d local_unique=%d", r, all_missing[offset + i]);
547 if (!any)
log_msg(NULL, 0, 0,
"DEBUG unique missing: none");
549 MPI_Gatherv(missing.data(), local_missing, MPI_INT,
550 nullptr,
nullptr,
nullptr, MPI_INT,
551 0, emi_surfmesh_w_counter_face.
comm);
558 SF::init_vector(&dbg_unique, emi_surfmesh_unique_face, dpn, alg_surface_type);
559 SF::init_vector(&dbg_both, emi_surfmesh_w_counter_face, dpn, alg_surface_type);
560 SF::init_vector(&dbg_back, emi_surfmesh_unique_face, dpn, alg_surface_type);
561 dbg_unique->
set(1.0);
562 operator_unique_to_both_faces->
mult(*dbg_unique, *dbg_both);
563 operator_both_to_unique_face->
mult(*dbg_both, *dbg_back);
569 SF_real err = std::abs(p[i] - 1.0);
570 if (err > local_max_err) local_max_err = err;
571 if (std::abs(p[i] - 0.5) < 1e-12) local_half_count++;
576 MPI_Allreduce(&local_max_err, &global_max_err, 1, MPI_DOUBLE, MPI_MAX, emi_surfmesh_w_counter_face.
comm);
577 unsigned long long local_half_count_ull =
static_cast<unsigned long long>(local_half_count);
578 unsigned long long global_half_count_ull = 0;
579 MPI_Allreduce(&local_half_count_ull, &global_half_count_ull, 1, MPI_UNSIGNED_LONG_LONG, MPI_SUM, emi_surfmesh_w_counter_face.
comm);
580 global_half_count =
static_cast<mesh_int_t>(global_half_count_ull);
582 log_msg(NULL, 0, 0,
"DEBUG map_unique_to_both consistency: max_err=%.6e half_count=%d",
583 (
double)global_max_err, (
int)global_half_count);
587 const int max_print = 5;
588 const int fields = 9;
589 std::vector<int> local_buf(max_print * fields, -1);
592 for (
const auto& [local_unique_idx, both_pair] : map_elem_uniqueFace_to_elem_bothface) {
593 if (filled >= max_print)
break;
594 const auto& first_both = both_pair.first;
595 const auto& second_both = both_pair.second;
597 const bool first_valid = (first_both.index >= 0 && first_both.rank >= 0);
598 const bool second_valid = (second_both.index >= 0 && second_both.rank >= 0);
599 int count = (first_valid ? 1 : 0) + (second_valid ? 1 : 0);
600 if (
count != 1)
continue;
602 mesh_int_t global_unique = layout_unique_dbg[dbg_rank] + local_unique_idx;
603 mesh_int_t global_first = first_valid ? (layout_both_dbg[first_both.rank] + first_both.index) : -1;
604 mesh_int_t global_second = second_valid ? (layout_both_dbg[second_both.rank] + second_both.index) : -1;
606 int base = filled * fields;
607 local_buf[base + 0] = dbg_rank;
608 local_buf[base + 1] = (int)local_unique_idx;
609 local_buf[base + 2] = (int)global_unique;
610 local_buf[base + 3] = (int)first_both.rank;
611 local_buf[base + 4] = (
int)first_both.index;
612 local_buf[base + 5] = (int)global_first;
613 local_buf[base + 6] = (int)second_both.rank;
614 local_buf[base + 7] = (
int)second_both.index;
615 local_buf[base + 8] = (int)global_second;
620 MPI_Comm_size(emi_surfmesh_w_counter_face.
comm, &comm_size);
621 std::vector<int> all_buf;
622 if (dbg_rank == 0) all_buf.resize(comm_size * max_print * fields, -1);
624 MPI_Gather(local_buf.data(), max_print * fields, MPI_INT,
625 dbg_rank == 0 ? all_buf.data() :
nullptr, max_print * fields, MPI_INT,
626 0, emi_surfmesh_w_counter_face.
comm);
629 for (
int r = 0; r < comm_size; r++) {
630 for (
int i = 0; i < max_print; i++) {
631 int base = (r * max_print + i) * fields;
632 if (all_buf[base + 1] < 0)
continue;
634 "DEBUG map_unique_to_both bad: rank=%d local_unique=%d global_unique=%d "
635 "first(rank=%d idx=%d glob=%d) second(rank=%d idx=%d glob=%d)",
636 all_buf[base + 0], all_buf[base + 1], all_buf[base + 2],
637 all_buf[base + 3], all_buf[base + 4], all_buf[base + 5],
638 all_buf[base + 6], all_buf[base + 7], all_buf[base + 8]);
697 template<
class tuple_key,
class tuple_value,
class tri_key,
class tri_value,
class quad_key,
class quad_value,
class T,
class S>
698 inline void assemble_restrict_operator( abstract_matrix<T,S> & B,
699 abstract_matrix<T,S> & Bi,
700 abstract_matrix<T,S> & BsM,
703 std::pair<mesh_int_t,mesh_int_t>> map_vertex_tag_to_dof_petsc,
705 std::pair<tuple_value, tuple_value>> line_face,
707 std::pair<tri_value, tri_value>> tri_face,
709 std::pair<quad_value, quad_value>> quad_face,
710 const meshdata<mesh_int_t,mesh_real_t> & surface_mesh,
711 const meshdata<mesh_int_t,mesh_real_t> & emi_mesh,
715 T row_dpn = 1; T col_dpn = 1;
717 const vector<SF_int> & petsc_nbr = emi_mesh.get_numbering(
NBR_PETSC);
721 for(
size_t i=0; i<rnod_emi.
size(); i++){
722 g2l_emi[rnod_emi[i]] = i;
723 l2g_emi[i] = rnod_emi[i];
731 for(
size_t i=0; i<rnod.
size(); i++){
746 const T* con_emi = emi_mesh.con.data();
747 const T* con = surface_mesh.con.data();
750 for(
size_t eidx=0; eidx < surface_mesh.l_numelem; eidx++)
752 T tag = surface_mesh.tag[eidx];
755 std::vector<int> elem_nodes;
756 std::vector<int> elem_nodes_old;
757 std::vector<int> petsc_first;
758 std::vector<int> petsc_second;
771 for (
int n = surface_mesh.dsp[eidx]; n < surface_mesh.dsp[eidx+1];n++)
773 T l_idx = surface_mesh.con[n];
775 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
776 Index_tag_old = std::make_pair(l2g[l_idx],tag);
777 mesh_int_t Index_new = map_vertex_tag_to_dof_petsc[Index_tag_old].first;
778 elem_nodes.push_back(Index_new);
779 elem_nodes_old.push_back(l2g[l_idx]);
782 std::sort(elem_nodes.begin(),elem_nodes.end());
783 if(elem_nodes.size()==2){
786 key.v1 = elem_nodes[0];
787 key.v2 = elem_nodes[1];
788 std::pair<tuple_value, tuple_value> value = line_face[key];
790 tag_first = value.first.tag;
791 tag_second = value.second.tag;
793 rank_first = value.first.rank;
794 rank_second = value.second.rank;
796 mem_first = value.first.mem;
797 mem_second = value.second.mem;
799 else if(elem_nodes.size()==3){
801 key.v1 = elem_nodes[0];
802 key.v2 = elem_nodes[1];
803 key.v3 = elem_nodes[2];
804 std::pair<tri_value, tri_value> value = tri_face[key];
806 tag_first = value.first.tag;
807 tag_second = value.second.tag;
809 rank_first = value.first.rank;
810 rank_second = value.second.rank;
812 mem_first = value.first.mem;
813 mem_second = value.second.mem;
815 else if(elem_nodes.size()==4){
817 key.v1 = elem_nodes[0];
818 key.v2 = elem_nodes[1];
819 key.v3 = elem_nodes[2];
820 key.v4 = elem_nodes[3];
821 std::pair<quad_value, quad_value> value = quad_face[key];
823 tag_first = value.first.tag;
824 tag_second = value.second.tag;
826 rank_first = value.first.rank;
827 rank_second = value.second.rank;
829 mem_first = value.first.mem;
830 mem_second = value.second.mem;
833 if(tag != tag_first) std::swap(tag_first, tag_second);
835 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
837 for (
int indx = 0; indx < elem_nodes_old.size(); ++indx)
839 std::pair <mesh_int_t,mesh_int_t> Index_tag_old_first;
840 Index_tag_old_first = std::make_pair(elem_nodes_old[indx],tag_first);
842 auto it_first = map_vertex_tag_to_dof_petsc.find(Index_tag_old_first);
843 if (it_first == map_vertex_tag_to_dof_petsc.end()) {
844 std::cerr <<
"ERROR: tag_first=" << tag_first <<
" not found for vertex=" << elem_nodes_old[indx] << std::endl;
845 throw std::runtime_error(
"PETSc index not found for first tag");
847 std::pair <mesh_int_t,mesh_int_t> newIndex_petsc_first = it_first->second;
848 mesh_int_t newIndex_first = newIndex_petsc_first.first;
849 petsc_first.push_back(newIndex_petsc_first.second);
851 std::pair <mesh_int_t,mesh_int_t> Index_tag_old_second;
852 Index_tag_old_second = std::make_pair(elem_nodes_old[indx],tag_second);
854 auto it_second = map_vertex_tag_to_dof_petsc.find(Index_tag_old_second);
855 if (it_second == map_vertex_tag_to_dof_petsc.end()) {
856 std::cerr <<
"ERROR: tag_second=" << tag_second <<
" not found for vertex=" << elem_nodes_old[indx] << std::endl;
857 throw std::runtime_error(
"PETSc index not found for counter-face tag");
859 std::pair <mesh_int_t,mesh_int_t> newIndex_petsc_second = it_second->second;
860 mesh_int_t newIndex_second = newIndex_petsc_second.first;
861 petsc_second.push_back(newIndex_petsc_second.second);
864 if(mem_first==1 and elemTag_surface_mesh[eidx]==1)
866 else if (mem_first==2 and tag<tag_second)
870 SF_int nnodes = elem_nodes.size();
871 vector<SF::Point> face_coordinates(nnodes);
873 row_idx.resize(nnodes*row_dpn);
874 row_idx_counter.resize(nnodes*row_dpn);
875 col_idx.resize(nnodes*col_dpn);
876 col_idx_counter.resize(nnodes*col_dpn);
879 for(
SF_int i=0; i<nnodes; i++){
881 for(
short j=0; j<row_dpn; j++){
882 row_idx.data()[i*row_dpn + j] = emi_surfmesh_elem[eidx]*row_dpn;
885 for(
short j=0; j<col_dpn; j++){
886 col_idx[i*col_dpn + j] = (petsc_first[i])*col_dpn + j;
887 col_idx_counter[i*col_dpn + j] = (petsc_second[i])*col_dpn + j;
893 ebuff.
assign(nnodes, nnodes, 0.0);
894 ebuff_s.assign(nnodes, nnodes, 0.0);
896 ebuff_counter.assign(nnodes, nnodes, 0.0);
898 for (
int n = surface_mesh.dsp[eidx], i = 0; n < surface_mesh.dsp[eidx+1];n++,i++)
900 T l_idx = surface_mesh.con[n];
902 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
903 Index_tag_old = std::make_pair(l2g[l_idx],tag);
904 mesh_int_t Index_new = map_vertex_tag_to_dof_petsc[Index_tag_old].first;
906 double x = emi_mesh.xyz[g2l_emi[Index_new]*3+0];
907 double y = emi_mesh.xyz[g2l_emi[Index_new]*3+1];
908 double z = emi_mesh.xyz[g2l_emi[Index_new]*3+2];
910 face_coordinates[i].x = x;
911 face_coordinates[i].y = y;
912 face_coordinates[i].z = z;
914 compute_integrate_matrix_barycentric(face_coordinates, nnodes, ebuff, ebuff_s, ebuff_counter, mass_scale);
917 const bool add =
true;
920 Bi.set_values(row_idx, col_idx, ebuff.data(), add);
921 Bi.set_values(row_idx, col_idx_counter, ebuff_counter.data(), add);
924 B.set_values(row_idx, col_idx, ebuff.data(), add);
925 ebuff_counter*=(-
sign);
926 B.set_values(row_idx, col_idx_counter, ebuff_counter.data(), add);
930 BsM.set_values(col_idx, row_idx, ebuff_s.data(), add);
934 Bi.finish_assembly();
935 BsM.finish_assembly();
954 template<
class tuple_key,
class tuple_value,
class tri_key,
class tri_value,
class quad_key,
class quad_value,
class T,
class S>
955 inline void assemble_lhs_emi(abstract_matrix<T,S> & mat,
956 abstract_matrix<T,S> & mat_surf,
957 const meshdata<mesh_int_t,mesh_real_t> & emi_mesh,
958 const meshdata<mesh_int_t,mesh_real_t> & surface_mesh,
959 hashmap::unordered_map<std::pair<mesh_int_t,mesh_int_t>, std::pair<mesh_int_t,mesh_int_t>> map_vertex_tag_to_dof_petsc,
961 std::pair<tuple_value, tuple_value>> line_face,
963 std::pair<tri_value, tri_value>> tri_face,
965 std::pair<quad_value, quad_value>> quad_face,
966 matrix_integrator<mesh_int_t,mesh_real_t> & stiffness_integrator,
967 matrix_integrator<mesh_int_t, mesh_real_t> & mass_integrator,
972 T row_dpn = 1; T col_dpn = 1;
982 const vector<mesh_int_t> & stiffness_petsc_nbr = emi_mesh.get_numbering(
NBR_PETSC);
983 element_view<mesh_int_t, mesh_real_t> stiffness_view(emi_mesh,
NBR_PETSC);
986 for(
size_t eidx=0; eidx < emi_mesh.l_numelem; eidx++)
989 stiffness_view.set_elem(eidx);
992 mesh_int_t nnodes = stiffness_view.num_nodes();
994 row_idx.resize(nnodes*row_dpn);
995 col_idx.resize(nnodes*col_dpn);
996 canonic_indices<mesh_int_t,SF_int>(stiffness_view.nodes(), stiffness_petsc_nbr.data(), nnodes, row_dpn, row_idx.data());
997 canonic_indices<mesh_int_t,SF_int>(stiffness_view.nodes(), stiffness_petsc_nbr.data(), nnodes, col_dpn, col_idx.data());
1000 stiffness_integrator(stiffness_view, ebuff);
1001 ebuff *= stiffness_scale;
1004 const bool add =
true;
1005 mat.set_values(row_idx, col_idx, ebuff.data(), add);
1012 const vector<SF_int> & ref_nbr = surface_mesh.get_numbering(
SF::NBR_REF);
1013 const vector<SF_int> & petsc_nbr = surface_mesh.get_numbering(
SF::NBR_PETSC);
1018 for(
size_t i=0; i<rnod_emi.
size(); i++){
1019 g2l_emi[rnod_emi[i]] = i;
1020 l2g_emi[i] = rnod_emi[i];
1026 for(
size_t i=0; i<rnod.
size(); i++){
1032 element_view<mesh_int_t, mesh_real_t> view(surface_mesh,
NBR_PETSC);
1033 for(
size_t eidx=0; eidx < surface_mesh.l_numelem; eidx++)
1036 view.set_elem(eidx);
1040 std::vector<int> elem_nodes;
1041 std::vector<int> elem_nodes_old;
1042 std::vector<int> elem_nodes_first;
1043 std::vector<int> elem_nodes_second;
1045 std::vector<int> petsc_first;
1046 std::vector<int> petsc_second;
1051 for (
int n = surface_mesh.dsp[eidx]; n < surface_mesh.dsp[eidx+1];n++)
1053 T l_idx = surface_mesh.con[n];
1055 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1056 Index_tag_old = std::make_pair(l2g[l_idx],tag);
1057 mesh_int_t Index_new = map_vertex_tag_to_dof_petsc[Index_tag_old].first;
1058 elem_nodes.push_back(Index_new);
1059 elem_nodes_old.push_back(l2g[l_idx]);
1062 std::sort(elem_nodes.begin(),elem_nodes.end());
1063 if(elem_nodes.size()==2){
1066 key.v1 = elem_nodes[0];
1067 key.v2 = elem_nodes[1];
1068 std::pair<tuple_value, tuple_value> value = line_face[key];
1070 tag_first = value.first.tag;
1071 tag_second = value.second.tag;
1073 else if(elem_nodes.size()==3){
1075 key.v1 = elem_nodes[0];
1076 key.v2 = elem_nodes[1];
1077 key.v3 = elem_nodes[2];
1078 std::pair<tri_value, tri_value> value = tri_face[key];
1080 tag_first = value.first.tag;
1081 tag_second = value.second.tag;
1083 else if(elem_nodes.size()==4){
1085 key.v1 = elem_nodes[0];
1086 key.v2 = elem_nodes[1];
1087 key.v3 = elem_nodes[2];
1088 key.v4 = elem_nodes[3];
1089 std::pair<quad_value, quad_value> value = quad_face[key];
1091 tag_first = value.first.tag;
1092 tag_second = value.second.tag;
1095 if(tag != tag_first) std::swap(tag_first, tag_second);
1097 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1099 for (
int indx = 0; indx < elem_nodes_old.size(); ++indx)
1101 std::pair <mesh_int_t,mesh_int_t> Index_tag_old_first;
1102 Index_tag_old_first = std::make_pair(elem_nodes_old[indx],tag_first);
1103 std::pair <mesh_int_t,mesh_int_t> newIndex_petsc_first = map_vertex_tag_to_dof_petsc[Index_tag_old_first];
1104 mesh_int_t newIndex_first = newIndex_petsc_first.first;
1105 petsc_first.push_back(newIndex_petsc_first.second);
1107 std::pair <mesh_int_t,mesh_int_t> Index_tag_old_second;
1108 Index_tag_old_second = std::make_pair(elem_nodes_old[indx],tag_second);
1109 std::pair <mesh_int_t,mesh_int_t> newIndex_petsc_second = map_vertex_tag_to_dof_petsc[Index_tag_old_second];
1110 mesh_int_t newIndex_second = newIndex_petsc_second.first;
1111 petsc_second.push_back(newIndex_petsc_second.second);
1115 SF_int nnodes = view.num_nodes();
1116 idx.resize(nnodes*row_dpn);
1117 idx_counter.resize(nnodes*col_dpn);
1120 for(T i=0; i<nnodes; i++)
1122 for(
short j=0; j<row_dpn; j++){
1123 idx[i*row_dpn + j] = (petsc_first[i])*row_dpn + j;
1125 for(
short j=0; j<col_dpn; j++){
1126 idx_counter[i*col_dpn + j] = (petsc_second[i])*col_dpn + j;
1132 const bool add =
true;
1135 mass_integrator(view, ebuff);
1136 ebuff_mass.assign(nnodes, nnodes, 0.0);
1140 ebuff*=0.5 * mass_scale;
1143 mat.set_values(idx, idx, ebuff.data(), add);
1144 mat.set_values(idx_counter, idx_counter, ebuff.data(), add);
1146 mat_surf.set_values(idx, idx, ebuff_mass.data(), add);
1147 mat_surf.set_values(idx_counter, idx_counter, ebuff_mass.data(), add);
1152 mat.set_values(idx, idx_counter, ebuff.data(), add);
1153 mat.set_values(idx_counter, idx, ebuff.data(), add);
1155 mat_surf.set_values(idx, idx_counter, ebuff_mass.data(), add);
1156 mat_surf.set_values(idx_counter, idx, ebuff_mass.data(), add);
1168 mat.finish_assembly();
1169 mat_surf.finish_assembly();
1189 template<
class tuple_key,
class tuple_value,
class tri_key,
class tri_value,
class quad_key,
class quad_value,
class T,
class S>
1190 inline void assign_resting_potential_from_ionic_models_on_myocyte(abstract_matrix<T,S> & Vm_emi,
1191 abstract_vector<T, S>* vb,
1194 std::pair<T,T>> map_vertex_tag_to_dof_petsc,
1196 std::pair<tuple_value, tuple_value>> line_face,
1198 std::pair<tri_value, tri_value>> tri_face,
1200 std::pair<quad_value, quad_value>> quad_face,
1201 const meshdata<T,mesh_real_t> & surface_mesh,
1202 const meshdata<T,mesh_real_t> & emi_mesh)
1205 T row_dpn = 1; T col_dpn = 1;
1207 const vector<SF_int> & petsc_nbr = emi_mesh.get_numbering(
NBR_PETSC);
1211 for(
size_t i=0; i<rnod_emi.
size(); i++){
1212 g2l_emi[rnod_emi[i]] = i;
1213 l2g_emi[i] = rnod_emi[i];
1217 const vector<SF_int> & petsc_nbr_surface = surface_mesh.get_numbering(
NBR_PETSC);
1224 for(
size_t i=0; i<rnod.
size(); i++){
1228 auto vb_data = vb->const_ptr();
1231 for(
size_t eidx=0; eidx < surface_mesh.l_numelem; eidx++)
1233 T tag = surface_mesh.tag[eidx];
1236 std::vector<int> elem_nodes;
1245 for (
int n = surface_mesh.dsp[eidx], i = 0; n < surface_mesh.dsp[eidx+1];n++,i++)
1247 T l_idx = surface_mesh.con[n];
1248 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1249 Index_tag_old = std::make_pair(l2g[l_idx],tag);
1250 mesh_int_t Index_new = map_vertex_tag_to_dof_petsc[Index_tag_old].first;
1251 elem_nodes.push_back(Index_new);
1254 std::sort(elem_nodes.begin(),elem_nodes.end());
1255 if(elem_nodes.size()==2){
1258 key.v1 = elem_nodes[0];
1259 key.v2 = elem_nodes[1];
1260 std::pair<tuple_value, tuple_value> value = line_face[key];
1262 tag_first = value.first.tag;
1263 tag_second = value.second.tag;
1265 mem_first = value.first.mem;
1266 mem_second = value.second.mem;
1268 else if(elem_nodes.size()==3){
1270 key.v1 = elem_nodes[0];
1271 key.v2 = elem_nodes[1];
1272 key.v3 = elem_nodes[2];
1273 std::pair<tri_value, tri_value> value = tri_face[key];
1275 tag_first = value.first.tag;
1276 tag_second = value.second.tag;
1278 mem_first = value.first.mem;
1279 mem_second = value.second.mem;
1281 else if(elem_nodes.size()==4){
1283 key.v1 = elem_nodes[0];
1284 key.v2 = elem_nodes[1];
1285 key.v3 = elem_nodes[2];
1286 key.v4 = elem_nodes[3];
1287 std::pair<quad_value, quad_value> value = quad_face[key];
1289 tag_first = value.first.tag;
1290 tag_second = value.second.tag;
1292 mem_first = value.first.mem;
1293 mem_second = value.second.mem;
1296 SF_int nnodes = elem_nodes.size();
1297 for (
int i = 0; i < nnodes; ++i)
1299 if(mem_first==1 || mem_second==1){
1300 tag_2_vm[tag_first] = vb_data[eidx];
1301 tag_2_vm[tag_second] = vb_data[eidx];
1306 vb->const_release_ptr(vb_data);
1321 const vector<mesh_int_t> & petsc_nbr = emi_mesh.get_numbering(
NBR_PETSC);
1324 element_view<mesh_int_t, mesh_real_t> view(emi_mesh,
NBR_PETSC);
1325 for(
size_t eidx=0; eidx < emi_mesh.l_numelem; eidx++)
1328 view.set_elem(eidx);
1329 T tag = emi_mesh.tag[eidx];
1333 row_idx.resize(nnodes*row_dpn);val_idx.resize(nnodes*row_dpn);
1334 col_idx.resize(nnodes*row_dpn);
1335 ebuff.assign(nnodes, nnodes, 0.0);
1336 canonic_indices<mesh_int_t,SF_int>(view.nodes(), petsc_nbr.data(), nnodes, row_dpn, row_idx.data());
1337 canonic_indices<mesh_int_t,SF_int>(view.nodes(), petsc_nbr.data(), nnodes, col_dpn, col_idx.data());
1339 for (
int i = 0; i < nnodes; ++i)
1343 if(elemTag_emi_mesh[eidx]==2){
1344 ebuff[i][i] = tag_2_vm[tag];
1347 Vm_emi.set_values(row_idx, col_idx, ebuff.data(),
false);
1349 Vm_emi.finish_assembly();
#define SF_MAX_ELEM_NODES
max #nodes defining an element
double SF_real
Use the general double as real type.
std::int32_t SF_int
Use the general std::int32_t as int type.
virtual void mult(const abstract_vector< T, S > &x, abstract_vector< T, S > &b) const =0
virtual void finish_assembly()=0
virtual void init(T iNRows, T iNCols, T ilrows, T ilcols, T loc_offset, T mxent)
virtual void set_values(const vector< T > &row_idx, const vector< T > &col_idx, const vector< S > &vals, bool add)=0
virtual void release_ptr(S *&p)=0
virtual T lsize() const =0
virtual void set(const vector< T > &idx, const vector< S > &vals, const bool additive=false, const bool local=false)=0
The mesh storage class. It contains both element and vertex data.
size_t l_numelem
local number of elements
size_t g_numelem
global number of elements
MPI_Comm comm
the parallel mesh is defined on a MPI world
size_t size() const
The current size of the vector.
void assign(InputIterator s, InputIterator e)
Assign a memory range.
T * data()
Pointer to the vector's start.
#define log_msg(F, L, O,...)
double mag(const Point &vect)
vector magnitude
double inner_prod(const Point &a, const Point &b)
void count(const vector< T > &data, vector< S > &cnt)
Count number of occurrences of indices.
void init_vector(SF::abstract_vector< T, S > **vec)
void init_matrix(SF::abstract_matrix< T, S > **mat)
Point cross(const Point &a, const Point &b)
cross product
V clamp(const V val, const W start, const W end)
Clamp a value into an interval [start, end].
@ NBR_PETSC
PETSc numbering of nodes.
@ 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).