openCARP
Doxygen code documentation for the open cardiac electrophysiology simulator openCARP
sf_interface.cc
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright (c) NumeriCor GmbH
2 // SPDX-License-Identifier: Apache-2.0
3 
12 #include "petsc_utils.h" // TODO: for EXIT
13 #include "sf_interface.h"
14 #include "sim_utils.h"
15 
16 namespace opencarp {
17 
18 sf_mesh & get_mesh(const mesh_t gt)
19 {
20  auto it = user_globals::mesh_reg.find(gt);
21  if(it == user_globals::mesh_reg.end()) {
22  log_msg(0,5,0, "%s error: mesh of type \"%s\" not found! Aborting!",
23  __func__, get_mesh_type_name(gt));
24  EXIT(EXIT_FAILURE);
25  }
26 
27  return it->second;
28 }
29 
30 const char*
32  switch(t) {
33  case intra_elec_msh: return "Intracellular Electric";
34  case extra_elec_msh: return "Extracellular Electric";
35  case eikonal_msh: return "Eikonal";
36  case elasticity_msh: return "Elasticity";
37  case fluid_msh: return "Fluid";
38  case emi_msh: return "EMI volume"; // includes both discontinuous faces and inner domain structures.
39  case emi_surface_msh: return "EMI surface"; // Interface mesh from EMI mesh (including gap junction face and membrane faces)
40  case emi_surface_counter_msh: return "EMI surface with counter"; // The interface mesh is constructed from the EMI mesh, incorporating both gap junction faces and membrane faces. Additionally, each face includes its corresponding counter face between two subdomains, where current will be computed on both face and counter face
41  case emi_surface_unique_face_msh: return "EMI surface with single face on EMI interface"; // Interface mesh from EMI mesh (including gap junction face and membrane faces)
42  case reference_msh: return "Reference";
43  case phie_recv_msh: return "Phie Recovery";
44  default: return NULL;
45  }
46 }
47 
48 bool mesh_is_registered(const mesh_t gt)
49 {
50  return user_globals::mesh_reg.find(gt) != user_globals::mesh_reg.end();
51 }
52 
54 register_scattering(const int from, const int to, const SF::SF_nbr nbr, const int dpn)
55 {
56  int rank = get_rank();
57 
58  sf_mesh & from_mesh = get_mesh(mesh_t(from));
59  // we compute the petsc numbering of only the algebraicly distributed nodes
60  const SF::vector<mesh_int_t> & from_alg_nod = from_mesh.pl.algebraic_nodes();
61  const SF::vector<mesh_int_t> & from_nodal_nbr = from_mesh.get_numbering(nbr);
62  SF::scattering* ret = NULL;
63  SF::quadruple<int> spec = {from, to, nbr, dpn};
64 
65  if(to != ALG_TO_NODAL) {
66  sf_mesh & to_mesh = get_mesh(mesh_t(to));
67  // we set up the inter-domain index mapping in the registry map_reg
69  SF::inter_domain_mapping(from_mesh, to_mesh, nbr, idx_map);
70 
71  SF::vector<mesh_int_t> to_numbering(from_alg_nod.size());
72  SF::vector<mesh_int_t> from_numbering(from_alg_nod.size());
73  int err = 0;
74 
75  for(size_t i=0; i<from_alg_nod.size(); i++) {
76  mesh_int_t from_idx = from_nodal_nbr[from_alg_nod[i]];
77  mesh_int_t to_idx = idx_map.forward_map(from_idx);
78 
79  if(to_idx < 0) {
80  err++;
81  break;
82  }
83 
84  from_numbering[i] = from_idx;
85  to_numbering[i] = to_idx;
86  }
87 
88  if(get_global(err, MPI_SUM)) {
89  log_msg(0,5,0, "%s error: Bad inter-domain mapping. Aborting!", __func__);
90  EXIT(1);
91  }
92 
93  ret = user_globals::scatter_reg.register_scattering(spec, from_mesh.pl.algebraic_layout(),
94  to_mesh.pl.algebraic_layout(), from_numbering, to_numbering, rank, dpn);
95 
96  }
97  else {
98  const SF::vector<mesh_int_t> & nodal_layout = from_mesh.pl.layout();
99  SF::vector<mesh_int_t> to_numbering(from_nodal_nbr.size());
100 
101  SF::interval(to_numbering, nodal_layout[rank], nodal_layout[rank+1]);
102 
103  ret = user_globals::scatter_reg.register_scattering(spec, from_mesh.pl.algebraic_layout(),
104  nodal_layout, from_nodal_nbr, to_numbering, rank, dpn);
105  }
106 
107  return ret;
108 }
109 
110 SF::scattering* get_scattering(const int from, const int to, const SF::SF_nbr nbr, const int dpn)
111 {
112  SF::quadruple<int> spec = {from, to, int(nbr), dpn};
114 
115  if(sc == NULL)
116  return register_scattering(from, to, nbr, dpn);
117  else
118  return sc;
119 }
120 
121 bool have_scattering(const int from, const int to, const SF::SF_nbr nbr, const int dpn)
122 {
123  SF::quadruple<int> spec = {from, to, int(nbr), dpn};
125 
126  return sc != NULL;
127 }
128 
130 register_permutation(const int mesh_id, const int perm_id, const int dpn)
131 {
132  sf_mesh & mesh = get_mesh(mesh_t(mesh_id));
133  const SF::vector<mesh_int_t> & petsc_nbr = mesh.get_numbering(SF::NBR_PETSC);
134  const SF::vector<mesh_int_t> & alg_nod = mesh.pl.algebraic_nodes();
135  SF::quadruple<int> spec = {mesh_id, perm_id, 0, dpn};
136 
137  switch(perm_id) {
138  case PETSC_TO_CANONICAL:
139  {
140  const SF::vector<mesh_int_t> & canon_nbr = mesh.get_numbering(SF::NBR_SUBMESH);
141  SF::vector<mesh_int_t> petsc_alg_nod(alg_nod.size()), canon_alg_nod(alg_nod.size());
142 
143  for(size_t i=0; i<alg_nod.size(); i++)
144  {
145  petsc_alg_nod[i] = petsc_nbr[alg_nod[i]];
146  canon_alg_nod[i] = canon_nbr[alg_nod[i]];
147  }
148 
149  return user_globals::scatter_reg.register_permutation(spec, petsc_alg_nod, canon_alg_nod,
150  mesh.g_numpts, mesh.g_numpts, dpn);
151  }
152 
154  {
156  const SF::vector<mesh_int_t> & elem_layout = mesh.epl.algebraic_layout();
157  const int rank = get_rank();
158 
159  SF::vector<mesh_int_t> petsc_nod(canon_nbr.size()), canon_nod(canon_nbr.size());
160 
161  for(size_t i=0; i<canon_nbr.size(); i++)
162  {
163  petsc_nod[i] = elem_layout[rank] + i;
164  canon_nod[i] = canon_nbr[i];
165  }
166 
167  return user_globals::scatter_reg.register_permutation(spec, petsc_nod, canon_nod,
168  mesh.g_numelem, mesh.g_numelem, dpn);
169  }
170 /*
171  case PETSC_TO_PT:
172  {
173  const SF::vector<mesh_int_t> & pt_nbr = mesh.get_numbering(SF::NBR_SOLVER);
174  SF::vector<mesh_int_t> petsc_alg_nod(alg_nod.size()), pt_alg_nod(alg_nod.size());
175 
176  for(size_t i=0; i<alg_nod.size(); i++)
177  {
178  petsc_alg_nod[i] = petsc_nbr[alg_nod[i]];
179  pt_alg_nod[i] = pt_nbr[alg_nod[i]];
180  }
181 
182  return user_globals::scatter_reg.register_permutation(spec, petsc_alg_nod, pt_alg_nod,
183  mesh.g_numpts, mesh.g_numpts, dpn);
184  }
185 */
186  default:
187  log_msg(0,5,0, "%s error: Unknown permutation id. Aborting!", __func__);
188  EXIT(1);
189  }
190 }
191 
193 get_permutation(const int mesh_id, const int perm_id, const int dpn)
194 {
195  SF::quadruple<int> spec = {mesh_id, perm_id, 0, dpn};
197 
198  if(sc == NULL)
199  return register_permutation(mesh_id, perm_id, dpn);
200  else
201  return sc;
202 }
203 
204 bool have_permutation(const int mesh_id, const int perm_id, const int dpn)
205 {
206  SF::quadruple<int> spec = {mesh_id, perm_id, 0, dpn};
208 
209  return sc != NULL;
210 }
211 
212 int get_phys_index(int physreg)
213 {
214  int idx = -1;
215  for(int i=0; i<param_globals::num_phys_regions; i++) {
216  if(param_globals::phys_region[i].ptype == physreg) {
217  idx = i;
218  break;
219  }
220  }
221  return idx;
222 }
223 
224 bool phys_defined(int physreg)
225 {
226  int idx = get_phys_index(physreg);
227  return idx > -1;
228 }
229 
230 
231 } // namespace opencarp
232 
opencarp::local_index_t mesh_int_t
Definition: SF_container.h:31
T forward_map(T idx) const
Map one index from a to b.
Definition: SF_container.h:249
overlapping_layout< T > pl
nodal parallel layout
Definition: SF_container.h:414
size_t g_numpts
global number of points
Definition: SF_container.h:385
size_t g_numelem
global number of elements
Definition: SF_container.h:383
vector< T > & get_numbering(SF_nbr nbr_type)
Get the vector defining a certain numbering.
Definition: SF_container.h:449
non_overlapping_layout< T > epl
element parallel layout
Definition: SF_container.h:415
scattering * register_scattering(const quadruple< int > spec, const vector< T > &layout_a, const vector< T > &layout_b, const vector< T > &idx_a, const vector< T > &idx_b, const int rank, const int dpn)
Register a scattering.
scattering * register_permutation(const quadruple< int > spec, const vector< T > &nbr_a, const vector< T > &nbr_b, const size_t gsize_a, const size_t gsize_b, const short dpn)
Register a permutation scattering.
scattering * get_scattering(const quadruple< int > spec)
Access an previously registered scattering.
Container for a PETSc VecScatter.
size_t size() const
The current size of the vector.
Definition: SF_vector.h:89
void interval(vector< T > &vec, size_t start, size_t end)
Create an integer interval between start and end.
Definition: SF_vector.h:335
void inter_domain_mapping(const meshdata< T, S > &mesh_a, const meshdata< T, S > &mesh_b, const SF_nbr snbr, index_mapping< T > &a_to_b)
Submesh index mapping between different domains/meshes.
SF_nbr
Enumeration encoding the different supported numberings.
Definition: SF_container.h:185
@ NBR_PETSC
PETSc numbering of nodes.
Definition: SF_container.h:188
@ NBR_SUBMESH
Submesh nodal numbering: The globally ascending sorted reference indices are reindexed.
Definition: SF_container.h:187
@ NBR_ELEM_SUBMESH
Submesh element numbering: The globally ascending sorted reference indices are reindexed.
Definition: SF_container.h:190
std::map< SF::quadruple< int >, SF::index_mapping< mesh_int_t > > map_reg
Registriy for the inter domain mappings.
Definition: main.cc:36
SF::scatter_registry scatter_reg
Registry for the different scatter objects.
Definition: main.cc:32
std::map< mesh_t, sf_mesh > mesh_reg
Registry for the different meshes used in a multi-physics simulation.
Definition: main.cc:34
SF::scattering * get_scattering(const int from, const int to, const SF::SF_nbr nbr, const int dpn)
Get a scattering from the global scatter registry.
sf_mesh & get_mesh(const mesh_t gt)
Get a mesh by specifying the gridID.
Definition: sf_interface.cc:18
SF::scattering * register_scattering(const int from, const int to, const SF::SF_nbr nbr, const int dpn)
Register a scattering between to grids, or between algebraic and nodal representation of data on the ...
Definition: sf_interface.cc:54
SF::scattering * get_permutation(const int mesh_id, const int perm_id, const int dpn)
Get the PETSC to canonical permutation scattering for a given mesh and number of dpn.
bool have_scattering(const int from, const int to, const SF::SF_nbr nbr, const int dpn)
int get_rank(MPI_Comm comm=PETSC_COMM_WORLD)
Definition: basics.h:269
T get_global(T in, MPI_Op OP, MPI_Comm comm=PETSC_COMM_WORLD)
Do a global reduction on a variable.
Definition: basics.h:218
const char * get_mesh_type_name(mesh_t t)
get a char* to the name of a mesh type
Definition: sf_interface.cc:31
bool phys_defined(int physreg)
function to check if certain physics are defined
bool have_permutation(const int mesh_id, const int perm_id, const int dpn)
SF::scattering * register_permutation(const int mesh_id, const int perm_id, const int dpn)
Register a permutation between two orderings for a mesh.
int get_phys_index(int physreg)
get index in param_globals::phys_region array for a certain phys region
void log_msg(FILE_SPEC out, int level, unsigned char flag, const char *fmt,...)
Definition: basics.cc:57
mesh_t
The enum identifying the different meshes we might want to load.
Definition: sf_interface.h:44
@ reference_msh
Definition: sf_interface.h:54
@ elasticity_msh
Definition: sf_interface.h:48
@ emi_surface_unique_face_msh
Definition: sf_interface.h:53
@ extra_elec_msh
Definition: sf_interface.h:46
@ phie_recv_msh
Definition: sf_interface.h:55
@ intra_elec_msh
Definition: sf_interface.h:45
@ emi_surface_msh
Definition: sf_interface.h:51
@ emi_surface_counter_msh
Definition: sf_interface.h:52
bool mesh_is_registered(const mesh_t gt)
check wheter a SF mesh is set
Definition: sf_interface.cc:48
Interface to SlimFem.
#define PETSC_TO_CANONICAL
Permute algebraic data from PETSC to canonical ordering.
Definition: sf_interface.h:64
#define ALG_TO_NODAL
Scatter algebraic to nodal.
Definition: sf_interface.h:62
#define ELEM_PETSC_TO_CANONICAL
Permute algebraic element data from PETSC to canonical ordering.
Definition: sf_interface.h:66
Simulator-level utility execution control functions.