openCARP
Doxygen code documentation for the open cardiac electrophysiology simulator openCARP
ION_IF.cc
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright (c) NumeriCor GmbH
2 // SPDX-License-Identifier: LicenseRef-APL-1.1
3 
13 /*
14  * Specify an interface for an IMP
15  *
16  * To use an IMP by itself outside of MULTI_IF.h, one must \n
17  * -# alloc_IIF()
18  * -# set the rdata pointers in the ::IMPDataStruct
19  * -# initialize_params()
20  * -# initialize_IIF()
21  * -# call the compute() method of the IMP
22  *
23  * The IMP library tries to avoid undo computation by using lookup
24  * tables to avoid computation of costly mathematical functions.
25  * Tables indices may be computed based on vltage, calcium concentrations,
26  * or any other quantity.
27  *
28  * One common scenario is commonly encountered with first-order differential
29  * equations:
30  * \f[ \frac{dz}{dt} = \frac{z_{\infty}(x) - z}{\tau_z(x)} \f]
31  *
32  * Using an exponential solution assuming that
33  * \f$z_{\inf}(x)\f$ and \f$\tau_z(x)\f$ constant over a time step:
34  *
35  * \f[ \begin{split}
36  * z_{i+1} & = z_{\infty}(x) - (z_{\infty}(x)-z_i)
37  * \exp\Large (-\Delta t/\tau_z(x) \Large ) \\
38  * & = A(x) + B(x) z_i
39  * \end{split}\f]
40  * where A(x) and B(x) are entered into a look up table which is
41  * indexed by \em x:
42  * \f[ \begin{split}
43  * A(x) &= z_{\infty}(x)\Large ( 1 - \exp(-\Delta t/\tau_z(x)\Large ) \\
44  * &= -z_{\infty}(x) expm1\Large ( -\Delta t/\tau_z(x) \Large ) \\
45  * B(x) &= \exp(-\Delta t/\tau_z(x))
46  * \end{split}\f]
47  *
48  */
49 #include "limpet_types.h"
50 #include "ION_IF.h"
51 #include "petsc_utils.h" // for EXIT
52 #include <stdarg.h>
53 
54 #ifdef USE_CVODE
55 #include <nvector/nvector_serial.h>
56 #include <cvode/cvode.h>
57 #include <cvode/cvode_diag.h>
58 #endif
59 
60 namespace limpet {
61 
65 using ::opencarp::Salt_list;
66 
67 #ifdef USE_HDF5
68 FILE_SPEC _nc_logf = (FILE_SPEC)calloc(1, sizeof(fileptr));
69 #else
71 #endif
72 
73 
74 char* tokstr_r(char *s1, const char *s2, char **lasts)
75 {
76  char *ret;
77 
78  if (s1 == NULL)
79  s1 = *lasts;
80  while(*s1 && strchr(s2, *s1))
81  ++s1;
82  if(*s1 == '\0')
83  return NULL;
84  ret = s1;
85  while(*s1 && !strchr(s2, *s1))
86  ++s1;
87  if(*s1)
88  *s1++ = '\0';
89  *lasts = s1;
90  return ret;
91 }
92 
93 
94 #ifndef offsetof
95 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
96 #endif
97 
98 // struct exception_context the_exception_context[1];
99 
101 
103  for (auto& lut : host)
104  destroy_lut(&lut, target);
105  if (device != nullptr)
106  deallocate_on_target<LUT>(target, device);
107 }
108 
109 IonIfBase::IonIfBase(const IonType& type, Target target, node_count_t num_node, const std::vector<std::reference_wrapper<IonType>>& plugins)
110  : _type(type), _target(type.select_target(target)), _num_node(num_node) {
111  this->_tstp = {};
112  this->_reqdat = type.reqdat();
113  this->_moddat = type.moddat();
114  this->_plugins = {};
115 
116  for (const auto& plugin : plugins) {
117  auto child = plugin.get().make_ion_if(target, num_node, {});
118  child->_parent = this;
119  this->_plugins.push_back(child);
120 
121  this->_reqdat |= child->_reqdat;
122  this->_moddat |= child->_moddat;
123  }
124 }
125 
127  for (auto plugin : this->_plugins) {
128  plugin->get_type().destroy_ion_if(plugin);
129  }
130 
131  this->_type.destroy(*this);
132 }
133 
134 const IonType& IonIfBase::get_type() const {
135  return this->_type;
136 }
137 
139  return this->_num_node;
140 }
141 
142 std::size_t IonIfBase::get_num_threads() const {
143  std::size_t num_threads = 0;
144  switch (this->_target) {
145  // CPU target threads number depends on wether OpenMP is enabled or not
146  case Target::CPU:
147  case Target::MLIR_CPU:
148 #ifdef _OPENMP
149  num_threads = omp_get_max_threads();
150 #else
151  num_threads = 1;
152 #endif
153  break;
154  // GPU targets threads numbers is the number of cells
155  case Target::MLIR_CUDA:
156  case Target::MLIR_ROCM:
157  num_threads = this->get_num_node();
158  break;
159  default:
160  throw std::logic_error("The IonIf execution target " + std::to_string(this->_target) + " is invalid");
161  break;
162  }
163  return num_threads;
164 }
165 
167  return this->_parent;
168 }
169 
171  this->_parent = parent;
172 }
173 
174 std::vector<IonIfBase*>& IonIfBase::plugins() {
175  return this->_plugins;
176 }
177 
178 uint32_t IonIfBase::get_reqdat() const {
179  return this->_reqdat;
180 }
181 
182 uint32_t IonIfBase::get_moddat() const {
183  return this->_moddat;
184 }
185 
186 void IonIfBase::set_moddat(uint32_t data) {
187  this->_moddat = data;
188 }
189 
190 float IonIfBase::get_dt() const {
191  return this->dt;
192 }
193 
194 void IonIfBase::set_dt(float dt) {
195  this->dt = dt;
196 }
197 
199  return this->_tstp;
200 }
201 
202 std::vector<LUT>& IonIfBase::tables() {
203  if (!this->_tables)
204  this->_tables = std::make_shared<LutSet>(this->_target);
205  return this->_tables->host;
206 }
207 
209  return this->_n_tables_d;
210 }
211 
213  Target selected_target = this->get_type().select_target(target);
214  if (is_concrete(selected_target)) {
215  if (this->_target != selected_target)
216  this->destroy_luts();
217  this->_target = selected_target;
218  }
219  else {
220  throw std::invalid_argument("new target set for IMP is unavailable or not concrete (AUTO, UNKNWOWN, ...)");
221  }
222 }
223 
225  this->_type.initialize_params(*this);
226 
227  for (auto& plugin : this->_plugins) {
228  plugin->initialize_params();
229  }
230 }
231 
232 void IonIfBase::initialize(double dt, GlobalData_t **impdat) {
239  this->dt = dt;
240  this->rebuild_lookup_tables();
241 
242  this->_type.initialize_sv(*this, impdat);
243  this->ldata = impdat;
244 
245  for (auto& plugin : this->_plugins)
246  plugin->initialize(dt, impdat);
247 }
248 
249 void IonIfBase::initialize_state(double dt, GlobalData_t **impdat) {
250  this->dt = dt;
251  this->_type.initialize_sv(*this, impdat);
252  this->ldata = impdat;
253 
254  for (auto& plugin : this->_plugins)
255  plugin->initialize_state(dt, impdat);
256 }
257 
259  this->_type.compute(this->_target, start, end, *this, data);
260 }
261 
262 char* IonIfBase::fill_buf(char *buf, int* n, opencarp::Salt_list *l) const {
263  int iif_sz = this->get_sv_size();
264 
265  for (auto& plugin : this->_plugins) {
266  iif_sz += plugin->get_sv_size();
267  }
268 
269  buf = (char *) realloc(buf, *n + l->nitems*iif_sz) + *n;
270  *n += l->nitems * iif_sz;
271 
272  return buf - *n + l->nitems * iif_sz;
273 }
274 
276  size_t *offset, IMPinfo *impinfo, const global_node_index_t* loc2canon) {
277  // restore_state aborts on an incompatible model or plugin before reaching this point
278  assert(impinfo->compatible);
279 
280  char *ptr = (char *)(this->get_sv_address());
281  long base = ftell(in->fd);
282  node_count_t mismatch = 0;
283 
284  // Restoration of the model data need to take care of the data layout
285  // optimization. (if it is disabled, the vector size should be 1 anyways
286  std::size_t vec_size = this->get_type().dlo_vector_size();
287  for( node_index_t i=0; i<n; i+=vec_size ) {
288  node_index_t index = i / vec_size;
289  global_node_index_t canon = loc2canon[pos[i]];
290  if(mask[canon] == this->miifIdx) {
291  fseek(in->fd, base+offset[canon], SEEK_SET);
292  fread(ptr+index*impinfo->sz, impinfo->sz, 1, in->fd);
293 
294  for(int j=0; j<impinfo->nplug; j++) {
295  assert(impinfo->plug[j].compatible);
296  fread((char*)(this->_plugins[impinfo->plug[j].map]->get_sv_address())+index*impinfo->plug[j].sz,
297  impinfo->plug[j].sz, 1, in->fd);
298  }
299  }
300  else
301  mismatch++;
302  }
303  return mismatch;
304 }
305 
306 const std::vector<IonIfBase::sv_field>& IonIfBase::sv_layout() const {
307  if (!_sv_layout_valid) {
308  char** list = NULL;
309  int nsv = this->get_type().get_sv_list(&list);
310  _sv_layout.reserve(nsv);
311  for (int i = 0; i < nsv; i++) {
312  int off = 0, sz = 0, type = 0;
313  char* type_name = NULL;
314  this->get_type().get_sv_offset(list[i], &off, &sz);
315  this->get_type().get_sv_type(list[i], &type, &type_name);
316  free(type_name);
317  _sv_layout.push_back({list[i], off, sz, type});
318  free(list[i]);
319  }
320  free(list);
321  _sv_layout_valid = true;
322  }
323  return _sv_layout;
324 }
325 
326 void IonIfBase::get_sv_layout(std::vector<std::pair<int, int>>& fields) const {
327  const std::vector<sv_field>& layout = this->sv_layout();
328  fields.clear();
329  fields.reserve(layout.size());
330  for (const auto& f : layout)
331  fields.emplace_back(f.off, f.sz);
332 }
333 
335  size_t total = 0;
336  for (const auto& f : this->sv_layout())
337  total += static_cast<size_t>(f.sz);
338  return total;
339 }
340 
341 uint64_t IonIfBase::sv_fingerprint() const {
342  constexpr uint64_t kFNVOffsetBasis = 0xcbf29ce484222325ULL; // 14695981039346656037
343  constexpr uint64_t kFNVPrime = 0x100000001b3ULL; // 1099511628211
344  uint64_t h = kFNVOffsetBasis;
345  auto mix = [&h](unsigned char b) { h ^= b; h *= kFNVPrime; };
346  for (const auto& f : this->sv_layout()) {
347  for (unsigned char c : f.name) mix(c);
348  mix(0); // name terminator, so {"ab","c"} and {"a","bc"} differ
349  for (int b = 0; b < 4; b++)
350  mix((static_cast<uint32_t>(f.sz) >> (8 * b)) & 0xff);
351  for (int b = 0; b < 4; b++)
352  mix((static_cast<uint32_t>(f.type) >> (8 * b)) & 0xff);
353  }
354  return h;
355 }
356 
358  IIF_Mask_t *mask, size_t *offset, IMPinfo *impinfo,
359  const global_node_index_t* loc2canon) {
360  // restore_state aborts on an incompatible model or plugin before reaching this point
361  assert(impinfo->compatible);
362 
363  long base = ftell(in->fd);
364  node_count_t mismatch = 0;
365 
366  // field layouts are model properties: gather them once, not per node
367  std::vector<std::pair<int, int>> main_fields;
368  this->get_sv_layout(main_fields);
369 
370  std::vector<std::vector<std::pair<int, int>>> plug_fields(impinfo->nplug);
371  for (int j = 0; j < impinfo->nplug; j++) {
372  assert(impinfo->plug[j].compatible);
373  this->_plugins[impinfo->plug[j].map]->get_sv_layout(plug_fields[j]);
374  }
375 
376  for( node_index_t i=0; i<n; i++ ) {
377  global_node_index_t canon = loc2canon[pos[i]];
378  if(mask[canon] == this->miifIdx) {
379  fseek(in->fd, base+offset[canon], SEEK_SET);
380  // a short read means the checkpoint is truncated within the state payload,
381  // which the header-level checks in restore_state cannot catch; abort rather
382  // than scatter stale bytes into the state. A zero-width field (e.g. a
383  // placeholder SV whose per-lane size rounds to 0 under DLO) reads nothing;
384  // fread reports 0 items for size 0, which must not be read as truncation.
385  auto scatter = [&](char* dst, std::size_t sz) {
386  if (sz && fread(dst, sz, 1, in->fd) != 1) {
387  log_msg(NULL, 5, 0, "Truncated ionic-state checkpoint during restore");
388  EXIT(EXIT_FAILURE);
389  }
390  };
391 
392  this->for_each_sv_field(i, main_fields, scatter);
393  for(int j=0; j<impinfo->nplug; j++)
394  this->_plugins[impinfo->plug[j].map]->for_each_sv_field(i, plug_fields[j], scatter);
395  }
396  else
397  mismatch++;
398  }
399  return mismatch;
400 }
401 
402 int IonIfBase::dump_luts(bool zipped) {
403  if (!this->_tables)
404  return 0;
405 
406  std::string name;
407  std::string ext = zipped ? ".gz" : "";
408  auto& tables = this->_tables->host;
409 
410  int dcnt = 0;
411  for (size_t i = 0; i < tables.size(); i++) {
412  // determine file name
413  if (strcmp(tables[i].name, ""))
414  name = this->_type.get_name() + "_LUT_" + tables[i].name + ".bin" + ext;
415  else
416  name = this->_type.get_name() + "_LUT_" + std::to_string(i) + ".bin" + ext;
417 
418  // dump table
419  int err = LUT_dump(&tables[i], name.c_str());
420  if (!err) dcnt++;
421  }
422  return dcnt;
423 }
424 
426  // Dropping a shared handle detaches this IMP before it rebuilds tables.
427  this->_tables.reset();
428  this->_tables_d = nullptr;
429  this->_n_tables_d = 0;
430 }
431 
433  this->destroy_luts();
434  if (!this->_num_node)
435  return;
436 
437  this->_type.construct_tables(*this);
438  auto& tables = this->tables();
439  if (is_gpu(this->get_target()) && !tables.empty()) {
440  this->_tables->device = allocate_on_target<LUT>(this->get_target(), tables.size());
441  for (size_t i = 0; i < tables.size(); ++i)
442  this->_tables->device[i] = tables[i];
443  this->_tables->device_count = tables.size();
444  this->_tables_d = this->_tables->device;
445  this->_n_tables_d = this->_tables->device_count;
446  }
447 }
448 
450  if (this->get_type() != other.get_type() || this->get_target() != other.get_target())
451  throw std::logic_error("cannot share LUTs between different IMP types or targets");
452  this->_tables = other._tables;
453  this->_tables_d = other._tables_d;
454  this->_n_tables_d = other._n_tables_d;
455 }
456 
457 void IonIfBase::tune(const char *im_par, const char *plugs, const char *plug_par) {
458  char *opar, *oplg, *plg, *nplg, *parlst, *nparlst;
459 
460  if( im_par && *im_par != '\0' ) {
461  log_msg( _nc_logf, 0, 0, "Ionic model: %s", this->_type.get_name().c_str());
462  this->_type.tune(*this, im_par);
463  }
464  opar = parlst = dupstr(plug_par);
465  oplg = plg = dupstr(plugs);
466 
467  while( plg!=NULL && *plg!='\0' ) {
468  nparlst = get_next_list( parlst, ':' );
469  nplg = get_next_list( plg, ':' );
470 
471  log_msg( _nc_logf, 0, 0, "Plug-in: %s", plg );
472 
473  if( parlst==NULL || *parlst=='\0' ) {
474  parlst = nparlst;
475  plg = nplg;
476  continue;
477  }
478 
479  // find apropriate plugin
480  IonType* plugin = get_ion_type(plg);
481  int j;
482 
483  for(j = 0; j < this->_plugins.size(); j++) {
484  if(this->_plugins[j]->get_type() == *plugin) break;
485  }
486 
487  if(j == this->_plugins.size()) {
488  log_msg( _nc_logf, 2, 0, "Plugin %s not used with IM", plg );
489  plg = nplg;
490  parlst = nparlst;
491  continue;
492  }
493 
494  plugin->tune(*this->_plugins[j], parlst);
495  plg = nplg;
496  parlst = nparlst;
497  }
498 
499  log_msg( _nc_logf, 0, 0, "" );
500  free( opar );
501  free( oplg );
502 }
503 
504 int IonIfBase::read_svs(FILE* file) {
505  if(this->get_num_node())
506  return this->_type.read_svs(*this, file);
507  else
508  return 1;
509 }
510 
511 int IonIfBase::write_svs(FILE* file, node_index_t node) {
512  return this->_type.write_svs(*this, file, node);
513 }
514 
516  this->_plugins = {};
517 
518  for (auto& plugin : other.plugins()) {
519  auto copy = plugin->get_type().make_ion_if(this->_target, plugin->get_num_node(), {});
520  copy->_parent = this;
521  this->_plugins.push_back(copy);
522  copy->copy_SVs_from(*plugin, true);
523  }
524 }
525 
526 void IonIfBase::for_each(const std::function<void(IonIfBase&)>& consumer) {
527  consumer(*this);
528 
529  for (auto& plugin : this->_plugins) {
530  consumer(*plugin);
531  }
532 }
533 
545 // Is this ever used?
546 void initialize_ts(Target target, ts *tstp, int ng, int *skp, double dt)
547 {
548  // initialize step counter that will run linearly as long the
549  // simulation goes
550  tstp->cnt = -1;
551  tstp->ng = ng;
552  tstp->tcg = allocate_on_target<tc_grp>(target, ng);
553 
554  // initialize time constant grouping
555  // fast variables, use dt=dt
556  tstp->tcg[0].skp = 1;
557  tstp->tcg[0].dt = dt;
558  tstp->tcg[0].update = 1;
559 
560  for (int i=1;i<ng;i++) {
561  tstp->tcg[i].skp = skp[i];
562  tstp->tcg[i].dt = tstp->tcg[i].skp*dt;
563  }
564 }
565 
566 
575 void update_ts(ts *ptstp)
576 {
577  ptstp->cnt++;
578 
579  tc_grp *ptcg = ptstp->tcg;
580  for (int i=1;i<ptstp->ng;i++)
581  ptcg[i].update = !(ptstp->cnt%ptcg[i].skp);
582 }
583 
584 
585 #ifndef _GNU_SOURCE
595 void *memmem( void *haystack, int sz_hay, void *needle, int sz_n )
596 {
597  if( !sz_n ) return NULL;
598 
599  char *h = (char *)haystack;
600 
601  for( int i=0; i>sz_hay-sz_n+1; i++, h++ )
602  if( !memcmp( h, needle, sz_n ) )
603  return (void *)h;
604  break;
605 
606  return NULL;
607 }
608 #endif
609 
610 
621 char *get_next_list( char *lst, char delimiter )
622 {
623  if( lst == NULL || *lst == '\0' )
624  return NULL;
625 
626  while( *lst != delimiter && *lst != '\0' )
627  lst++;
628 
629  if( *lst != '\0' ) {
630  *lst = '\0';
631  return lst+1;
632  } else
633  return lst;
634 }
635 
636 
644  bool verify_flags( const char *flags, const char* given )
645  {
646  char *flag, *ptr, *gvn_cp = dupstr( given );
647 
648  flag = tokstr_r( gvn_cp, "|", &ptr );
649  while( flag ) {
650  if( !flag_set( flags, flag ) )
651  break;
652  flag = tokstr_r( NULL, "|", &ptr );
653  }
654 
655  free( gvn_cp );
656  return flag ? false : true;
657 }
658 
666 bool flag_set( const char *flags, const char *target )
667 {
668  if( !flags ) return false;
669 
670  char *f = dupstr( flags ), *last, *pos;
671 
672  pos = tokstr_r( f, "|", &last );
673  while( pos && strcmp( pos, target ) ) {
674  pos = tokstr_r( NULL, "|", &last );
675  }
676  free( f );
677 
678  return pos? true : false;
679 }
680 
681 
682 #ifdef USE_CVODE
683 
686 void __bogus_function_for_cvode() {
687 
688  int flag;
689  int N_CVODE = 1;
690 #if SUNDIALS_VERSION_MAJOR < 4
691  void* cvode_mem = CVodeCreate(CV_BDF, CV_NEWTON);
692 #elif SUNDIALS_VERSION_MAJOR < 6
693  void* cvode_mem = CVodeCreate(CV_BDF);
694 #elif SUNDIALS_VERSION_MAJOR < 7
695  SUNContext sunctx;
696  MPI_Comm comm = PETSC_COMM_WORLD;
697  if( SUNContext_Create(&comm, &sunctx )<0 ){
698  assert(0);
699  }
700  void* cvode_mem = CVodeCreate(CV_BDF, sunctx);
701 #else // version from 7.0.0
702  SUNContext sunctx;
703  SUNComm comm = PETSC_COMM_WORLD;
704  if( SUNContext_Create( comm, &sunctx )<0 ){
705  assert(0);
706  }
707  void* cvode_mem = CVodeCreate(CV_BDF, sunctx);
708 #endif
709  assert(cvode_mem != NULL);
710 #if SUNDIALS_VERSION_MAJOR >= 6
711  N_Vector cvode_y = N_VNew_Serial(N_CVODE, sunctx);
712 #else
713  N_Vector cvode_y = N_VNew_Serial(N_CVODE);
714 #endif
715  flag = CVodeInit(cvode_mem, NULL, 0, cvode_y);
716  assert(flag == CV_SUCCESS);
717  N_VDestroy(cvode_y);
718 
719  flag = CVodeSStolerances(cvode_mem, 1e-5, 1e-6);
720  assert(flag == CV_SUCCESS);
721  flag = CVodeSetMaxStep(cvode_mem, 1);
722  assert(flag == CV_SUCCESS);
723  flag = CVodeSetUserData(cvode_mem, NULL);
724  assert(flag == CV_SUCCESS);
725  flag = CVDiag(cvode_mem);
726  assert(flag == CV_SUCCESS);
727 
728  NV_Ith_S(cvode_y,0) = 0;
729 
730  {
731  int CVODE_flag;
732  CVODE_flag = CVodeReInit(NULL, 1, NULL);
733  assert(CVODE_flag == CV_SUCCESS);
734  CVODE_flag = CVodeSetInitStep(NULL, 1);
735  assert(CVODE_flag == CV_SUCCESS);
736 #if SUNDIALS_VERSION_MAJOR >= 7
737  sunrealtype tret;
738 #else
739  realtype tret;
740 #endif
741  CVODE_flag = CVode(cvode_mem, 1, NULL, &tret, CV_NORMAL);
742  assert(CVODE_flag == CV_SUCCESS);
743  }
744 }
745 #endif
746 
747 } // namespace limpet
Represents the ionic model and plug-in (IMP) data structure.
Definition: ION_IF.h:168
virtual void initialize(double dt, GlobalData_t **impdat)
Initializes lookup table and state variable tables.
Definition: ION_IF.cc:232
void rebuild_lookup_tables()
Rebuilds this IMP's lookup tables and GPU definition mirror.
Definition: ION_IF.cc:432
void tune(const char *im_par, const char *plugs, const char *plug_par)
Tunes specific IMP parameters from files.
Definition: ION_IF.cc:457
Target _target
execution target for this IMP
Definition: ION_IF.h:181
void set_parent(IonIfBase *parent)
Definition: ION_IF.cc:170
node_count_t restore_per_node(opencarp::FILE_SPEC in, node_count_t n, const node_index_t *pos, IIF_Mask_t *mask, size_t *offset, IMPinfo *impinfo, const global_node_index_t *loc2canon)
Reads in the state variables for an IMP from a per-node (format >= 3) dump.
Definition: ION_IF.cc:357
virtual void set_target(Target target)
Definition: ION_IF.cc:212
const IonType & get_type() const
Gets this IMP's model type.
Definition: ION_IF.cc:134
char * fill_buf(char *buf, int *n, opencarp::Salt_list *l) const
Appends the state variables to a buffer.
Definition: ION_IF.cc:262
float get_dt() const
Gets the basic integration time step.
Definition: ION_IF.cc:190
int read_svs(FILE *file)
Reads state variable values for one cell from a file.
Definition: ION_IF.cc:504
void for_each_sv_field(node_index_t node, const std::vector< std::pair< int, int >> &fields, Fn &&fn)
Visits each state-variable field of one node, in storage order.
Definition: ION_IF.h:505
std::vector< LUT > & tables()
Gets the array of state variables.
Definition: ION_IF.cc:202
ts _tstp
control time stepping
Definition: ION_IF.h:183
std::vector< IonIfBase * > & plugins()
Returns a vector containing the plugins of this IMP.
Definition: ION_IF.cc:174
int dump_luts(bool zipped)
Dumps array of LUTs to file.
Definition: ION_IF.cc:402
void get_sv_layout(std::vector< std::pair< int, int >> &fields) const
Describes the per-node memory layout of this IMP's state variables.
Definition: ION_IF.cc:326
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
virtual ~IonIfBase()
Virtual destructor declaration.
Definition: ION_IF.cc:126
int write_svs(FILE *file, node_index_t node)
Definition: ION_IF.cc:511
size_t get_sv_per_node_size() const
Size in bytes of one node's de-interleaved state-variable record.
Definition: ION_IF.cc:334
uint64_t sv_fingerprint() const
Fingerprint of this IMP's state-variable layout.
Definition: ION_IF.cc:341
void set_moddat(uint32_t data)
Set the data flag for this IMP's modified data.
Definition: ION_IF.cc:186
void set_dt(float dt)
Sets the basic integration time step.
Definition: ION_IF.cc:194
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
size_t get_n_tables_d() const
Gets the size of the array returned by IonIf::tables_d.
Definition: ION_IF.cc:208
IonIfBase * parent() const
Gets the parent IMP.
Definition: ION_IF.cc:166
void destroy_luts()
Releases this IMP's lookup-table handle.
Definition: ION_IF.cc:425
void share_lookup_tables_from(const IonIfBase &other)
Shares an initialized lookup-table set with an equivalent IMP.
Definition: ION_IF.cc:449
virtual void initialize_state(double dt, GlobalData_t **impdat)
Initializes state and private workspace without constructing LUTs.
Definition: ION_IF.cc:249
Target get_target() const
Definition: ION_IF.h:381
node_count_t restore(opencarp::FILE_SPEC in, node_count_t n, const node_index_t *pos, IIF_Mask_t *mask, size_t *offset, IMPinfo *impinfo, const global_node_index_t *loc2canon)
Reads in the state variables for an IMP.
Definition: ION_IF.cc:275
uint32_t get_moddat() const
Gets the data flags for this IMP's modified data.
Definition: ION_IF.cc:182
int miifIdx
imp index within miif
Definition: ION_IF.h:180
virtual std::size_t get_sv_size() const =0
Gets the size of the structure this IMP uses for state variables.
void copy_plugins_from(IonIfBase &other)
Copies the plugins of an IMP.
Definition: ION_IF.cc:515
virtual void * get_sv_address()=0
Gets the raw address of the state variables for this IMP.
void initialize_params()
Initializes user modifiable parameters with default values defined in the respective ionic models.
Definition: ION_IF.cc:224
IonIfBase(const IonType &type, Target target, node_count_t num_node, const std::vector< std::reference_wrapper< IonType >> &plugins)
Constructor for IonIfBase.
Definition: ION_IF.cc:109
uint32_t get_reqdat() const
Gets the data flags for this IMP's required data.
Definition: ION_IF.cc:178
node_count_t get_num_node() const
Gets the number of nodes handled by this IMP.
Definition: ION_IF.cc:138
std::size_t get_num_threads() const
Gets the number of threads used for running this IMP.
Definition: ION_IF.cc:142
Abstract class representing an ionic model type.
Definition: ion_type.h:44
const std::string & get_name() const
Gets the model name.
Definition: ion_type.cc:8
virtual void initialize_params(IonIfBase &imp) const =0
Initializes the parameters in the given IMP.
virtual SVgetfcn get_sv_offset(const char *svname, int *off, int *sz) const =0
Get the offset and size of a state variable of the model, as well as an access function.
virtual int get_sv_list(char ***list) const =0
Returns a list of SVs.
virtual uint32_t moddat() const =0
Gets data flags for this IMP's modified data.
virtual int read_svs(IonIfBase &imp, FILE *file) const =0
Reads state variable values for one cell from a file.
virtual void tune(IonIfBase &imp, const char *im_par) const =0
Handles setting of this model's parameters.
virtual int get_sv_type(const char *svname, int *type, char **type_name) const =0
Determines the type of a SV.
virtual void compute(Target target, node_index_t start, node_index_t end, IonIfBase &imp, GlobalData_t **data) const =0
Performs computation for 1 time step.
virtual void initialize_sv(IonIfBase &imp, GlobalData_t **data) const =0
Initializes the state variables of the given IMP.
virtual int write_svs(IonIfBase &imp, FILE *file, node_index_t node) const =0
Write state variable values for one cell to a file/.
virtual uint32_t reqdat() const =0
Gets data flags for this IMP's required data.
virtual Target select_target(Target target) const =0
Gets a supported target from the given target.
virtual void construct_tables(IonIfBase &imp) const =0
Contructs lookup tables.
virtual void destroy(IonIfBase &imp) const =0
Destroys the given IMP.
virtual size_t dlo_vector_size() const =0
Gets the vector size when using data layout optimization (DLO).
LUT * device
Definition: ION_IF.h:158
std::vector< LUT > host
Definition: ION_IF.h:157
#define log_msg(F, L, O,...)
Definition: filament.h:8
node_index_t * curr_node_list
needed to determine the global node number
Definition: ION_IF.cc:100
bool is_concrete(Target const target)
Checks if target is a real, concrete target.
Definition: target.cc:56
Target
enum that represents different targets to run ionic models on.
Definition: target.h:30
@ MLIR_ROCM
ROCM code for AMD GPUs generated with MLIR.
Definition: target.h:35
@ CPU
baseline CPU model generated with the original opencarp code generator
Definition: target.h:33
@ MLIR_CUDA
CUDA code for NVIDIA GPUs generated with MLIR.
Definition: target.h:36
@ MLIR_CPU
vectorized CPU code generated with MLIR
Definition: target.h:34
bool flag_set(const char *flags, const char *target)
Definition: ION_IF.cc:666
IonType * get_ion_type(const std::string &name)
SF_real GlobalData_t
Definition: limpet_types.h:12
int LUT_dump(LUT *plut, const char *fname)
Definition: LUT.cc:59
bool is_gpu(Target const target)
Checks if this is a GPU target.
Definition: target.cc:52
bool verify_flags(const char *flags, const char *given)
Definition: ION_IF.cc:644
FILE_SPEC _nc_logf
Definition: ION_IF.cc:70
void destroy_lut(LUT *plut, Target target)
Definition: LUT.cc:86
void update_ts(ts *ptstp)
Definition: ION_IF.cc:575
opencarp::local_index_t node_count_t
Definition: limpet_types.h:14
char * get_next_list(char *lst, char delimiter)
Definition: ION_IF.cc:621
char IIF_Mask_t
Definition: ion_type.h:35
opencarp::global_index_t global_node_index_t
Definition: limpet_types.h:15
void * memmem(void *haystack, int sz_hay, void *needle, int sz_n)
Definition: ION_IF.cc:595
opencarp::local_index_t node_index_t
Definition: limpet_types.h:13
char * tokstr_r(char *s1, const char *s2, char **lasts)
Definition: ION_IF.cc:74
void initialize_ts(Target target, ts *tstp, int ng, int *skp, double dt)
Definition: ION_IF.cc:546
char * dupstr(const char *old_str)
Definition: basics.cc:29
file_desc * FILE_SPEC
Definition: basics.h:125
int sz
storage required
Definition: ION_IF.h:133
int map
which plugin does this IMO match
Definition: ION_IF.h:137
IMPinfo * plug
plugins
Definition: ION_IF.h:135
bool compatible
does IM match stored IM
Definition: ION_IF.h:136
int nplug
number of plugins
Definition: ION_IF.h:134
time constant groups
Definition: ION_IF.h:80
int update
Definition: ION_IF.h:84
float dt
Definition: ION_IF.h:81
time stepper
Definition: ION_IF.h:91
int cnt
Definition: ION_IF.h:92
int ng
Definition: ION_IF.h:93
tc_grp * tcg
Definition: ION_IF.h:94
saltatory list – memory is allocated in chunks
Definition: basics.h:44
int nitems
number of items
Definition: basics.h:47