28 #include <type_traits>
44 Point edge1 = p2 - p1;
45 Point edge2 = p3 - p1;
51 double crossProductMagnitude =
mag(crossProduct);
53 return 0.5 * crossProductMagnitude;
66 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)
70 length = std::sqrt(lengthSquared);
73 double lambda2 =
inner_prod(v, d) / lengthSquared;
74 double lambda1 = 1.0 - lambda2;
76 interpolationCoefficients[0] = lambda1;
77 interpolationCoefficients[1] = lambda2;
91 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)
94 area = computeTriangleArea(p1, p2, p3);
109 double denom = d00 * d11 - d01 * d01;
110 double beta = (d11 * d20 - d01 * d21) / denom;
111 double gamma = (d00 * d21 - d01 * d20) / denom;
112 double alpha = 1.0 - beta - gamma;
113 interpolationCoefficients[0] = alpha;
114 interpolationCoefficients[1] = beta;
115 interpolationCoefficients[2] = gamma;
131 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)
134 double area1 = computeTriangleArea(p1, p2, p4);
135 double area2 = computeTriangleArea(p2, p3, p4);
136 area = area1 + area2;
153 interpolationCoefficients[0] = (1 - u) * (1 - v);
154 interpolationCoefficients[1] = u * (1 - v);
155 interpolationCoefficients[2] = u * v;
156 interpolationCoefficients[3] = (1 - u) * v;
171 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)
177 for (
int i = 0; i < nnodes; ++i)
179 x += face_coordinates[i].x;
180 y += face_coordinates[i].y;
181 z += face_coordinates[i].z;
183 SF::Point b; b.
x = x/nnodes; b.
y = y/nnodes; b.
z = z/nnodes;
185 std::array<double, SF_MAX_ELEM_NODES> interpolationCoefficients{};
188 compute_barycentric_coordinates_coefficients(face_coordinates[0], face_coordinates[1], b, interpolationCoefficients, area);
192 compute_barycentric_coordinates_coefficients(face_coordinates[0], face_coordinates[1], face_coordinates[2], b, interpolationCoefficients, area);
195 compute_barycentric_coordinates_coefficients(face_coordinates[0], face_coordinates[1], face_coordinates[2], face_coordinates[3], b, interpolationCoefficients, area);
200 ebuff[0][0] = interpolationCoefficients[0];
201 ebuff[0][1] = interpolationCoefficients[1];
203 ebuff_counter[0][0] = interpolationCoefficients[0];
204 ebuff_counter[0][1] = interpolationCoefficients[1];
206 ebuff_s[0][0] = mass_scale*area*interpolationCoefficients[0];
207 ebuff_s[0][1] = mass_scale*area*interpolationCoefficients[1];
210 ebuff[0][0] = interpolationCoefficients[0];
211 ebuff[0][1] = interpolationCoefficients[1];
212 ebuff[0][2] = interpolationCoefficients[2];
214 ebuff_counter[0][0] = interpolationCoefficients[0];
215 ebuff_counter[0][1] = interpolationCoefficients[1];
216 ebuff_counter[0][2] = interpolationCoefficients[2];
218 ebuff_s[0][0] = mass_scale*area*interpolationCoefficients[0];
219 ebuff_s[0][1] = mass_scale*area*interpolationCoefficients[1];
220 ebuff_s[0][2] = mass_scale*area*interpolationCoefficients[2];
223 ebuff[0][0] = interpolationCoefficients[0];
224 ebuff[0][1] = interpolationCoefficients[1];
225 ebuff[0][2] = interpolationCoefficients[2];
226 ebuff[0][3] = interpolationCoefficients[3];
228 ebuff_counter[0][0] = interpolationCoefficients[0];
229 ebuff_counter[0][1] = interpolationCoefficients[1];
230 ebuff_counter[0][2] = interpolationCoefficients[2];
231 ebuff_counter[0][3] = interpolationCoefficients[3];
233 ebuff_s[0][0] = mass_scale*area*interpolationCoefficients[0];
234 ebuff_s[0][1] = mass_scale*area*interpolationCoefficients[1];
235 ebuff_s[0][2] = mass_scale*area*interpolationCoefficients[2];
236 ebuff_s[0][3] = mass_scale*area*interpolationCoefficients[3];
272 template<
class T,
class S,
class emi_index_rank>
273 inline void construct_direct_unique_both_operators(
281 int max_row_entries_emi,
286 T M = emi_surfmesh_w_counter_face.
g_numelem;
287 T m = emi_surfmesh_w_counter_face.
l_numelem;
288 T M_unique_face = emi_surfmesh_unique_face.
g_numelem;
289 T m_unique_face = emi_surfmesh_unique_face.
l_numelem;
293 MPI_Comm_rank(emi_surfmesh_w_counter_face.
comm, &rank);
294 MPI_Comm_size(emi_surfmesh_w_counter_face.
comm, &comm_size);
297 SF::layout_from_count<long int>(emi_surfmesh_w_counter_face.
l_numelem, layout, emi_surfmesh_w_counter_face.
comm);
298 T m_l = layout[rank];
301 SF::layout_from_count<long int>(emi_surfmesh_unique_face.
l_numelem, layout_unique_face, emi_surfmesh_unique_face.
comm);
302 T m_unique_face_l = layout_unique_face[rank];
305 map_elem_uniqueFace_to_elem_bothface.clear();
324 auto exchange_entries_by_rank = [&](
const auto& entries_by_rank,
const char* overflow_message) {
325 using bucket_t = std::decay_t<decltype(entries_by_rank[0])>;
326 using entry_t =
typename bucket_t::value_type;
328 std::vector<int> send_counts(comm_size, 0), recv_counts(comm_size, 0);
329 std::vector<int> send_displs(comm_size, 0), recv_displs(comm_size, 0);
331 int total_send_bytes = 0;
332 for (
int r = 0; r < comm_size; r++) {
333 const size_t nbytes = entries_by_rank[r].size() *
sizeof(entry_t);
336 throw std::runtime_error(overflow_message);
338 send_displs[r] = total_send_bytes;
339 send_counts[r] =
static_cast<int>(nbytes);
340 total_send_bytes += send_counts[r];
343 MPI_Alltoall(send_counts.data(), 1, MPI_INT,
344 recv_counts.data(), 1, MPI_INT,
345 emi_surfmesh_w_counter_face.
comm);
347 int total_recv_bytes = 0;
348 for (
int r = 0; r < comm_size; r++) {
349 recv_displs[r] = total_recv_bytes;
351 throw std::runtime_error(overflow_message);
353 total_recv_bytes += recv_counts[r];
356 std::vector<entry_t> send_buffer(total_send_bytes /
sizeof(entry_t));
357 for (
int r = 0; r < comm_size; r++) {
358 if (entries_by_rank[r].empty())
continue;
359 std::copy(entries_by_rank[r].begin(), entries_by_rank[r].end(),
360 send_buffer.begin() + send_displs[r] /
static_cast<int>(
sizeof(entry_t)));
363 std::vector<entry_t> recv_buffer(total_recv_bytes /
sizeof(entry_t));
364 MPI_Alltoallv(
reinterpret_cast<const unsigned char*
>(send_buffer.data()),
365 send_counts.data(), send_displs.data(), MPI_BYTE,
366 reinterpret_cast<unsigned char*
>(recv_buffer.data()),
367 recv_counts.data(), recv_displs.data(), MPI_BYTE,
368 emi_surfmesh_w_counter_face.
comm);
372 struct one_to_both_query {
379 struct one_to_both_reply {
387 for (
mesh_int_t both_idx = 0; both_idx < static_cast<mesh_int_t>(vec_both_to_one_face.
size()); both_idx++) {
388 const mesh_int_t one_idx = vec_both_to_one_face[both_idx];
389 if (one_idx < 0)
continue;
391 auto inserted = local_one_to_both.
insert({one_idx, std::make_pair(
static_cast<mesh_int_t>(-1),
393 auto& both_pair = inserted.first->second;
394 if (both_pair.first < 0) both_pair.first = both_idx;
395 else both_pair.second = both_idx;
398 std::vector<std::vector<one_to_both_query>> one_to_both_queries(comm_size);
399 auto queue_one_to_both_query = [&](
mesh_int_t unique_idx,
400 const emi_index_rank& one_face_idx,
403 if (one_face_idx.rank < 0 || one_face_idx.rank >= comm_size || one_face_idx.index < 0) {
406 one_to_both_queries[one_face_idx.rank].push_back(
407 {unique_idx,
static_cast<mesh_int_t>(one_face_idx.index), slot, use_second ? 1 : 0, rank});
412 for (
const auto& [unique_idx, one_face_pair] : map_elem_uniqueFace_to_elem_oneface) {
413 const auto& first_oneface = one_face_pair.first;
414 const auto& second_oneface = one_face_pair.second;
416 const bool same_oneface =
417 (first_oneface.index >= 0 && second_oneface.index >= 0 &&
418 first_oneface.index == second_oneface.index &&
419 first_oneface.rank == second_oneface.rank);
421 emi_index_rank invalid_both_face;
422 invalid_both_face.index = -1;
423 invalid_both_face.rank = -1;
424 map_elem_uniqueFace_to_elem_bothface[unique_idx] =
425 std::make_pair(invalid_both_face, invalid_both_face);
426 queue_one_to_both_query(unique_idx, first_oneface, 0,
false);
427 queue_one_to_both_query(unique_idx, second_oneface, 1, same_oneface);
430 std::vector<one_to_both_query> local_one_to_both_queries =
431 exchange_entries_by_rank(one_to_both_queries,
432 "EMI one-face to both-face lookup exchange exceeds INT_MAX bytes on one rank");
434 std::vector<std::vector<one_to_both_reply>> one_to_both_replies(comm_size);
435 for (
const one_to_both_query& query : local_one_to_both_queries) {
436 if (query.requester_rank < 0 || query.requester_rank >= comm_size)
continue;
439 auto it = local_one_to_both.
find(query.one_idx);
440 if (it != local_one_to_both.
end()) {
441 both_idx = query.use_second ? it->second.second : it->second.first;
443 one_to_both_replies[query.requester_rank].push_back({query.unique_idx, both_idx, query.slot, rank});
446 std::vector<one_to_both_reply> local_one_to_both_replies =
447 exchange_entries_by_rank(one_to_both_replies,
448 "EMI one-face to both-face lookup reply exchange exceeds INT_MAX bytes on one rank");
450 for (
const auto& reply : local_one_to_both_replies) {
451 if (reply.both_idx < 0 || reply.both_rank < 0 || reply.both_rank >= comm_size)
continue;
452 auto it = map_elem_uniqueFace_to_elem_bothface.find(reply.unique_idx);
453 if (it == map_elem_uniqueFace_to_elem_bothface.end())
continue;
454 emi_index_rank both_face;
455 both_face.index = reply.both_idx;
456 both_face.rank = reply.both_rank;
457 if (reply.slot == 0) it->second.first = both_face;
458 else it->second.second = both_face;
464 operator_unique_to_both_faces->
init(M, M_unique_face, m, m_unique_face, m_l, 1);
465 operator_unique_to_both_faces->
zero();
467 struct unique_to_both_entry {
472 std::vector<std::vector<unique_to_both_entry>> send_entries(comm_size);
473 auto queue_unique_to_both_entry = [&](
const emi_index_rank& both_face,
475 T previous_global_both_row) {
476 if (both_face.rank < 0 || both_face.rank >= comm_size || both_face.index < 0) {
477 return previous_global_both_row;
480 const T global_both_row =
static_cast<T
>(layout[both_face.rank]) +
static_cast<T
>(both_face.index);
481 if (global_both_row == previous_global_both_row) {
482 return previous_global_both_row;
485 send_entries[both_face.rank].push_back({global_both_row, global_unique_col});
486 return global_both_row;
489 for (
const auto& [local_unique_idx, both_pair] : map_elem_uniqueFace_to_elem_bothface) {
490 const T global_unique_col =
491 static_cast<T
>(layout_unique_face[rank]) +
static_cast<T
>(local_unique_idx);
492 T previous_global_both_row =
static_cast<T
>(-1);
493 previous_global_both_row =
494 queue_unique_to_both_entry(both_pair.first, global_unique_col, previous_global_both_row);
495 queue_unique_to_both_entry(both_pair.second, global_unique_col, previous_global_both_row);
498 std::vector<unique_to_both_entry> local_unique_to_both_entries =
499 exchange_entries_by_rank(send_entries,
500 "EMI unique-face transfer entry exchange exceeds INT_MAX bytes on one rank");
502 auto assemble_unique_to_both = [&]() {
505 ebuff.assign(1, 1, 1.0);
507 for (
const auto& entry : local_unique_to_both_entries) {
508 row_idx[0] = entry.row;
509 col_idx[0] = entry.col;
510 operator_unique_to_both_faces->
set_values(row_idx, col_idx, ebuff.data(),
false);
516 assemble_unique_to_both();
519 assemble_unique_to_both();
523 operator_both_to_unique_face->
init(M_unique_face, M, m_unique_face, m, m_unique_face_l, 2);
524 operator_both_to_unique_face->
zero();
526 assemble_map_both_to_unique(*operator_both_to_unique_face,
527 map_elem_uniqueFace_to_elem_bothface,
528 emi_surfmesh_unique_face,
529 emi_surfmesh_w_counter_face);
532 assemble_map_both_to_unique(*operator_both_to_unique_face,
533 map_elem_uniqueFace_to_elem_bothface,
534 emi_surfmesh_unique_face,
535 emi_surfmesh_w_counter_face);
537 #ifdef EMI_DEBUG_MESH
541 mesh_int_t local_valid_first = 0, local_valid_second = 0;
544 SF::layout_from_count<long int>(emi_surfmesh_w_counter_face.
l_numelem, layout_both_dbg, emi_surfmesh_w_counter_face.
comm);
546 SF::layout_from_count<long int>(emi_surfmesh_unique_face.
l_numelem, layout_unique_dbg, emi_surfmesh_unique_face.
comm);
548 for (
const auto& [uidx, both_pair] : map_elem_uniqueFace_to_elem_bothface) {
549 if (both_pair.first.index >= 0) local_valid_first++;
550 if (both_pair.second.index >= 0) local_valid_second++;
552 if (both_pair.first.index >= 0 && both_pair.second.index >= 0 &&
553 both_pair.first.rank >= 0 && both_pair.second.rank >= 0) {
554 mesh_int_t global_first = layout_both_dbg[both_pair.first.rank] + both_pair.first.index;
555 mesh_int_t global_second = layout_both_dbg[both_pair.second.rank] + both_pair.second.index;
556 if (global_first == global_second) local_same_column++;
559 mesh_int_t global_valid_first = local_valid_first;
560 mesh_int_t global_valid_second = local_valid_second;
561 mesh_int_t global_same_column = local_same_column;
562 const MPI_Datatype mesh_mpi_t = opencarp::mpi_datatype<mesh_int_t>();
563 MPI_Allreduce(MPI_IN_PLACE, &global_valid_first, 1, mesh_mpi_t, MPI_SUM, emi_surfmesh_w_counter_face.
comm);
564 MPI_Allreduce(MPI_IN_PLACE, &global_valid_second, 1, mesh_mpi_t, MPI_SUM, emi_surfmesh_w_counter_face.
comm);
565 MPI_Allreduce(MPI_IN_PLACE, &global_same_column, 1, mesh_mpi_t, MPI_SUM, emi_surfmesh_w_counter_face.
comm);
568 MPI_Comm_rank(emi_surfmesh_w_counter_face.
comm, &dbg_rank);
570 log_msg(NULL, 0, 0,
"DEBUG map_unique_to_both: valid_first=%jd valid_second=%jd (global M=%zu, M_unique=%zu)",
573 (
size_t)emi_surfmesh_w_counter_face.
g_numelem,
574 (
size_t)emi_surfmesh_unique_face.
g_numelem);
579 std::vector<char> present(emi_surfmesh_unique_face.
l_numelem, 0);
580 for (
const auto& [uidx, both_pair] : map_elem_uniqueFace_to_elem_bothface) {
581 if (uidx >= 0 && uidx < (
mesh_int_t)present.size()) present[uidx] = 1;
583 std::vector<int> missing;
585 if (!present[i]) missing.push_back((
int)i);
587 int local_missing = (int)missing.size();
588 int comm_size_dbg = 0;
589 MPI_Comm_size(emi_surfmesh_w_counter_face.
comm, &comm_size_dbg);
590 std::vector<int> counts(comm_size_dbg, 0), displs(comm_size_dbg, 0);
591 MPI_Gather(&local_missing, 1, MPI_INT,
592 dbg_rank == 0 ? counts.data() :
nullptr, 1, MPI_INT,
593 0, emi_surfmesh_w_counter_face.
comm);
596 for (
int r = 0; r < comm_size_dbg; r++) {
600 std::vector<int> all_missing(total, -1);
601 MPI_Gatherv(missing.data(), local_missing, MPI_INT,
602 all_missing.data(), counts.data(), displs.data(), MPI_INT,
603 0, emi_surfmesh_w_counter_face.
comm);
606 for (
int r = 0; r < comm_size_dbg; r++) {
607 if (counts[r] == 0) {
612 log_msg(NULL, 0, 0,
"DEBUG unique missing: rank=%d count=%d", r, counts[r]);
613 int to_print = counts[r] < 10 ? counts[r] : 10;
614 for (
int i = 0; i < to_print; i++) {
615 log_msg(NULL, 0, 0,
"DEBUG unique missing: rank=%d local_unique=%d", r, all_missing[offset + i]);
619 if (!any)
log_msg(NULL, 0, 0,
"DEBUG unique missing: none");
621 MPI_Gatherv(missing.data(), local_missing, MPI_INT,
622 nullptr,
nullptr,
nullptr, MPI_INT,
623 0, emi_surfmesh_w_counter_face.
comm);
630 SF::init_vector(&dbg_unique, emi_surfmesh_unique_face, dpn, alg_surface_type);
631 SF::init_vector(&dbg_both, emi_surfmesh_w_counter_face, dpn, alg_surface_type);
632 SF::init_vector(&dbg_back, emi_surfmesh_unique_face, dpn, alg_surface_type);
633 dbg_unique->
set(1.0);
634 operator_unique_to_both_faces->
mult(*dbg_unique, *dbg_both);
635 operator_both_to_unique_face->
mult(*dbg_both, *dbg_back);
641 SF_real err = std::abs(p[i] - 1.0);
642 if (err > local_max_err) local_max_err = err;
643 if (std::abs(p[i] - 0.5) < 1e-12) local_half_count++;
648 MPI_Allreduce(&local_max_err, &global_max_err, 1, opencarp::mpi_datatype<SF_real>(),
649 MPI_MAX, emi_surfmesh_w_counter_face.
comm);
650 global_half_count = local_half_count;
651 MPI_Allreduce(MPI_IN_PLACE, &global_half_count, 1, mesh_mpi_t, MPI_SUM,
652 emi_surfmesh_w_counter_face.
comm);
654 log_msg(NULL, 0, 0,
"DEBUG map_unique_to_both consistency: max_err=%.6e half_count=%jd",
659 const int max_print = 5;
660 const int fields = 9;
661 std::vector<int> local_buf(max_print * fields, -1);
664 for (
const auto& [local_unique_idx, both_pair] : map_elem_uniqueFace_to_elem_bothface) {
665 if (filled >= max_print)
break;
666 const auto& first_both = both_pair.first;
667 const auto& second_both = both_pair.second;
669 const bool first_valid = (first_both.index >= 0 && first_both.rank >= 0);
670 const bool second_valid = (second_both.index >= 0 && second_both.rank >= 0);
671 int count = (first_valid ? 1 : 0) + (second_valid ? 1 : 0);
672 if (
count != 1)
continue;
674 mesh_int_t global_unique = layout_unique_dbg[dbg_rank] + local_unique_idx;
675 mesh_int_t global_first = first_valid ? (layout_both_dbg[first_both.rank] + first_both.index) : -1;
676 mesh_int_t global_second = second_valid ? (layout_both_dbg[second_both.rank] + second_both.index) : -1;
678 int base = filled * fields;
679 local_buf[base + 0] = dbg_rank;
680 local_buf[base + 1] = (int)local_unique_idx;
681 local_buf[base + 2] = (int)global_unique;
682 local_buf[base + 3] = (int)first_both.rank;
683 local_buf[base + 4] = (
int)first_both.index;
684 local_buf[base + 5] = (int)global_first;
685 local_buf[base + 6] = (int)second_both.rank;
686 local_buf[base + 7] = (
int)second_both.index;
687 local_buf[base + 8] = (int)global_second;
692 MPI_Comm_size(emi_surfmesh_w_counter_face.
comm, &comm_size);
693 std::vector<int> all_buf;
694 if (dbg_rank == 0) all_buf.resize(comm_size * max_print * fields, -1);
696 MPI_Gather(local_buf.data(), max_print * fields, MPI_INT,
697 dbg_rank == 0 ? all_buf.data() :
nullptr, max_print * fields, MPI_INT,
698 0, emi_surfmesh_w_counter_face.
comm);
701 for (
int r = 0; r < comm_size; r++) {
702 for (
int i = 0; i < max_print; i++) {
703 int base = (r * max_print + i) * fields;
704 if (all_buf[base + 1] < 0)
continue;
706 "DEBUG map_unique_to_both bad: rank=%d local_unique=%d global_unique=%d "
707 "first(rank=%d idx=%d glob=%d) second(rank=%d idx=%d glob=%d)",
708 all_buf[base + 0], all_buf[base + 1], all_buf[base + 2],
709 all_buf[base + 3], all_buf[base + 4], all_buf[base + 5],
710 all_buf[base + 6], all_buf[base + 7], all_buf[base + 8]);
745 template<
class tuple_key,
class tuple_value,
class tri_key,
class tri_value,
class quad_key,
class quad_value,
class T,
class S>
746 inline void assemble_restrict_operator( abstract_matrix<T,S> & B,
747 abstract_matrix<T,S> & Bi,
748 abstract_matrix<T,S> & BsM,
751 std::pair<mesh_int_t,mesh_int_t>> & map_vertex_tag_to_dof_petsc,
753 std::pair<tuple_value, tuple_value>> & line_face,
755 std::pair<tri_value, tri_value>> & tri_face,
757 std::pair<quad_value, quad_value>> & quad_face,
758 const meshdata<mesh_int_t,mesh_real_t> & surface_mesh,
759 const meshdata<mesh_int_t,mesh_real_t> & emi_mesh,
763 T row_dpn = 1; T col_dpn = 1;
768 for(
size_t i=0; i<rnod_emi.
size(); i++){
769 g2l_emi[rnod_emi[i]] = i;
775 auto find_petsc_index = [&](
const std::pair<mesh_int_t,mesh_int_t>& key) ->
const std::pair<mesh_int_t,mesh_int_t>& {
776 auto it = map_vertex_tag_to_dof_petsc.find(key);
777 if (it == map_vertex_tag_to_dof_petsc.end()) {
778 std::cerr <<
"ERROR: PETSc index not found for vertex=" << key.first
779 <<
" tag=" << key.second << std::endl;
780 throw std::runtime_error(
"PETSc index not found for vertex/tag pair");
795 std::vector<mesh_int_t> elem_nodes;
796 std::vector<mesh_int_t> elem_nodes_old;
797 std::vector<mesh_int_t> petsc_first;
798 std::vector<mesh_int_t> petsc_second;
799 vector<SF::Point> face_coordinates;
807 for(
size_t eidx=0; eidx < surface_mesh.l_numelem; eidx++)
809 T tag = surface_mesh.tag[eidx];
813 elem_nodes_old.clear();
815 petsc_second.clear();
825 for (
int n = surface_mesh.dsp[eidx]; n < surface_mesh.dsp[eidx+1];n++)
827 T l_idx = surface_mesh.con[n];
829 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
830 Index_tag_old = std::make_pair(rnod[l_idx],tag);
831 mesh_int_t Index_new = find_petsc_index(Index_tag_old).first;
832 elem_nodes.push_back(Index_new);
833 elem_nodes_old.push_back(rnod[l_idx]);
836 std::sort(elem_nodes.begin(),elem_nodes.end());
837 if(elem_nodes.size()==2){
840 key.v1 = elem_nodes[0];
841 key.v2 = elem_nodes[1];
842 auto it = line_face.find(key);
843 if (it == line_face.end())
throw std::runtime_error(
"Line interface face not found");
844 const std::pair<tuple_value, tuple_value> & value = it->second;
846 tag_first = value.first.tag;
847 tag_second = value.second.tag;
849 mem_first = value.first.mem;
850 mem_second = value.second.mem;
853 else if(elem_nodes.size()==3){
855 key.v1 = elem_nodes[0];
856 key.v2 = elem_nodes[1];
857 key.v3 = elem_nodes[2];
858 auto it = tri_face.find(key);
859 if (it == tri_face.end())
throw std::runtime_error(
"Triangular interface face not found");
860 const std::pair<tri_value, tri_value> & value = it->second;
862 tag_first = value.first.tag;
863 tag_second = value.second.tag;
865 mem_first = value.first.mem;
866 mem_second = value.second.mem;
869 else if(elem_nodes.size()==4){
871 key.v1 = elem_nodes[0];
872 key.v2 = elem_nodes[1];
873 key.v3 = elem_nodes[2];
874 key.v4 = elem_nodes[3];
875 auto it = quad_face.find(key);
876 if (it == quad_face.end())
throw std::runtime_error(
"Quadrilateral interface face not found");
877 const std::pair<quad_value, quad_value> & value = it->second;
879 tag_first = value.first.tag;
880 tag_second = value.second.tag;
882 mem_first = value.first.mem;
883 mem_second = value.second.mem;
887 if(tag != tag_first) {
888 std::swap(tag_first, tag_second);
889 std::swap(mem_first, mem_second);
892 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
894 for (
size_t indx = 0; indx < elem_nodes_old.size(); ++indx)
896 std::pair <mesh_int_t,mesh_int_t> Index_tag_old_first;
897 Index_tag_old_first = std::make_pair(elem_nodes_old[indx],tag_first);
899 auto it_first = map_vertex_tag_to_dof_petsc.find(Index_tag_old_first);
900 if (it_first == map_vertex_tag_to_dof_petsc.end()) {
901 std::cerr <<
"ERROR: tag_first=" << tag_first <<
" not found for vertex=" << elem_nodes_old[indx] << std::endl;
902 throw std::runtime_error(
"PETSc index not found for first tag");
904 std::pair <mesh_int_t,mesh_int_t> newIndex_petsc_first = it_first->second;
905 mesh_int_t newIndex_first = newIndex_petsc_first.first;
906 petsc_first.push_back(newIndex_petsc_first.second);
908 std::pair <mesh_int_t,mesh_int_t> Index_tag_old_second;
909 Index_tag_old_second = std::make_pair(elem_nodes_old[indx],tag_second);
911 auto it_second = map_vertex_tag_to_dof_petsc.find(Index_tag_old_second);
912 if (it_second == map_vertex_tag_to_dof_petsc.end()) {
913 std::cerr <<
"ERROR: tag_second=" << tag_second <<
" not found for vertex=" << elem_nodes_old[indx] << std::endl;
914 throw std::runtime_error(
"PETSc index not found for counter-face tag");
916 std::pair <mesh_int_t,mesh_int_t> newIndex_petsc_second = it_second->second;
917 mesh_int_t newIndex_second = newIndex_petsc_second.first;
918 petsc_second.push_back(newIndex_petsc_second.second);
921 if(mem_first==1 and elemTag_surface_mesh[eidx]==1)
923 else if (mem_first==2 and tag<tag_second)
927 SF_int nnodes = elem_nodes.size();
928 face_coordinates.resize(nnodes);
930 row_idx.resize(nnodes*row_dpn);
931 row_idx_counter.resize(nnodes*row_dpn);
932 col_idx.resize(nnodes*col_dpn);
933 col_idx_counter.resize(nnodes*col_dpn);
936 for(
SF_int i=0; i<nnodes; i++){
938 for(
short j=0; j<row_dpn; j++){
939 row_idx.data()[i*row_dpn + j] = emi_surfmesh_elem[eidx]*row_dpn;
942 for(
short j=0; j<col_dpn; j++){
943 col_idx[i*col_dpn + j] = (petsc_first[i])*col_dpn + j;
944 col_idx_counter[i*col_dpn + j] = (petsc_second[i])*col_dpn + j;
950 ebuff.
assign(nnodes, nnodes, 0.0);
951 ebuff_s.assign(nnodes, nnodes, 0.0);
953 ebuff_counter.assign(nnodes, nnodes, 0.0);
955 for (
int n = surface_mesh.dsp[eidx], i = 0; n < surface_mesh.dsp[eidx+1];n++,i++)
957 T l_idx = surface_mesh.con[n];
959 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
960 Index_tag_old = std::make_pair(rnod[l_idx],tag);
961 mesh_int_t Index_new = find_petsc_index(Index_tag_old).first;
963 double x = emi_mesh.xyz[g2l_emi[Index_new]*3+0];
964 double y = emi_mesh.xyz[g2l_emi[Index_new]*3+1];
965 double z = emi_mesh.xyz[g2l_emi[Index_new]*3+2];
967 face_coordinates[i].x = x;
968 face_coordinates[i].y = y;
969 face_coordinates[i].z = z;
971 compute_integrate_matrix_barycentric(face_coordinates, nnodes, ebuff, ebuff_s, ebuff_counter, mass_scale);
974 const bool add =
true;
977 Bi.set_values(row_idx, col_idx, ebuff.data(), add);
978 Bi.set_values(row_idx, col_idx_counter, ebuff_counter.data(), add);
981 B.set_values(row_idx, col_idx, ebuff.data(), add);
982 ebuff_counter*=(-
sign);
983 B.set_values(row_idx, col_idx_counter, ebuff_counter.data(), add);
988 for(
SF_int i = 0; i < nnodes; i++) {
989 BsM.set_value(col_idx[i], row_idx[0], ebuff_s[0][i], add);
994 Bi.finish_assembly();
995 BsM.finish_assembly();
1018 template<
class tuple_key,
class tuple_value,
class tri_key,
class tri_value,
class quad_key,
class quad_value,
class T,
class S>
1019 inline void assemble_lhs_emi(abstract_matrix<T,S> & mat,
1020 abstract_matrix<T,S> & mat_surf,
1021 const meshdata<mesh_int_t,mesh_real_t> & emi_mesh,
1022 const meshdata<mesh_int_t,mesh_real_t> & surface_mesh,
1023 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,
1025 std::pair<tuple_value, tuple_value>> & line_face,
1027 std::pair<tri_value, tri_value>> & tri_face,
1029 std::pair<quad_value, quad_value>> & quad_face,
1030 matrix_integrator<mesh_int_t,mesh_real_t> & stiffness_integrator,
1031 matrix_integrator<mesh_int_t, mesh_real_t> & mass_integrator,
1036 T row_dpn = 1; T col_dpn = 1;
1046 const vector<mesh_int_t> & stiffness_petsc_nbr = emi_mesh.get_numbering(
NBR_PETSC);
1047 element_view<mesh_int_t, mesh_real_t> stiffness_view(emi_mesh,
NBR_PETSC);
1050 for(
size_t eidx=0; eidx < emi_mesh.l_numelem; eidx++)
1053 stiffness_view.set_elem(eidx);
1056 mesh_int_t nnodes = stiffness_view.num_nodes();
1058 row_idx.resize(nnodes*row_dpn);
1059 col_idx.resize(nnodes*col_dpn);
1060 canonic_indices<mesh_int_t,SF_int>(stiffness_view.nodes(), stiffness_petsc_nbr.data(), nnodes, row_dpn, row_idx.data());
1061 canonic_indices<mesh_int_t,SF_int>(stiffness_view.nodes(), stiffness_petsc_nbr.data(), nnodes, col_dpn, col_idx.data());
1064 stiffness_integrator(stiffness_view, ebuff);
1065 ebuff *= stiffness_scale;
1068 const bool add =
true;
1069 mat.set_values(row_idx, col_idx, ebuff.data(), add);
1078 auto find_petsc_index = [&](
const std::pair<mesh_int_t,mesh_int_t>& key) ->
const std::pair<mesh_int_t,mesh_int_t>& {
1079 auto it = map_vertex_tag_to_dof_petsc.find(key);
1080 if (it == map_vertex_tag_to_dof_petsc.end()) {
1081 std::cerr <<
"ERROR: PETSc index not found for vertex=" << key.first
1082 <<
" tag=" << key.second << std::endl;
1083 throw std::runtime_error(
"PETSc index not found for vertex/tag pair");
1089 element_view<mesh_int_t, mesh_real_t> view(surface_mesh,
NBR_PETSC);
1090 for(
size_t eidx=0; eidx < surface_mesh.l_numelem; eidx++)
1093 view.set_elem(eidx);
1097 std::vector<mesh_int_t> elem_nodes;
1098 std::vector<mesh_int_t> elem_nodes_old;
1099 std::vector<mesh_int_t> elem_nodes_first;
1100 std::vector<mesh_int_t> elem_nodes_second;
1102 std::vector<mesh_int_t> petsc_first;
1103 std::vector<mesh_int_t> petsc_second;
1108 for (
int n = surface_mesh.dsp[eidx]; n < surface_mesh.dsp[eidx+1];n++)
1110 T l_idx = surface_mesh.con[n];
1112 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1113 Index_tag_old = std::make_pair(rnod[l_idx],tag);
1114 mesh_int_t Index_new = find_petsc_index(Index_tag_old).first;
1115 elem_nodes.push_back(Index_new);
1116 elem_nodes_old.push_back(rnod[l_idx]);
1119 std::sort(elem_nodes.begin(),elem_nodes.end());
1120 if(elem_nodes.size()==2){
1123 key.v1 = elem_nodes[0];
1124 key.v2 = elem_nodes[1];
1125 auto it = line_face.find(key);
1126 if (it == line_face.end())
throw std::runtime_error(
"Line interface face not found");
1127 const std::pair<tuple_value, tuple_value> & value = it->second;
1129 tag_first = value.first.tag;
1130 tag_second = value.second.tag;
1132 else if(elem_nodes.size()==3){
1134 key.v1 = elem_nodes[0];
1135 key.v2 = elem_nodes[1];
1136 key.v3 = elem_nodes[2];
1137 auto it = tri_face.find(key);
1138 if (it == tri_face.end())
throw std::runtime_error(
"Triangular interface face not found");
1139 const std::pair<tri_value, tri_value> & value = it->second;
1141 tag_first = value.first.tag;
1142 tag_second = value.second.tag;
1144 else if(elem_nodes.size()==4){
1146 key.v1 = elem_nodes[0];
1147 key.v2 = elem_nodes[1];
1148 key.v3 = elem_nodes[2];
1149 key.v4 = elem_nodes[3];
1150 auto it = quad_face.find(key);
1151 if (it == quad_face.end())
throw std::runtime_error(
"Quadrilateral interface face not found");
1152 const std::pair<quad_value, quad_value> & value = it->second;
1154 tag_first = value.first.tag;
1155 tag_second = value.second.tag;
1158 if(tag != tag_first) std::swap(tag_first, tag_second);
1160 std::pair <mesh_int_t,mesh_int_t> Index_tag_old;
1162 for (
size_t indx = 0; indx < elem_nodes_old.size(); ++indx)
1164 std::pair <mesh_int_t,mesh_int_t> Index_tag_old_first;
1165 Index_tag_old_first = std::make_pair(elem_nodes_old[indx],tag_first);
1166 std::pair <mesh_int_t,mesh_int_t> newIndex_petsc_first = find_petsc_index(Index_tag_old_first);
1167 mesh_int_t newIndex_first = newIndex_petsc_first.first;
1168 petsc_first.push_back(newIndex_petsc_first.second);
1170 std::pair <mesh_int_t,mesh_int_t> Index_tag_old_second;
1171 Index_tag_old_second = std::make_pair(elem_nodes_old[indx],tag_second);
1172 std::pair <mesh_int_t,mesh_int_t> newIndex_petsc_second = find_petsc_index(Index_tag_old_second);
1173 mesh_int_t newIndex_second = newIndex_petsc_second.first;
1174 petsc_second.push_back(newIndex_petsc_second.second);
1178 SF_int nnodes = view.num_nodes();
1179 idx.resize(nnodes*row_dpn);
1180 idx_counter.resize(nnodes*col_dpn);
1183 for(T i=0; i<nnodes; i++)
1185 for(
short j=0; j<row_dpn; j++){
1186 idx[i*row_dpn + j] = (petsc_first[i])*row_dpn + j;
1188 for(
short j=0; j<col_dpn; j++){
1189 idx_counter[i*col_dpn + j] = (petsc_second[i])*col_dpn + j;
1195 const bool add =
true;
1198 mass_integrator(view, ebuff);
1199 ebuff_mass.assign(nnodes, nnodes, 0.0);
1203 ebuff*=0.5 * mass_scale;
1206 mat.set_values(idx, idx, ebuff.data(), add);
1207 mat.set_values(idx_counter, idx_counter, ebuff.data(), add);
1209 mat_surf.set_values(idx, idx, ebuff_mass.data(), add);
1210 mat_surf.set_values(idx_counter, idx_counter, ebuff_mass.data(), add);
1215 mat.set_values(idx, idx_counter, ebuff.data(), add);
1216 mat.set_values(idx_counter, idx, ebuff.data(), add);
1218 mat_surf.set_values(idx, idx_counter, ebuff_mass.data(), add);
1219 mat_surf.set_values(idx_counter, idx, ebuff_mass.data(), add);
1231 mat.finish_assembly();
1232 mat_surf.finish_assembly();
1253 template<
class tuple_key,
class tuple_value,
class tri_key,
class tri_value,
class quad_key,
class quad_value,
class T,
class S>
1254 inline void assign_resting_potential_from_ionic_models_on_myocyte(abstract_vector<T,S> & ui,
1255 abstract_vector<T, S>* vb,
1258 std::pair<T,T>> & map_vertex_tag_to_dof_petsc,
1260 std::pair<tuple_value, tuple_value>> & line_face,
1262 std::pair<tri_value, tri_value>> & tri_face,
1264 std::pair<quad_value, quad_value>> & quad_face,
1265 const meshdata<T,mesh_real_t> & surface_mesh,
1266 const meshdata<T,mesh_real_t> & emi_mesh)
1274 auto find_petsc_index = [&](
const std::pair<T,T>& key) ->
const std::pair<T,T>& {
1275 auto it = map_vertex_tag_to_dof_petsc.
find(key);
1276 if (it == map_vertex_tag_to_dof_petsc.end()) {
1277 std::cerr <<
"ERROR: PETSc index not found for vertex=" << key.first
1278 <<
" tag=" << key.second << std::endl;
1279 throw std::runtime_error(
"PETSc index not found for vertex/tag pair");
1284 auto vb_data = vb->const_ptr();
1287 for(
size_t eidx=0; eidx < surface_mesh.l_numelem; eidx++)
1289 T tag = surface_mesh.tag[eidx];
1292 std::vector<mesh_int_t> elem_nodes;
1298 for (
int n = surface_mesh.dsp[eidx], i = 0; n < surface_mesh.dsp[eidx+1];n++,i++)
1300 T l_idx = surface_mesh.con[n];
1301 std::pair <T,T> Index_tag_old;
1302 Index_tag_old = std::make_pair(rnod[l_idx],tag);
1303 mesh_int_t Index_new = find_petsc_index(Index_tag_old).first;
1304 elem_nodes.push_back(Index_new);
1307 std::sort(elem_nodes.begin(),elem_nodes.end());
1308 if(elem_nodes.size()==2){
1311 key.v1 = elem_nodes[0];
1312 key.v2 = elem_nodes[1];
1313 auto it = line_face.find(key);
1314 if (it == line_face.end())
throw std::runtime_error(
"Line interface face not found");
1315 const std::pair<tuple_value, tuple_value> & value = it->second;
1317 tag_first = value.first.tag;
1318 tag_second = value.second.tag;
1320 mem_first = value.first.mem;
1321 mem_second = value.second.mem;
1323 else if(elem_nodes.size()==3){
1325 key.v1 = elem_nodes[0];
1326 key.v2 = elem_nodes[1];
1327 key.v3 = elem_nodes[2];
1328 auto it = tri_face.find(key);
1329 if (it == tri_face.end())
throw std::runtime_error(
"Triangular interface face not found");
1330 const std::pair<tri_value, tri_value> & value = it->second;
1332 tag_first = value.first.tag;
1333 tag_second = value.second.tag;
1335 mem_first = value.first.mem;
1336 mem_second = value.second.mem;
1338 else if(elem_nodes.size()==4){
1340 key.v1 = elem_nodes[0];
1341 key.v2 = elem_nodes[1];
1342 key.v3 = elem_nodes[2];
1343 key.v4 = elem_nodes[3];
1344 auto it = quad_face.find(key);
1345 if (it == quad_face.end())
throw std::runtime_error(
"Quadrilateral interface face not found");
1346 const std::pair<quad_value, quad_value> & value = it->second;
1348 tag_first = value.first.tag;
1349 tag_second = value.second.tag;
1351 mem_first = value.first.mem;
1352 mem_second = value.second.mem;
1355 SF_int nnodes = elem_nodes.size();
1356 for (
int i = 0; i < nnodes; ++i)
1358 if(mem_first==1 || mem_second==1){
1359 tag_2_vm[tag_first] = vb_data[eidx];
1360 tag_2_vm[tag_second] = vb_data[eidx];
1365 vb->const_release_ptr(vb_data);
1372 const vector<mesh_int_t> & petsc_nbr = emi_mesh.get_numbering(
NBR_PETSC);
1373 T start = 0, stop = 0;
1374 ui.get_ownership_range(start, stop);
1376 S* ui_data = ui.ptr();
1378 element_view<mesh_int_t, mesh_real_t> view(emi_mesh,
NBR_PETSC);
1379 for(
size_t eidx=0; eidx < emi_mesh.l_numelem; eidx++)
1381 view.set_elem(eidx);
1382 T tag = emi_mesh.tag[eidx];
1385 row_idx.resize(nnodes*row_dpn);
1386 canonic_indices<mesh_int_t,SF_int>(view.nodes(), petsc_nbr.data(), nnodes, row_dpn, row_idx.data());
1388 for (
int i = 0; i < nnodes; ++i)
1391 if(elemTag_emi_mesh[eidx]==2){
1392 if(row_idx[i] >= start && row_idx[i] < stop) {
1393 auto vm_it = tag_2_vm.
find(tag);
1394 if (vm_it != tag_2_vm.
end()) ui_data[row_idx[i] - start] = vm_it->second;
1399 ui.release_ptr(ui_data);
1400 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.
iterator find(const K &key)
Search for key. Return iterator.
void insert(InputIterator first, InputIterator last)
Insert Iterator range.
#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)