29 using vertex_tag = std::pair<mesh_int_t, mesh_int_t>;
36 void check(
bool ok,
const std::string& what)
39 std::cerr <<
"FAILED: " << what <<
'\n';
44 void build_mesh(
int rank,
int size, MPI_Comm comm,
mesh_t& mesh)
46 const std::vector<mesh_int_t> myocyte{0, 1, 2, 3}, extra{1, 2, 3, 5};
47 std::vector<std::pair<mesh_int_t, const std::vector<mesh_int_t>*>> elems;
48 if (rank == 0) elems.push_back({MYOCYTE, &myocyte});
49 if (rank == size - 1) elems.push_back({EXTRA, &extra});
53 for (
const auto& [tag, nodes] : elems) {
55 mesh.tag.push_back(tag);
59 mesh.l_numelem = elems.size();
63 eref.
resize(mesh.l_numelem);
64 for (
size_t i = 0; i < eref.
size(); i++) eref[i] = (rank == 0 ? 0 : 1) + i;
67 mesh.generate_par_layout();
72 int main(
int argc,
char** argv)
74 MPI_Init(&argc, &argv);
75 MPI_Comm comm = MPI_COMM_WORLD;
77 MPI_Comm_size(comm, &size);
78 MPI_Comm_rank(comm, &rank);
81 build_mesh(rank, size, comm, mesh);
82 check(mesh.g_numpts == 5,
"g_numpts counts the 5 used points");
85 hashmap::unordered_map<mesh_int_t, mesh_int_t> ptsdata{{0, 0}, {1, 1}, {2, 1}, {3, 1}, {5, 0}};
88 SF::compute_map_vertex_to_dof(mesh,
SF::NBR_REF, ptsdata, extra_tags, dofs);
91 std::vector<mesh_int_t> local;
92 for (
const auto& [key, dof] : dofs) local.insert(local.end(), {key.first, key.second, dof});
94 std::vector<int> counts(size), displs(size);
95 MPI_Gather(&n, 1, MPI_INT, counts.data(), 1, MPI_INT, 0, comm);
96 for (
int r = 1; r < size; r++) displs[r] = displs[r - 1] + counts[r - 1];
97 std::vector<mesh_int_t> all(rank == 0 ? displs[size - 1] + counts[size - 1] : 0);
98 MPI_Datatype type =
sizeof(
mesh_int_t) == 8 ? MPI_LONG_LONG : MPI_INT;
99 MPI_Gatherv(local.data(), n, type, all.data(), counts.data(), displs.data(), type, 0, comm);
102 std::map<vertex_tag, mesh_int_t> dof_of;
103 for (
size_t i = 0; i < all.size(); i += 3) {
104 const vertex_tag key{all[i], all[i + 1]};
105 auto [it, inserted] = dof_of.insert({key, all[i + 2]});
106 check(inserted || it->second == all[i + 2],
"one DOF per (vertex, tag)");
109 check(dof_of.count({v, MYOCYTE}) && dof_of.count({v, EXTRA}),
110 "membrane vertex " + std::to_string(v) +
" has a myocyte and an extracellular DOF");
111 check(dof_of[{v, MYOCYTE}] != dof_of[{v, EXTRA}],
112 "membrane vertex " + std::to_string(v) +
" is decoupled");
114 std::map<mesh_int_t, mesh_int_t> vertex_of;
115 for (
const auto& [key, dof] : dof_of) {
116 auto [it, inserted] = vertex_of.insert({dof, key.first});
117 check(inserted || it->second == key.first,
118 "DOF " + std::to_string(dof) +
" belongs to vertices " + std::to_string(it->second) +
119 " and " + std::to_string(key.first));
124 MPI_Allreduce(&failures, &total, 1, MPI_INT, MPI_SUM, comm);
126 return total ? 1 : 0;
opencarp::local_index_t mesh_int_t
Basic utility structs and functions, mostly IO related.
MPI_Comm comm
the parallel mesh is defined on a MPI world
size_t size() const
The current size of the vector.
void resize(size_t n)
Resize a vector.
void dsp_from_cnt(const vector< T > &cnt, vector< T > &dsp)
Compute displacements from counts.
@ 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).
mesh_t
The enum identifying the different meshes we might want to load.
int main(int argc, char **argv)