openCARP
Doxygen code documentation for the open cardiac electrophysiology simulator openCARP
emi.h
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright (c) NumeriCor GmbH
2 // SPDX-License-Identifier: Apache-2.0
3 
11 #if WITH_EMI_MODEL
12 
13 #ifndef _EMI_H
14 #define _EMI_H
15 
16 #include "electrics.h"
17 #include "ionicsOnFace.h"
18 
19 namespace opencarp {
20 
21 class parabolic_solver_emi
22 {
23  public:
24 
25  // Has to be kept in line with param_globals::parab_solve
26  enum parabolic_t {SEMI_IMPLICIT = 0};
27  //
28  // There are three surface meshes in the EMI model:
29 
30  // - `emi_surface_msh`:
31  // Contains the local one-sided interface representation used by the ionic
32  // model and surface output. Each local element corresponds to the interface
33  // side owned by this rank.
34 
35  // - `emi_surface_counter_msh`:
36  // Contains both faces and counter-faces for all membrane interfaces,
37  // regardless of whether the two sides are on the same MPI rank or on
38  // different ranks. This is the row space for the barycentric both-face
39  // vectors and for B/Bi.
40 
41  // - `emi_surface_unique_face_msh`:
42  // Contains one representative face per physical membrane/gap-junction
43  // interface. This is the vector layout used by the ionic model.
44  //
45  sf_vec* ui = nullptr;
46  sf_vec* dui = nullptr;
47  sf_vec* ui_pre = nullptr;
48  sf_vec* vb = nullptr;
49  sf_vec* vb_one_face = nullptr;
50  sf_vec* vb_both_face = nullptr;
51  sf_vec* vb_unique_face = nullptr;
52  sf_vec* Ib = nullptr;
53  sf_vec* Ib_one_face = nullptr;
54  sf_vec* Ib_both_face = nullptr;
55  sf_vec* Ib_unique_face = nullptr;
56  sf_vec* Iij_stim = nullptr;
57  sf_vec* Iij_temp = nullptr;
58  sf_vec* Irhs = nullptr;
59 
60  sf_mat* mass_emi = nullptr;
61  sf_mat* mass_surf_emi = nullptr;
62  sf_mat* lhs_emi = nullptr;
63  sf_mat* stiffness_emi = nullptr;
64  sf_mat* B = nullptr;
65  sf_mat* Bi = nullptr;
66  sf_mat* BsM = nullptr;
67 
68  // Direct transfer operators between unique-face and both-face layouts.
69  sf_mat* operator_unique_to_both_faces = nullptr;
70  sf_mat* operator_both_to_unique_face = nullptr;
71 
73  std::pair<SF::emi_face<mesh_int_t,SF::tuple<mesh_int_t>>,
74  SF::emi_face<mesh_int_t,SF::tuple<mesh_int_t>>>> line_face;
76  std::pair<SF::emi_face<mesh_int_t,SF::triple<mesh_int_t>>,
77  SF::emi_face<mesh_int_t,SF::triple<mesh_int_t>>>> tri_face;
79  std::pair<SF::emi_face<mesh_int_t,SF::quadruple<mesh_int_t>>,
80  SF::emi_face<mesh_int_t,SF::quadruple<mesh_int_t>>>> quad_face;
81 
83  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;
84 
88 
89  hashmap::unordered_set<int> extra_tags;
90  hashmap::unordered_set<int> intra_tags;
91 
92  // Element-side markers: 1 for extracellular/membrane side, 2 for intracellular/gap-junction side.
93  SF::vector<mesh_int_t> elemTag_emi_mesh;
94  SF::vector<mesh_int_t> elemTag_surface_mesh;
95  SF::vector<mesh_int_t> elemTag_surface_w_counter_mesh;
96 
97 
98  // map via vector from emi_surfmesh_w_counter_face element indices to emi_surfmesh (both -> one)
99  SF::vector<mesh_int_t> vec_both_to_one_face;
100 
101  hashmap::unordered_map<mesh_int_t, std::pair<SF::emi_index_rank<mesh_int_t>, SF::emi_index_rank<mesh_int_t>>> map_elem_uniqueFace_to_elem_oneface;
102 
103 
104  // Direct mapping (unique -> both face indices, no intermediate)
105  hashmap::unordered_map<mesh_int_t, std::pair<SF::emi_index_rank<mesh_int_t>, SF::emi_index_rank<mesh_int_t>>> map_elem_uniqueFace_to_elem_bothface;
106 
108  // the linear solver
109  sf_sol* lin_solver = nullptr;
110 
111  // linear solver stats
112  lin_solver_stats stats;
113 
115  dbc_manager* dbc = nullptr;
116  bool phie_mat_has_nullspace = false;
117  bool fem_matrices_exact_preallocated = false;
118 
119  // solver config
120  double tol = 1e-8;
121  int max_it = 100;
122  parabolic_t parab_tech = SEMI_IMPLICIT;
123 
124  // solver statistics
125  double final_residual = -1.0;
126  int niter = -1;
127 
128  ~parabolic_solver_emi()
129  {
130  if(dbc) delete dbc;
131  if (lin_solver) delete lin_solver;
132  // matrices
133  if (mass_emi) delete mass_emi;
134  if (mass_surf_emi) delete mass_surf_emi;
135  if (lhs_emi) delete lhs_emi;
136  if (stiffness_emi) delete stiffness_emi;
137  if (B) delete B;
138  if (Bi) delete Bi;
139  if (BsM) delete BsM;
140 
141  if (operator_unique_to_both_faces) delete operator_unique_to_both_faces;
142  if (operator_both_to_unique_face) delete operator_both_to_unique_face;
143 
144  // vectors
145  if (ui) delete ui;
146  if (dui) delete dui;
147  if (ui_pre) delete ui_pre;
148  if (vb) delete vb;
149 
150  if (vb_both_face) delete vb_both_face;
151  if (vb_unique_face) delete vb_unique_face;
152  if (Ib) delete Ib;
153 
154  if (Ib_both_face) delete Ib_both_face;
155  if (Ib_unique_face) delete Ib_unique_face;
156  if (Iij_stim) delete Iij_stim;
157  if (Iij_temp) delete Iij_temp;
158  if (Irhs) delete Irhs;
159 
160  line_face.clear();
161  tri_face.clear();
162  quad_face.clear();
163  }
164 
166  void init();
167 
169  void rebuild_matrices(MaterialType* mtype, limpet::MULTI_IF & miif, SF::vector<stimulus> & stimuli, FILE_SPEC logger);
170 
172  void solve();
173 
174  private:
175  void setup_linear_solver(FILE_SPEC logger);
176 
177  void solve_semiImplicit();
178 };
179 
180 class EMI : public Basic_physic
181 {
182  public:
183 
185  MaterialType mtype_vol[1];
186  MaterialType_EMI mtype_face;
188  SF::vector<stimulus> stimuli;
190  SF::vector<sf_vec*> itm_faces;
191 
194  IonicsOnFace ion;
195 
197  parabolic_solver_emi parab_solver;
198 
200  gvec_data_OnFace gvec;
201 
203  igb_output_manager output_manager;
204 
206  hashmap::unordered_set<int> output_tags;
207  SF::vector<mesh_int_t> phie_output_idx;
208  SF::vector<mesh_int_t> vm_output_idx;
209 
211  phie_recovery_data phie_rcv;
212 
213  generic_timing_stats IO_stats;
214 
219 
223  EMI() : ion(emi_surface_unique_face_msh)
224  {
225  name = "EMI";
226  }
227 
236  void initialize();
237 
238  void destroy();
239 
240  // This funcs from the Basic_physic interface are currently empty
241  void compute_step();
242  void output_step();
243 
244  inline void output_timings()
245  {
246  // since ionics are included in electrics, we subtract ionic timings from electric timings
247  compute_time -= ion.compute_time;
248  initialize_time -= ion.initialize_time;
249 
250  // now we call the base class timings output for Electrics
252  // and then for ionics
253  ion.output_timings();
254  }
255 
256  ~EMI()
257  {
258  };
259 
261  double timer_val(const int timer_id);
262 
264  std::string timer_unit(const int timer_id);
265 
266  private:
305  void setup_stimuli();
306 
330  void apply_current_stimulus();
331 
340  void setup_itm_faces();
341 
361  void apply_dbc_stimulus();
362 
398  void balance_electrodes();
399 
449  void scale_total_stimulus_current(SF::vector<stimulus>& stimuli,
450  sf_mat& mass_vol,
451  FILE_SPEC logger);
452 
454  void setup_solvers();
455 
457  void setup_mappings();
458 
460  void setup_output();
461 
463  void dump_matrices();
464 
465  void checkpointing();
466 
469  void dump_field_state(const char* roe_fnm);
470 
473  void restore_field_state(const char* roe_fnm);
474 
476  void setup_EMI_mesh();
477 };
478 
486 void log_mesh_local_element_ranges(const sf_mesh& emi_mesh,
487  const sf_mesh& emi_surfmesh_w_counter_face,
488  const sf_mesh& emi_surfmesh_unique_face);
489 
491 void extract_unique_tag(SF::vector<mesh_int_t>& unique_tags);
492 
494 void compute_tags_per_rank(int num_tags, SF::vector<mesh_int_t>& num_tags_per_rank);
495 
497 void distribute_elements_based_tags(SF::meshdata<mesh_int_t, mesh_real_t>& mesh,
498  int total_num_tags);
499 
501 void partition_based_tags(int num_tags,
503  SF::vector<mesh_int_t> num_tags_per_rank,
504  SF::vector<mesh_int_t>& part);
505 
507 void map_tags_to_rank(int size, const SF::vector<mesh_int_t> & unique_tags, const SF::vector<mesh_int_t> & num_tags_per_rank, hashmap::unordered_map<mesh_int_t, mesh_int_t> &tags_to_rank_map);
508 
511 bool load_partitions_from_file(hashmap::unordered_map<mesh_int_t, mesh_int_t>& tags_to_rank_map,
512  int expected_num_tags,
513  MPI_Comm comm);
514 
516 void permute_mesh_locally_based_on_tag_elemIdx(SF::meshdata<mesh_int_t, mesh_real_t>& mesh);
517 
518 } // namespace opencarp
519 
520 
521 #endif
522 #endif
opencarp::local_index_t mesh_int_t
Definition: SF_container.h:31
virtual void output_timings()
Definition: physics_types.h:61
Tissue level electrics, main Electrics physics class.
LIMPET ionics and gap-junction models on the EMI unique-face interface mesh.
SF::abstract_linear_solver< SF_int, SF_real > sf_sol
Definition: sf_interface.h:39
SF::meshdata< mesh_int_t, mesh_real_t > sf_mesh
Definition: sf_interface.h:33
@ emi_surface_unique_face_msh
Definition: sf_interface.h:53
SF::abstract_vector< SF_int, SF_real > sf_vec
Definition: sf_interface.h:35
SF::abstract_matrix< SF_int, SF_real > sf_mat
Definition: sf_interface.h:37
file_desc * FILE_SPEC
Definition: basics.h:126