openCARP
Doxygen code documentation for the open cardiac electrophysiology simulator openCARP
ionics.cc
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright (c) NumeriCor GmbH
2 // SPDX-License-Identifier: LicenseRef-APL-1.1
3 
12 #include "ionics.h"
13 
14 #include "SF_init.h"
15 
16 namespace opencarp {
17 
19 {
20  double t1, t2;
21  get_time(t1);
22 
24 
25  double comp_time = timing(t2, t1);
26  this->compute_time += comp_time;
27 
28  comp_stats.calls++;
29  comp_stats.tot_time += comp_time;
30 
33 }
34 
36 {
37  miif->free_MIIF();
38 }
39 
41 {}
42 
44 {
45  double t1, t2;
46  get_time(t1);
47 
48  set_dir(OUTPUT);
49 
50  // initialize generic logger for ODE timings per time_dt
51  comp_stats.init_logger("ODE_stats.dat");
52 
53  double tstart = 0.;
54  sf_mesh & mesh = get_mesh(ion_domain);
55  limpet::node_count_t loc_size = mesh.pl.num_algebraic_idx();
56 
57  // create ionic current vector and register it
58  sf_vec *IIon;
59  sf_vec *Vmv;
60  SF::init_vector(&IIon, mesh, 1, sf_vec::algebraic);
61  SF::init_vector(&Vmv, mesh, 1, sf_vec::algebraic);
62  register_data(IIon, iion_vec);
63  register_data(Vmv, vm_vec);
64 
65  // setup miif
66  miif = new limpet::MULTI_IF();
67  // hand down the physics log file, so that what MULTI_IF reports while setting up and
68  // restoring state is recorded rather than only echoed to the console
69  miif->logger = logger;
70  // store IIF_IDs and Plugins in arrays
71  miif->name = "myocardium";
72  miif->gdata[limpet::Vm] = Vmv;
73  miif->gdata[limpet::Iion] = IIon;
74 
75  SF::vector<RegionSpecs> rs(param_globals::num_imp_regions);
76  for (size_t i = 0; i < rs.size(); i++ ) {
77  rs[i].nsubregs = param_globals::imp_region[i].num_IDs;
78  rs[i].subregtags = param_globals::imp_region[i].ID;
79  }
80 
81  SF::vector<int> reg_mask;
82  region_mask(ion_domain, rs, reg_mask, false, "imp_region", logger);
83 
84  int purkfLen = 1;
85  tstart = setup_MIIF(loc_size, param_globals::num_imp_regions, param_globals::imp_region,
86  reg_mask.data(), param_globals::start_statef, param_globals::num_adjustments,
87  param_globals::adjustment, param_globals::dt, purkfLen > 0);
88 
89  miif->extUpdateVm = !param_globals::operator_splitting;
90 
91  // if we start at a non-zero time (i.e. we have restored a state), we notify the
92  // timer manager
93  if(tstart > 0.) {
94  log_msg(logger, 0, 0, "Changing simulation start time to %.2lf", tstart);
95  user_globals::tm_manager->setup(param_globals::dt, tstart, param_globals::tend);
97  }
98 
99  set_dir(INPUT);
100 
101  this->initialize_time += timing(t2, t1);
102 }
103 
104 double Ionics::setup_MIIF(limpet::node_count_t nnodes, int nreg, IMPregion* impreg, int* mask,
105  const char *start_fn, int numadjust, IMPVariableAdjustment *adjust,
106  double time_step, bool close)
107 {
108  double tstart = 0;
109 
110  miif->N_IIF = nreg;
111  miif->numNode = nnodes;
112  miif->iontypes = {};
113  miif->numplugs = (int*)calloc( miif->N_IIF, sizeof(int));
114  miif->plugtypes = std::vector<limpet::IonTypeList>(miif->N_IIF);
115  miif->targets = std::vector<limpet::Target>(miif->N_IIF, limpet::Target::AUTO);
116 
117  log_msg(logger,0,ECHO, "\nSetting up ionic models and plugins\n" \
118  "-----------------------------------\n\n" \
119  "Assigning IMPS to tagged regions:" );
120 
121  for (int i=0;i<miif->N_IIF;i++) {
122  auto pT = limpet::get_ion_type(std::string(impreg[i].im));
123  if (pT != NULL)
124  {
125  miif->iontypes.push_back(*pT);
126  log_msg(logger, 0, ECHO|NONL, "\tIonic model: %s to tag region(s)", impreg[i].im);
127 
128  // a single region covers the whole mesh regardless of its ID list
129  if(miif->N_IIF == 1) {
130  log_msg(logger,0,ECHO, " all");
131  }
132  else if(impreg[i].num_IDs > 0) {
133  for(int j = 0; j < impreg[i].num_IDs; j++)
134  log_msg(logger,0,ECHO|NONL, " [%d],", impreg[i].ID[j]);
135  log_msg(logger,0,ECHO,"\b.");
136  }
137  else {
138  log_msg(logger,0,ECHO, " none");
139  }
140  }
141  else {
142  log_msg(NULL,5,ECHO, "Illegal IM specified: %s\n", impreg[i].im );
143  log_msg(NULL,5,ECHO, "Run bench --list-imps for a list of all available models.\n" );
144  EXIT(1);
145  }
146  if (limpet::get_plug_flag( impreg[i].plugins, &miif->numplugs[i], miif->plugtypes[i]))
147  {
148  if(impreg[i].plugins[0] != '\0') {
149  log_msg(logger,0, ECHO|NONL, "\tPlug-in(s) : %s to tag region(s)", impreg[i].plugins);
150 
151  for(int j = 0; j < impreg[i].num_IDs; j++)
152  log_msg(logger,0,ECHO|NONL, " [%d],", impreg[i].ID[j]);
153  log_msg(logger,0,ECHO,"\b.");
154  }
155  }
156  else {
157  log_msg(NULL,5,ECHO,"Illegal plugin specified: %s\n", impreg[i].plugins);
158  log_msg(NULL,5,ECHO, "Run bench --list-imps for a list of all available plugins.\n" );
159  EXIT(1);
160  }
161  }
162 
164 
165  // The mask is a nodal vector with the region IDs of each node.
166  // It is already reduced during the region_mask call to guarantee unique values
167  // for overlapping interface nodes
168  if (mask) {
169  for (limpet::node_index_t i=0; i<miif->numNode; i++)
170  miif->IIFmask[i] = (limpet::IIF_Mask_t) mask[i];
171  }
172 
174 
175  for(int i=0; i<miif->N_IIF; i++)
176  if(!miif->IIF[i]->cgeom().SVratio)
177  miif->IIF[i]->cgeom().SVratio = param_globals::imp_region[i].cellSurfVolRatio;
178 
179  for (int i=0;i<miif->N_IIF;i++) {
180  // the IMP tuning does not handle spaces well, thus we remove them here
181  remove_char(impreg[i].im_param, strlen(impreg[i].im_param), ' ');
182  miif->IIF[i]->tune(impreg[i].im_param, impreg[i].plugins, impreg[i].plug_param);
183  }
184 
185  set_dir(INPUT);
186  miif->initialize_currents(time_step, param_globals::ode_fac);
187 
188  // overriding initial values goes here
189  // read in single cell state vector and spread it out over the entire region
190  set_dir(INPUT);
191  for (int i=0;i<miif->N_IIF;i++) {
192  if (impreg[i].im_sv_init && strlen(impreg[i].im_sv_init) > 0)
193  if (read_sv(miif, i, impreg[i].im_sv_init)) {
194  log_msg(NULL, 5, ECHO|FLUSH, "State vector initialization failed for %s.\n", impreg[i].name);
195  EXIT(-1);
196  }
197  }
198 
199  if( !start_fn || strlen(start_fn)>0 )
200  tstart = (double) miif->restore_state(start_fn, ion_domain, close);
201 
202  for (int i=0; i<numadjust; i++)
203  {
204  set_dir(INPUT);
205 
206  SF::vector<SF_int> indices;
207  SF::vector<SF_real> values;
208  bool restrict_to_algebraic = true;
209 
210  sf_mesh & imesh = get_mesh(ion_domain);
211  std::map<std::string,std::string> metadata;
212  read_metadata(adjust[i].file, metadata, PETSC_COMM_WORLD);
213 
214  SF::SF_nbr nbr = SF::NBR_REF;
215  if(metadata.count("grid") && metadata["grid"].compare("intra") == 0) {
216  nbr = SF::NBR_SUBMESH;
217  }
218  read_indices_with_data(indices, values, adjust[i].file, imesh, nbr, restrict_to_algebraic, 1, PETSC_COMM_WORLD);
219 
220  int rank = get_rank();
221 
222  for(size_t gi = 0; gi < indices.size(); gi++)
223  indices[gi] = SF::local_nodal_to_local_petsc<mesh_int_t,mesh_real_t>(imesh, rank, indices[gi]);
224 
225  // debug, output parameters on global intracellular vector
226  if(adjust[i].dump) {
227  sf_vec* adjPars;
228  SF::init_vector(&adjPars, imesh, 1, sf_vec::algebraic);
229  adjPars->set(indices, values, false, true);
230 
231  set_dir(OUTPUT);
232  char fname[2085];
233  snprintf(fname, sizeof fname, "adj_%s_perm.dat", adjust[i].variable);
234  adjPars->write_ascii(fname, false);
235 
236  // get the scattering to the canonical permutation
238  if(sc == NULL) {
239  log_msg(0,3,0, "%s warning: PETSC_TO_CANONICAL permutation needed registering!", __func__);
241  }
242 
243  (*sc)(*adjPars, true);
244  snprintf(fname, sizeof fname, "adj_%s_canonical.dat", adjust[i].variable);
245  adjPars->write_ascii(fname, false);
246  }
247 
248  int nc = miif->adjust_MIIF_variables(adjust[i].variable, indices, values);
249  log_msg(logger, 0, 0, "Adjusted %d values for %s", nc, adjust[i].variable);
250  }
251 
252  return tstart;
253 }
254 
267  const char* gridname, const char* reglist, FILE_SPEC logger)
268 {
269  bool AllTagsExist = true;
270 
272  tagset.insert(tags.begin(), tags.end());
273 
274  // cycle through all user-specified regions
275  for (size_t reg=0; reg<regspec.size(); reg++)
276  // cycle through all tags which belong to the region
277  for (int k=0; k<regspec[reg].nsubregs; k++) {
278  // check whether this tag exists in element list
279  int n = 0;
280  if(tagset.count(regspec[reg].subregtags[k])) n++;
281  // globalize n
282  int N = get_global(n, MPI_SUM);
283  if (N==0) {
284  if(strcmp(reglist, "gregion_vol"))
285  log_msg(logger, 3, ECHO,
286  "%s[%d] references tag %d, but no element in the %s grid carries this tag — region will have no elements.\n",
287  reglist, reg, regspec[reg].subregtags[k], gridname);
288  AllTagsExist = false;
289  }
290  }
291 
292  if (!AllTagsExist) {
293  log_msg(logger, 4, ECHO,"One or more configured regions are empty. Check that region tag IDs match the tags in your mesh or tagfile.\n");
294  }
295 
296  return AllTagsExist;
297 }
298 
299 static const char* one_region_per_tag = "Every element tag must be listed in exactly one region.\n";
300 
307  const hashmap::unordered_map<mesh_int_t,int> & tag_to_reg,
308  const char* gridname, const char* reglist, FILE_SPEC logger)
309 {
310  SF::vector<mesh_int_t> unmatched;
311  long int n_unassigned = 0;
312  for (const mesh_int_t & t : tags) {
313  if (!tag_to_reg.count(t)) {
314  unmatched.push_back(t);
315  n_unassigned++;
316  }
317  }
318 
319  n_unassigned = get_global(n_unassigned, MPI_SUM);
320  if (!n_unassigned) return;
321 
322  binary_sort(unmatched);
323  unique_resize(unmatched);
324  make_global(unmatched, PETSC_COMM_WORLD);
325  binary_sort(unmatched);
326  unique_resize(unmatched);
327 
328  std::string taglist;
329  for (size_t i = 0; i < unmatched.size(); i++) {
330  if (i) taglist += ", ";
331  taglist += std::to_string(unmatched[i]);
332  }
333 
334  log_msg(logger, 5, ECHO|FLUSH,
335  "%s: %ld element(s) in %s grid carry tags {%s} not assigned to any %s region.\n%s",
336  __func__, n_unassigned, gridname, taglist.c_str(), reglist, one_region_per_tag);
337  EXIT(EXIT_FAILURE);
338 }
339 
340 void region_mask(mesh_t meshspec, SF::vector<RegionSpecs> & regspec,
341  SF::vector<int> & regionIDs, bool mask_elem, const char* reglist,
342  FILE_SPEC logger)
343 {
344  if(regspec.size() == 1) return;
345 
346  sf_mesh & mesh = get_mesh(meshspec);
348 
349  size_t rIDsize = mask_elem ? mesh.l_numelem : mesh.l_numpts;
350 
351  size_t nelem = mesh.l_numelem;
352  const SF::vector<mesh_int_t> & tags = mesh.tag;
353 
354  // the parameter parser fills IDs missing from a list shorter than num_IDs with -1
355  for (size_t reg=0; reg < regspec.size(); reg++)
356  for (int k=0; k < regspec[reg].nsubregs; k++)
357  if (regspec[reg].subregtags[k] == -1) {
358  log_msg(logger, 5, ECHO|FLUSH, "%s: %s[%zu] lists fewer tags than its num_IDs.\n",
359  __func__, reglist, reg);
360  EXIT(EXIT_FAILURE);
361  }
362 
363  // check whether all specified tags exist in the element list
364  check_tags_in_elems(tags, regspec, mesh.name.c_str(), reglist, logger);
365 
366  // A tag listed in two regions has no well-defined owner, so the region layout is rejected
367  // rather than resolved by list order. regspec is identical on all ranks, so every rank
368  // reaches the same verdict.
370  for (size_t reg=0; reg < regspec.size(); reg++) {
371  for (int k=0; k < regspec[reg].nsubregs; k++) {
372  mesh_int_t curtag = regspec[reg].subregtags[k];
373  auto it = tag_to_reg.find(curtag);
374  if (it != tag_to_reg.end() && it->second != int(reg)) {
375  log_msg(logger, 5, ECHO|FLUSH, "%s: tag %ld is listed in both %s[%d] and %s[%zu].\n%s",
376  __func__, long(curtag), reglist, it->second, reglist, reg, one_region_per_tag);
377  EXIT(EXIT_FAILURE);
378  }
379  tag_to_reg[curtag] = reg;
380  }
381  }
382 
383  check_unassigned_tags(tags, tag_to_reg, mesh.name.c_str(), reglist, logger);
384 
385  regionIDs.resize(rIDsize);
386 
387  SF::vector<mesh_int_t> mx_tag(regionIDs.size(), -1);
388 
389  // cycle through the element list
390  for(size_t i=0; i<nelem; i++) {
391  const mesh_int_t & cur_tag = tags[i];
392 
393  if (mask_elem) regionIDs[i] = tag_to_reg.at(cur_tag);
394  else {
395  eview.set_elem(i);
396 
397  for (int j=0; j < eview.num_nodes(); j++) {
398  mesh_int_t n = eview.node(j);
399  if (cur_tag > mx_tag[n]) mx_tag[n] = cur_tag;
400  }
401  }
402  }
403 
404  if(mask_elem) return;
405 
406  // The tie between the tags meeting at a node must be broken on the tags themselves.
407  // Reducing the region IDs instead would let the highest region win at nodes shared
408  // between ranks while the highest tag wins everywhere else, making the assignment
409  // depend on the partitioning whenever the tags are not listed in ascending order.
410  mesh.pl.reduce(mx_tag, "max");
411 
412  for(size_t i=0; i < regionIDs.size(); i++)
413  regionIDs[i] = tag_to_reg.at(mx_tag[i]);
414 
415  const SF::vector<mesh_int_t> & alg_nod = mesh.pl.algebraic_nodes();
417 
418  SF::vector<int> alg_reg(alg_nod.size());
419  SF::vector<int> gids (alg_nod.size());
420 
421  for(size_t i=0; i<alg_nod.size(); i++) {
422  alg_reg[i] = regionIDs[alg_nod[i]];
423  gids[i] = nbr[alg_nod[i]];
424  }
425 
426  regionIDs = alg_reg;
427 
428  if(param_globals::dump_imp_region) {
429  set_dir(OUTPUT);
430  write_data_ascii(PETSC_COMM_WORLD, gids, regionIDs, std::string(reglist)+".dat");
431  }
432 }
433 
436 double Ionics::timer_val(const int timer_id)
437 {
438  double val = std::nan("NaN");
439  return val;
440 }
441 
444 std::string Ionics::timer_unit(const int timer_id)
445 {
446  std::string s_unit;
447  return s_unit;
448 }
449 
451 {
452  if (impdata[limpet::Iion] != NULL)
453  impdata[limpet::Iion][n] = 0;
454 
455  pIF.for_each([&](limpet::IonIfBase& imp) {
456  update_ts(&imp.get_tstp());
457  imp.compute(n, n + 1, impdata);
458  });
459 }
460 
472 void* find_SV_in_IMP(limpet::MULTI_IF* miif, const int idx, const char *IMP, const char *SV,
473  int* offset, int* sz, int* plugin_idx)
474 {
475  *plugin_idx = -1;
476 
477  if(strcmp(IMP, miif->iontypes[idx].get().get_name().c_str()) == 0) {
478  return (void*) miif->iontypes[idx].get().get_sv_offset(SV, offset, sz);
479  }
480  else {
481  for(int k=0; k<miif->numplugs[idx]; k++)
482  if(strcmp(IMP, miif->plugtypes[idx][k].get().get_name().c_str()) == 0) {
483  *plugin_idx = k;
484  return (void*) miif->plugtypes[idx][k].get().get_sv_offset(SV, offset, sz);
485  }
486  }
487 
488  return NULL;
489 }
490 
491 
501 void alloc_gvec_data(const int nGVcs, const int nRegs,
502  GVecs *prmGVecs, gvec_data &glob_vecs)
503 {
504  glob_vecs.nRegs = nRegs;
505 
506  if (nGVcs) {
507  glob_vecs.vecs.resize(nGVcs);
508 
509  for (size_t i = 0; i < glob_vecs.vecs.size(); i++) {
510  sv_data &gvec = glob_vecs.vecs[i];
511 
512  gvec.name = dupstr(prmGVecs[i].name);
513  gvec.units = dupstr(prmGVecs[i].units);
514  gvec.bogus = prmGVecs[i].bogus;
515 
516  gvec.imps = (char**) calloc(nRegs, sizeof(char *));
517  gvec.svNames = (char**) calloc(nRegs, sizeof(char *));
518  gvec.svSizes = (int*) calloc(nRegs, sizeof(int));
519  gvec.svOff = (int*) calloc(nRegs, sizeof(int));
520  gvec.plugin_idx = (int*) calloc(nRegs, sizeof(int));
521  gvec.getsv = (void**) calloc(nRegs, sizeof(limpet::SVgetfcn));
522 
523  for (int j = 0; j < nRegs; j++) {
524  gvec.plugin_idx[j] = -1;
525  if (strlen(prmGVecs[i].imp)) gvec.imps[j] = dupstr(prmGVecs[i].imp);
526 #ifdef WITH_PURK
527  else if (j < param_globals::num_imp_regions)
528  gvec.imps[j] = dupstr(param_globals::imp_region[j].im);
529  else
530  gvec.imps[j] = dupstr(param_globals::PurkIon[j - param_globals::num_imp_regions].im);
531 #else
532  else if (j < param_globals::num_imp_regions)
533  gvec.imps[j] = dupstr(param_globals::imp_region[j].im);
534 #endif
535  gvec.svNames[j] = dupstr(prmGVecs[i].ID[j]);
536  }
537  }
538  }
539 }
540 
554  igb_output_manager & output_manager)
555 {
556  GVs.inclPS = false;
557  // int num_purk_regions = GVs->inclPS ? purk->ion.N_IIF : 0;
558  int num_purk_regions = 0;
559  int nRegs = param_globals::num_imp_regions + num_purk_regions;
560 
561  alloc_gvec_data(param_globals::num_gvecs, nRegs, param_globals::gvec, GVs);
562 
563 #ifdef WITH_PURK
564  if (GVs->inclPS) sample_PS_ionSVs(purk);
565 #endif
566 
567  for (unsigned int i = 0; i < GVs.vecs.size(); i++) {
568  sv_data & gv = GVs.vecs[i];
569  int noSV = 0;
570 
571  for (int j = 0; j < miif->N_IIF; j++) {
572  gv.getsv[j] = find_SV_in_IMP(miif, j, gv.imps[j], gv.svNames[j], gv.svOff + j, gv.svSizes + j, gv.plugin_idx + j);
573 
574  if (gv.getsv[j] == NULL) {
575  log_msg(NULL, 3, ECHO, "\tWarning: SV(%s) not found in region %d\n", gv.svNames[j], j);
576  noSV++;
577  }
578  }
579 
580  SF::init_vector(&gv.ordered, &tmpl);
581  output_manager.register_output(gv.ordered, intra_elec_msh, 1, gv.name, gv.units);
582 
583 #ifdef WITH_PURK
584  // same procedure for Purkinje
585  if (GVs->inclPS) {
586  IF_PURK_PROC(purk) {
587  MULTI_IF* pmiif = &purk->ion;
588  for (int j = miif->N_IIF; j < nRegs; j++) {
589  gv.getsv[j] = find_SV_in_IMP(pmiif, j - miif->N_IIF, gv.imps[j],
590  gv.svNames[j], gv.svOff + j, gv.svSizes + j, gv.plugin_idx + j);
591 
592  if (gv.getsv[j] == NULL) {
593  LOG_MSG(NULL, 3, ECHO, "\tWarning: state variable \"%s\" not found in region %d\n", gv.svNames[j], j);
594  noSV++;
595  }
596  }
597  RVector_dup(purk->vm_pt, &gv.orderedPS_PS);
598  MYO_COMM(purk);
599  }
600  RVector_dup(purk->vm_pt_over, &gv.orderedPS);
601  initialize_grid_output(grid, NULL, tmo, intra_elec_msh, GRID_WRITE, 0., 1., gv.units, gv.orderedPS,
602  1, gv.GVcName, -purk->npt, param_globals::output_level);
603  }
604 #endif
605 
606  if (noSV == nRegs) {
607  log_msg(NULL, 5, ECHO, "\tError: no state variables found for global vector %d\n", i);
608  log_msg(NULL, 5, ECHO, "Run bench --imp=YourModel --imp-info to get a list of all parameters.\\n");
609  exit(1);
610  }
611  }
612 }
613 
625 {
626  for(size_t i=0; i<gvecs.vecs.size(); i++ ) {
627  sv_data & gv = gvecs.vecs[i];
628 
629  // set to the defalt value
630  gv.ordered->set(gv.bogus);
631  SF_int start, stop;
632  gv.ordered->get_ownership_range(start, stop);
633 
634  for( int n = 0; n<miif->N_IIF; n++ ) {
635  if( !gv.getsv[n] ) continue;
636 
637  SF::vector<SF_real> data (miif->N_Nodes[n]);
638  SF::vector<SF_int> indices(miif->N_Nodes[n]);
639 
640  limpet::IonIfBase* base_im = miif->IIF[n];
641  int plugin_idx = gv.plugin_idx[n];
642  limpet::IonIfBase* imp = plugin_idx > -1 ? base_im->plugins()[plugin_idx] : base_im;
643 
644  for( limpet::node_index_t j=0; j<miif->N_Nodes[n]; j++ ) {
645  indices[j] = miif->NodeLists[n][j] + start;
646  data[j] = ((limpet::SVgetfcn)(gv.getsv[n]))( *imp, j, gv.svOff[n]);
647  }
648 
649  bool add = false;
650  gv.ordered->set(indices, data, add);
651  }
652  }
653 }
654 
655 
656 } // namespace opencarp
opencarp::local_index_t mesh_int_t
Definition: SF_container.h:31
opencarp::global_index_t SF_int
Global algebraic index type.
Definition: SF_globals.h:17
#define FLUSH
Definition: basics.h:304
#define ECHO
Definition: basics.h:301
#define NONL
Definition: basics.h:305
virtual void get_ownership_range(T &start, T &stop) const =0
virtual void set(const vector< T > &idx, const vector< S > &vals, const bool additive=false, const bool local=false)=0
Comfort class. Provides getter functions to access the mesh member variables more comfortably.
Definition: SF_fem_utils.h:689
const T & node(short nidx) const
Access the connectivity information.
Definition: SF_fem_utils.h:778
void set_elem(size_t eidx)
Set the view to a new element.
Definition: SF_fem_utils.h:716
T num_nodes() const
Getter function for the number of nodes.
Definition: SF_fem_utils.h:746
overlapping_layout< T > pl
nodal parallel layout
Definition: SF_container.h:414
size_t l_numelem
local number of elements
Definition: SF_container.h:384
std::string name
the mesh name
Definition: SF_container.h:392
size_t l_numpts
local number of points
Definition: SF_container.h:386
vector< T > & get_numbering(SF_nbr nbr_type)
Get the vector defining a certain numbering.
Definition: SF_container.h:449
vector< T > tag
element tag
Definition: SF_container.h:402
Container for a PETSc VecScatter.
A vector storing arbitrary data.
Definition: SF_vector.h:28
size_t size() const
The current size of the vector.
Definition: SF_vector.h:89
void resize(size_t n)
Resize a vector.
Definition: SF_vector.h:194
const T * end() const
Pointer to the vector's end.
Definition: SF_vector.h:113
const T * begin() const
Pointer to the vector's start.
Definition: SF_vector.h:101
T * data()
Pointer to the vector's start.
Definition: SF_vector.h:76
T & push_back(T val)
Definition: SF_vector.h:268
iterator find(const K &key)
Search for key. Return iterator.
Definition: hashmap.hpp:626
hm_int count(const K &key) const
Check if key exists.
Definition: hashmap.hpp:612
T & at(const K &key)
Data access by key.
Definition: hashmap.hpp:646
Custom unordered_set implementation.
Definition: hashmap.hpp:739
hm_int count(const K &key) const
Definition: hashmap.hpp:1067
void insert(InputIterator first, InputIterator last)
Definition: hashmap.hpp:1037
Represents the ionic model and plug-in (IMP) data structure.
Definition: ION_IF.h:168
std::vector< IonIfBase * > & plugins()
Returns a vector containing the plugins of this IMP.
Definition: ION_IF.cc:174
void compute(node_index_t start, node_index_t end, GlobalData_t **data)
Perform ionic model computation for 1 time step.
Definition: ION_IF.cc:258
ts & get_tstp()
Gets the time stepper.
Definition: ION_IF.cc:198
void for_each(const std::function< void(IonIfBase &)> &consumer)
Executes the consumer functions on this IMP and each of its plugins.
Definition: ION_IF.cc:526
bool extUpdateVm
flag indicating update function for Vm
Definition: MULTI_ION_IF.h:204
std::vector< IonIfBase * > IIF
array of IIF's
Definition: MULTI_ION_IF.h:198
opencarp::sf_vec * gdata[NUM_IMP_DATA_TYPES]
data used by all IMPs
Definition: MULTI_ION_IF.h:212
node_count_t numNode
local number of nodes
Definition: MULTI_ION_IF.h:206
int * numplugs
number of plugins for each region
Definition: MULTI_ION_IF.h:205
std::vector< Target > targets
target for each region
Definition: MULTI_ION_IF.h:209
std::vector< IonTypeList > plugtypes
plugins types for each region
Definition: MULTI_ION_IF.h:211
IonTypeList iontypes
type for each region
Definition: MULTI_ION_IF.h:208
void initialize_currents(double, int)
float restore_state(const char *, opencarp::mesh_t gid, bool)
int N_IIF
how many different IIF's
Definition: MULTI_ION_IF.h:207
void compute_ionic_current(bool flag_send=1, bool flag_receive=1)
GPU kernel to emulate the add_scaled call made to adjust the Vm values when the update to Vm is not m...
node_count_t * N_Nodes
#nodes for each IMP
Definition: MULTI_ION_IF.h:196
opencarp::FILE_SPEC logger
Definition: MULTI_ION_IF.h:213
node_index_t ** NodeLists
local partitioned node lists for each IMP stored
Definition: MULTI_ION_IF.h:197
IIF_Mask_t * IIFmask
region for each node
Definition: MULTI_ION_IF.h:210
int adjust_MIIF_variables(const char *variable, const SF::vector< SF_int > &indices, const SF::vector< SF_real > &values)
std::string name
name for MIIF region
Definition: MULTI_ION_IF.h:194
FILE_SPEC logger
The logger of the physic, each physic should have one.
Definition: physics_types.h:49
const char * name
The name of the physic, each physic should have one.
Definition: physics_types.h:47
void output_step()
Definition: ionics.cc:40
mesh_t ion_domain
Definition: ionics.h:57
generic_timing_stats comp_stats
Definition: ionics.h:59
limpet::MULTI_IF * miif
Definition: ionics.h:56
void compute_step()
Definition: ionics.cc:18
void initialize()
Definition: ionics.cc:43
void destroy()
Definition: ionics.cc:35
std::string timer_unit(const int timer_id)
figure out units of a signal linked to a given timer
Definition: ionics.cc:444
double timer_val(const int timer_id)
figure out current value of a signal linked to a given timer
Definition: ionics.cc:436
void register_output(sf_vec *inp_data, const mesh_t inp_meshid, const int dpn, const char *name, const char *units, const SF::vector< mesh_int_t > *idx=NULL, bool elem_data=false)
Register a data vector for output.
Definition: sim_utils.cc:2850
void setup(double inp_dt, double inp_start, double inp_end)
Initialize the timer_manager.
Definition: timer_utils.cc:21
void reset_timers()
Reset time in timer_manager and then reset registered timers.
Definition: timer_utils.h:101
Electrical ionics functions and LIMPET wrappers.
void write_data_ascii(const MPI_Comm comm, const vector< T > &idx, const vector< S > &data, std::string file, short dpn=1)
void make_global(const vector< T > &vec, vector< T > &out, MPI_Comm comm)
make a parallel vector global
Definition: SF_network.h:210
void unique_resize(vector< T > &_P)
Definition: SF_sort.h:338
void init_vector(SF::abstract_vector< T, S > **vec)
Definition: SF_init.h:110
void binary_sort(vector< T > &_V)
Definition: SF_sort.h:274
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_REF
The nodal numbering of the reference mesh (the one stored on HD).
Definition: SF_container.h:186
@ NBR_SUBMESH
Submesh nodal numbering: The globally ascending sorted reference indices are reindexed.
Definition: SF_container.h:187
int get_plug_flag(char *plgstr, int *out_num_plugins, IonTypeList &out_plugins)
@ AUTO
Definition: target.h:31
IonType * get_ion_type(const std::string &name)
SF_real GlobalData_t
Definition: limpet_types.h:12
GlobalData_t(* SVgetfcn)(IonIfBase &, node_index_t, int)
Definition: ion_type.h:33
void update_ts(ts *ptstp)
Definition: ION_IF.cc:575
opencarp::local_index_t node_count_t
Definition: limpet_types.h:14
int read_sv(MULTI_IF *, int, const char *)
char IIF_Mask_t
Definition: ion_type.h:35
opencarp::local_index_t node_index_t
Definition: limpet_types.h:13
std::map< int, std::string > units
Definition: stimulate.cc:26
timer_manager * tm_manager
a manager for the various physics timers
Definition: main.cc:40
void compute_IIF(limpet::IonIfBase &pIF, limpet::GlobalData_t **impdata, limpet::node_index_t n)
Definition: ionics.cc:450
void region_mask(mesh_t meshspec, SF::vector< RegionSpecs > &regspec, SF::vector< int > &regionIDs, bool mask_elem, const char *reglist, FILE_SPEC logger)
classify elements/points as belonging to a region
Definition: ionics.cc:340
void * find_SV_in_IMP(limpet::MULTI_IF *miif, const int idx, const char *IMP, const char *SV, int *offset, int *sz, int *plugin_idx)
Definition: ionics.cc:472
@ iotm_console
Definition: timer_utils.h:29
sf_mesh & get_mesh(const mesh_t gt)
Get a mesh by specifying the gridID.
Definition: sf_interface.cc:18
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.
SF::meshdata< mesh_int_t, mesh_real_t > sf_mesh
Definition: sf_interface.h:33
int set_dir(IO_t dest)
Definition: sim_utils.cc:1615
void read_metadata(const std::string filename, std::map< std::string, std::string > &metadata, MPI_Comm comm)
Read metadata from the header.
Definition: fem_utils.cc:57
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
void check_unassigned_tags(const SF::vector< mesh_int_t > &tags, const hashmap::unordered_map< mesh_int_t, int > &tag_to_reg, const char *gridname, const char *reglist, FILE_SPEC logger)
Abort if any element carries a tag that no region lists.
Definition: ionics.cc:306
SF::scattering * register_permutation(const int mesh_id, const int perm_id, const int dpn)
Register a permutation between two orderings for a mesh.
void register_data(sf_vec *dat, datavec_t d)
Register a data vector in the global registry.
Definition: sim_utils.cc:2090
@ OUTPUT
Definition: sim_utils.h:39
bool check_tags_in_elems(const SF::vector< mesh_int_t > &tags, SF::vector< RegionSpecs > &regspec, const char *gridname, const char *reglist, FILE_SPEC logger)
Check whether the tags in the region spec struct matches with an array of tags.
Definition: ionics.cc:266
void init_sv_gvec(gvec_data &GVs, limpet::MULTI_IF *miif, sf_vec &tmpl, igb_output_manager &output_manager)
Definition: ionics.cc:553
void assemble_sv_gvec(gvec_data &gvecs, limpet::MULTI_IF *miif)
Definition: ionics.cc:624
char * dupstr(const char *old_str)
Definition: basics.cc:29
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
@ intra_elec_msh
Definition: sf_interface.h:45
void alloc_gvec_data(const int nGVcs, const int nRegs, GVecs *prmGVecs, gvec_data &glob_vecs)
Definition: ionics.cc:501
void get_time(double &tm)
Definition: basics.h:429
SF::abstract_vector< SF_int, SF_real > sf_vec
Definition: sf_interface.h:35
void remove_char(char *buff, const int buffsize, const char c)
Definition: basics.h:349
void read_indices_with_data(SF::vector< T > &idx, SF::vector< S > &dat, const std::string filename, const hashmap::unordered_map< mesh_int_t, mesh_int_t > &dd_map, const int dpn, MPI_Comm comm)
like read_indices, but with associated data for each index
Definition: fem_utils.h:254
V timing(V &t2, const V &t1)
Definition: basics.h:441
#define PETSC_TO_CANONICAL
Permute algebraic data from PETSC to canonical ordering.
Definition: sf_interface.h:64
File descriptor struct.
Definition: basics.h:120
void log_stats(double tm, bool cflg)
Definition: timers.cc:96
void init_logger(const char *filename)
Definition: timers.cc:80
int calls
# calls for this interval, this is incremented externally
Definition: timers.h:75
double tot_time
total time, this is incremented externally
Definition: timers.h:77
SF::vector< sv_data > vecs
store sv dump indices for global vectors
Definition: ionics.h:139
unsigned int nRegs
number of imp regions
Definition: ionics.h:137
bool inclPS
include PS if exists
Definition: ionics.h:138
float bogus
value indicating sv not in region
Definition: ionics.h:133
void ** getsv
functions to retrieve sv
Definition: ionics.h:130
char * name
Name of global composite sv vector.
Definition: ionics.h:122
int * plugin_idx
per-region plugin index in the IMP's plugin list, or -1 for the base IMP
Definition: ionics.h:128
int * svOff
sv size in bytes
Definition: ionics.h:127
char ** svNames
sv names of components forming global vector
Definition: ionics.h:124
int * svSizes
sv size in bytes
Definition: ionics.h:126
char ** imps
Name of imp to which sv belongs.
Definition: ionics.h:123
char * units
units of sv
Definition: ionics.h:132
sf_vec * ordered
vector in which to place ordered data
Definition: ionics.h:131