42 #include <type_traits>
58 Point edge1 = p2 - p1;
59 Point edge2 = p3 - p1;
65 double crossProductMagnitude =
mag(crossProduct);
67 return 0.5 * crossProductMagnitude;
80 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)
84 length = std::sqrt(lengthSquared);
87 double lambda2 =
inner_prod(v, d) / lengthSquared;
88 double lambda1 = 1.0 - lambda2;
90 interpolationCoefficients[0] = lambda1;
91 interpolationCoefficients[1] = lambda2;
105 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)
108 area = computeTriangleArea(p1, p2, p3);
123 double denom = d00 * d11 - d01 * d01;
124 double beta = (d11 * d20 - d01 * d21) / denom;
125 double gamma = (d00 * d21 - d01 * d20) / denom;
126 double alpha = 1.0 - beta - gamma;
127 interpolationCoefficients[0] = alpha;
128 interpolationCoefficients[1] = beta;
129 interpolationCoefficients[2] = gamma;
145 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)
148 double area1 = computeTriangleArea(p1, p2, p4);
149 double area2 = computeTriangleArea(p2, p3, p4);
150 area = area1 + area2;
167 interpolationCoefficients[0] = (1 - u) * (1 - v);
168 interpolationCoefficients[1] = u * (1 - v);
169 interpolationCoefficients[2] = u * v;
170 interpolationCoefficients[3] = (1 - u) * v;
185 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)
191 for (
int i = 0; i < nnodes; ++i)
193 x += face_coordinates[i].x;
194 y += face_coordinates[i].y;
195 z += face_coordinates[i].z;
197 SF::Point b; b.
x = x/nnodes; b.
y = y/nnodes; b.
z = z/nnodes;
199 std::array<double, SF_MAX_ELEM_NODES> interpolationCoefficients{};
202 compute_barycentric_coordinates_coefficients(face_coordinates[0], face_coordinates[1], b, interpolationCoefficients, area);
206 compute_barycentric_coordinates_coefficients(face_coordinates[0], face_coordinates[1], face_coordinates[2], b, interpolationCoefficients, area);
209 compute_barycentric_coordinates_coefficients(face_coordinates[0], face_coordinates[1], face_coordinates[2], face_coordinates[3], b, interpolationCoefficients, area);
214 ebuff[0][0] = interpolationCoefficients[0];
215 ebuff[0][1] = interpolationCoefficients[1];
217 ebuff_counter[0][0] = interpolationCoefficients[0];
218 ebuff_counter[0][1] = interpolationCoefficients[1];
220 ebuff_s[0][0] = mass_scale*area*interpolationCoefficients[0];
221 ebuff_s[0][1] = mass_scale*area*interpolationCoefficients[1];
224 ebuff[0][0] = interpolationCoefficients[0];
225 ebuff[0][1] = interpolationCoefficients[1];
226 ebuff[0][2] = interpolationCoefficients[2];
228 ebuff_counter[0][0] = interpolationCoefficients[0];
229 ebuff_counter[0][1] = interpolationCoefficients[1];
230 ebuff_counter[0][2] = interpolationCoefficients[2];
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];
237 ebuff[0][0] = interpolationCoefficients[0];
238 ebuff[0][1] = interpolationCoefficients[1];
239 ebuff[0][2] = interpolationCoefficients[2];
240 ebuff[0][3] = interpolationCoefficients[3];
242 ebuff_counter[0][0] = interpolationCoefficients[0];
243 ebuff_counter[0][1] = interpolationCoefficients[1];
244 ebuff_counter[0][2] = interpolationCoefficients[2];
245 ebuff_counter[0][3] = interpolationCoefficients[3];
247 ebuff_s[0][0] = mass_scale*area*interpolationCoefficients[0];
248 ebuff_s[0][1] = mass_scale*area*interpolationCoefficients[1];
249 ebuff_s[0][2] = mass_scale*area*interpolationCoefficients[2];
250 ebuff_s[0][3] = mass_scale*area*interpolationCoefficients[3];
286 template<
class T,
class S,
class emi_index_rank>
287 inline void construct_direct_unique_both_operators(
295 int max_row_entries_emi,
300 T M = emi_surfmesh_w_counter_face.
g_numelem;
301 T m = emi_surfmesh_w_counter_face.
l_numelem;
302 T M_unique_face = emi_surfmesh_unique_face.
g_numelem;
303 T m_unique_face = emi_surfmesh_unique_face.
l_numelem;
307 MPI_Comm_rank(emi_surfmesh_w_counter_face.
comm, &rank);
308 MPI_Comm_size(emi_surfmesh_w_counter_face.
comm, &comm_size);
311 SF::layout_from_count<long int>(emi_surfmesh_w_counter_face.
l_numelem, layout, emi_surfmesh_w_counter_face.
comm);
312 T m_l = layout[rank];
315 SF::layout_from_count<long int>(emi_surfmesh_unique_face.
l_numelem, layout_unique_face, emi_surfmesh_unique_face.
comm);
316 T m_unique_face_l = layout_unique_face[rank];
319 map_elem_uniqueFace_to_elem_bothface.clear();
323 std::vector<int> both_counts(comm_size, 0), both_displs(comm_size, 0);
324 int local_both_count =
static_cast<int>(vec_both_to_one_face.
size());
325 MPI_Allgather(&local_both_count, 1, MPI_INT, both_counts.data(), 1, MPI_INT,
326 emi_surfmesh_w_counter_face.
comm);
328 int total_both_count = 0;
329 for (
int i = 0; i < comm_size; i++) {
330 both_displs[i] = total_both_count;
331 total_both_count += both_counts[i];
334 std::vector<mesh_int_t> all_both_to_one(total_both_count);
337 std::vector<int> both_byte_counts(comm_size, 0), both_byte_displs(comm_size, 0);
338 for (
int i = 0; i < comm_size; i++) {
339 both_byte_counts[i] = both_counts[i] *
static_cast<int>(
sizeof(
mesh_int_t));
340 both_byte_displs[i] = both_displs[i] *
static_cast<int>(
sizeof(
mesh_int_t));
342 const int local_both_bytes = local_both_count *
static_cast<int>(
sizeof(
mesh_int_t));
343 MPI_Allgatherv(
reinterpret_cast<const unsigned char*
>(vec_both_to_one_face.
data()),
344 local_both_bytes, MPI_BYTE,
345 reinterpret_cast<unsigned char*
>(all_both_to_one.data()),
346 both_byte_counts.data(), both_byte_displs.data(), MPI_BYTE,
347 emi_surfmesh_w_counter_face.
comm);
351 std::vector<std::vector<mesh_int_t>> one_to_both_first(comm_size);
352 std::vector<std::vector<mesh_int_t>> one_to_both_second(comm_size);
353 for (
int r = 0; r < comm_size; r++) {
355 for (
int i = 0; i < both_counts[r]; i++) {
356 mesh_int_t one_idx = all_both_to_one[both_displs[r] + i];
357 if (one_idx > max_one) max_one = one_idx;
359 if (max_one < 0)
continue;
361 one_to_both_first[r].assign(max_one + 1, -1);
362 one_to_both_second[r].assign(max_one + 1, -1);
363 for (
int i = 0; i < both_counts[r]; i++) {
364 mesh_int_t one_idx = all_both_to_one[both_displs[r] + i];
365 if (one_idx < 0)
continue;
366 if (one_to_both_first[r][one_idx] < 0) one_to_both_first[r][one_idx] = i;
367 else one_to_both_second[r][one_idx] = i;
372 for (
const auto& [unique_idx, one_face_pair] : map_elem_uniqueFace_to_elem_oneface) {
373 const auto& first_oneface = one_face_pair.first;
374 const auto& second_oneface = one_face_pair.second;
376 auto map_one_to_both = [&](
const emi_index_rank& one_face_idx,
bool use_second) {
377 emi_index_rank both_face_idx;
378 both_face_idx.index = -1;
379 both_face_idx.rank = -1;
381 if (one_face_idx.rank < 0 || one_face_idx.rank >= comm_size || one_face_idx.index < 0) {
382 return both_face_idx;
384 if (one_face_idx.index >=
static_cast<int>(one_to_both_first[one_face_idx.rank].size())) {
385 return both_face_idx;
388 mesh_int_t both_idx = one_to_both_first[one_face_idx.rank][one_face_idx.index];
390 one_face_idx.index <
static_cast<int>(one_to_both_second[one_face_idx.rank].size()) &&
391 one_to_both_second[one_face_idx.rank][one_face_idx.index] >= 0) {
392 both_idx = one_to_both_second[one_face_idx.rank][one_face_idx.index];
396 both_face_idx.index = both_idx;
397 both_face_idx.rank = one_face_idx.rank;
399 return both_face_idx;
402 const bool same_oneface =
403 (first_oneface.index >= 0 && second_oneface.index >= 0 &&
404 first_oneface.index == second_oneface.index &&
405 first_oneface.rank == second_oneface.rank);
407 map_elem_uniqueFace_to_elem_bothface[unique_idx] = std::make_pair(
408 map_one_to_both(first_oneface,
false),
409 map_one_to_both(second_oneface, same_oneface));
415 operator_unique_to_both_faces->
init(M, M_unique_face, m, m_unique_face, m_l, 1);
416 operator_unique_to_both_faces->
zero();
423 throw std::runtime_error(
424 "EMI unique-face transfer operator currently requires fewer than INT_MAX unique faces");
426 const int M_unique_global =
static_cast<int>(emi_surfmesh_unique_face.
g_numelem);
427 std::vector<int> first_rank(M_unique_global, -1), first_idx(M_unique_global, -1);
428 std::vector<int> second_rank(M_unique_global, -1), second_idx(M_unique_global, -1);
430 for (
const auto& [local_unique_idx, both_pair] : map_elem_uniqueFace_to_elem_bothface) {
431 int global_unique =
static_cast<int>(layout_unique_face[rank] + local_unique_idx);
432 if (global_unique < 0 || global_unique >= M_unique_global)
continue;
434 first_rank[global_unique] =
static_cast<int>(both_pair.first.rank);
435 first_idx[global_unique] =
static_cast<int>(both_pair.first.index);
436 second_rank[global_unique] =
static_cast<int>(both_pair.second.rank);
437 second_idx[global_unique] =
static_cast<int>(both_pair.second.index);
440 MPI_Allreduce(MPI_IN_PLACE, first_rank.data(), M_unique_global, MPI_INT, MPI_MAX, emi_surfmesh_w_counter_face.
comm);
441 MPI_Allreduce(MPI_IN_PLACE, first_idx.data(), M_unique_global, MPI_INT, MPI_MAX, emi_surfmesh_w_counter_face.
comm);
442 MPI_Allreduce(MPI_IN_PLACE, second_rank.data(), M_unique_global, MPI_INT, MPI_MAX, emi_surfmesh_w_counter_face.
comm);
443 MPI_Allreduce(MPI_IN_PLACE, second_idx.data(), M_unique_global, MPI_INT, MPI_MAX, emi_surfmesh_w_counter_face.
comm);
445 auto assemble_unique_to_both = [&]() {
448 ebuff.assign(1, 1, 1.0);
450 for (
int gid = 0; gid < M_unique_global; gid++) {
452 if (first_rank[gid] == rank && first_idx[gid] >= 0) {
453 row_idx[0] =
static_cast<SF_int>(layout[rank] + first_idx[gid]);
454 operator_unique_to_both_faces->
set_values(row_idx, col_idx, ebuff.data(),
false);
456 if (second_rank[gid] == rank && second_idx[gid] >= 0) {
457 row_idx[0] =
static_cast<SF_int>(layout[rank] + second_idx[gid]);
458 operator_unique_to_both_faces->
set_values(row_idx, col_idx, ebuff.data(),
false);
465 assemble_unique_to_both();
468 assemble_unique_to_both();
472 operator_both_to_unique_face->
init(M_unique_face, M, m_unique_face, m, m_unique_face_l, 2);
473 operator_both_to_unique_face->
zero();
475 assemble_map_both_to_unique(*operator_both_to_unique_face,
476 map_elem_uniqueFace_to_elem_bothface,
477 emi_surfmesh_unique_face,
478 emi_surfmesh_w_counter_face);
481 assemble_map_both_to_unique(*operator_both_to_unique_face,
482 map_elem_uniqueFace_to_elem_bothface,
483 emi_surfmesh_unique_face,
484 emi_surfmesh_w_counter_face);
486 #ifdef EMI_DEBUG_MESH
490 mesh_int_t local_valid_first = 0, local_valid_second = 0;
493 SF::layout_from_count<long int>(emi_surfmesh_w_counter_face.
l_numelem, layout_both_dbg, emi_surfmesh_w_counter_face.
comm);
495 SF::layout_from_count<long int>(emi_surfmesh_unique_face.
l_numelem, layout_unique_dbg, emi_surfmesh_unique_face.
comm);
497 for (
const auto& [uidx, both_pair] : map_elem_uniqueFace_to_elem_bothface) {
498 if (both_pair.first.index >= 0) local_valid_first++;
499 if (both_pair.second.index >= 0) local_valid_second++;
501 if (both_pair.first.index >= 0 && both_pair.second.index >= 0 &&
502 both_pair.first.rank >= 0 && both_pair.second.rank >= 0) {
503 mesh_int_t global_first = layout_both_dbg[both_pair.first.rank] + both_pair.first.index;
504 mesh_int_t global_second = layout_both_dbg[both_pair.second.rank] + both_pair.second.index;
505 if (global_first == global_second) local_same_column++;
508 mesh_int_t global_valid_first = local_valid_first;
509 mesh_int_t global_valid_second = local_valid_second;
510 mesh_int_t global_same_column = local_same_column;
511 const MPI_Datatype mesh_mpi_t = opencarp::mpi_datatype<mesh_int_t>();
512 MPI_Allreduce(MPI_IN_PLACE, &global_valid_first, 1, mesh_mpi_t, MPI_SUM, emi_surfmesh_w_counter_face.
comm);
513 MPI_Allreduce(MPI_IN_PLACE, &global_valid_second, 1, mesh_mpi_t, MPI_SUM, emi_surfmesh_w_counter_face.
comm);
514 MPI_Allreduce(MPI_IN_PLACE, &global_same_column, 1, mesh_mpi_t, MPI_SUM, emi_surfmesh_w_counter_face.
comm);
517 MPI_Comm_rank(emi_surfmesh_w_counter_face.
comm, &dbg_rank);
519 log_msg(NULL, 0, 0,
"DEBUG map_unique_to_both: valid_first=%jd valid_second=%jd (global M=%zu, M_unique=%zu)",
522 (
size_t)emi_surfmesh_w_counter_face.
g_numelem,
523 (
size_t)emi_surfmesh_unique_face.
g_numelem);
528 std::vector<char> present(emi_surfmesh_unique_face.
l_numelem, 0);
529 for (
const auto& [uidx, both_pair] : map_elem_uniqueFace_to_elem_bothface) {
530 if (uidx >= 0 && uidx < (
mesh_int_t)present.size()) present[uidx] = 1;
532 std::vector<int> missing;
534 if (!present[i]) missing.push_back((
int)i);
536 int local_missing = (int)missing.size();
537 int comm_size_dbg = 0;
538 MPI_Comm_size(emi_surfmesh_w_counter_face.
comm, &comm_size_dbg);
539 std::vector<int> counts(comm_size_dbg, 0), displs(comm_size_dbg, 0);
540 MPI_Gather(&local_missing, 1, MPI_INT,
541 dbg_rank == 0 ? counts.data() :
nullptr, 1, MPI_INT,
542 0, emi_surfmesh_w_counter_face.
comm);
545 for (
int r = 0; r < comm_size_dbg; r++) {
549 std::vector<int> all_missing(total, -1);
550 MPI_Gatherv(missing.data(), local_missing, MPI_INT,
551 all_missing.data(), counts.data(), displs.data(), MPI_INT,
552 0, emi_surfmesh_w_counter_face.
comm);
555 for (
int r = 0; r < comm_size_dbg; r++) {
556 if (counts[r] == 0) {
561 log_msg(NULL, 0, 0,
"DEBUG unique missing: rank=%d count=%d", r, counts[r]);
562 int to_print = counts[r] < 10 ? counts[r] : 10;
563 for (
int i = 0; i < to_print; i++) {
564 log_msg(NULL, 0, 0,
"DEBUG unique missing: rank=%d local_unique=%d", r, all_missing[offset + i]);
568 if (!any)
log_msg(NULL, 0, 0,
"DEBUG unique missing: none");
570 MPI_Gatherv(missing.data(), local_missing, MPI_INT,
571 nullptr,
nullptr,
nullptr, MPI_INT,
572 0, emi_surfmesh_w_counter_face.
comm);
579 SF::init_vector(&dbg_unique, emi_surfmesh_unique_face, dpn, alg_surface_type);
580 SF::init_vector(&dbg_both, emi_surfmesh_w_counter_face, dpn, alg_surface_type);
581 SF::init_vector(&dbg_back, emi_surfmesh_unique_face, dpn, alg_surface_type);
582 dbg_unique->
set(1.0);
583 operator_unique_to_both_faces->
mult(*dbg_unique, *dbg_both);
584 operator_both_to_unique_face->
mult(*dbg_both, *dbg_back);
590 SF_real err = std::abs(p[i] - 1.0);
591 if (err > local_max_err) local_max_err = err;
592 if (std::abs(p[i] - 0.5) < 1e-12) local_half_count++;
597 MPI_Allreduce(&local_max_err, &global_max_err, 1, opencarp::mpi_datatype<SF_real>(),
598 MPI_MAX, emi_surfmesh_w_counter_face.
comm);
599 global_half_count = local_half_count;
600 MPI_Allreduce(MPI_IN_PLACE, &global_half_count, 1, mesh_mpi_t, MPI_SUM,
601 emi_surfmesh_w_counter_face.
comm);
603 log_msg(NULL, 0, 0,
"DEBUG map_unique_to_both consistency: max_err=%.6e half_count=%jd",
608 const int max_print = 5;
609 const int fields = 9;
610 std::vector<int> local_buf(max_print * fields, -1);
613 for (
const auto& [local_unique_idx, both_pair] : map_elem_uniqueFace_to_elem_bothface) {
614 if (filled >= max_print)
break;
615 const auto& first_both = both_pair.first;
616 const auto& second_both = both_pair.second;
618 const bool first_valid = (first_both.index >= 0 && first_both.rank >= 0);
619 const bool second_valid = (second_both.index >= 0 && second_both.rank >= 0);
620 int count = (first_valid ? 1 : 0) + (second_valid ? 1 : 0);
621 if (
count != 1)
continue;
623 mesh_int_t global_unique = layout_unique_dbg[dbg_rank] + local_unique_idx;
624 mesh_int_t global_first = first_valid ? (layout_both_dbg[first_both.rank] + first_both.index) : -1;
625 mesh_int_t global_second = second_valid ? (layout_both_dbg[second_both.rank] + second_both.index) : -1;
627 int base = filled * fields;
628 local_buf[base + 0] = dbg_rank;
629 local_buf[base + 1] = (int)local_unique_idx;
630 local_buf[base + 2] = (int)global_unique;
631 local_buf[base + 3] = (int)first_both.rank;
632 local_buf[base + 4] = (
int)first_both.index;
633 local_buf[base + 5] = (int)global_first;
634 local_buf[base + 6] = (int)second_both.rank;
635 local_buf[base + 7] = (
int)second_both.index;
636 local_buf[base + 8] = (int)global_second;
641 MPI_Comm_size(emi_surfmesh_w_counter_face.
comm, &comm_size);
642 std::vector<int> all_buf;
643 if (dbg_rank == 0) all_buf.resize(comm_size * max_print * fields, -1);
645 MPI_Gather(local_buf.data(), max_print * fields, MPI_INT,
646 dbg_rank == 0 ? all_buf.data() :
nullptr, max_print * fields, MPI_INT,
647 0, emi_surfmesh_w_counter_face.
comm);
650 for (
int r = 0; r < comm_size; r++) {
651 for (
int i = 0; i < max_print; i++) {
652 int base = (r * max_print + i) * fields;
653 if (all_buf[base + 1] < 0)
continue;
655 "DEBUG map_unique_to_both bad: rank=%d local_unique=%d global_unique=%d "
656 "first(rank=%d idx=%d glob=%d) second(rank=%d idx=%d glob=%d)",
657 all_buf[base + 0], all_buf[base + 1], all_buf[base + 2],
658 all_buf[base + 3], all_buf[base + 4], all_buf[base + 5],
659 all_buf[base + 6], all_buf[base + 7], all_buf[base + 8]);
694 template<
class tuple_key,
class tuple_value,
class tri_key,
class tri_value,
class quad_key,
class quad_value,
class T,
class S>
695 inline void assemble_restrict_operator( abstract_matrix<T,S> & B,
696 abstract_matrix<T,S> & Bi,
697 abstract_matrix<T,S> & BsM,
700 std::pair<mesh_int_t,mesh_int_t>> & map_vertex_tag_to_dof_petsc,
702 std::pair<tuple_value, tuple_value>> & line_face,
704 std::pair<tri_value, tri_value>> & tri_face,
706 std::pair<quad_value, quad_value>> & quad_face,
707 const meshdata<mesh_int_t,mesh_real_t> & surface_mesh,
708 const meshdata<mesh_int_t,mesh_real_t> & emi_mesh,
712 T row_dpn = 1; T col_dpn = 1;
717 for(
size_t i=0; i<rnod_emi.
size(); i++){
718 g2l_emi[rnod_emi[i]] = i;
724 auto find_petsc_index = [&](
const std::pair<mesh_int_t,mesh_int_t>& key) ->
const std::pair<mesh_int_t,mesh_int_t>& {
725 auto it = map_vertex_tag_to_dof_petsc.find(key);
726 if (it == map_vertex_tag_to_dof_petsc.end()) {
727 std::cerr <<
"ERROR: PETSc index not found for vertex=" << key.first
728 <<
" tag=" << key.second << std::endl;
729 throw std::runtime_error(
"PETSc index not found for vertex/tag pair");
744 std::vector<mesh_int_t> elem_nodes;
745 std::vector<mesh_int_t> elem_nodes_old;
746 std::vector<mesh_int_t> petsc_first;
747 std::vector<mesh_int_t> petsc_second;
748 vector<SF::Point> face_coordinates;
756 for(
size_t eidx=0; eidx < surface_mesh.l_numelem; eidx++)
758 T tag = surface_mesh.tag[eidx];
762 elem_nodes_old.clear();
764 petsc_second.clear();
774 for (
int n = surface_mesh.dsp[eidx]; n < surface_mesh.dsp[eidx+1];n++)
776 T l_idx = surface_mesh.con[n];
778 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
779 Index_tag_old = std::make_pair(rnod[l_idx],tag);
780 mesh_int_t Index_new = find_petsc_index(Index_tag_old).first;
781 elem_nodes.push_back(Index_new);
782 elem_nodes_old.push_back(rnod[l_idx]);
785 std::sort(elem_nodes.begin(),elem_nodes.end());
786 if(elem_nodes.size()==2){
789 key.v1 = elem_nodes[0];
790 key.v2 = elem_nodes[1];
791 auto it = line_face.find(key);
792 if (it == line_face.end())
throw std::runtime_error(
"Line interface face not found");
793 const std::pair<tuple_value, tuple_value> & value = it->second;
795 tag_first = value.first.tag;
796 tag_second = value.second.tag;
798 mem_first = value.first.mem;
799 mem_second = value.second.mem;
802 else if(elem_nodes.size()==3){
804 key.v1 = elem_nodes[0];
805 key.v2 = elem_nodes[1];
806 key.v3 = elem_nodes[2];
807 auto it = tri_face.find(key);
808 if (it == tri_face.end())
throw std::runtime_error(
"Triangular interface face not found");
809 const std::pair<tri_value, tri_value> & value = it->second;
811 tag_first = value.first.tag;
812 tag_second = value.second.tag;
814 mem_first = value.first.mem;
815 mem_second = value.second.mem;
818 else if(elem_nodes.size()==4){
820 key.v1 = elem_nodes[0];
821 key.v2 = elem_nodes[1];
822 key.v3 = elem_nodes[2];
823 key.v4 = elem_nodes[3];
824 auto it = quad_face.find(key);
825 if (it == quad_face.end())
throw std::runtime_error(
"Quadrilateral interface face not found");
826 const std::pair<quad_value, quad_value> & value = it->second;
828 tag_first = value.first.tag;
829 tag_second = value.second.tag;
831 mem_first = value.first.mem;
832 mem_second = value.second.mem;
836 if(tag != tag_first) {
837 std::swap(tag_first, tag_second);
838 std::swap(mem_first, mem_second);
841 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
843 for (
size_t indx = 0; indx < elem_nodes_old.size(); ++indx)
845 std::pair <mesh_int_t,mesh_int_t> Index_tag_old_first;
846 Index_tag_old_first = std::make_pair(elem_nodes_old[indx],tag_first);
848 auto it_first = map_vertex_tag_to_dof_petsc.find(Index_tag_old_first);
849 if (it_first == map_vertex_tag_to_dof_petsc.end()) {
850 std::cerr <<
"ERROR: tag_first=" << tag_first <<
" not found for vertex=" << elem_nodes_old[indx] << std::endl;
851 throw std::runtime_error(
"PETSc index not found for first tag");
853 std::pair <mesh_int_t,mesh_int_t> newIndex_petsc_first = it_first->second;
854 mesh_int_t newIndex_first = newIndex_petsc_first.first;
855 petsc_first.push_back(newIndex_petsc_first.second);
857 std::pair <mesh_int_t,mesh_int_t> Index_tag_old_second;
858 Index_tag_old_second = std::make_pair(elem_nodes_old[indx],tag_second);
860 auto it_second = map_vertex_tag_to_dof_petsc.find(Index_tag_old_second);
861 if (it_second == map_vertex_tag_to_dof_petsc.end()) {
862 std::cerr <<
"ERROR: tag_second=" << tag_second <<
" not found for vertex=" << elem_nodes_old[indx] << std::endl;
863 throw std::runtime_error(
"PETSc index not found for counter-face tag");
865 std::pair <mesh_int_t,mesh_int_t> newIndex_petsc_second = it_second->second;
866 mesh_int_t newIndex_second = newIndex_petsc_second.first;
867 petsc_second.push_back(newIndex_petsc_second.second);
870 if(mem_first==1 and elemTag_surface_mesh[eidx]==1)
872 else if (mem_first==2 and tag<tag_second)
876 SF_int nnodes = elem_nodes.size();
877 face_coordinates.resize(nnodes);
879 row_idx.resize(nnodes*row_dpn);
880 row_idx_counter.resize(nnodes*row_dpn);
881 col_idx.resize(nnodes*col_dpn);
882 col_idx_counter.resize(nnodes*col_dpn);
885 for(
SF_int i=0; i<nnodes; i++){
887 for(
short j=0; j<row_dpn; j++){
888 row_idx.data()[i*row_dpn + j] = emi_surfmesh_elem[eidx]*row_dpn;
891 for(
short j=0; j<col_dpn; j++){
892 col_idx[i*col_dpn + j] = (petsc_first[i])*col_dpn + j;
893 col_idx_counter[i*col_dpn + j] = (petsc_second[i])*col_dpn + j;
899 ebuff.
assign(nnodes, nnodes, 0.0);
900 ebuff_s.assign(nnodes, nnodes, 0.0);
902 ebuff_counter.assign(nnodes, nnodes, 0.0);
904 for (
int n = surface_mesh.dsp[eidx], i = 0; n < surface_mesh.dsp[eidx+1];n++,i++)
906 T l_idx = surface_mesh.con[n];
908 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
909 Index_tag_old = std::make_pair(rnod[l_idx],tag);
910 mesh_int_t Index_new = find_petsc_index(Index_tag_old).first;
912 double x = emi_mesh.xyz[g2l_emi[Index_new]*3+0];
913 double y = emi_mesh.xyz[g2l_emi[Index_new]*3+1];
914 double z = emi_mesh.xyz[g2l_emi[Index_new]*3+2];
916 face_coordinates[i].x = x;
917 face_coordinates[i].y = y;
918 face_coordinates[i].z = z;
920 compute_integrate_matrix_barycentric(face_coordinates, nnodes, ebuff, ebuff_s, ebuff_counter, mass_scale);
923 const bool add =
true;
926 Bi.set_values(row_idx, col_idx, ebuff.data(), add);
927 Bi.set_values(row_idx, col_idx_counter, ebuff_counter.data(), add);
930 B.set_values(row_idx, col_idx, ebuff.data(), add);
931 ebuff_counter*=(-
sign);
932 B.set_values(row_idx, col_idx_counter, ebuff_counter.data(), add);
937 for(
SF_int i = 0; i < nnodes; i++) {
938 BsM.set_value(col_idx[i], row_idx[0], ebuff_s[0][i], add);
943 Bi.finish_assembly();
944 BsM.finish_assembly();
967 template<
class tuple_key,
class tuple_value,
class tri_key,
class tri_value,
class quad_key,
class quad_value,
class T,
class S>
968 inline void assemble_lhs_emi(abstract_matrix<T,S> & mat,
969 abstract_matrix<T,S> & mat_surf,
970 const meshdata<mesh_int_t,mesh_real_t> & emi_mesh,
971 const meshdata<mesh_int_t,mesh_real_t> & surface_mesh,
972 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,
974 std::pair<tuple_value, tuple_value>> & line_face,
976 std::pair<tri_value, tri_value>> & tri_face,
978 std::pair<quad_value, quad_value>> & quad_face,
979 matrix_integrator<mesh_int_t,mesh_real_t> & stiffness_integrator,
980 matrix_integrator<mesh_int_t, mesh_real_t> & mass_integrator,
985 T row_dpn = 1; T col_dpn = 1;
995 const vector<mesh_int_t> & stiffness_petsc_nbr = emi_mesh.get_numbering(
NBR_PETSC);
996 element_view<mesh_int_t, mesh_real_t> stiffness_view(emi_mesh,
NBR_PETSC);
999 for(
size_t eidx=0; eidx < emi_mesh.l_numelem; eidx++)
1002 stiffness_view.set_elem(eidx);
1005 mesh_int_t nnodes = stiffness_view.num_nodes();
1007 row_idx.resize(nnodes*row_dpn);
1008 col_idx.resize(nnodes*col_dpn);
1009 canonic_indices<mesh_int_t,SF_int>(stiffness_view.nodes(), stiffness_petsc_nbr.data(), nnodes, row_dpn, row_idx.data());
1010 canonic_indices<mesh_int_t,SF_int>(stiffness_view.nodes(), stiffness_petsc_nbr.data(), nnodes, col_dpn, col_idx.data());
1013 stiffness_integrator(stiffness_view, ebuff);
1014 ebuff *= stiffness_scale;
1017 const bool add =
true;
1018 mat.set_values(row_idx, col_idx, ebuff.data(), add);
1027 auto find_petsc_index = [&](
const std::pair<mesh_int_t,mesh_int_t>& key) ->
const std::pair<mesh_int_t,mesh_int_t>& {
1028 auto it = map_vertex_tag_to_dof_petsc.find(key);
1029 if (it == map_vertex_tag_to_dof_petsc.end()) {
1030 std::cerr <<
"ERROR: PETSc index not found for vertex=" << key.first
1031 <<
" tag=" << key.second << std::endl;
1032 throw std::runtime_error(
"PETSc index not found for vertex/tag pair");
1038 element_view<mesh_int_t, mesh_real_t> view(surface_mesh,
NBR_PETSC);
1039 for(
size_t eidx=0; eidx < surface_mesh.l_numelem; eidx++)
1042 view.set_elem(eidx);
1046 std::vector<mesh_int_t> elem_nodes;
1047 std::vector<mesh_int_t> elem_nodes_old;
1048 std::vector<mesh_int_t> elem_nodes_first;
1049 std::vector<mesh_int_t> elem_nodes_second;
1051 std::vector<mesh_int_t> petsc_first;
1052 std::vector<mesh_int_t> petsc_second;
1057 for (
int n = surface_mesh.dsp[eidx]; n < surface_mesh.dsp[eidx+1];n++)
1059 T l_idx = surface_mesh.con[n];
1061 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1062 Index_tag_old = std::make_pair(rnod[l_idx],tag);
1063 mesh_int_t Index_new = find_petsc_index(Index_tag_old).first;
1064 elem_nodes.push_back(Index_new);
1065 elem_nodes_old.push_back(rnod[l_idx]);
1068 std::sort(elem_nodes.begin(),elem_nodes.end());
1069 if(elem_nodes.size()==2){
1072 key.v1 = elem_nodes[0];
1073 key.v2 = elem_nodes[1];
1074 auto it = line_face.find(key);
1075 if (it == line_face.end())
throw std::runtime_error(
"Line interface face not found");
1076 const std::pair<tuple_value, tuple_value> & value = it->second;
1078 tag_first = value.first.tag;
1079 tag_second = value.second.tag;
1081 else if(elem_nodes.size()==3){
1083 key.v1 = elem_nodes[0];
1084 key.v2 = elem_nodes[1];
1085 key.v3 = elem_nodes[2];
1086 auto it = tri_face.find(key);
1087 if (it == tri_face.end())
throw std::runtime_error(
"Triangular interface face not found");
1088 const std::pair<tri_value, tri_value> & value = it->second;
1090 tag_first = value.first.tag;
1091 tag_second = value.second.tag;
1093 else if(elem_nodes.size()==4){
1095 key.v1 = elem_nodes[0];
1096 key.v2 = elem_nodes[1];
1097 key.v3 = elem_nodes[2];
1098 key.v4 = elem_nodes[3];
1099 auto it = quad_face.find(key);
1100 if (it == quad_face.end())
throw std::runtime_error(
"Quadrilateral interface face not found");
1101 const std::pair<quad_value, quad_value> & value = it->second;
1103 tag_first = value.first.tag;
1104 tag_second = value.second.tag;
1107 if(tag != tag_first) std::swap(tag_first, tag_second);
1109 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1111 for (
size_t indx = 0; indx < elem_nodes_old.size(); ++indx)
1113 std::pair <mesh_int_t,mesh_int_t> Index_tag_old_first;
1114 Index_tag_old_first = std::make_pair(elem_nodes_old[indx],tag_first);
1115 std::pair <mesh_int_t,mesh_int_t> newIndex_petsc_first = find_petsc_index(Index_tag_old_first);
1116 mesh_int_t newIndex_first = newIndex_petsc_first.first;
1117 petsc_first.push_back(newIndex_petsc_first.second);
1119 std::pair <mesh_int_t,mesh_int_t> Index_tag_old_second;
1120 Index_tag_old_second = std::make_pair(elem_nodes_old[indx],tag_second);
1121 std::pair <mesh_int_t,mesh_int_t> newIndex_petsc_second = find_petsc_index(Index_tag_old_second);
1122 mesh_int_t newIndex_second = newIndex_petsc_second.first;
1123 petsc_second.push_back(newIndex_petsc_second.second);
1127 SF_int nnodes = view.num_nodes();
1128 idx.resize(nnodes*row_dpn);
1129 idx_counter.resize(nnodes*col_dpn);
1132 for(T i=0; i<nnodes; i++)
1134 for(
short j=0; j<row_dpn; j++){
1135 idx[i*row_dpn + j] = (petsc_first[i])*row_dpn + j;
1137 for(
short j=0; j<col_dpn; j++){
1138 idx_counter[i*col_dpn + j] = (petsc_second[i])*col_dpn + j;
1144 const bool add =
true;
1147 mass_integrator(view, ebuff);
1148 ebuff_mass.assign(nnodes, nnodes, 0.0);
1152 ebuff*=0.5 * mass_scale;
1155 mat.set_values(idx, idx, ebuff.data(), add);
1156 mat.set_values(idx_counter, idx_counter, ebuff.data(), add);
1158 mat_surf.set_values(idx, idx, ebuff_mass.data(), add);
1159 mat_surf.set_values(idx_counter, idx_counter, ebuff_mass.data(), add);
1164 mat.set_values(idx, idx_counter, ebuff.data(), add);
1165 mat.set_values(idx_counter, idx, ebuff.data(), add);
1167 mat_surf.set_values(idx, idx_counter, ebuff_mass.data(), add);
1168 mat_surf.set_values(idx_counter, idx, ebuff_mass.data(), add);
1180 mat.finish_assembly();
1181 mat_surf.finish_assembly();
1202 template<
class tuple_key,
class tuple_value,
class tri_key,
class tri_value,
class quad_key,
class quad_value,
class T,
class S>
1203 inline void assign_resting_potential_from_ionic_models_on_myocyte(abstract_vector<T,S> & ui,
1204 abstract_vector<T, S>* vb,
1207 std::pair<T,T>> & map_vertex_tag_to_dof_petsc,
1209 std::pair<tuple_value, tuple_value>> & line_face,
1211 std::pair<tri_value, tri_value>> & tri_face,
1213 std::pair<quad_value, quad_value>> & quad_face,
1214 const meshdata<T,mesh_real_t> & surface_mesh,
1215 const meshdata<T,mesh_real_t> & emi_mesh)
1223 auto find_petsc_index = [&](
const std::pair<T,T>& key) ->
const std::pair<T,T>& {
1224 auto it = map_vertex_tag_to_dof_petsc.
find(key);
1225 if (it == map_vertex_tag_to_dof_petsc.end()) {
1226 std::cerr <<
"ERROR: PETSc index not found for vertex=" << key.first
1227 <<
" tag=" << key.second << std::endl;
1228 throw std::runtime_error(
"PETSc index not found for vertex/tag pair");
1233 auto vb_data = vb->const_ptr();
1236 for(
size_t eidx=0; eidx < surface_mesh.l_numelem; eidx++)
1238 T tag = surface_mesh.tag[eidx];
1241 std::vector<mesh_int_t> elem_nodes;
1247 for (
int n = surface_mesh.dsp[eidx], i = 0; n < surface_mesh.dsp[eidx+1];n++,i++)
1249 T l_idx = surface_mesh.con[n];
1250 std::pair <T,T> Index_tag_old;
1251 Index_tag_old = std::make_pair(rnod[l_idx],tag);
1252 mesh_int_t Index_new = find_petsc_index(Index_tag_old).first;
1253 elem_nodes.push_back(Index_new);
1256 std::sort(elem_nodes.begin(),elem_nodes.end());
1257 if(elem_nodes.size()==2){
1260 key.v1 = elem_nodes[0];
1261 key.v2 = elem_nodes[1];
1262 auto it = line_face.find(key);
1263 if (it == line_face.end())
throw std::runtime_error(
"Line interface face not found");
1264 const std::pair<tuple_value, tuple_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()==3){
1274 key.v1 = elem_nodes[0];
1275 key.v2 = elem_nodes[1];
1276 key.v3 = elem_nodes[2];
1277 auto it = tri_face.find(key);
1278 if (it == tri_face.end())
throw std::runtime_error(
"Triangular interface face not found");
1279 const std::pair<tri_value, tri_value> & value = it->second;
1281 tag_first = value.first.tag;
1282 tag_second = value.second.tag;
1284 mem_first = value.first.mem;
1285 mem_second = value.second.mem;
1287 else if(elem_nodes.size()==4){
1289 key.v1 = elem_nodes[0];
1290 key.v2 = elem_nodes[1];
1291 key.v3 = elem_nodes[2];
1292 key.v4 = elem_nodes[3];
1293 auto it = quad_face.find(key);
1294 if (it == quad_face.end())
throw std::runtime_error(
"Quadrilateral interface face not found");
1295 const std::pair<quad_value, quad_value> & value = it->second;
1297 tag_first = value.first.tag;
1298 tag_second = value.second.tag;
1300 mem_first = value.first.mem;
1301 mem_second = value.second.mem;
1304 SF_int nnodes = elem_nodes.size();
1305 for (
int i = 0; i < nnodes; ++i)
1307 if(mem_first==1 || mem_second==1){
1308 tag_2_vm[tag_first] = vb_data[eidx];
1309 tag_2_vm[tag_second] = vb_data[eidx];
1314 vb->const_release_ptr(vb_data);
1321 const vector<mesh_int_t> & petsc_nbr = emi_mesh.get_numbering(
NBR_PETSC);
1322 T start = 0, stop = 0;
1323 ui.get_ownership_range(start, stop);
1325 S* ui_data = ui.ptr();
1327 element_view<mesh_int_t, mesh_real_t> view(emi_mesh,
NBR_PETSC);
1328 for(
size_t eidx=0; eidx < emi_mesh.l_numelem; eidx++)
1330 view.set_elem(eidx);
1331 T tag = emi_mesh.tag[eidx];
1334 row_idx.resize(nnodes*row_dpn);
1335 canonic_indices<mesh_int_t,SF_int>(view.nodes(), petsc_nbr.data(), nnodes, row_dpn, row_idx.data());
1337 for (
int i = 0; i < nnodes; ++i)
1340 if(elemTag_emi_mesh[eidx]==2){
1341 if(row_idx[i] >= start && row_idx[i] < stop) {
1342 auto vm_it = tag_2_vm.
find(tag);
1343 if (vm_it != tag_2_vm.
end()) ui_data[row_idx[i] - start] = vm_it->second;
1348 ui.release_ptr(ui_data);
1349 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)