openCARP
Doxygen code documentation for the open cardiac electrophysiology simulator openCARP
ION_IF.h
Go to the documentation of this file.
1 
18 #ifndef IONIC_IF_H
19 #define IONIC_IF_H
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stddef.h>
25 #include <stdexcept>
26 #include "LUT.h"
27 #include "ODEint.h"
28 #include <math.h>
29 #include <assert.h>
30 #include <functional>
31 #ifdef _OPENMP
32 #include <omp.h>
33 #endif
34 #ifdef HAS_CUDA_MODEL
35 #include <cuda_runtime.h>
36 #endif
37 #ifdef HAS_ROCM_MODEL
38 #include <hip/hip_runtime.h>
39 #endif
40 
41 #include "basics.h"
42 #include "target.h"
43 
44 #ifdef I
45 #undef I
46 #endif
47 
48 namespace limpet {
49 
50 #ifndef M_PI //C99 does not define M_PI
51 #define M_PI 3.14159265358979323846264338327
52 #endif
53 
54 //Defines used in Slava's LIMPET model '
55 #define heav(x) ( (x)<0 ? 0 : 1)
56 #define sign(x) ( (x)<0 ? -1 : 1 )
57 #define square(x) ((x)*(x))
58 #define cube(x) ((x)*(x)*(x))
59 
60 // MPI message tags used in the IMP world
61 #define MPI_RESTORE_IMP_POLL_BUFSIZE_TAG 10
62 #define MPI_RESTORE_IMP_SNDRCV_BUFFER_TAG 11
63 #define MPI_DUMP_IMP_POLL_BUFSIZE_TAG 20
64 #define MPI_DUMP_IMP_SNDRCV_BUFFER_TAG 21
65 #define MPI_DUMP_SVS_POLL_BUFSIZE_TAG 30
66 #define MPI_DUMP_SVS_SNDRCV_BUFFER_TAG 31
67 
74 struct tc_grp {
75  float dt;
76  int skp;
77  int rat;
78  int update;
79 };
80 
85 struct ts {
86  int cnt;
87  int ng;
89 };
90 
91 
94 struct SV_TAB {
95  int svSize;
96  int numSeg;
97  void *y;
100 };
101 
112 #define NDEF 0
113 struct cell_geom {
114  float SVratio=NDEF;
115  float v_cell=NDEF;
116  float a_cap=NDEF;
117  float fr_myo=NDEF;
118  float sl_i2c=NDEF;
119 };
120 
121 }
122 #include "ion_type.h"
123 namespace limpet {
124 
125 struct IMPinfo {
126  char *name;
127  int sz;
128  int nplug;
130  bool compatible;
131  int map;
132  int offset;
133 };
134 
138 class IonIfBase {
139 private:
140  // Information about the model type.
141  const IonType& _type;
142  int _num_node;
143  IonIfBase* _parent;
144  std::vector<IonIfBase*> _plugins;
145  uint32_t _reqdat;
147  uint32_t _moddat;
149 public:
150  int miifIdx;
152 protected:
154 private:
155  cell_geom _cgeom;
156  float dt;
157  std::vector<LUT> _tables;
158  LUT * _tables_d = nullptr;
159  size_t _n_tables_d = 0;
160  GlobalData_t **ldata = nullptr;
163 public:
172  IonIfBase(const IonType& type, Target target, int num_node, const std::vector<std::reference_wrapper<IonType>>& plugins);
173 
177  virtual ~IonIfBase();
178 
185  const IonType& get_type() const;
186 
192  int get_num_node() const;
193 
199  std::size_t get_num_threads() const;
200 
206  IonIfBase* parent() const;
207 
208  // VERY UNRECOMMENDED TO CALL, THIS IS ONLY USED FOR AN UGLY HACK.
209  void set_parent(IonIfBase* parent);
210 
216  std::vector<IonIfBase*>& plugins();
217 
223  uint32_t get_reqdat() const;
224 
230  uint32_t get_moddat() const;
231 
237  void set_moddat(uint32_t data);
238 
244 #if defined HAS_CUDA_MODEL || defined HAS_ROCM_MODEL
245  __device__ __host__
246 #endif
248  return this->_cgeom;
249  }
250 
256  float get_dt() const;
257 
263  void set_dt(float dt);
264 
265 
271  ts& get_tstp();
272 
282  virtual void *get_sv_address() = 0;
283 
290  virtual std::size_t get_sv_size() const = 0;
291 
298 //#if defined HAS_CUDA_MODEL || defined HAS_ROCM_MODEL
299 // __device__ __host__
300 //#endif
301 // SV_TAB& sv_tab() {
302 // return this->_sv_tab;
303 // }
304 
311  std::vector<LUT>& tables();
312 
320 #if defined HAS_CUDA_MODEL || defined HAS_ROCM_MODEL
321  __device__ __host__
322 #endif
323  LUT *tables_d() const {
324  return this->_tables_d;
325  }
326 
333  size_t get_n_tables_d() const;
334 
335 #if defined HAS_GPU_MODEL
336  __device__ __host__
337 #endif
338  Target get_target() const {
339  return this->_target;
340  };
341 
342  virtual void set_target(Target target);
343 
348  void initialize_params();
349 
361  virtual void initialize(double dt, GlobalData_t **impdat);
362 
370  void compute(int start, int end, GlobalData_t** data);
371 
383  char* fill_buf(char *buf, int* n, opencarp::Salt_list *l) const;
384 
400  int restore(opencarp::FILE_SPEC in, int n, const int *pos, IIF_Mask_t *mask,
401  size_t *offset, IMPinfo *impinfo, const int* loc2canon);
402 
410  int dump_luts(bool zipped);
411 
415  void destroy_luts();
416 
443  void tune(const char *im_par, const char *plugs, const char *plug_par);
444 
452  int read_svs(FILE* file);
453 
454  int write_svs(FILE* file, int node);
455 
465  virtual void copy_SVs_from(IonIfBase& other, bool alloc) = 0;
466 
475  void copy_plugins_from(IonIfBase& other);
476 
483  void for_each(const std::function<void(IonIfBase&)>& consumer);
484 };
485 
496 template<typename T>
497 class IonIf : public IonIfBase {
505  struct has_rosenbrock_type {};
506  struct has_rosenbrock_vector_type {};
507  struct no_rosenbrock_type {};
508  public:
520  template<typename S>
521  class LimpetArray {
522  static constexpr bool is_void = std::is_void<S>::value;
525  S *_data;
526  std::size_t _size; //<! size of the SV array
527  bool _allocated = false;
528  Target _target;
529  public:
530 
534  LimpetArray() : _size(0), _target(Target::UNKNOWN) {
535  }
536 
543  LimpetArray(Target target, std::size_t size) : _size(size),
544  _target(target) {
545  this->allocate(target, size);
546  }
547 
552  // Check if memory was allocated, if it's the case, deallocate on the
553  // corresponding target
554  if (!is_void && _allocated) {
555  deallocate_on_target<S>(this->_target, this->_data);
556  }
557  }
558 
565  void allocate(Target target, std::size_t size) {
566  this->_size = size;
567  this->_target = target;
568  if (!is_void){
569  bool do_zero = false;
570  this->_data = allocate_on_target<S>(this->_target, this->_size, do_zero);
571  this->_allocated = true;
572  }
573  }
574 
581  template<typename Type = S>
582  typename std::enable_if<!std::is_void<Type>::value, std::size_t>::type get_element_size() const {
583  return sizeof(Type);
584  }
585 
586  template<typename Type = S>
587  typename std::enable_if<std::is_void<Type>::value, std::size_t>::type get_element_size() const {
588  return 0;
589  }
590 
596 #ifdef HAS_GPU_MODEL
597  __device__ __host__
598 #endif
599  S *data() const {
600  static_assert(!is_void, "The LimpetArray class can't be used with type 'void'");
601  return this->_data;
602  }
603 
609 #ifdef HAS_GPU_MODEL
610  __device__ __host__
611 #endif
612  std::size_t size() const {
613  static_assert(!is_void, "The LimpetArray class can't be used with type 'void'");
614  return this->_size;
615  }
616 
623  bool is_allocated() const {
624  return this->_allocated;
625  }
626 
634  if (this == &other) {
635  return *this;
636  }
637  this->_target = other._target;
638  this->_data = other._data;
639  this->_size = other._size;
640  if (other._allocated) {
641  this->_allocated = true;
642  other._allocated = false;
643  }
644  return *this;
645  }
646  };
647  private:
651 
658  using rosenbrock_usage = typename std::conditional<std::is_void<typename T::private_type>::value, no_rosenbrock_type, typename std::conditional<std::is_void<typename T::private_type_vector>::value, has_rosenbrock_type, has_rosenbrock_vector_type>::type>::type;
659 
660  // These fields are C-style arrays because they need to be accessible from device code
661  SvTab _sv_tabs[Target::N_TARGETS];
662  typename T::params_type* _params[Target::N_TARGETS] = {nullptr};
663  PrivateTab _ion_private[Target::N_TARGETS];
664  PrivateVectorTab _ion_private_vector;
665  size_t private_sz;
666  public:
667 
675  IonIf(const IonType &type, Target target, int num_node, const
676  std::vector<std::reference_wrapper<IonType>>& plugins) : IonIfBase(type,
677  target, num_node, plugins) {
678  this->allocate_model_data();
679  }
680 
686  ~IonIf() {
687  for (int i = 0; i < Target::N_TARGETS; ++i) {
688  if (this->_params[i] != nullptr) {
689  deallocate_on_target((Target) i, this->_params[i]);
690  }
691  }
692  }
693 
699 #ifdef HAS_GPU_MODEL
700  __device__ __host__
701 #endif
702  typename T::params_type *params() const {
703  return this->_params[this->get_target()];
704  }
705 
711 #ifdef HAS_GPU_MODEL
712  __device__ __host__
713 #endif
715  return this->_sv_tabs[this->get_target()];
716  }
717 
724 #ifdef HAS_GPU_MODEL
725  __device__ __host__
726 #endif
728  return this->_ion_private[this->get_target()];
729  }
730 
732  if (this->get_target() != Target::MLIR_CPU) {
733  throw std::logic_error("the vectorized ion private structure can only be used with the MLIR_CPU (vectorized CPU) target");
734  }
735  return this->_ion_private_vector;
736  }
737 
743  void * get_sv_address() override {
744  return (void *) this->_sv_tabs[this->get_target()].data();
745  }
746 
752  std::size_t get_sv_size() const override {
753  return sizeof(typename T::state_type);
754  }
755 
764  void set_target(Target target) override {
765  Target old_target = this->get_target();
766  IonIfBase::set_target(target);
767  this->allocate_model_data();
768  memcpy(this->sv_tab().data(), this->_sv_tabs[old_target].data(), this->sv_tab().size());
769  // TODO: Copy ion private data for Rosenbrock, making transformations as necessary between
770  // vectorized and non-vectorized structures
771  // memcpy(this->ion_private().data(), this->_ion_private[old_target].data(), this->ion_private().size());
772  memcpy(this->params(), this->_params[old_target], sizeof(typename T::params_type));
773  }
774 
779  std::size_t vec_size = this->get_type().dlo_vector_size();
780  if (!this->_sv_tabs[this->get_target()].is_allocated())
781  this->_sv_tabs[this->get_target()] =
782  SvTab(this->get_target(), (this->get_num_node() + vec_size - 1) / vec_size);
783  if (!this->_ion_private[this->get_target()].is_allocated())
784  this->_ion_private[this->get_target()] = PrivateTab(this->get_target(), this->get_num_threads());
785  // The private vector structure is always made for the vectorized CPU target
786  if (!this->_ion_private_vector.is_allocated() && this->get_target() == Target::MLIR_CPU)
787  this->_ion_private_vector = PrivateVectorTab(this->get_target(), this->get_num_threads());
788  if (this->_params[this->get_target()] == nullptr)
789  this->_params[this->get_target()] = allocate_on_target<typename T::params_type>(this->get_target(), 1, true);
790  }
791 
801  void initialize(double dt, GlobalData_t **impdat) override {
802  IonIfBase::initialize(dt, impdat);
803  this->init_ion_private(rosenbrock_usage {});
804  }
805 
820  void copy_SVs_from(IonIfBase& other_base, bool alloc) override {
821  IonIf<T>& other = static_cast<IonIf<T>&>(other_base);
822  int tcg_size = other.get_tstp().ng * sizeof(tc_grp);
823 
824  if (this->get_num_node() != other.get_num_node()) {
825  throw std::logic_error("cannot copy SVs if both IMPs don't handle the same amount of cells");
826  }
827 
828  memcpy(this->sv_tab().data(), other.sv_tab().data(), sizeof(typename T::state_type) * other.sv_tab().size());
829  // Only copy memory when the model actually defines a private type
830  this->copy_ion_private(other, rosenbrock_usage {});
831  memcpy(this->get_tstp().tcg, other.get_tstp().tcg, tcg_size);
832  }
833 
842  void copy_ion_private(IonIf<T>& other, has_rosenbrock_vector_type) {
843  if (this->get_target() == Target::MLIR_CPU) {
844  memcpy(this->ion_private_vector().data(), other.ion_private_vector().data(), sizeof(typename T::private_type_vector) * other.ion_private_vector().size());
845  }
846  else {
847  memcpy(this->ion_private().data(), other.ion_private().data(), sizeof(typename T::private_type) * other.ion_private().size());
848  }
849  }
850 
859  void copy_ion_private(IonIf<T>& other, has_rosenbrock_type) {
860  memcpy(this->ion_private().data(), other.ion_private().data(), sizeof(typename T::private_type) * other.ion_private().size());
861  }
862 
868  void copy_ion_private(IonIf<T>& other, no_rosenbrock_type) { }
869 
875  void init_ion_private(has_rosenbrock_vector_type) {
876  // We need to fill the vector version of the private data for vectorized CPU
877  if (this->get_target() == Target::MLIR_CPU) {
878  for (std::size_t i = 0; i < this->ion_private_vector().size(); ++i) {
879  this->ion_private_vector().data()[i].node_number = 0;
880  this->ion_private_vector().data()[i].IF = this;
881  }
882  }
883  else {
884  for (std::size_t i = 0; i < this->ion_private().size(); ++i) {
885  this->ion_private().data()[i].node_number = 0;
886  this->ion_private().data()[i].IF = this;
887  }
888  }
889  }
890 
896  void init_ion_private(has_rosenbrock_type) {
897  for (std::size_t i = 0; i < this->ion_private().size(); ++i) {
898  this->ion_private().data()[i].node_number = 0;
899  this->ion_private().data()[i].IF = this;
900  }
901  }
902 
909  void init_ion_private(no_rosenbrock_type) { }
910 };
911 
912 /*
913  function prototypes
914  */
915 
916 void initialize_ts(ts *tstp, int ng, int *skp, double dt);
917 void update_ts(ts *tstp);
918 void SV_alloc( SV_TAB *psv, int numSeg, int struct_size );
919 void SV_free( SV_TAB *psv );
920 void free_sv_table( void * );
921 void print_IMPs(void);
922 bool flag_set( const char *flags, const char *target );
923 void print_models(bool );
924 float modify_param( float a, char *expr );
925 int process_param_mod( char *pstr, char *par, char *mod );
926 char* get_typename(int type);
927 bool verify_flags( const char *flags, const char* given );
928 int load_ionic_module(const char*);
929 char *get_next_list( char *lst, char delimiter );
930 
931 // Functions for getting SVs in sv_init.c
933 
934 #include "ION_IF_sv.h"
935 
936 #define CHANGE_PARAM( T, P, V, F ) do { \
937  ((T##_Params *)P)->V = modify_param( ((T##_Params *)P)->V, F ); \
938  log_msg( _nc_logf,0, 0, " %-20s modifier: %-15s value: %g",\
939  #V,F,(float)((T##_Params *)P)->V);} while (0)
940 
941 } // namespace limpet
942 
943 #endif
Target _target
execution target for this IMP
Definition: ION_IF.h:151
GlobalData_t(* SVgetfcn)(IonIfBase &, int, int)
Definition: ion_type.h:48
char * get_typename(int type)
std::size_t get_sv_size() const override
Gets the size of a SV structure.
Definition: ION_IF.h:752
Utility class for handling arrays of data used by IMPs.
Definition: ION_IF.h:521
void initialize(double dt, GlobalData_t **impdat) override
Override of the initialization function to add the initialization of the private structures.
Definition: ION_IF.h:801
int numSeg
number of unknowns
Definition: ION_IF.h:96
bool compatible
does IM match stored IM
Definition: ION_IF.h:130
LimpetArray()
Default constructor with no allocated data.
Definition: ION_IF.h:534
PrivateVectorTab & ion_private_vector()
Definition: ION_IF.h:731
ts _tstp
control time stepping
Definition: ION_IF.h:153
#define NDEF
definition of cell geometry
Definition: ION_IF.h:112
tc_grp * tcg
Definition: ION_IF.h:88
void copy_SVs_from(IonIfBase &other_base, bool alloc) override
Copy state and private variables from another IMP.
Definition: ION_IF.h:820
int nplug
number of plugins
Definition: ION_IF.h:128
T::params_type * params() const
Gets a pointer to the parameter structure for the current target.
Definition: ION_IF.h:702
int process_param_mod(char *pstr, char *par, char *mod)
int update
Definition: ION_IF.h:78
Child class of IonIfBase specialized for each ionic model type.
Definition: ION_IF.h:497
void copy_ion_private(IonIf< T > &other, no_rosenbrock_type)
This function does nothing (overload of copy_ion_private(IonIf<T>&, has_rosenbrock_type)).
Definition: ION_IF.h:868
float modify_param(float a, char *expr)
vectorized CPU code generated with MLIR
Definition: target.h:49
void(* SVputfcn)(IonIfBase &, int, int, GlobalData_t)
Definition: ion_type.h:49
void print_IMPs(void)
std::enable_if< std::is_void< Type >::value, std::size_t >::type get_element_size() const
Definition: ION_IF.h:587
void init_ion_private(no_rosenbrock_type)
Doesn&#39;t do anything.
Definition: ION_IF.h:909
IMPinfo * plug
plugins
Definition: ION_IF.h:129
SVputfcn getPutSV(SVgetfcn)
Target get_target() const
Definition: ION_IF.h:338
int map
which plugin does this IMO match
Definition: ION_IF.h:131
array of stat variable structures
Definition: ION_IF.h:94
void SV_alloc(SV_TAB *psv, int numSeg, int struct_size)
int sz
storage required
Definition: ION_IF.h:127
V mod(const V &a, const V &b)
Definition: signals.h:50
~LimpetArray()
Destroy a limpet array.
Definition: ION_IF.h:551
~IonIf()
Destroy the IMP.
Definition: ION_IF.h:686
void free_sv_table(void *)
void print_models(bool)
void init_ion_private(has_rosenbrock_vector_type)
Initialize private data.
Definition: ION_IF.h:875
special value to handle unknown targets
Definition: target.h:47
Represents the ionic model and plug-in (IMP) data structure.
Definition: ION_IF.h:138
LimpetArray & operator=(LimpetArray &&other)
Move assignement operator.
Definition: ION_IF.h:633
bool is_allocated() const
Returns whether data has been allocated for this LimpetArray.
Definition: ION_IF.h:623
void init_ion_private(has_rosenbrock_type)
Initialize private data.
Definition: ION_IF.h:896
char IIF_Mask_t
Definition: ion_type.h:50
cell_geom & cgeom()
Gets the cell geometry data.
Definition: ION_IF.h:247
int svSize
size of structure holding SV&#39;s for a node
Definition: ION_IF.h:95
char * get_next_list(char *lst, char delimiter)
Definition: ION_IF.cc:512
void copy_ion_private(IonIf< T > &other, has_rosenbrock_type)
Copy the ion private array from other.
Definition: ION_IF.h:859
int ng
Definition: ION_IF.h:87
float dt
Definition: ION_IF.h:75
void set_target(Target target) override
Set a new execution target for this IMP.
Definition: ION_IF.h:764
a token to indicate the maximum number of targets
Definition: target.h:52
ts & get_tstp()
Gets the time stepper.
Definition: ION_IF.cc:208
LimpetArray(Target target, std::size_t size)
Constructs a LimpetArray.
Definition: ION_IF.h:543
virtual void initialize(double dt, GlobalData_t **impdat)
Initializes lookup table and state variable tables.
Definition: ION_IF.cc:237
std::enable_if<!std::is_void< Type >::value, std::size_t >::type get_element_size() const
Get the size of a single element (size of type S)
Definition: ION_IF.h:582
bool flag_set(const char *flags, const char *target)
Definition: ION_IF.cc:557
PrivateTab & ion_private()
Gets the ion private LimpetArray for the current target.
Definition: ION_IF.h:727
S * data() const
Gets a pointer to the underlying data.
Definition: ION_IF.h:599
File descriptor struct.
Definition: basics.h:133
int offset
offset into node data
Definition: ION_IF.h:132
virtual void set_target(Target target)
Definition: ION_IF.cc:220
Defines valid targets for an ionic model to run on and an allocator for allocating memory on a specif...
int get_num_node() const
Gets the number of nodes handled by this IMP.
Definition: ION_IF.cc:148
SvTab & sv_tab()
Gets the SV LimpetArray for the current target.
Definition: ION_IF.h:714
int cnt
Definition: ION_IF.h:86
time stepper
Definition: ION_IF.h:85
void update_ts(ts *ptstp)
Definition: ION_IF.cc:466
void allocate(Target target, std::size_t size)
Allocate the array on the given target.
Definition: ION_IF.h:565
char * name
IMP name.
Definition: ION_IF.h:126
std::size_t size() const
Gets the sizee of the array.
Definition: ION_IF.h:612
Target
enum that represents different targets to run ionic models on.
Definition: target.h:45
bool verify_flags(const char *flags, const char *given)
Definition: ION_IF.cc:535
saltatory list – memory is allocated in chunks
Definition: basics.h:57
void * y
Definition: ION_IF.h:97
lookup table structure
Definition: LUT.h:46
int load_ionic_module(const char *)
void initialize_ts(Target target, ts *tstp, int ng, int *skp, double dt)
Definition: ION_IF.cc:437
Abstract class representing an ionic model type.
Definition: ion_type.h:59
int miifIdx
imp index within miif
Definition: ION_IF.h:150
LUT * tables_d() const
Gets an array of LUTs.
Definition: ION_IF.h:323
Basic utility structs and functions, mostly IO related.
void copy_ion_private(IonIf< T > &other, has_rosenbrock_vector_type)
Copy the ion private array from other.
Definition: ION_IF.h:842
time constant groups
Definition: ION_IF.h:74
void SV_free(SV_TAB *psv)
void deallocate_on_target(Target target, T *ptr)
Utility function for deallocating memory on a target. See TargetAllocator.
Definition: target.h:318
void allocate_model_data()
Allocate memory for the IMP data for the current target.
Definition: ION_IF.h:778
void * get_sv_address() override
Gets the raw address of the SV array for the current target.
Definition: ION_IF.h:743
IonIf(const IonType &type, Target target, int num_node, const std::vector< std::reference_wrapper< IonType >> &plugins)
Constructs an IonIf object.
Definition: ION_IF.h:675
SF_real GlobalData_t
Definition: limpet_types.h:27