41 #include <type_traits>
57 Point edge1 = p2 - p1;
58 Point edge2 = p3 - p1;
64 double crossProductMagnitude =
mag(crossProduct);
66 return 0.5 * crossProductMagnitude;
79 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 & lengthSquared)
85 double lambda2 =
inner_prod(v, d) / lengthSquared;
86 double lambda1 = 1.0 - lambda2;
88 interpolationCoefficients[0] = lambda1;
89 interpolationCoefficients[1] = lambda2;
103 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)
106 area = computeTriangleArea(p1, p2, p3);
121 double denom = d00 * d11 - d01 * d01;
122 double beta = (d11 * d20 - d01 * d21) / denom;
123 double gamma = (d00 * d21 - d01 * d20) / denom;
124 double alpha = 1.0 - beta - gamma;
125 interpolationCoefficients[0] = alpha;
126 interpolationCoefficients[1] = beta;
127 interpolationCoefficients[2] = gamma;
143 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)
146 double area1 = computeTriangleArea(p1, p2, p4);
147 double area2 = computeTriangleArea(p2, p3, p4);
148 area = area1 + area2;
165 interpolationCoefficients[0] = (1 - u) * (1 - v);
166 interpolationCoefficients[1] = u * (1 - v);
167 interpolationCoefficients[2] = u * v;
168 interpolationCoefficients[3] = (1 - u) * v;
183 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)
189 for (
int i = 0; i < nnodes; ++i)
191 x += face_coordinates[i].x;
192 y += face_coordinates[i].y;
193 z += face_coordinates[i].z;
195 SF::Point b; b.
x = x/nnodes; b.
y = y/nnodes; b.
z = z/nnodes;
197 std::array<double, SF_MAX_ELEM_NODES> interpolationCoefficients{};
198 double area, weighted_area;
200 compute_barycentric_coordinates_coefficients(face_coordinates[0], face_coordinates[1], b, interpolationCoefficients, area);
204 compute_barycentric_coordinates_coefficients(face_coordinates[0], face_coordinates[1], face_coordinates[2], b, interpolationCoefficients, area);
207 compute_barycentric_coordinates_coefficients(face_coordinates[0], face_coordinates[1], face_coordinates[2], face_coordinates[3], b, interpolationCoefficients, area);
210 weighted_area = area/nnodes;
213 ebuff[0][0] = interpolationCoefficients[0];
214 ebuff[0][1] = interpolationCoefficients[1];
216 ebuff_counter[0][0] = interpolationCoefficients[0];
217 ebuff_counter[0][1] = interpolationCoefficients[1];
219 ebuff_s[0][0] = mass_scale*weighted_area;
220 ebuff_s[0][1] = mass_scale*weighted_area;
223 ebuff[0][0] = interpolationCoefficients[0];
224 ebuff[0][1] = interpolationCoefficients[1];
225 ebuff[0][2] = interpolationCoefficients[2];
227 ebuff_counter[0][0] = interpolationCoefficients[0];
228 ebuff_counter[0][1] = interpolationCoefficients[1];
229 ebuff_counter[0][2] = interpolationCoefficients[2];
231 ebuff_s[0][0] = mass_scale*weighted_area;
232 ebuff_s[0][1] = mass_scale*weighted_area;
233 ebuff_s[0][2] = mass_scale*weighted_area;
236 ebuff[0][0] = interpolationCoefficients[0];
237 ebuff[0][1] = interpolationCoefficients[1];
238 ebuff[0][2] = interpolationCoefficients[2];
239 ebuff[0][3] = interpolationCoefficients[3];
241 ebuff_counter[0][0] = interpolationCoefficients[0];
242 ebuff_counter[0][1] = interpolationCoefficients[1];
243 ebuff_counter[0][2] = interpolationCoefficients[2];
244 ebuff_counter[0][3] = interpolationCoefficients[3];
246 ebuff_s[0][0] = mass_scale*weighted_area;
247 ebuff_s[0][1] = mass_scale*weighted_area;
248 ebuff_s[0][2] = mass_scale*weighted_area;
249 ebuff_s[0][3] = mass_scale*weighted_area;
285 template<
class T,
class S,
class emi_index_rank>
286 inline void construct_direct_unique_both_operators(
294 int max_row_entries_emi,
299 T M = emi_surfmesh_w_counter_face.
g_numelem;
300 T m = emi_surfmesh_w_counter_face.
l_numelem;
301 T M_unique_face = emi_surfmesh_unique_face.
g_numelem;
302 T m_unique_face = emi_surfmesh_unique_face.
l_numelem;
306 MPI_Comm_rank(emi_surfmesh_w_counter_face.
comm, &rank);
307 MPI_Comm_size(emi_surfmesh_w_counter_face.
comm, &comm_size);
310 SF::layout_from_count<long int>(emi_surfmesh_w_counter_face.
l_numelem, layout, emi_surfmesh_w_counter_face.
comm);
311 T m_l = layout[rank];
314 SF::layout_from_count<long int>(emi_surfmesh_unique_face.
l_numelem, layout_unique_face, emi_surfmesh_unique_face.
comm);
315 T m_unique_face_l = layout_unique_face[rank];
318 map_elem_uniqueFace_to_elem_bothface.clear();
322 std::vector<int> both_counts(comm_size, 0), both_displs(comm_size, 0);
323 int local_both_count =
static_cast<int>(vec_both_to_one_face.
size());
324 MPI_Allgather(&local_both_count, 1, MPI_INT, both_counts.data(), 1, MPI_INT,
325 emi_surfmesh_w_counter_face.
comm);
327 int total_both_count = 0;
328 for (
int i = 0; i < comm_size; i++) {
329 both_displs[i] = total_both_count;
330 total_both_count += both_counts[i];
333 std::vector<mesh_int_t> all_both_to_one(total_both_count);
336 std::vector<int> both_byte_counts(comm_size, 0), both_byte_displs(comm_size, 0);
337 for (
int i = 0; i < comm_size; i++) {
338 both_byte_counts[i] = both_counts[i] *
static_cast<int>(
sizeof(
mesh_int_t));
339 both_byte_displs[i] = both_displs[i] *
static_cast<int>(
sizeof(
mesh_int_t));
341 const int local_both_bytes = local_both_count *
static_cast<int>(
sizeof(
mesh_int_t));
342 MPI_Allgatherv(
reinterpret_cast<const unsigned char*
>(vec_both_to_one_face.
data()),
343 local_both_bytes, MPI_BYTE,
344 reinterpret_cast<unsigned char*
>(all_both_to_one.data()),
345 both_byte_counts.data(), both_byte_displs.data(), MPI_BYTE,
346 emi_surfmesh_w_counter_face.
comm);
350 std::vector<std::vector<mesh_int_t>> one_to_both_first(comm_size);
351 std::vector<std::vector<mesh_int_t>> one_to_both_second(comm_size);
352 for (
int r = 0; r < comm_size; r++) {
354 for (
int i = 0; i < both_counts[r]; i++) {
355 mesh_int_t one_idx = all_both_to_one[both_displs[r] + i];
356 if (one_idx > max_one) max_one = one_idx;
358 if (max_one < 0)
continue;
360 one_to_both_first[r].assign(max_one + 1, -1);
361 one_to_both_second[r].assign(max_one + 1, -1);
362 for (
int i = 0; i < both_counts[r]; i++) {
363 mesh_int_t one_idx = all_both_to_one[both_displs[r] + i];
364 if (one_idx < 0)
continue;
365 if (one_to_both_first[r][one_idx] < 0) one_to_both_first[r][one_idx] = i;
366 else one_to_both_second[r][one_idx] = i;
371 for (
const auto& [unique_idx, one_face_pair] : map_elem_uniqueFace_to_elem_oneface) {
372 const auto& first_oneface = one_face_pair.first;
373 const auto& second_oneface = one_face_pair.second;
375 auto map_one_to_both = [&](
const emi_index_rank& one_face_idx,
bool use_second) {
376 emi_index_rank both_face_idx;
377 both_face_idx.index = -1;
378 both_face_idx.rank = -1;
380 if (one_face_idx.rank < 0 || one_face_idx.rank >= comm_size || one_face_idx.index < 0) {
381 return both_face_idx;
383 if (one_face_idx.index >=
static_cast<int>(one_to_both_first[one_face_idx.rank].size())) {
384 return both_face_idx;
387 mesh_int_t both_idx = one_to_both_first[one_face_idx.rank][one_face_idx.index];
389 one_face_idx.index <
static_cast<int>(one_to_both_second[one_face_idx.rank].size()) &&
390 one_to_both_second[one_face_idx.rank][one_face_idx.index] >= 0) {
391 both_idx = one_to_both_second[one_face_idx.rank][one_face_idx.index];
395 both_face_idx.index = both_idx;
396 both_face_idx.rank = one_face_idx.rank;
398 return both_face_idx;
401 const bool same_oneface =
402 (first_oneface.index >= 0 && second_oneface.index >= 0 &&
403 first_oneface.index == second_oneface.index &&
404 first_oneface.rank == second_oneface.rank);
406 map_elem_uniqueFace_to_elem_bothface[unique_idx] = std::make_pair(
407 map_one_to_both(first_oneface,
false),
408 map_one_to_both(second_oneface, same_oneface));
414 operator_unique_to_both_faces->
init(M, M_unique_face, m, m_unique_face, m_l, 1);
415 operator_unique_to_both_faces->
zero();
422 throw std::runtime_error(
423 "EMI unique-face transfer operator currently requires fewer than INT_MAX unique faces");
425 const int M_unique_global =
static_cast<int>(emi_surfmesh_unique_face.
g_numelem);
426 std::vector<int> first_rank(M_unique_global, -1), first_idx(M_unique_global, -1);
427 std::vector<int> second_rank(M_unique_global, -1), second_idx(M_unique_global, -1);
429 for (
const auto& [local_unique_idx, both_pair] : map_elem_uniqueFace_to_elem_bothface) {
430 int global_unique =
static_cast<int>(layout_unique_face[rank] + local_unique_idx);
431 if (global_unique < 0 || global_unique >= M_unique_global)
continue;
433 first_rank[global_unique] =
static_cast<int>(both_pair.first.rank);
434 first_idx[global_unique] =
static_cast<int>(both_pair.first.index);
435 second_rank[global_unique] =
static_cast<int>(both_pair.second.rank);
436 second_idx[global_unique] =
static_cast<int>(both_pair.second.index);
439 MPI_Allreduce(MPI_IN_PLACE, first_rank.data(), M_unique_global, MPI_INT, MPI_MAX, emi_surfmesh_w_counter_face.
comm);
440 MPI_Allreduce(MPI_IN_PLACE, first_idx.data(), M_unique_global, MPI_INT, MPI_MAX, emi_surfmesh_w_counter_face.
comm);
441 MPI_Allreduce(MPI_IN_PLACE, second_rank.data(), M_unique_global, MPI_INT, MPI_MAX, emi_surfmesh_w_counter_face.
comm);
442 MPI_Allreduce(MPI_IN_PLACE, second_idx.data(), M_unique_global, MPI_INT, MPI_MAX, emi_surfmesh_w_counter_face.
comm);
444 auto assemble_unique_to_both = [&]() {
447 ebuff.assign(1, 1, 1.0);
449 for (
int gid = 0; gid < M_unique_global; gid++) {
451 if (first_rank[gid] == rank && first_idx[gid] >= 0) {
452 row_idx[0] =
static_cast<SF_int>(layout[rank] + first_idx[gid]);
453 operator_unique_to_both_faces->
set_values(row_idx, col_idx, ebuff.data(),
false);
455 if (second_rank[gid] == rank && second_idx[gid] >= 0) {
456 row_idx[0] =
static_cast<SF_int>(layout[rank] + second_idx[gid]);
457 operator_unique_to_both_faces->
set_values(row_idx, col_idx, ebuff.data(),
false);
464 assemble_unique_to_both();
467 assemble_unique_to_both();
471 operator_both_to_unique_face->
init(M_unique_face, M, m_unique_face, m, m_unique_face_l, 2);
472 operator_both_to_unique_face->
zero();
474 assemble_map_both_to_unique(*operator_both_to_unique_face,
475 map_elem_uniqueFace_to_elem_bothface,
476 emi_surfmesh_unique_face,
477 emi_surfmesh_w_counter_face);
480 assemble_map_both_to_unique(*operator_both_to_unique_face,
481 map_elem_uniqueFace_to_elem_bothface,
482 emi_surfmesh_unique_face,
483 emi_surfmesh_w_counter_face);
485 #ifdef EMI_DEBUG_MESH
489 mesh_int_t local_valid_first = 0, local_valid_second = 0;
492 SF::layout_from_count<long int>(emi_surfmesh_w_counter_face.
l_numelem, layout_both_dbg, emi_surfmesh_w_counter_face.
comm);
494 SF::layout_from_count<long int>(emi_surfmesh_unique_face.
l_numelem, layout_unique_dbg, emi_surfmesh_unique_face.
comm);
496 for (
const auto& [uidx, both_pair] : map_elem_uniqueFace_to_elem_bothface) {
497 if (both_pair.first.index >= 0) local_valid_first++;
498 if (both_pair.second.index >= 0) local_valid_second++;
500 if (both_pair.first.index >= 0 && both_pair.second.index >= 0 &&
501 both_pair.first.rank >= 0 && both_pair.second.rank >= 0) {
502 mesh_int_t global_first = layout_both_dbg[both_pair.first.rank] + both_pair.first.index;
503 mesh_int_t global_second = layout_both_dbg[both_pair.second.rank] + both_pair.second.index;
504 if (global_first == global_second) local_same_column++;
507 mesh_int_t global_valid_first = local_valid_first;
508 mesh_int_t global_valid_second = local_valid_second;
509 mesh_int_t global_same_column = local_same_column;
510 const MPI_Datatype mesh_mpi_t = opencarp::mpi_datatype<mesh_int_t>();
511 MPI_Allreduce(MPI_IN_PLACE, &global_valid_first, 1, mesh_mpi_t, MPI_SUM, emi_surfmesh_w_counter_face.
comm);
512 MPI_Allreduce(MPI_IN_PLACE, &global_valid_second, 1, mesh_mpi_t, MPI_SUM, emi_surfmesh_w_counter_face.
comm);
513 MPI_Allreduce(MPI_IN_PLACE, &global_same_column, 1, mesh_mpi_t, MPI_SUM, emi_surfmesh_w_counter_face.
comm);
516 MPI_Comm_rank(emi_surfmesh_w_counter_face.
comm, &dbg_rank);
518 log_msg(NULL, 0, 0,
"DEBUG map_unique_to_both: valid_first=%jd valid_second=%jd (global M=%zu, M_unique=%zu)",
521 (
size_t)emi_surfmesh_w_counter_face.
g_numelem,
522 (
size_t)emi_surfmesh_unique_face.
g_numelem);
527 std::vector<char> present(emi_surfmesh_unique_face.
l_numelem, 0);
528 for (
const auto& [uidx, both_pair] : map_elem_uniqueFace_to_elem_bothface) {
529 if (uidx >= 0 && uidx < (
mesh_int_t)present.size()) present[uidx] = 1;
531 std::vector<int> missing;
533 if (!present[i]) missing.push_back((
int)i);
535 int local_missing = (int)missing.size();
536 int comm_size_dbg = 0;
537 MPI_Comm_size(emi_surfmesh_w_counter_face.
comm, &comm_size_dbg);
538 std::vector<int> counts(comm_size_dbg, 0), displs(comm_size_dbg, 0);
539 MPI_Gather(&local_missing, 1, MPI_INT,
540 dbg_rank == 0 ? counts.data() :
nullptr, 1, MPI_INT,
541 0, emi_surfmesh_w_counter_face.
comm);
544 for (
int r = 0; r < comm_size_dbg; r++) {
548 std::vector<int> all_missing(total, -1);
549 MPI_Gatherv(missing.data(), local_missing, MPI_INT,
550 all_missing.data(), counts.data(), displs.data(), MPI_INT,
551 0, emi_surfmesh_w_counter_face.
comm);
554 for (
int r = 0; r < comm_size_dbg; r++) {
555 if (counts[r] == 0) {
560 log_msg(NULL, 0, 0,
"DEBUG unique missing: rank=%d count=%d", r, counts[r]);
561 int to_print = counts[r] < 10 ? counts[r] : 10;
562 for (
int i = 0; i < to_print; i++) {
563 log_msg(NULL, 0, 0,
"DEBUG unique missing: rank=%d local_unique=%d", r, all_missing[offset + i]);
567 if (!any)
log_msg(NULL, 0, 0,
"DEBUG unique missing: none");
569 MPI_Gatherv(missing.data(), local_missing, MPI_INT,
570 nullptr,
nullptr,
nullptr, MPI_INT,
571 0, emi_surfmesh_w_counter_face.
comm);
578 SF::init_vector(&dbg_unique, emi_surfmesh_unique_face, dpn, alg_surface_type);
579 SF::init_vector(&dbg_both, emi_surfmesh_w_counter_face, dpn, alg_surface_type);
580 SF::init_vector(&dbg_back, emi_surfmesh_unique_face, dpn, alg_surface_type);
581 dbg_unique->
set(1.0);
582 operator_unique_to_both_faces->
mult(*dbg_unique, *dbg_both);
583 operator_both_to_unique_face->
mult(*dbg_both, *dbg_back);
589 SF_real err = std::abs(p[i] - 1.0);
590 if (err > local_max_err) local_max_err = err;
591 if (std::abs(p[i] - 0.5) < 1e-12) local_half_count++;
596 MPI_Allreduce(&local_max_err, &global_max_err, 1, opencarp::mpi_datatype<SF_real>(),
597 MPI_MAX, emi_surfmesh_w_counter_face.
comm);
598 global_half_count = local_half_count;
599 MPI_Allreduce(MPI_IN_PLACE, &global_half_count, 1, mesh_mpi_t, MPI_SUM,
600 emi_surfmesh_w_counter_face.
comm);
602 log_msg(NULL, 0, 0,
"DEBUG map_unique_to_both consistency: max_err=%.6e half_count=%jd",
607 const int max_print = 5;
608 const int fields = 9;
609 std::vector<int> local_buf(max_print * fields, -1);
612 for (
const auto& [local_unique_idx, both_pair] : map_elem_uniqueFace_to_elem_bothface) {
613 if (filled >= max_print)
break;
614 const auto& first_both = both_pair.first;
615 const auto& second_both = both_pair.second;
617 const bool first_valid = (first_both.index >= 0 && first_both.rank >= 0);
618 const bool second_valid = (second_both.index >= 0 && second_both.rank >= 0);
619 int count = (first_valid ? 1 : 0) + (second_valid ? 1 : 0);
620 if (
count != 1)
continue;
622 mesh_int_t global_unique = layout_unique_dbg[dbg_rank] + local_unique_idx;
623 mesh_int_t global_first = first_valid ? (layout_both_dbg[first_both.rank] + first_both.index) : -1;
624 mesh_int_t global_second = second_valid ? (layout_both_dbg[second_both.rank] + second_both.index) : -1;
626 int base = filled * fields;
627 local_buf[base + 0] = dbg_rank;
628 local_buf[base + 1] = (int)local_unique_idx;
629 local_buf[base + 2] = (int)global_unique;
630 local_buf[base + 3] = (int)first_both.rank;
631 local_buf[base + 4] = (
int)first_both.index;
632 local_buf[base + 5] = (int)global_first;
633 local_buf[base + 6] = (int)second_both.rank;
634 local_buf[base + 7] = (
int)second_both.index;
635 local_buf[base + 8] = (int)global_second;
640 MPI_Comm_size(emi_surfmesh_w_counter_face.
comm, &comm_size);
641 std::vector<int> all_buf;
642 if (dbg_rank == 0) all_buf.resize(comm_size * max_print * fields, -1);
644 MPI_Gather(local_buf.data(), max_print * fields, MPI_INT,
645 dbg_rank == 0 ? all_buf.data() :
nullptr, max_print * fields, MPI_INT,
646 0, emi_surfmesh_w_counter_face.
comm);
649 for (
int r = 0; r < comm_size; r++) {
650 for (
int i = 0; i < max_print; i++) {
651 int base = (r * max_print + i) * fields;
652 if (all_buf[base + 1] < 0)
continue;
654 "DEBUG map_unique_to_both bad: rank=%d local_unique=%d global_unique=%d "
655 "first(rank=%d idx=%d glob=%d) second(rank=%d idx=%d glob=%d)",
656 all_buf[base + 0], all_buf[base + 1], all_buf[base + 2],
657 all_buf[base + 3], all_buf[base + 4], all_buf[base + 5],
658 all_buf[base + 6], all_buf[base + 7], all_buf[base + 8]);
693 template<
class tuple_key,
class tuple_value,
class tri_key,
class tri_value,
class quad_key,
class quad_value,
class T,
class S>
694 inline void assemble_restrict_operator( abstract_matrix<T,S> & B,
695 abstract_matrix<T,S> & Bi,
696 abstract_matrix<T,S> & BsM,
699 std::pair<mesh_int_t,mesh_int_t>> & map_vertex_tag_to_dof_petsc,
701 std::pair<tuple_value, tuple_value>> & line_face,
703 std::pair<tri_value, tri_value>> & tri_face,
705 std::pair<quad_value, quad_value>> & quad_face,
706 const meshdata<mesh_int_t,mesh_real_t> & surface_mesh,
707 const meshdata<mesh_int_t,mesh_real_t> & emi_mesh,
711 T row_dpn = 1; T col_dpn = 1;
716 for(
size_t i=0; i<rnod_emi.
size(); i++){
717 g2l_emi[rnod_emi[i]] = i;
723 auto find_petsc_index = [&](
const std::pair<mesh_int_t,mesh_int_t>& key) ->
const std::pair<mesh_int_t,mesh_int_t>& {
724 auto it = map_vertex_tag_to_dof_petsc.find(key);
725 if (it == map_vertex_tag_to_dof_petsc.end()) {
726 std::cerr <<
"ERROR: PETSc index not found for vertex=" << key.first
727 <<
" tag=" << key.second << std::endl;
728 throw std::runtime_error(
"PETSc index not found for vertex/tag pair");
743 std::vector<mesh_int_t> elem_nodes;
744 std::vector<mesh_int_t> elem_nodes_old;
745 std::vector<mesh_int_t> petsc_first;
746 std::vector<mesh_int_t> petsc_second;
747 vector<SF::Point> face_coordinates;
755 for(
size_t eidx=0; eidx < surface_mesh.l_numelem; eidx++)
757 T tag = surface_mesh.tag[eidx];
761 elem_nodes_old.clear();
763 petsc_second.clear();
776 for (
int n = surface_mesh.dsp[eidx]; n < surface_mesh.dsp[eidx+1];n++)
778 T l_idx = surface_mesh.con[n];
780 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
781 Index_tag_old = std::make_pair(rnod[l_idx],tag);
782 mesh_int_t Index_new = find_petsc_index(Index_tag_old).first;
783 elem_nodes.push_back(Index_new);
784 elem_nodes_old.push_back(rnod[l_idx]);
787 std::sort(elem_nodes.begin(),elem_nodes.end());
788 if(elem_nodes.size()==2){
791 key.v1 = elem_nodes[0];
792 key.v2 = elem_nodes[1];
793 auto it = line_face.find(key);
794 if (it == line_face.end())
throw std::runtime_error(
"Line interface face not found");
795 const std::pair<tuple_value, tuple_value> & value = it->second;
797 tag_first = value.first.tag;
798 tag_second = value.second.tag;
800 rank_first = value.first.rank;
801 rank_second = value.second.rank;
803 mem_first = value.first.mem;
804 mem_second = value.second.mem;
807 else if(elem_nodes.size()==3){
809 key.v1 = elem_nodes[0];
810 key.v2 = elem_nodes[1];
811 key.v3 = elem_nodes[2];
812 auto it = tri_face.find(key);
813 if (it == tri_face.end())
throw std::runtime_error(
"Triangular interface face not found");
814 const std::pair<tri_value, tri_value> & value = it->second;
816 tag_first = value.first.tag;
817 tag_second = value.second.tag;
819 rank_first = value.first.rank;
820 rank_second = value.second.rank;
822 mem_first = value.first.mem;
823 mem_second = value.second.mem;
826 else if(elem_nodes.size()==4){
828 key.v1 = elem_nodes[0];
829 key.v2 = elem_nodes[1];
830 key.v3 = elem_nodes[2];
831 key.v4 = elem_nodes[3];
832 auto it = quad_face.find(key);
833 if (it == quad_face.end())
throw std::runtime_error(
"Quadrilateral interface face not found");
834 const std::pair<quad_value, quad_value> & value = it->second;
836 tag_first = value.first.tag;
837 tag_second = value.second.tag;
839 rank_first = value.first.rank;
840 rank_second = value.second.rank;
842 mem_first = value.first.mem;
843 mem_second = value.second.mem;
847 if(tag != tag_first) std::swap(tag_first, tag_second);
849 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
851 for (
size_t indx = 0; indx < elem_nodes_old.size(); ++indx)
853 std::pair <mesh_int_t,mesh_int_t> Index_tag_old_first;
854 Index_tag_old_first = std::make_pair(elem_nodes_old[indx],tag_first);
856 auto it_first = map_vertex_tag_to_dof_petsc.find(Index_tag_old_first);
857 if (it_first == map_vertex_tag_to_dof_petsc.end()) {
858 std::cerr <<
"ERROR: tag_first=" << tag_first <<
" not found for vertex=" << elem_nodes_old[indx] << std::endl;
859 throw std::runtime_error(
"PETSc index not found for first tag");
861 std::pair <mesh_int_t,mesh_int_t> newIndex_petsc_first = it_first->second;
862 mesh_int_t newIndex_first = newIndex_petsc_first.first;
863 petsc_first.push_back(newIndex_petsc_first.second);
865 std::pair <mesh_int_t,mesh_int_t> Index_tag_old_second;
866 Index_tag_old_second = std::make_pair(elem_nodes_old[indx],tag_second);
868 auto it_second = map_vertex_tag_to_dof_petsc.find(Index_tag_old_second);
869 if (it_second == map_vertex_tag_to_dof_petsc.end()) {
870 std::cerr <<
"ERROR: tag_second=" << tag_second <<
" not found for vertex=" << elem_nodes_old[indx] << std::endl;
871 throw std::runtime_error(
"PETSc index not found for counter-face tag");
873 std::pair <mesh_int_t,mesh_int_t> newIndex_petsc_second = it_second->second;
874 mesh_int_t newIndex_second = newIndex_petsc_second.first;
875 petsc_second.push_back(newIndex_petsc_second.second);
878 if(mem_first==1 and elemTag_surface_mesh[eidx]==1)
880 else if (mem_first==2 and tag<tag_second)
884 SF_int nnodes = elem_nodes.size();
885 face_coordinates.resize(nnodes);
887 row_idx.resize(nnodes*row_dpn);
888 row_idx_counter.resize(nnodes*row_dpn);
889 col_idx.resize(nnodes*col_dpn);
890 col_idx_counter.resize(nnodes*col_dpn);
893 for(
SF_int i=0; i<nnodes; i++){
895 for(
short j=0; j<row_dpn; j++){
896 row_idx.data()[i*row_dpn + j] = emi_surfmesh_elem[eidx]*row_dpn;
899 for(
short j=0; j<col_dpn; j++){
900 col_idx[i*col_dpn + j] = (petsc_first[i])*col_dpn + j;
901 col_idx_counter[i*col_dpn + j] = (petsc_second[i])*col_dpn + j;
907 ebuff.
assign(nnodes, nnodes, 0.0);
908 ebuff_s.assign(nnodes, nnodes, 0.0);
910 ebuff_counter.assign(nnodes, nnodes, 0.0);
912 for (
int n = surface_mesh.dsp[eidx], i = 0; n < surface_mesh.dsp[eidx+1];n++,i++)
914 T l_idx = surface_mesh.con[n];
916 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
917 Index_tag_old = std::make_pair(rnod[l_idx],tag);
918 mesh_int_t Index_new = find_petsc_index(Index_tag_old).first;
920 double x = emi_mesh.xyz[g2l_emi[Index_new]*3+0];
921 double y = emi_mesh.xyz[g2l_emi[Index_new]*3+1];
922 double z = emi_mesh.xyz[g2l_emi[Index_new]*3+2];
924 face_coordinates[i].x = x;
925 face_coordinates[i].y = y;
926 face_coordinates[i].z = z;
928 compute_integrate_matrix_barycentric(face_coordinates, nnodes, ebuff, ebuff_s, ebuff_counter, mass_scale);
931 const bool add =
true;
934 Bi.set_values(row_idx, col_idx, ebuff.data(), add);
935 Bi.set_values(row_idx, col_idx_counter, ebuff_counter.data(), add);
938 B.set_values(row_idx, col_idx, ebuff.data(), add);
939 ebuff_counter*=(-
sign);
940 B.set_values(row_idx, col_idx_counter, ebuff_counter.data(), add);
944 BsM.set_values(col_idx, row_idx, ebuff_s.data(), add);
948 Bi.finish_assembly();
949 BsM.finish_assembly();
972 template<
class tuple_key,
class tuple_value,
class tri_key,
class tri_value,
class quad_key,
class quad_value,
class T,
class S>
973 inline void assemble_lhs_emi(abstract_matrix<T,S> & mat,
974 abstract_matrix<T,S> & mat_surf,
975 const meshdata<mesh_int_t,mesh_real_t> & emi_mesh,
976 const meshdata<mesh_int_t,mesh_real_t> & surface_mesh,
977 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,
979 std::pair<tuple_value, tuple_value>> & line_face,
981 std::pair<tri_value, tri_value>> & tri_face,
983 std::pair<quad_value, quad_value>> & quad_face,
984 matrix_integrator<mesh_int_t,mesh_real_t> & stiffness_integrator,
985 matrix_integrator<mesh_int_t, mesh_real_t> & mass_integrator,
990 T row_dpn = 1; T col_dpn = 1;
1000 const vector<mesh_int_t> & stiffness_petsc_nbr = emi_mesh.get_numbering(
NBR_PETSC);
1001 element_view<mesh_int_t, mesh_real_t> stiffness_view(emi_mesh,
NBR_PETSC);
1004 for(
size_t eidx=0; eidx < emi_mesh.l_numelem; eidx++)
1007 stiffness_view.set_elem(eidx);
1010 mesh_int_t nnodes = stiffness_view.num_nodes();
1012 row_idx.resize(nnodes*row_dpn);
1013 col_idx.resize(nnodes*col_dpn);
1014 canonic_indices<mesh_int_t,SF_int>(stiffness_view.nodes(), stiffness_petsc_nbr.data(), nnodes, row_dpn, row_idx.data());
1015 canonic_indices<mesh_int_t,SF_int>(stiffness_view.nodes(), stiffness_petsc_nbr.data(), nnodes, col_dpn, col_idx.data());
1018 stiffness_integrator(stiffness_view, ebuff);
1019 ebuff *= stiffness_scale;
1022 const bool add =
true;
1023 mat.set_values(row_idx, col_idx, ebuff.data(), add);
1032 auto find_petsc_index = [&](
const std::pair<mesh_int_t,mesh_int_t>& key) ->
const std::pair<mesh_int_t,mesh_int_t>& {
1033 auto it = map_vertex_tag_to_dof_petsc.find(key);
1034 if (it == map_vertex_tag_to_dof_petsc.end()) {
1035 std::cerr <<
"ERROR: PETSc index not found for vertex=" << key.first
1036 <<
" tag=" << key.second << std::endl;
1037 throw std::runtime_error(
"PETSc index not found for vertex/tag pair");
1043 element_view<mesh_int_t, mesh_real_t> view(surface_mesh,
NBR_PETSC);
1044 for(
size_t eidx=0; eidx < surface_mesh.l_numelem; eidx++)
1047 view.set_elem(eidx);
1051 std::vector<mesh_int_t> elem_nodes;
1052 std::vector<mesh_int_t> elem_nodes_old;
1053 std::vector<mesh_int_t> elem_nodes_first;
1054 std::vector<mesh_int_t> elem_nodes_second;
1056 std::vector<mesh_int_t> petsc_first;
1057 std::vector<mesh_int_t> petsc_second;
1062 for (
int n = surface_mesh.dsp[eidx]; n < surface_mesh.dsp[eidx+1];n++)
1064 T l_idx = surface_mesh.con[n];
1066 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1067 Index_tag_old = std::make_pair(rnod[l_idx],tag);
1068 mesh_int_t Index_new = find_petsc_index(Index_tag_old).first;
1069 elem_nodes.push_back(Index_new);
1070 elem_nodes_old.push_back(rnod[l_idx]);
1073 std::sort(elem_nodes.begin(),elem_nodes.end());
1074 if(elem_nodes.size()==2){
1077 key.v1 = elem_nodes[0];
1078 key.v2 = elem_nodes[1];
1079 auto it = line_face.find(key);
1080 if (it == line_face.end())
throw std::runtime_error(
"Line interface face not found");
1081 const std::pair<tuple_value, tuple_value> & value = it->second;
1083 tag_first = value.first.tag;
1084 tag_second = value.second.tag;
1086 else if(elem_nodes.size()==3){
1088 key.v1 = elem_nodes[0];
1089 key.v2 = elem_nodes[1];
1090 key.v3 = elem_nodes[2];
1091 auto it = tri_face.find(key);
1092 if (it == tri_face.end())
throw std::runtime_error(
"Triangular interface face not found");
1093 const std::pair<tri_value, tri_value> & value = it->second;
1095 tag_first = value.first.tag;
1096 tag_second = value.second.tag;
1098 else if(elem_nodes.size()==4){
1100 key.v1 = elem_nodes[0];
1101 key.v2 = elem_nodes[1];
1102 key.v3 = elem_nodes[2];
1103 key.v4 = elem_nodes[3];
1104 auto it = quad_face.find(key);
1105 if (it == quad_face.end())
throw std::runtime_error(
"Quadrilateral interface face not found");
1106 const std::pair<quad_value, quad_value> & value = it->second;
1108 tag_first = value.first.tag;
1109 tag_second = value.second.tag;
1112 if(tag != tag_first) std::swap(tag_first, tag_second);
1114 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1116 for (
size_t indx = 0; indx < elem_nodes_old.size(); ++indx)
1118 std::pair <mesh_int_t,mesh_int_t> Index_tag_old_first;
1119 Index_tag_old_first = std::make_pair(elem_nodes_old[indx],tag_first);
1120 std::pair <mesh_int_t,mesh_int_t> newIndex_petsc_first = find_petsc_index(Index_tag_old_first);
1121 mesh_int_t newIndex_first = newIndex_petsc_first.first;
1122 petsc_first.push_back(newIndex_petsc_first.second);
1124 std::pair <mesh_int_t,mesh_int_t> Index_tag_old_second;
1125 Index_tag_old_second = std::make_pair(elem_nodes_old[indx],tag_second);
1126 std::pair <mesh_int_t,mesh_int_t> newIndex_petsc_second = find_petsc_index(Index_tag_old_second);
1127 mesh_int_t newIndex_second = newIndex_petsc_second.first;
1128 petsc_second.push_back(newIndex_petsc_second.second);
1132 SF_int nnodes = view.num_nodes();
1133 idx.resize(nnodes*row_dpn);
1134 idx_counter.resize(nnodes*col_dpn);
1137 for(T i=0; i<nnodes; i++)
1139 for(
short j=0; j<row_dpn; j++){
1140 idx[i*row_dpn + j] = (petsc_first[i])*row_dpn + j;
1142 for(
short j=0; j<col_dpn; j++){
1143 idx_counter[i*col_dpn + j] = (petsc_second[i])*col_dpn + j;
1149 const bool add =
true;
1152 mass_integrator(view, ebuff);
1153 ebuff_mass.assign(nnodes, nnodes, 0.0);
1157 ebuff*=0.5 * mass_scale;
1160 mat.set_values(idx, idx, ebuff.data(), add);
1161 mat.set_values(idx_counter, idx_counter, ebuff.data(), add);
1163 mat_surf.set_values(idx, idx, ebuff_mass.data(), add);
1164 mat_surf.set_values(idx_counter, idx_counter, ebuff_mass.data(), add);
1169 mat.set_values(idx, idx_counter, ebuff.data(), add);
1170 mat.set_values(idx_counter, idx, ebuff.data(), add);
1172 mat_surf.set_values(idx, idx_counter, ebuff_mass.data(), add);
1173 mat_surf.set_values(idx_counter, idx, ebuff_mass.data(), add);
1185 mat.finish_assembly();
1186 mat_surf.finish_assembly();
1207 template<
class tuple_key,
class tuple_value,
class tri_key,
class tri_value,
class quad_key,
class quad_value,
class T,
class S>
1208 inline void assign_resting_potential_from_ionic_models_on_myocyte(abstract_vector<T,S> & ui,
1209 abstract_vector<T, S>* vb,
1212 std::pair<T,T>> & map_vertex_tag_to_dof_petsc,
1214 std::pair<tuple_value, tuple_value>> & line_face,
1216 std::pair<tri_value, tri_value>> & tri_face,
1218 std::pair<quad_value, quad_value>> & quad_face,
1219 const meshdata<T,mesh_real_t> & surface_mesh,
1220 const meshdata<T,mesh_real_t> & emi_mesh)
1228 auto find_petsc_index = [&](
const std::pair<T,T>& key) ->
const std::pair<T,T>& {
1229 auto it = map_vertex_tag_to_dof_petsc.
find(key);
1230 if (it == map_vertex_tag_to_dof_petsc.end()) {
1231 std::cerr <<
"ERROR: PETSc index not found for vertex=" << key.first
1232 <<
" tag=" << key.second << std::endl;
1233 throw std::runtime_error(
"PETSc index not found for vertex/tag pair");
1238 auto vb_data = vb->const_ptr();
1241 for(
size_t eidx=0; eidx < surface_mesh.l_numelem; eidx++)
1243 T tag = surface_mesh.tag[eidx];
1246 std::vector<mesh_int_t> elem_nodes;
1252 for (
int n = surface_mesh.dsp[eidx], i = 0; n < surface_mesh.dsp[eidx+1];n++,i++)
1254 T l_idx = surface_mesh.con[n];
1255 std::pair <T,T> Index_tag_old;
1256 Index_tag_old = std::make_pair(rnod[l_idx],tag);
1257 mesh_int_t Index_new = find_petsc_index(Index_tag_old).first;
1258 elem_nodes.push_back(Index_new);
1261 std::sort(elem_nodes.begin(),elem_nodes.end());
1262 if(elem_nodes.size()==2){
1265 key.v1 = elem_nodes[0];
1266 key.v2 = elem_nodes[1];
1267 auto it = line_face.find(key);
1268 if (it == line_face.end())
throw std::runtime_error(
"Line interface face not found");
1269 const std::pair<tuple_value, tuple_value> & value = it->second;
1271 tag_first = value.first.tag;
1272 tag_second = value.second.tag;
1274 mem_first = value.first.mem;
1275 mem_second = value.second.mem;
1277 else if(elem_nodes.size()==3){
1279 key.v1 = elem_nodes[0];
1280 key.v2 = elem_nodes[1];
1281 key.v3 = elem_nodes[2];
1282 auto it = tri_face.find(key);
1283 if (it == tri_face.end())
throw std::runtime_error(
"Triangular interface face not found");
1284 const std::pair<tri_value, tri_value> & value = it->second;
1286 tag_first = value.first.tag;
1287 tag_second = value.second.tag;
1289 mem_first = value.first.mem;
1290 mem_second = value.second.mem;
1292 else if(elem_nodes.size()==4){
1294 key.v1 = elem_nodes[0];
1295 key.v2 = elem_nodes[1];
1296 key.v3 = elem_nodes[2];
1297 key.v4 = elem_nodes[3];
1298 auto it = quad_face.find(key);
1299 if (it == quad_face.end())
throw std::runtime_error(
"Quadrilateral interface face not found");
1300 const std::pair<quad_value, quad_value> & value = it->second;
1302 tag_first = value.first.tag;
1303 tag_second = value.second.tag;
1305 mem_first = value.first.mem;
1306 mem_second = value.second.mem;
1309 SF_int nnodes = elem_nodes.size();
1310 for (
int i = 0; i < nnodes; ++i)
1312 if(mem_first==1 || mem_second==1){
1313 tag_2_vm[tag_first] = vb_data[eidx];
1314 tag_2_vm[tag_second] = vb_data[eidx];
1319 vb->const_release_ptr(vb_data);
1326 const vector<mesh_int_t> & petsc_nbr = emi_mesh.get_numbering(
NBR_PETSC);
1327 T start = 0, stop = 0;
1328 ui.get_ownership_range(start, stop);
1330 S* ui_data = ui.ptr();
1332 element_view<mesh_int_t, mesh_real_t> view(emi_mesh,
NBR_PETSC);
1333 for(
size_t eidx=0; eidx < emi_mesh.l_numelem; eidx++)
1335 view.set_elem(eidx);
1336 T tag = emi_mesh.tag[eidx];
1339 row_idx.resize(nnodes*row_dpn);
1340 canonic_indices<mesh_int_t,SF_int>(view.nodes(), petsc_nbr.data(), nnodes, row_dpn, row_idx.data());
1342 for (
int i = 0; i < nnodes; ++i)
1345 if(elemTag_emi_mesh[eidx]==2){
1346 if(row_idx[i] >= start && row_idx[i] < stop) {
1347 auto vm_it = tag_2_vm.
find(tag);
1348 if (vm_it != tag_2_vm.
end()) ui_data[row_idx[i] - start] = vm_it->second;
1353 ui.release_ptr(ui_data);
1354 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)