openCARP
Doxygen code documentation for the open cardiac electrophysiology simulator openCARP
sf_interface.cc
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // openCARP is an open cardiac electrophysiology simulator.
3 //
4 // Copyright (C) 2020 openCARP project
5 //
6 // This program is licensed under the openCARP Academic Public License (APL)
7 // v1.0: You can use and redistribute it and/or modify it in non-commercial
8 // academic environments under the terms of APL as published by the openCARP
9 // project v1.0, or (at your option) any later version. Commercial use requires
10 // a commercial license (info@opencarp.org).
11 //
12 // This program is distributed without any warranty; see the openCARP APL for
13 // more details.
14 //
15 // You should have received a copy of the openCARP APL along with this program
16 // and can find it online: http://www.opencarp.org/license
17 // ----------------------------------------------------------------------------
18 
27 #include "petsc_utils.h" // TODO: for EXIT
28 #include "sf_interface.h"
29 #include "sim_utils.h"
30 
31 namespace opencarp {
32 
33 sf_mesh & get_mesh(const mesh_t gt)
34 {
35  auto it = user_globals::mesh_reg.find(gt);
36  if(it == user_globals::mesh_reg.end()) {
37  log_msg(0,5,0, "%s error: mesh of type \"%s\" not found! Aborting!",
38  __func__, get_mesh_type_name(gt));
39  EXIT(EXIT_FAILURE);
40  }
41 
42  return it->second;
43 }
44 
45 const char*
47  switch(t) {
48  case intra_elec_msh: return "Intracellular Electric";
49  case extra_elec_msh: return "Extracellular Electric";
50  case eikonal_msh: return "Eikonal";
51  case elasticity_msh: return "Elasticity";
52  case fluid_msh: return "Fluid";
53  case emi_msh: return "EMI volume"; // includes both discontinuous faces and inner domain structures.
54  case emi_surface_msh: return "EMI surface"; // Interface mesh from EMI mesh (including gap junction face and membrane faces)
55  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
56  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)
57  case reference_msh: return "Reference";
58  case phie_recv_msh: return "Phie Recovery";
59  default: return NULL;
60  }
61 }
62 
63 bool mesh_is_registered(const mesh_t gt)
64 {
65  return user_globals::mesh_reg.find(gt) != user_globals::mesh_reg.end();
66 }
67 
69 register_scattering(const int from, const int to, const SF::SF_nbr nbr, const int dpn)
70 {
71  int rank = get_rank();
72 
73  sf_mesh & from_mesh = get_mesh(mesh_t(from));
74  // we compute the petsc numbering of only the algebraicly distributed nodes
75  const SF::vector<mesh_int_t> & from_alg_nod = from_mesh.pl.algebraic_nodes();
76  const SF::vector<mesh_int_t> & from_nodal_nbr = from_mesh.get_numbering(nbr);
77  SF::scattering* ret = NULL;
78  SF::quadruple<int> spec = {from, to, nbr, dpn};
79 
80  if(to != ALG_TO_NODAL) {
81  sf_mesh & to_mesh = get_mesh(mesh_t(to));
82  // we set up the inter-domain index mapping in the registry map_reg
84  SF::inter_domain_mapping(from_mesh, to_mesh, nbr, idx_map);
85 
86  SF::vector<mesh_int_t> to_numbering(from_alg_nod.size());
87  SF::vector<mesh_int_t> from_numbering(from_alg_nod.size());
88  int err = 0;
89 
90  for(size_t i=0; i<from_alg_nod.size(); i++) {
91  mesh_int_t from_idx = from_nodal_nbr[from_alg_nod[i]];
92  mesh_int_t to_idx = idx_map.forward_map(from_idx);
93 
94  if(to_idx < 0) {
95  err++;
96  break;
97  }
98 
99  from_numbering[i] = from_idx;
100  to_numbering[i] = to_idx;
101  }
102 
103  if(get_global(err, MPI_SUM)) {
104  log_msg(0,5,0, "%s error: Bad inter-domain mapping. Aborting!", __func__);
105  EXIT(1);
106  }
107 
108  ret = user_globals::scatter_reg.register_scattering(spec, from_mesh.pl.algebraic_layout(),
109  to_mesh.pl.algebraic_layout(), from_numbering, to_numbering, rank, dpn);
110 
111  }
112  else {
113  const SF::vector<mesh_int_t> & nodal_layout = from_mesh.pl.layout();
114  SF::vector<mesh_int_t> to_numbering(from_nodal_nbr.size());
115 
116  SF::interval(to_numbering, nodal_layout[rank], nodal_layout[rank+1]);
117 
118  ret = user_globals::scatter_reg.register_scattering(spec, from_mesh.pl.algebraic_layout(),
119  nodal_layout, from_nodal_nbr, to_numbering, rank, dpn);
120  }
121 
122  return ret;
123 }
124 
125 SF::scattering* get_scattering(const int from, const int to, const SF::SF_nbr nbr, const int dpn)
126 {
127  SF::quadruple<int> spec = {from, to, int(nbr), dpn};
129 
130  if(sc == NULL)
131  return register_scattering(from, to, nbr, dpn);
132  else
133  return sc;
134 }
135 
136 bool have_scattering(const int from, const int to, const SF::SF_nbr nbr, const int dpn)
137 {
138  SF::quadruple<int> spec = {from, to, int(nbr), dpn};
140 
141  return sc != NULL;
142 }
143 
145 register_permutation(const int mesh_id, const int perm_id, const int dpn)
146 {
147  sf_mesh & mesh = get_mesh(mesh_t(mesh_id));
148  const SF::vector<mesh_int_t> & petsc_nbr = mesh.get_numbering(SF::NBR_PETSC);
149  const SF::vector<mesh_int_t> & alg_nod = mesh.pl.algebraic_nodes();
150  SF::quadruple<int> spec = {mesh_id, perm_id, 0, dpn};
151 
152  switch(perm_id) {
153  case PETSC_TO_CANONICAL:
154  {
155  const SF::vector<mesh_int_t> & canon_nbr = mesh.get_numbering(SF::NBR_SUBMESH);
156  SF::vector<mesh_int_t> petsc_alg_nod(alg_nod.size()), canon_alg_nod(alg_nod.size());
157 
158  for(size_t i=0; i<alg_nod.size(); i++)
159  {
160  petsc_alg_nod[i] = petsc_nbr[alg_nod[i]];
161  canon_alg_nod[i] = canon_nbr[alg_nod[i]];
162  }
163 
164  return user_globals::scatter_reg.register_permutation(spec, petsc_alg_nod, canon_alg_nod,
165  mesh.g_numpts, mesh.g_numpts, dpn);
166  }
167 
169  {
171  const SF::vector<mesh_int_t> & elem_layout = mesh.epl.algebraic_layout();
172  const int rank = get_rank();
173 
174  SF::vector<mesh_int_t> petsc_nod(canon_nbr.size()), canon_nod(canon_nbr.size());
175 
176  for(size_t i=0; i<canon_nbr.size(); i++)
177  {
178  petsc_nod[i] = elem_layout[rank] + i;
179  canon_nod[i] = canon_nbr[i];
180  }
181 
182  return user_globals::scatter_reg.register_permutation(spec, petsc_nod, canon_nod,
183  mesh.g_numelem, mesh.g_numelem, dpn);
184  }
185 /*
186  case PETSC_TO_PT:
187  {
188  const SF::vector<mesh_int_t> & pt_nbr = mesh.get_numbering(SF::NBR_SOLVER);
189  SF::vector<mesh_int_t> petsc_alg_nod(alg_nod.size()), pt_alg_nod(alg_nod.size());
190 
191  for(size_t i=0; i<alg_nod.size(); i++)
192  {
193  petsc_alg_nod[i] = petsc_nbr[alg_nod[i]];
194  pt_alg_nod[i] = pt_nbr[alg_nod[i]];
195  }
196 
197  return user_globals::scatter_reg.register_permutation(spec, petsc_alg_nod, pt_alg_nod,
198  mesh.g_numpts, mesh.g_numpts, dpn);
199  }
200 */
201  default:
202  log_msg(0,5,0, "%s error: Unknown permutation id. Aborting!", __func__);
203  EXIT(1);
204  }
205 }
206 
208 get_permutation(const int mesh_id, const int perm_id, const int dpn)
209 {
210  SF::quadruple<int> spec = {mesh_id, perm_id, 0, dpn};
212 
213  if(sc == NULL)
214  return register_permutation(mesh_id, perm_id, dpn);
215  else
216  return sc;
217 }
218 
219 bool have_permutation(const int mesh_id, const int perm_id, const int dpn)
220 {
221  SF::quadruple<int> spec = {mesh_id, perm_id, 0, dpn};
223 
224  return sc != NULL;
225 }
226 
227 int get_phys_index(int physreg)
228 {
229  int idx = -1;
230  for(int i=0; i<param_globals::num_phys_regions; i++) {
231  if(param_globals::phys_region[i].ptype == physreg) {
232  idx = i;
233  break;
234  }
235  }
236  return idx;
237 }
238 
239 bool phys_defined(int physreg)
240 {
241  int idx = get_phys_index(physreg);
242  return idx > -1;
243 }
244 
245 
246 } // namespace opencarp
247 
int mesh_int_t
Definition: SF_container.h:46
T forward_map(T idx) const
Map one index from a to b.
Definition: SF_container.h:264
overlapping_layout< T > pl
nodal parallel layout
Definition: SF_container.h:429
size_t g_numpts
global number of points
Definition: SF_container.h:400
size_t g_numelem
global number of elements
Definition: SF_container.h:398
vector< T > & get_numbering(SF_nbr nbr_type)
Get the vector defining a certain numbering.
Definition: SF_container.h:464
non_overlapping_layout< T > epl
element parallel layout
Definition: SF_container.h:430
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:104
void interval(vector< T > &vec, size_t start, size_t end)
Create an integer interval between start and end.
Definition: SF_vector.h:350
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:200
@ NBR_PETSC
PETSc numbering of nodes.
Definition: SF_container.h:203
@ NBR_SUBMESH
Submesh nodal numbering: The globally ascending sorted reference indices are reindexed.
Definition: SF_container.h:202
@ NBR_ELEM_SUBMESH
Submesh element numbering: The globally ascending sorted reference indices are reindexed.
Definition: SF_container.h:205
std::map< SF::quadruple< int >, SF::index_mapping< int > > map_reg
Registriy for the inter domain mappings.
Definition: main.cc:54
SF::scatter_registry scatter_reg
Registry for the different scatter objects.
Definition: main.cc:50
std::map< mesh_t, sf_mesh > mesh_reg
Registry for the different meshes used in a multi-physics simulation.
Definition: main.cc:52
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:33
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:69
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:276
T get_global(T in, MPI_Op OP, MPI_Comm comm=PETSC_COMM_WORLD)
Do a global reduction on a variable.
Definition: basics.h:233
const char * get_mesh_type_name(mesh_t t)
get a char* to the name of a mesh type
Definition: sf_interface.cc:46
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:72
mesh_t
The enum identifying the different meshes we might want to load.
Definition: sf_interface.h:59
@ reference_msh
Definition: sf_interface.h:69
@ elasticity_msh
Definition: sf_interface.h:63
@ emi_surface_unique_face_msh
Definition: sf_interface.h:68
@ extra_elec_msh
Definition: sf_interface.h:61
@ phie_recv_msh
Definition: sf_interface.h:70
@ intra_elec_msh
Definition: sf_interface.h:60
@ emi_surface_msh
Definition: sf_interface.h:66
@ emi_surface_counter_msh
Definition: sf_interface.h:67
bool mesh_is_registered(const mesh_t gt)
check wheter a SF mesh is set
Definition: sf_interface.cc:63
Interface to SlimFem.
#define PETSC_TO_CANONICAL
Permute algebraic data from PETSC to canonical ordering.
Definition: sf_interface.h:79
#define ALG_TO_NODAL
Scatter algebraic to nodal.
Definition: sf_interface.h:77
#define ELEM_PETSC_TO_CANONICAL
Permute algebraic element data from PETSC to canonical ordering.
Definition: sf_interface.h:81
Simulator-level utility execution control functions.