27 #include <type_traits>
43 Point edge1 = p2 - p1;
44 Point edge2 = p3 - p1;
50 double crossProductMagnitude =
mag(crossProduct);
52 return 0.5 * crossProductMagnitude;
65 inline void compute_barycentric_coordinates_coefficients(
const SF::Point& p1,
const SF::Point& p2,
const SF::Point& P, std::array<double, SF_MAX_ELEM_NODES>& interpolationCoefficients,
double & length)
69 length = std::sqrt(lengthSquared);
72 double lambda2 =
inner_prod(v, d) / lengthSquared;
73 double lambda1 = 1.0 - lambda2;
75 interpolationCoefficients[0] = lambda1;
76 interpolationCoefficients[1] = lambda2;
90 inline void compute_barycentric_coordinates_coefficients(
const SF::Point& p1,
const SF::Point& p2,
const SF::Point& p3,
const SF::Point& P, std::array<double, SF_MAX_ELEM_NODES>& interpolationCoefficients,
double & area)
93 area = computeTriangleArea(p1, p2, p3);
108 double denom = d00 * d11 - d01 * d01;
109 double beta = (d11 * d20 - d01 * d21) / denom;
110 double gamma = (d00 * d21 - d01 * d20) / denom;
111 double alpha = 1.0 - beta - gamma;
112 interpolationCoefficients[0] = alpha;
113 interpolationCoefficients[1] = beta;
114 interpolationCoefficients[2] = gamma;
130 inline void compute_barycentric_coordinates_coefficients(
const SF::Point& p1,
const SF::Point& p2,
const SF::Point& p3,
const SF::Point& p4,
const SF::Point& P, std::array<double, SF_MAX_ELEM_NODES>& interpolationCoefficients,
double & area)
133 double area1 = computeTriangleArea(p1, p2, p4);
134 double area2 = computeTriangleArea(p2, p3, p4);
135 area = area1 + area2;
152 interpolationCoefficients[0] = (1 - u) * (1 - v);
153 interpolationCoefficients[1] = u * (1 - v);
154 interpolationCoefficients[2] = u * v;
155 interpolationCoefficients[3] = (1 - u) * v;
170 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)
176 for (
int i = 0; i < nnodes; ++i)
178 x += face_coordinates[i].x;
179 y += face_coordinates[i].y;
180 z += face_coordinates[i].z;
182 SF::Point b; b.
x = x/nnodes; b.
y = y/nnodes; b.
z = z/nnodes;
184 std::array<double, SF_MAX_ELEM_NODES> interpolationCoefficients{};
187 compute_barycentric_coordinates_coefficients(face_coordinates[0], face_coordinates[1], b, interpolationCoefficients, area);
191 compute_barycentric_coordinates_coefficients(face_coordinates[0], face_coordinates[1], face_coordinates[2], b, interpolationCoefficients, area);
194 compute_barycentric_coordinates_coefficients(face_coordinates[0], face_coordinates[1], face_coordinates[2], face_coordinates[3], b, interpolationCoefficients, area);
199 ebuff[0][0] = interpolationCoefficients[0];
200 ebuff[0][1] = interpolationCoefficients[1];
202 ebuff_counter[0][0] = interpolationCoefficients[0];
203 ebuff_counter[0][1] = interpolationCoefficients[1];
205 ebuff_s[0][0] = mass_scale*area*interpolationCoefficients[0];
206 ebuff_s[0][1] = mass_scale*area*interpolationCoefficients[1];
209 ebuff[0][0] = interpolationCoefficients[0];
210 ebuff[0][1] = interpolationCoefficients[1];
211 ebuff[0][2] = interpolationCoefficients[2];
213 ebuff_counter[0][0] = interpolationCoefficients[0];
214 ebuff_counter[0][1] = interpolationCoefficients[1];
215 ebuff_counter[0][2] = interpolationCoefficients[2];
217 ebuff_s[0][0] = mass_scale*area*interpolationCoefficients[0];
218 ebuff_s[0][1] = mass_scale*area*interpolationCoefficients[1];
219 ebuff_s[0][2] = mass_scale*area*interpolationCoefficients[2];
222 ebuff[0][0] = interpolationCoefficients[0];
223 ebuff[0][1] = interpolationCoefficients[1];
224 ebuff[0][2] = interpolationCoefficients[2];
225 ebuff[0][3] = interpolationCoefficients[3];
227 ebuff_counter[0][0] = interpolationCoefficients[0];
228 ebuff_counter[0][1] = interpolationCoefficients[1];
229 ebuff_counter[0][2] = interpolationCoefficients[2];
230 ebuff_counter[0][3] = interpolationCoefficients[3];
232 ebuff_s[0][0] = mass_scale*area*interpolationCoefficients[0];
233 ebuff_s[0][1] = mass_scale*area*interpolationCoefficients[1];
234 ebuff_s[0][2] = mass_scale*area*interpolationCoefficients[2];
235 ebuff_s[0][3] = mass_scale*area*interpolationCoefficients[3];
271 template<
class T,
class S,
class emi_index_rank>
272 inline void construct_direct_unique_both_operators(
280 int max_row_entries_emi,
285 T M = emi_surfmesh_w_counter_face.
g_numelem;
286 T m = emi_surfmesh_w_counter_face.
l_numelem;
287 T M_unique_face = emi_surfmesh_unique_face.
g_numelem;
288 T m_unique_face = emi_surfmesh_unique_face.
l_numelem;
292 MPI_Comm_rank(emi_surfmesh_w_counter_face.
comm, &rank);
293 MPI_Comm_size(emi_surfmesh_w_counter_face.
comm, &comm_size);
296 SF::layout_from_count<long int>(emi_surfmesh_w_counter_face.
l_numelem, layout, emi_surfmesh_w_counter_face.
comm);
297 T m_l = layout[rank];
300 SF::layout_from_count<long int>(emi_surfmesh_unique_face.
l_numelem, layout_unique_face, emi_surfmesh_unique_face.
comm);
301 T m_unique_face_l = layout_unique_face[rank];
304 map_elem_uniqueFace_to_elem_bothface.clear();
308 std::vector<int> both_counts(comm_size, 0), both_displs(comm_size, 0);
309 int local_both_count =
static_cast<int>(vec_both_to_one_face.
size());
310 MPI_Allgather(&local_both_count, 1, MPI_INT, both_counts.data(), 1, MPI_INT,
311 emi_surfmesh_w_counter_face.
comm);
313 int total_both_count = 0;
314 for (
int i = 0; i < comm_size; i++) {
315 both_displs[i] = total_both_count;
316 total_both_count += both_counts[i];
319 std::vector<mesh_int_t> all_both_to_one(total_both_count);
322 std::vector<int> both_byte_counts(comm_size, 0), both_byte_displs(comm_size, 0);
323 for (
int i = 0; i < comm_size; i++) {
324 both_byte_counts[i] = both_counts[i] *
static_cast<int>(
sizeof(
mesh_int_t));
325 both_byte_displs[i] = both_displs[i] *
static_cast<int>(
sizeof(
mesh_int_t));
327 const int local_both_bytes = local_both_count *
static_cast<int>(
sizeof(
mesh_int_t));
328 MPI_Allgatherv(
reinterpret_cast<const unsigned char*
>(vec_both_to_one_face.
data()),
329 local_both_bytes, MPI_BYTE,
330 reinterpret_cast<unsigned char*
>(all_both_to_one.data()),
331 both_byte_counts.data(), both_byte_displs.data(), MPI_BYTE,
332 emi_surfmesh_w_counter_face.
comm);
336 std::vector<std::vector<mesh_int_t>> one_to_both_first(comm_size);
337 std::vector<std::vector<mesh_int_t>> one_to_both_second(comm_size);
338 for (
int r = 0; r < comm_size; r++) {
340 for (
int i = 0; i < both_counts[r]; i++) {
341 mesh_int_t one_idx = all_both_to_one[both_displs[r] + i];
342 if (one_idx > max_one) max_one = one_idx;
344 if (max_one < 0)
continue;
346 one_to_both_first[r].assign(max_one + 1, -1);
347 one_to_both_second[r].assign(max_one + 1, -1);
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 < 0)
continue;
351 if (one_to_both_first[r][one_idx] < 0) one_to_both_first[r][one_idx] = i;
352 else one_to_both_second[r][one_idx] = i;
357 for (
const auto& [unique_idx, one_face_pair] : map_elem_uniqueFace_to_elem_oneface) {
358 const auto& first_oneface = one_face_pair.first;
359 const auto& second_oneface = one_face_pair.second;
361 auto map_one_to_both = [&](
const emi_index_rank& one_face_idx,
bool use_second) {
362 emi_index_rank both_face_idx;
363 both_face_idx.index = -1;
364 both_face_idx.rank = -1;
366 if (one_face_idx.rank < 0 || one_face_idx.rank >= comm_size || one_face_idx.index < 0) {
367 return both_face_idx;
369 if (one_face_idx.index >=
static_cast<int>(one_to_both_first[one_face_idx.rank].size())) {
370 return both_face_idx;
373 mesh_int_t both_idx = one_to_both_first[one_face_idx.rank][one_face_idx.index];
375 one_face_idx.index <
static_cast<int>(one_to_both_second[one_face_idx.rank].size()) &&
376 one_to_both_second[one_face_idx.rank][one_face_idx.index] >= 0) {
377 both_idx = one_to_both_second[one_face_idx.rank][one_face_idx.index];
381 both_face_idx.index = both_idx;
382 both_face_idx.rank = one_face_idx.rank;
384 return both_face_idx;
387 const bool same_oneface =
388 (first_oneface.index >= 0 && second_oneface.index >= 0 &&
389 first_oneface.index == second_oneface.index &&
390 first_oneface.rank == second_oneface.rank);
392 map_elem_uniqueFace_to_elem_bothface[unique_idx] = std::make_pair(
393 map_one_to_both(first_oneface,
false),
394 map_one_to_both(second_oneface, same_oneface));
400 operator_unique_to_both_faces->
init(M, M_unique_face, m, m_unique_face, m_l, 1);
401 operator_unique_to_both_faces->
zero();
408 throw std::runtime_error(
409 "EMI unique-face transfer operator currently requires fewer than INT_MAX unique faces");
411 const int M_unique_global =
static_cast<int>(emi_surfmesh_unique_face.
g_numelem);
412 std::vector<int> first_rank(M_unique_global, -1), first_idx(M_unique_global, -1);
413 std::vector<int> second_rank(M_unique_global, -1), second_idx(M_unique_global, -1);
415 for (
const auto& [local_unique_idx, both_pair] : map_elem_uniqueFace_to_elem_bothface) {
416 int global_unique =
static_cast<int>(layout_unique_face[rank] + local_unique_idx);
417 if (global_unique < 0 || global_unique >= M_unique_global)
continue;
419 first_rank[global_unique] =
static_cast<int>(both_pair.first.rank);
420 first_idx[global_unique] =
static_cast<int>(both_pair.first.index);
421 second_rank[global_unique] =
static_cast<int>(both_pair.second.rank);
422 second_idx[global_unique] =
static_cast<int>(both_pair.second.index);
425 MPI_Allreduce(MPI_IN_PLACE, first_rank.data(), M_unique_global, MPI_INT, MPI_MAX, emi_surfmesh_w_counter_face.
comm);
426 MPI_Allreduce(MPI_IN_PLACE, first_idx.data(), M_unique_global, MPI_INT, MPI_MAX, emi_surfmesh_w_counter_face.
comm);
427 MPI_Allreduce(MPI_IN_PLACE, second_rank.data(), M_unique_global, MPI_INT, MPI_MAX, emi_surfmesh_w_counter_face.
comm);
428 MPI_Allreduce(MPI_IN_PLACE, second_idx.data(), M_unique_global, MPI_INT, MPI_MAX, emi_surfmesh_w_counter_face.
comm);
430 auto assemble_unique_to_both = [&]() {
433 ebuff.assign(1, 1, 1.0);
435 for (
int gid = 0; gid < M_unique_global; gid++) {
437 if (first_rank[gid] == rank && first_idx[gid] >= 0) {
438 row_idx[0] =
static_cast<SF_int>(layout[rank] + first_idx[gid]);
439 operator_unique_to_both_faces->
set_values(row_idx, col_idx, ebuff.data(),
false);
441 if (second_rank[gid] == rank && second_idx[gid] >= 0) {
442 row_idx[0] =
static_cast<SF_int>(layout[rank] + second_idx[gid]);
443 operator_unique_to_both_faces->
set_values(row_idx, col_idx, ebuff.data(),
false);
450 assemble_unique_to_both();
453 assemble_unique_to_both();
457 operator_both_to_unique_face->
init(M_unique_face, M, m_unique_face, m, m_unique_face_l, 2);
458 operator_both_to_unique_face->
zero();
460 assemble_map_both_to_unique(*operator_both_to_unique_face,
461 map_elem_uniqueFace_to_elem_bothface,
462 emi_surfmesh_unique_face,
463 emi_surfmesh_w_counter_face);
466 assemble_map_both_to_unique(*operator_both_to_unique_face,
467 map_elem_uniqueFace_to_elem_bothface,
468 emi_surfmesh_unique_face,
469 emi_surfmesh_w_counter_face);
471 #ifdef EMI_DEBUG_MESH
475 mesh_int_t local_valid_first = 0, local_valid_second = 0;
478 SF::layout_from_count<long int>(emi_surfmesh_w_counter_face.
l_numelem, layout_both_dbg, emi_surfmesh_w_counter_face.
comm);
480 SF::layout_from_count<long int>(emi_surfmesh_unique_face.
l_numelem, layout_unique_dbg, emi_surfmesh_unique_face.
comm);
482 for (
const auto& [uidx, both_pair] : map_elem_uniqueFace_to_elem_bothface) {
483 if (both_pair.first.index >= 0) local_valid_first++;
484 if (both_pair.second.index >= 0) local_valid_second++;
486 if (both_pair.first.index >= 0 && both_pair.second.index >= 0 &&
487 both_pair.first.rank >= 0 && both_pair.second.rank >= 0) {
488 mesh_int_t global_first = layout_both_dbg[both_pair.first.rank] + both_pair.first.index;
489 mesh_int_t global_second = layout_both_dbg[both_pair.second.rank] + both_pair.second.index;
490 if (global_first == global_second) local_same_column++;
493 mesh_int_t global_valid_first = local_valid_first;
494 mesh_int_t global_valid_second = local_valid_second;
495 mesh_int_t global_same_column = local_same_column;
496 const MPI_Datatype mesh_mpi_t = opencarp::mpi_datatype<mesh_int_t>();
497 MPI_Allreduce(MPI_IN_PLACE, &global_valid_first, 1, mesh_mpi_t, MPI_SUM, emi_surfmesh_w_counter_face.
comm);
498 MPI_Allreduce(MPI_IN_PLACE, &global_valid_second, 1, mesh_mpi_t, MPI_SUM, emi_surfmesh_w_counter_face.
comm);
499 MPI_Allreduce(MPI_IN_PLACE, &global_same_column, 1, mesh_mpi_t, MPI_SUM, emi_surfmesh_w_counter_face.
comm);
502 MPI_Comm_rank(emi_surfmesh_w_counter_face.
comm, &dbg_rank);
504 log_msg(NULL, 0, 0,
"DEBUG map_unique_to_both: valid_first=%jd valid_second=%jd (global M=%zu, M_unique=%zu)",
507 (
size_t)emi_surfmesh_w_counter_face.
g_numelem,
508 (
size_t)emi_surfmesh_unique_face.
g_numelem);
513 std::vector<char> present(emi_surfmesh_unique_face.
l_numelem, 0);
514 for (
const auto& [uidx, both_pair] : map_elem_uniqueFace_to_elem_bothface) {
515 if (uidx >= 0 && uidx < (
mesh_int_t)present.size()) present[uidx] = 1;
517 std::vector<int> missing;
519 if (!present[i]) missing.push_back((
int)i);
521 int local_missing = (int)missing.size();
522 int comm_size_dbg = 0;
523 MPI_Comm_size(emi_surfmesh_w_counter_face.
comm, &comm_size_dbg);
524 std::vector<int> counts(comm_size_dbg, 0), displs(comm_size_dbg, 0);
525 MPI_Gather(&local_missing, 1, MPI_INT,
526 dbg_rank == 0 ? counts.data() :
nullptr, 1, MPI_INT,
527 0, emi_surfmesh_w_counter_face.
comm);
530 for (
int r = 0; r < comm_size_dbg; r++) {
534 std::vector<int> all_missing(total, -1);
535 MPI_Gatherv(missing.data(), local_missing, MPI_INT,
536 all_missing.data(), counts.data(), displs.data(), MPI_INT,
537 0, emi_surfmesh_w_counter_face.
comm);
540 for (
int r = 0; r < comm_size_dbg; r++) {
541 if (counts[r] == 0) {
546 log_msg(NULL, 0, 0,
"DEBUG unique missing: rank=%d count=%d", r, counts[r]);
547 int to_print = counts[r] < 10 ? counts[r] : 10;
548 for (
int i = 0; i < to_print; i++) {
549 log_msg(NULL, 0, 0,
"DEBUG unique missing: rank=%d local_unique=%d", r, all_missing[offset + i]);
553 if (!any)
log_msg(NULL, 0, 0,
"DEBUG unique missing: none");
555 MPI_Gatherv(missing.data(), local_missing, MPI_INT,
556 nullptr,
nullptr,
nullptr, MPI_INT,
557 0, emi_surfmesh_w_counter_face.
comm);
564 SF::init_vector(&dbg_unique, emi_surfmesh_unique_face, dpn, alg_surface_type);
565 SF::init_vector(&dbg_both, emi_surfmesh_w_counter_face, dpn, alg_surface_type);
566 SF::init_vector(&dbg_back, emi_surfmesh_unique_face, dpn, alg_surface_type);
567 dbg_unique->
set(1.0);
568 operator_unique_to_both_faces->
mult(*dbg_unique, *dbg_both);
569 operator_both_to_unique_face->
mult(*dbg_both, *dbg_back);
575 SF_real err = std::abs(p[i] - 1.0);
576 if (err > local_max_err) local_max_err = err;
577 if (std::abs(p[i] - 0.5) < 1e-12) local_half_count++;
582 MPI_Allreduce(&local_max_err, &global_max_err, 1, opencarp::mpi_datatype<SF_real>(),
583 MPI_MAX, emi_surfmesh_w_counter_face.
comm);
584 global_half_count = local_half_count;
585 MPI_Allreduce(MPI_IN_PLACE, &global_half_count, 1, mesh_mpi_t, MPI_SUM,
586 emi_surfmesh_w_counter_face.
comm);
588 log_msg(NULL, 0, 0,
"DEBUG map_unique_to_both consistency: max_err=%.6e half_count=%jd",
593 const int max_print = 5;
594 const int fields = 9;
595 std::vector<int> local_buf(max_print * fields, -1);
598 for (
const auto& [local_unique_idx, both_pair] : map_elem_uniqueFace_to_elem_bothface) {
599 if (filled >= max_print)
break;
600 const auto& first_both = both_pair.first;
601 const auto& second_both = both_pair.second;
603 const bool first_valid = (first_both.index >= 0 && first_both.rank >= 0);
604 const bool second_valid = (second_both.index >= 0 && second_both.rank >= 0);
605 int count = (first_valid ? 1 : 0) + (second_valid ? 1 : 0);
606 if (
count != 1)
continue;
608 mesh_int_t global_unique = layout_unique_dbg[dbg_rank] + local_unique_idx;
609 mesh_int_t global_first = first_valid ? (layout_both_dbg[first_both.rank] + first_both.index) : -1;
610 mesh_int_t global_second = second_valid ? (layout_both_dbg[second_both.rank] + second_both.index) : -1;
612 int base = filled * fields;
613 local_buf[base + 0] = dbg_rank;
614 local_buf[base + 1] = (int)local_unique_idx;
615 local_buf[base + 2] = (int)global_unique;
616 local_buf[base + 3] = (int)first_both.rank;
617 local_buf[base + 4] = (
int)first_both.index;
618 local_buf[base + 5] = (int)global_first;
619 local_buf[base + 6] = (int)second_both.rank;
620 local_buf[base + 7] = (
int)second_both.index;
621 local_buf[base + 8] = (int)global_second;
626 MPI_Comm_size(emi_surfmesh_w_counter_face.
comm, &comm_size);
627 std::vector<int> all_buf;
628 if (dbg_rank == 0) all_buf.resize(comm_size * max_print * fields, -1);
630 MPI_Gather(local_buf.data(), max_print * fields, MPI_INT,
631 dbg_rank == 0 ? all_buf.data() :
nullptr, max_print * fields, MPI_INT,
632 0, emi_surfmesh_w_counter_face.
comm);
635 for (
int r = 0; r < comm_size; r++) {
636 for (
int i = 0; i < max_print; i++) {
637 int base = (r * max_print + i) * fields;
638 if (all_buf[base + 1] < 0)
continue;
640 "DEBUG map_unique_to_both bad: rank=%d local_unique=%d global_unique=%d "
641 "first(rank=%d idx=%d glob=%d) second(rank=%d idx=%d glob=%d)",
642 all_buf[base + 0], all_buf[base + 1], all_buf[base + 2],
643 all_buf[base + 3], all_buf[base + 4], all_buf[base + 5],
644 all_buf[base + 6], all_buf[base + 7], all_buf[base + 8]);
679 template<
class tuple_key,
class tuple_value,
class tri_key,
class tri_value,
class quad_key,
class quad_value,
class T,
class S>
680 inline void assemble_restrict_operator( abstract_matrix<T,S> & B,
681 abstract_matrix<T,S> & Bi,
682 abstract_matrix<T,S> & BsM,
685 std::pair<mesh_int_t,mesh_int_t>> & map_vertex_tag_to_dof_petsc,
687 std::pair<tuple_value, tuple_value>> & line_face,
689 std::pair<tri_value, tri_value>> & tri_face,
691 std::pair<quad_value, quad_value>> & quad_face,
692 const meshdata<mesh_int_t,mesh_real_t> & surface_mesh,
693 const meshdata<mesh_int_t,mesh_real_t> & emi_mesh,
697 T row_dpn = 1; T col_dpn = 1;
702 for(
size_t i=0; i<rnod_emi.
size(); i++){
703 g2l_emi[rnod_emi[i]] = i;
709 auto find_petsc_index = [&](
const std::pair<mesh_int_t,mesh_int_t>& key) ->
const std::pair<mesh_int_t,mesh_int_t>& {
710 auto it = map_vertex_tag_to_dof_petsc.find(key);
711 if (it == map_vertex_tag_to_dof_petsc.end()) {
712 std::cerr <<
"ERROR: PETSc index not found for vertex=" << key.first
713 <<
" tag=" << key.second << std::endl;
714 throw std::runtime_error(
"PETSc index not found for vertex/tag pair");
729 std::vector<mesh_int_t> elem_nodes;
730 std::vector<mesh_int_t> elem_nodes_old;
731 std::vector<mesh_int_t> petsc_first;
732 std::vector<mesh_int_t> petsc_second;
733 vector<SF::Point> face_coordinates;
741 for(
size_t eidx=0; eidx < surface_mesh.l_numelem; eidx++)
743 T tag = surface_mesh.tag[eidx];
747 elem_nodes_old.clear();
749 petsc_second.clear();
759 for (
int n = surface_mesh.dsp[eidx]; n < surface_mesh.dsp[eidx+1];n++)
761 T l_idx = surface_mesh.con[n];
763 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
764 Index_tag_old = std::make_pair(rnod[l_idx],tag);
765 mesh_int_t Index_new = find_petsc_index(Index_tag_old).first;
766 elem_nodes.push_back(Index_new);
767 elem_nodes_old.push_back(rnod[l_idx]);
770 std::sort(elem_nodes.begin(),elem_nodes.end());
771 if(elem_nodes.size()==2){
774 key.v1 = elem_nodes[0];
775 key.v2 = elem_nodes[1];
776 auto it = line_face.find(key);
777 if (it == line_face.end())
throw std::runtime_error(
"Line interface face not found");
778 const std::pair<tuple_value, tuple_value> & value = it->second;
780 tag_first = value.first.tag;
781 tag_second = value.second.tag;
783 mem_first = value.first.mem;
784 mem_second = value.second.mem;
787 else if(elem_nodes.size()==3){
789 key.v1 = elem_nodes[0];
790 key.v2 = elem_nodes[1];
791 key.v3 = elem_nodes[2];
792 auto it = tri_face.find(key);
793 if (it == tri_face.end())
throw std::runtime_error(
"Triangular interface face not found");
794 const std::pair<tri_value, tri_value> & value = it->second;
796 tag_first = value.first.tag;
797 tag_second = value.second.tag;
799 mem_first = value.first.mem;
800 mem_second = value.second.mem;
803 else if(elem_nodes.size()==4){
805 key.v1 = elem_nodes[0];
806 key.v2 = elem_nodes[1];
807 key.v3 = elem_nodes[2];
808 key.v4 = elem_nodes[3];
809 auto it = quad_face.find(key);
810 if (it == quad_face.end())
throw std::runtime_error(
"Quadrilateral interface face not found");
811 const std::pair<quad_value, quad_value> & value = it->second;
813 tag_first = value.first.tag;
814 tag_second = value.second.tag;
816 mem_first = value.first.mem;
817 mem_second = value.second.mem;
821 if(tag != tag_first) {
822 std::swap(tag_first, tag_second);
823 std::swap(mem_first, mem_second);
826 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
828 for (
size_t indx = 0; indx < elem_nodes_old.size(); ++indx)
830 std::pair <mesh_int_t,mesh_int_t> Index_tag_old_first;
831 Index_tag_old_first = std::make_pair(elem_nodes_old[indx],tag_first);
833 auto it_first = map_vertex_tag_to_dof_petsc.find(Index_tag_old_first);
834 if (it_first == map_vertex_tag_to_dof_petsc.end()) {
835 std::cerr <<
"ERROR: tag_first=" << tag_first <<
" not found for vertex=" << elem_nodes_old[indx] << std::endl;
836 throw std::runtime_error(
"PETSc index not found for first tag");
838 std::pair <mesh_int_t,mesh_int_t> newIndex_petsc_first = it_first->second;
839 mesh_int_t newIndex_first = newIndex_petsc_first.first;
840 petsc_first.push_back(newIndex_petsc_first.second);
842 std::pair <mesh_int_t,mesh_int_t> Index_tag_old_second;
843 Index_tag_old_second = std::make_pair(elem_nodes_old[indx],tag_second);
845 auto it_second = map_vertex_tag_to_dof_petsc.find(Index_tag_old_second);
846 if (it_second == map_vertex_tag_to_dof_petsc.end()) {
847 std::cerr <<
"ERROR: tag_second=" << tag_second <<
" not found for vertex=" << elem_nodes_old[indx] << std::endl;
848 throw std::runtime_error(
"PETSc index not found for counter-face tag");
850 std::pair <mesh_int_t,mesh_int_t> newIndex_petsc_second = it_second->second;
851 mesh_int_t newIndex_second = newIndex_petsc_second.first;
852 petsc_second.push_back(newIndex_petsc_second.second);
855 if(mem_first==1 and elemTag_surface_mesh[eidx]==1)
857 else if (mem_first==2 and tag<tag_second)
861 SF_int nnodes = elem_nodes.size();
862 face_coordinates.resize(nnodes);
864 row_idx.resize(nnodes*row_dpn);
865 row_idx_counter.resize(nnodes*row_dpn);
866 col_idx.resize(nnodes*col_dpn);
867 col_idx_counter.resize(nnodes*col_dpn);
870 for(
SF_int i=0; i<nnodes; i++){
872 for(
short j=0; j<row_dpn; j++){
873 row_idx.data()[i*row_dpn + j] = emi_surfmesh_elem[eidx]*row_dpn;
876 for(
short j=0; j<col_dpn; j++){
877 col_idx[i*col_dpn + j] = (petsc_first[i])*col_dpn + j;
878 col_idx_counter[i*col_dpn + j] = (petsc_second[i])*col_dpn + j;
884 ebuff.
assign(nnodes, nnodes, 0.0);
885 ebuff_s.assign(nnodes, nnodes, 0.0);
887 ebuff_counter.assign(nnodes, nnodes, 0.0);
889 for (
int n = surface_mesh.dsp[eidx], i = 0; n < surface_mesh.dsp[eidx+1];n++,i++)
891 T l_idx = surface_mesh.con[n];
893 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
894 Index_tag_old = std::make_pair(rnod[l_idx],tag);
895 mesh_int_t Index_new = find_petsc_index(Index_tag_old).first;
897 double x = emi_mesh.xyz[g2l_emi[Index_new]*3+0];
898 double y = emi_mesh.xyz[g2l_emi[Index_new]*3+1];
899 double z = emi_mesh.xyz[g2l_emi[Index_new]*3+2];
901 face_coordinates[i].x = x;
902 face_coordinates[i].y = y;
903 face_coordinates[i].z = z;
905 compute_integrate_matrix_barycentric(face_coordinates, nnodes, ebuff, ebuff_s, ebuff_counter, mass_scale);
908 const bool add =
true;
911 Bi.set_values(row_idx, col_idx, ebuff.data(), add);
912 Bi.set_values(row_idx, col_idx_counter, ebuff_counter.data(), add);
915 B.set_values(row_idx, col_idx, ebuff.data(), add);
916 ebuff_counter*=(-
sign);
917 B.set_values(row_idx, col_idx_counter, ebuff_counter.data(), add);
922 for(
SF_int i = 0; i < nnodes; i++) {
923 BsM.set_value(col_idx[i], row_idx[0], ebuff_s[0][i], add);
928 Bi.finish_assembly();
929 BsM.finish_assembly();
952 template<
class tuple_key,
class tuple_value,
class tri_key,
class tri_value,
class quad_key,
class quad_value,
class T,
class S>
953 inline void assemble_lhs_emi(abstract_matrix<T,S> & mat,
954 abstract_matrix<T,S> & mat_surf,
955 const meshdata<mesh_int_t,mesh_real_t> & emi_mesh,
956 const meshdata<mesh_int_t,mesh_real_t> & surface_mesh,
957 const 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,
959 std::pair<tuple_value, tuple_value>> & line_face,
961 std::pair<tri_value, tri_value>> & tri_face,
963 std::pair<quad_value, quad_value>> & quad_face,
964 matrix_integrator<mesh_int_t,mesh_real_t> & stiffness_integrator,
965 matrix_integrator<mesh_int_t, mesh_real_t> & mass_integrator,
970 T row_dpn = 1; T col_dpn = 1;
980 const vector<mesh_int_t> & stiffness_petsc_nbr = emi_mesh.get_numbering(
NBR_PETSC);
981 element_view<mesh_int_t, mesh_real_t> stiffness_view(emi_mesh,
NBR_PETSC);
984 for(
size_t eidx=0; eidx < emi_mesh.l_numelem; eidx++)
987 stiffness_view.set_elem(eidx);
990 mesh_int_t nnodes = stiffness_view.num_nodes();
992 row_idx.resize(nnodes*row_dpn);
993 col_idx.resize(nnodes*col_dpn);
994 canonic_indices<mesh_int_t,SF_int>(stiffness_view.nodes(), stiffness_petsc_nbr.data(), nnodes, row_dpn, row_idx.data());
995 canonic_indices<mesh_int_t,SF_int>(stiffness_view.nodes(), stiffness_petsc_nbr.data(), nnodes, col_dpn, col_idx.data());
998 stiffness_integrator(stiffness_view, ebuff);
999 ebuff *= stiffness_scale;
1002 const bool add =
true;
1003 mat.set_values(row_idx, col_idx, ebuff.data(), add);
1012 auto find_petsc_index = [&](
const std::pair<mesh_int_t,mesh_int_t>& key) ->
const std::pair<mesh_int_t,mesh_int_t>& {
1013 auto it = map_vertex_tag_to_dof_petsc.find(key);
1014 if (it == map_vertex_tag_to_dof_petsc.end()) {
1015 std::cerr <<
"ERROR: PETSc index not found for vertex=" << key.first
1016 <<
" tag=" << key.second << std::endl;
1017 throw std::runtime_error(
"PETSc index not found for vertex/tag pair");
1023 element_view<mesh_int_t, mesh_real_t> view(surface_mesh,
NBR_PETSC);
1024 for(
size_t eidx=0; eidx < surface_mesh.l_numelem; eidx++)
1027 view.set_elem(eidx);
1031 std::vector<mesh_int_t> elem_nodes;
1032 std::vector<mesh_int_t> elem_nodes_old;
1033 std::vector<mesh_int_t> elem_nodes_first;
1034 std::vector<mesh_int_t> elem_nodes_second;
1036 std::vector<mesh_int_t> petsc_first;
1037 std::vector<mesh_int_t> petsc_second;
1042 for (
int n = surface_mesh.dsp[eidx]; n < surface_mesh.dsp[eidx+1];n++)
1044 T l_idx = surface_mesh.con[n];
1046 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1047 Index_tag_old = std::make_pair(rnod[l_idx],tag);
1048 mesh_int_t Index_new = find_petsc_index(Index_tag_old).first;
1049 elem_nodes.push_back(Index_new);
1050 elem_nodes_old.push_back(rnod[l_idx]);
1053 std::sort(elem_nodes.begin(),elem_nodes.end());
1054 if(elem_nodes.size()==2){
1057 key.v1 = elem_nodes[0];
1058 key.v2 = elem_nodes[1];
1059 auto it = line_face.find(key);
1060 if (it == line_face.end())
throw std::runtime_error(
"Line interface face not found");
1061 const std::pair<tuple_value, tuple_value> & value = it->second;
1063 tag_first = value.first.tag;
1064 tag_second = value.second.tag;
1066 else if(elem_nodes.size()==3){
1068 key.v1 = elem_nodes[0];
1069 key.v2 = elem_nodes[1];
1070 key.v3 = elem_nodes[2];
1071 auto it = tri_face.find(key);
1072 if (it == tri_face.end())
throw std::runtime_error(
"Triangular interface face not found");
1073 const std::pair<tri_value, tri_value> & value = it->second;
1075 tag_first = value.first.tag;
1076 tag_second = value.second.tag;
1078 else if(elem_nodes.size()==4){
1080 key.v1 = elem_nodes[0];
1081 key.v2 = elem_nodes[1];
1082 key.v3 = elem_nodes[2];
1083 key.v4 = elem_nodes[3];
1084 auto it = quad_face.find(key);
1085 if (it == quad_face.end())
throw std::runtime_error(
"Quadrilateral interface face not found");
1086 const std::pair<quad_value, quad_value> & value = it->second;
1088 tag_first = value.first.tag;
1089 tag_second = value.second.tag;
1092 if(tag != tag_first) std::swap(tag_first, tag_second);
1094 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1096 for (
size_t indx = 0; indx < elem_nodes_old.size(); ++indx)
1098 std::pair <mesh_int_t,mesh_int_t> Index_tag_old_first;
1099 Index_tag_old_first = std::make_pair(elem_nodes_old[indx],tag_first);
1100 std::pair <mesh_int_t,mesh_int_t> newIndex_petsc_first = find_petsc_index(Index_tag_old_first);
1101 mesh_int_t newIndex_first = newIndex_petsc_first.first;
1102 petsc_first.push_back(newIndex_petsc_first.second);
1104 std::pair <mesh_int_t,mesh_int_t> Index_tag_old_second;
1105 Index_tag_old_second = std::make_pair(elem_nodes_old[indx],tag_second);
1106 std::pair <mesh_int_t,mesh_int_t> newIndex_petsc_second = find_petsc_index(Index_tag_old_second);
1107 mesh_int_t newIndex_second = newIndex_petsc_second.first;
1108 petsc_second.push_back(newIndex_petsc_second.second);
1112 SF_int nnodes = view.num_nodes();
1113 idx.resize(nnodes*row_dpn);
1114 idx_counter.resize(nnodes*col_dpn);
1117 for(T i=0; i<nnodes; i++)
1119 for(
short j=0; j<row_dpn; j++){
1120 idx[i*row_dpn + j] = (petsc_first[i])*row_dpn + j;
1122 for(
short j=0; j<col_dpn; j++){
1123 idx_counter[i*col_dpn + j] = (petsc_second[i])*col_dpn + j;
1129 const bool add =
true;
1132 mass_integrator(view, ebuff);
1133 ebuff_mass.assign(nnodes, nnodes, 0.0);
1137 ebuff*=0.5 * mass_scale;
1140 mat.set_values(idx, idx, ebuff.data(), add);
1141 mat.set_values(idx_counter, idx_counter, ebuff.data(), add);
1143 mat_surf.set_values(idx, idx, ebuff_mass.data(), add);
1144 mat_surf.set_values(idx_counter, idx_counter, ebuff_mass.data(), add);
1149 mat.set_values(idx, idx_counter, ebuff.data(), add);
1150 mat.set_values(idx_counter, idx, ebuff.data(), add);
1152 mat_surf.set_values(idx, idx_counter, ebuff_mass.data(), add);
1153 mat_surf.set_values(idx_counter, idx, ebuff_mass.data(), add);
1165 mat.finish_assembly();
1166 mat_surf.finish_assembly();
1187 template<
class tuple_key,
class tuple_value,
class tri_key,
class tri_value,
class quad_key,
class quad_value,
class T,
class S>
1188 inline void assign_resting_potential_from_ionic_models_on_myocyte(abstract_vector<T,S> & ui,
1189 abstract_vector<T, S>* vb,
1192 std::pair<T,T>> & map_vertex_tag_to_dof_petsc,
1194 std::pair<tuple_value, tuple_value>> & line_face,
1196 std::pair<tri_value, tri_value>> & tri_face,
1198 std::pair<quad_value, quad_value>> & quad_face,
1199 const meshdata<T,mesh_real_t> & surface_mesh,
1200 const meshdata<T,mesh_real_t> & emi_mesh)
1208 auto find_petsc_index = [&](
const std::pair<T,T>& key) ->
const std::pair<T,T>& {
1209 auto it = map_vertex_tag_to_dof_petsc.
find(key);
1210 if (it == map_vertex_tag_to_dof_petsc.end()) {
1211 std::cerr <<
"ERROR: PETSc index not found for vertex=" << key.first
1212 <<
" tag=" << key.second << std::endl;
1213 throw std::runtime_error(
"PETSc index not found for vertex/tag pair");
1218 auto vb_data = vb->const_ptr();
1221 for(
size_t eidx=0; eidx < surface_mesh.l_numelem; eidx++)
1223 T tag = surface_mesh.tag[eidx];
1226 std::vector<mesh_int_t> elem_nodes;
1232 for (
int n = surface_mesh.dsp[eidx], i = 0; n < surface_mesh.dsp[eidx+1];n++,i++)
1234 T l_idx = surface_mesh.con[n];
1235 std::pair <T,T> Index_tag_old;
1236 Index_tag_old = std::make_pair(rnod[l_idx],tag);
1237 mesh_int_t Index_new = find_petsc_index(Index_tag_old).first;
1238 elem_nodes.push_back(Index_new);
1241 std::sort(elem_nodes.begin(),elem_nodes.end());
1242 if(elem_nodes.size()==2){
1245 key.v1 = elem_nodes[0];
1246 key.v2 = elem_nodes[1];
1247 auto it = line_face.find(key);
1248 if (it == line_face.end())
throw std::runtime_error(
"Line interface face not found");
1249 const std::pair<tuple_value, tuple_value> & value = it->second;
1251 tag_first = value.first.tag;
1252 tag_second = value.second.tag;
1254 mem_first = value.first.mem;
1255 mem_second = value.second.mem;
1257 else if(elem_nodes.size()==3){
1259 key.v1 = elem_nodes[0];
1260 key.v2 = elem_nodes[1];
1261 key.v3 = elem_nodes[2];
1262 auto it = tri_face.find(key);
1263 if (it == tri_face.end())
throw std::runtime_error(
"Triangular interface face not found");
1264 const std::pair<tri_value, tri_value> & value = it->second;
1266 tag_first = value.first.tag;
1267 tag_second = value.second.tag;
1269 mem_first = value.first.mem;
1270 mem_second = value.second.mem;
1272 else if(elem_nodes.size()==4){
1274 key.v1 = elem_nodes[0];
1275 key.v2 = elem_nodes[1];
1276 key.v3 = elem_nodes[2];
1277 key.v4 = elem_nodes[3];
1278 auto it = quad_face.find(key);
1279 if (it == quad_face.end())
throw std::runtime_error(
"Quadrilateral interface face not found");
1280 const std::pair<quad_value, quad_value> & value = it->second;
1282 tag_first = value.first.tag;
1283 tag_second = value.second.tag;
1285 mem_first = value.first.mem;
1286 mem_second = value.second.mem;
1289 SF_int nnodes = elem_nodes.size();
1290 for (
int i = 0; i < nnodes; ++i)
1292 if(mem_first==1 || mem_second==1){
1293 tag_2_vm[tag_first] = vb_data[eidx];
1294 tag_2_vm[tag_second] = vb_data[eidx];
1299 vb->const_release_ptr(vb_data);
1306 const vector<mesh_int_t> & petsc_nbr = emi_mesh.get_numbering(
NBR_PETSC);
1307 T start = 0, stop = 0;
1308 ui.get_ownership_range(start, stop);
1310 S* ui_data = ui.ptr();
1312 element_view<mesh_int_t, mesh_real_t> view(emi_mesh,
NBR_PETSC);
1313 for(
size_t eidx=0; eidx < emi_mesh.l_numelem; eidx++)
1315 view.set_elem(eidx);
1316 T tag = emi_mesh.tag[eidx];
1319 row_idx.resize(nnodes*row_dpn);
1320 canonic_indices<mesh_int_t,SF_int>(view.nodes(), petsc_nbr.data(), nnodes, row_dpn, row_idx.data());
1322 for (
int i = 0; i < nnodes; ++i)
1325 if(elemTag_emi_mesh[eidx]==2){
1326 if(row_idx[i] >= start && row_idx[i] < stop) {
1327 auto vm_it = tag_2_vm.
find(tag);
1328 if (vm_it != tag_2_vm.
end()) ui_data[row_idx[i] - start] = vm_it->second;
1333 ui.release_ptr(ui_data);
1334 ui.finish_assembly();
opencarp::local_index_t mesh_int_t
#define SF_MAX_ELEM_NODES
max #nodes defining an element
opencarp::real_t SF_real
Global scalar type.
opencarp::global_index_t SF_int
Global algebraic index type.
virtual void mult(const abstract_vector< T, S > &x, abstract_vector< T, S > &b) const =0
virtual void finish_assembly()=0
virtual void finalize_exact_preallocation()
virtual bool begin_exact_preallocation()
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
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.
iterator find(const K &key)
Search for key. Return iterator.
#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).
constexpr T max(T a, T b)
std::intmax_t printable_int(T value)