openCARP
Doxygen code documentation for the open cardiac electrophysiology simulator openCARP
emi.h
Go to the documentation of this file.
1 //
2 // Copyright (C) 2020 openCARP project
3 //
4 // This program is licensed under the openCARP Academic Public License (APL)
5 // v1.0: You can use and redistribute it and/or modify it in non-commercial
6 // academic environments under the terms of APL as published by the openCARP
7 // project v1.0, or (at your option) any later version. Commercial use requires
8 // a commercial license (info@opencarp.org).
9 //
10 // This program is distributed without any warranty; see the openCARP APL for
11 // more details.
12 //
13 // You should have received a copy of the openCARP APL along with this program
14 // and can find it online: http://www.opencarp.org/license
15 // ----------------------------------------------------------------------------
16 
24 #if WITH_EMI_MODEL
25 
26 #ifndef _EMI_H
27 #define _EMI_H
28 
29 #include "electrics.h"
30 #include "ionicsOnFace.h"
31 
32 namespace opencarp {
33 
34 class parabolic_solver_emi
35 {
36  public:
37 
38  // Has to be kept in line with param_globals::parab_solve
39  enum parabolic_t {SEMI_IMPLICIT = 0};
40  //
41  // There are three surface meshes in EMI model:
42 
43  // - `emi_surface_msh`:
44  // Contains face/counter-face information only when the extracellular and intracellular sides are not located on the same MPI rank, i.e., when the membrane interface is split across ranks and a counter-face representation is required.
45  // This mesh is associated with the vector `one_face`.
46 
47  // - `emi_surface_counter_msh`:
48  // Contains both faces and counter-faces for all membrane interfaces, i.e., regardless of whether the extracellular and intracellular parts are located on the same MPI rank or on different ranks.
49  // This mesh is associated with the vector `both_face`.
50 
51  // - `emi_surface_unique_face_msh`:
52  // Contains only unique faces, where each physical membrane face appears exactly once, independent of whether its two sides are located on the same MPI rank or on different ranks.
53  // This mesh is associated with the vector `unique_face`.
54  //
55  sf_vec* ui = nullptr;
56  sf_vec* dui = nullptr;
57  sf_vec* ui_pre = nullptr;
58  sf_vec* vb = nullptr;
59  sf_vec* vb_one_face = nullptr;
60  sf_vec* vb_both_face = nullptr;
61  sf_vec* vb_unique_face = nullptr;
62  sf_vec* Ib = nullptr;
63  sf_vec* Ib_one_face = nullptr;
64  sf_vec* Ib_both_face = nullptr;
65  sf_vec* Ib_unique_face = nullptr;
66  sf_vec* Iij_stim = nullptr;
67  sf_vec* Iij_temp = nullptr;
68  sf_vec* Irhs = nullptr;
69 
70  sf_mat* mass_emi = nullptr;
71  sf_mat* mass_surf_emi = nullptr;
72  sf_mat* lhs_emi = nullptr;
73  sf_mat* stiffness_emi = nullptr;
74  sf_mat* B = nullptr;
75  sf_mat* Bi = nullptr;
76  sf_mat* BsM = nullptr;
77  sf_mat* Vm_myocyte_emi = nullptr;
78 
79  // Direct operators (unique <-> both, skipping intermediate one-face)
80  sf_mat* operator_unique_to_both_faces = nullptr;
81  sf_mat* operator_both_to_unique_face = nullptr;
82 
83 
85  std::pair<SF::emi_face<mesh_int_t,SF::tuple<mesh_int_t>>,
86  SF::emi_face<mesh_int_t,SF::tuple<mesh_int_t>>>> line_face;
88  std::pair<SF::emi_face<mesh_int_t,SF::triple<mesh_int_t>>,
89  SF::emi_face<mesh_int_t,SF::triple<mesh_int_t>>>> tri_face;
91  std::pair<SF::emi_face<mesh_int_t,SF::quadruple<mesh_int_t>>,
92  SF::emi_face<mesh_int_t,SF::quadruple<mesh_int_t>>>> quad_face;
93 
95  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;
96 
100 
101  hashmap::unordered_set<int> extra_tags;
102  hashmap::unordered_set<int> intra_tags;
103 
104  // here for any element, we set 1 for membrane and 2 for gap-junction
105  SF::vector<mesh_int_t> elemTag_emi_mesh;
106  SF::vector<mesh_int_t> elemTag_surface_mesh;
107  SF::vector<mesh_int_t> elemTag_surface_w_counter_mesh;
108 
109 
110  // map via vector from emi_surfmesh_w_counter_face element indices to emi_surfmesh (both -> one)
111  SF::vector<mesh_int_t> vec_both_to_one_face;
112 
113  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;
114 
115 
116  // Direct mapping (unique -> both face indices, no intermediate)
117  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;
118 
120  // the linear solver
121  sf_sol* lin_solver = nullptr;
122 
123  // linear solver stats
124  lin_solver_stats stats;
125 
127  dbc_manager* dbc = nullptr;
128  bool phie_mat_has_nullspace = false;
129 
130  // solver config
131  double tol = 1e-8;
132  int max_it = 100;
133  parabolic_t parab_tech = SEMI_IMPLICIT;
134 
135  // solver statistics
136  double final_residual = -1.0;
137  int niter = -1;
138 
139  ~parabolic_solver_emi()
140  {
141  if(dbc) delete dbc;
142  if (lin_solver) delete lin_solver;
143  // matrices
144  if (mass_emi) delete mass_emi;
145  if (mass_surf_emi) delete mass_surf_emi;
146  if (lhs_emi) delete lhs_emi;
147  if (stiffness_emi) delete stiffness_emi;
148  if (B) delete B;
149  if (Bi) delete Bi;
150  if (BsM) delete BsM;
151  if (Vm_myocyte_emi) delete Vm_myocyte_emi;
152 
153  if (operator_unique_to_both_faces) delete operator_unique_to_both_faces;
154  if (operator_both_to_unique_face) delete operator_both_to_unique_face;
155 
156  // vectors
157  if (ui) delete ui;
158  if (dui) delete dui;
159  if (ui_pre) delete ui_pre;
160  if (vb) delete vb;
161 
162  if (vb_both_face) delete vb_both_face;
163  if (vb_unique_face) delete vb_unique_face;
164  if (Ib) delete Ib;
165 
166  if (Ib_both_face) delete Ib_both_face;
167  if (Ib_unique_face) delete Ib_unique_face;
168  if (Iij_stim) delete Iij_stim;
169  if (Iij_temp) delete Iij_temp;
170  if (Irhs) delete Irhs;
171 
172  line_face.clear();
173  tri_face.clear();
174  quad_face.clear();
175  }
176 
177  void init();
178  void rebuild_matrices(MaterialType* mtype, limpet::MULTI_IF & miif, SF::vector<stimulus> & stimuli, FILE_SPEC logger);
179  void solve();
180 
181  private:
182  void setup_linear_solver(FILE_SPEC logger);
183 
184  void solve_semiImplicit();
185 };
186 
187 class EMI : public Basic_physic
188 {
189  public:
190 
192  MaterialType mtype_vol[1];
193  MaterialType_EMI mtype_face;
195  SF::vector<stimulus> stimuli;
196 
199  IonicsOnFace ion;
200 
202  parabolic_solver_emi parab_solver;
203 
205  gvec_data_OnFace gvec;
206 
208  igb_output_manager output_manager;
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 substract 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 
340  void apply_current_stimulus();
341 
361  void apply_dbc_stimulus();
362 
398  void balance_electrodes();
399 
452  void scale_total_stimulus_current(SF::vector<stimulus>& stimuli,
453  sf_mat& mass_vol,
454  sf_mat& mass_surf,
455  FILE_SPEC logger);
456 
458  void setup_solvers();
459 
461  void setup_mappings();
462 
464  void setup_output();
465 
467  void dump_matrices();
468 
469  void checkpointing();
470 
472  void setup_EMI_mesh();
473 };
474 
477 void log_mesh_local_element_ranges(const sf_mesh& emi_mesh,
478  const sf_mesh& emi_surfmesh_w_counter_face,
479  const sf_mesh& emi_surfmesh_unique_face);
486 void set_elec_tissue_properties_emi_volume(MaterialType* mtype, FILE_SPEC logger);
487 
489 void extract_unique_tag(SF::vector<mesh_int_t>& unique_tags);
490 
492 void compute_tags_per_rank(int num_tags, SF::vector<mesh_int_t>& num_tags_per_rank);
493 
495 void distribute_elements_based_tags(SF::meshdata<mesh_int_t, mesh_real_t>& mesh,
496  int total_num_tags);
497 
499 void partition_based_tags(int num_tags,
501  SF::vector<mesh_int_t> num_tags_per_rank,
502  SF::vector<mesh_int_t>& part);
503 
505 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);
506 
509 bool load_partitions_from_file(hashmap::unordered_map<mesh_int_t, mesh_int_t>& tags_to_rank_map,
510  int expected_num_tags,
511  MPI_Comm comm);
512 
514 void permute_mesh_locally_based_on_tag_elemIdx(SF::meshdata<mesh_int_t, mesh_real_t>& mesh);
515 
516 } // namespace opencarp
517 
518 
519 #endif
520 #endif
int mesh_int_t
Definition: SF_container.h:46
virtual void output_timings()
Definition: physics_types.h:76
Tissue level electrics, main Electrics physics class.
Electrical ionics functions (gap junction + ionic current) on the face of interface mesh for EMI mesh...
SF::abstract_linear_solver< SF_int, SF_real > sf_sol
Definition: sf_interface.h:54
SF::meshdata< mesh_int_t, mesh_real_t > sf_mesh
Definition: sf_interface.h:48
@ emi_surface_unique_face_msh
Definition: sf_interface.h:68
SF::abstract_vector< SF_int, SF_real > sf_vec
Definition: sf_interface.h:50
SF::abstract_matrix< SF_int, SF_real > sf_mat
Definition: sf_interface.h:52
file_desc * FILE_SPEC
Definition: basics.h:138