51 #include "petsc_utils.h"
55 #include <nvector/nvector_serial.h>
56 #include <cvode/cvode.h>
57 #include <cvode/cvode_diag.h>
65 using ::opencarp::Salt_list;
74 char*
tokstr_r(
char *s1,
const char *s2,
char **lasts)
80 while(*s1 && strchr(s2, *s1))
85 while(*s1 && !strchr(s2, *s1))
95 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
103 for (
auto& lut :
host)
106 deallocate_on_target<LUT>(target,
device);
110 : _type(type), _target(type.select_target(target)), _num_node(num_node) {
112 this->_reqdat = type.
reqdat();
113 this->_moddat = type.
moddat();
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);
121 this->_reqdat |= child->_reqdat;
122 this->_moddat |= child->_moddat;
127 for (
auto plugin : this->_plugins) {
128 plugin->get_type().destroy_ion_if(plugin);
139 return this->_num_node;
143 std::size_t num_threads = 0;
149 num_threads = omp_get_max_threads();
160 throw std::logic_error(
"The IonIf execution target " + std::to_string(this->
_target) +
" is invalid");
167 return this->_parent;
175 return this->_plugins;
179 return this->_reqdat;
183 return this->_moddat;
187 this->_moddat = data;
204 this->_tables = std::make_shared<LutSet>(this->
_target);
205 return this->_tables->host;
209 return this->_n_tables_d;
215 if (this->
_target != selected_target)
217 this->
_target = selected_target;
220 throw std::invalid_argument(
"new target set for IMP is unavailable or not concrete (AUTO, UNKNWOWN, ...)");
227 for (
auto& plugin : this->_plugins) {
228 plugin->initialize_params();
243 this->ldata = impdat;
245 for (
auto& plugin : this->_plugins)
246 plugin->initialize(dt, impdat);
252 this->ldata = impdat;
254 for (
auto& plugin : this->_plugins)
255 plugin->initialize_state(dt, impdat);
265 for (
auto& plugin : this->_plugins) {
266 iif_sz += plugin->get_sv_size();
269 buf = (
char *) realloc(buf, *n + l->
nitems*iif_sz) + *n;
272 return buf - *n + l->
nitems * iif_sz;
281 long base = ftell(in->fd);
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);
294 for(
int j=0; j<impinfo->
nplug; j++) {
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);
306 const std::vector<IonIfBase::sv_field>& IonIfBase::sv_layout()
const {
307 if (!_sv_layout_valid) {
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;
317 _sv_layout.push_back({list[i], off, sz, type});
321 _sv_layout_valid =
true;
327 const std::vector<sv_field>& layout = this->sv_layout();
329 fields.reserve(layout.size());
330 for (
const auto& f : layout)
331 fields.emplace_back(f.off, f.sz);
336 for (
const auto& f : this->sv_layout())
337 total +=
static_cast<size_t>(f.sz);
342 constexpr uint64_t kFNVOffsetBasis = 0xcbf29ce484222325ULL;
343 constexpr uint64_t kFNVPrime = 0x100000001b3ULL;
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);
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);
363 long base = ftell(in->fd);
367 std::vector<std::pair<int, int>> main_fields;
370 std::vector<std::vector<std::pair<int, int>>> plug_fields(impinfo->
nplug);
371 for (
int j = 0; j < impinfo->
nplug; j++) {
373 this->_plugins[impinfo->
plug[j].
map]->get_sv_layout(plug_fields[j]);
378 if(mask[canon] == this->
miifIdx) {
379 fseek(in->fd, base+offset[canon], SEEK_SET);
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");
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);
407 std::string ext = zipped ?
".gz" :
"";
408 auto&
tables = this->_tables->host;
411 for (
size_t i = 0; i <
tables.size(); i++) {
413 if (strcmp(
tables[i].name,
""))
414 name = this->_type.
get_name() +
"_LUT_" +
tables[i].name +
".bin" + ext;
416 name = this->_type.
get_name() +
"_LUT_" + std::to_string(i) +
".bin" + ext;
427 this->_tables.reset();
428 this->_tables_d =
nullptr;
429 this->_n_tables_d = 0;
434 if (!this->_num_node)
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;
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;
458 char *opar, *oplg, *plg, *nplg, *parlst, *nparlst;
460 if( im_par && *im_par !=
'\0' ) {
462 this->_type.
tune(*
this, im_par);
464 opar = parlst =
dupstr(plug_par);
465 oplg = plg =
dupstr(plugs);
467 while( plg!=NULL && *plg!=
'\0' ) {
473 if( parlst==NULL || *parlst==
'\0' ) {
483 for(j = 0; j < this->_plugins.size(); j++) {
484 if(this->_plugins[j]->
get_type() == *plugin)
break;
487 if(j == this->_plugins.size()) {
494 plugin->
tune(*this->_plugins[j], parlst);
506 return this->_type.
read_svs(*
this, file);
512 return this->_type.
write_svs(*
this, file, node);
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);
529 for (
auto& plugin : this->_plugins) {
552 tstp->
tcg = allocate_on_target<tc_grp>(target, ng);
557 tstp->
tcg[0].
dt = dt;
560 for (
int i=1;i<ng;i++) {
561 tstp->
tcg[i].
skp = skp[i];
580 for (
int i=1;i<ptstp->
ng;i++)
581 ptcg[i].update = !(ptstp->
cnt%ptcg[i].
skp);
595 void *
memmem(
void *haystack,
int sz_hay,
void *needle,
int sz_n )
597 if( !sz_n )
return NULL;
599 char *h = (
char *)haystack;
601 for(
int i=0; i>sz_hay-sz_n+1; i++, h++ )
602 if( !memcmp( h, needle, sz_n ) )
623 if( lst == NULL || *lst ==
'\0' )
626 while( *lst != delimiter && *lst !=
'\0' )
646 char *flag, *ptr, *gvn_cp =
dupstr( given );
648 flag =
tokstr_r( gvn_cp,
"|", &ptr );
656 return flag ? false :
true;
666 bool flag_set(
const char *flags,
const char *target )
668 if( !flags )
return false;
670 char *f =
dupstr( flags ), *last, *pos;
673 while( pos && strcmp( pos, target ) ) {
678 return pos? true :
false;
686 void __bogus_function_for_cvode() {
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
696 MPI_Comm comm = PETSC_COMM_WORLD;
697 if( SUNContext_Create(&comm, &sunctx )<0 ){
700 void* cvode_mem = CVodeCreate(CV_BDF, sunctx);
703 SUNComm comm = PETSC_COMM_WORLD;
704 if( SUNContext_Create( comm, &sunctx )<0 ){
707 void* cvode_mem = CVodeCreate(CV_BDF, sunctx);
709 assert(cvode_mem != NULL);
710 #if SUNDIALS_VERSION_MAJOR >= 6
711 N_Vector cvode_y = N_VNew_Serial(N_CVODE, sunctx);
713 N_Vector cvode_y = N_VNew_Serial(N_CVODE);
715 flag = CVodeInit(cvode_mem, NULL, 0, cvode_y);
716 assert(flag == CV_SUCCESS);
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);
728 NV_Ith_S(cvode_y,0) = 0;
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
741 CVODE_flag = CVode(cvode_mem, 1, NULL, &tret, CV_NORMAL);
742 assert(CVODE_flag == CV_SUCCESS);
Represents the ionic model and plug-in (IMP) data structure.
virtual void initialize(double dt, GlobalData_t **impdat)
Initializes lookup table and state variable tables.
void rebuild_lookup_tables()
Rebuilds this IMP's lookup tables and GPU definition mirror.
void tune(const char *im_par, const char *plugs, const char *plug_par)
Tunes specific IMP parameters from files.
Target _target
execution target for this IMP
void set_parent(IonIfBase *parent)
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.
virtual void set_target(Target target)
const IonType & get_type() const
Gets this IMP's model type.
char * fill_buf(char *buf, int *n, opencarp::Salt_list *l) const
Appends the state variables to a buffer.
float get_dt() const
Gets the basic integration time step.
int read_svs(FILE *file)
Reads state variable values for one cell from a file.
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.
std::vector< LUT > & tables()
Gets the array of state variables.
ts _tstp
control time stepping
std::vector< IonIfBase * > & plugins()
Returns a vector containing the plugins of this IMP.
int dump_luts(bool zipped)
Dumps array of LUTs to file.
void get_sv_layout(std::vector< std::pair< int, int >> &fields) const
Describes the per-node memory layout of this IMP's state variables.
void compute(node_index_t start, node_index_t end, GlobalData_t **data)
Perform ionic model computation for 1 time step.
virtual ~IonIfBase()
Virtual destructor declaration.
int write_svs(FILE *file, node_index_t node)
size_t get_sv_per_node_size() const
Size in bytes of one node's de-interleaved state-variable record.
uint64_t sv_fingerprint() const
Fingerprint of this IMP's state-variable layout.
void set_moddat(uint32_t data)
Set the data flag for this IMP's modified data.
void set_dt(float dt)
Sets the basic integration time step.
ts & get_tstp()
Gets the time stepper.
void for_each(const std::function< void(IonIfBase &)> &consumer)
Executes the consumer functions on this IMP and each of its plugins.
size_t get_n_tables_d() const
Gets the size of the array returned by IonIf::tables_d.
IonIfBase * parent() const
Gets the parent IMP.
void destroy_luts()
Releases this IMP's lookup-table handle.
void share_lookup_tables_from(const IonIfBase &other)
Shares an initialized lookup-table set with an equivalent IMP.
virtual void initialize_state(double dt, GlobalData_t **impdat)
Initializes state and private workspace without constructing LUTs.
Target get_target() const
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.
uint32_t get_moddat() const
Gets the data flags for this IMP's modified data.
int miifIdx
imp index within miif
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.
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.
IonIfBase(const IonType &type, Target target, node_count_t num_node, const std::vector< std::reference_wrapper< IonType >> &plugins)
Constructor for IonIfBase.
uint32_t get_reqdat() const
Gets the data flags for this IMP's required data.
node_count_t get_num_node() const
Gets the number of nodes handled by this IMP.
std::size_t get_num_threads() const
Gets the number of threads used for running this IMP.
Abstract class representing an ionic model type.
const std::string & get_name() const
Gets the model name.
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).
#define log_msg(F, L, O,...)
node_index_t * curr_node_list
needed to determine the global node number
bool is_concrete(Target const target)
Checks if target is a real, concrete target.
Target
enum that represents different targets to run ionic models on.
@ MLIR_ROCM
ROCM code for AMD GPUs generated with MLIR.
@ CPU
baseline CPU model generated with the original opencarp code generator
@ MLIR_CUDA
CUDA code for NVIDIA GPUs generated with MLIR.
@ MLIR_CPU
vectorized CPU code generated with MLIR
bool flag_set(const char *flags, const char *target)
IonType * get_ion_type(const std::string &name)
int LUT_dump(LUT *plut, const char *fname)
bool is_gpu(Target const target)
Checks if this is a GPU target.
bool verify_flags(const char *flags, const char *given)
void destroy_lut(LUT *plut, Target target)
void update_ts(ts *ptstp)
opencarp::local_index_t node_count_t
char * get_next_list(char *lst, char delimiter)
opencarp::global_index_t global_node_index_t
void * memmem(void *haystack, int sz_hay, void *needle, int sz_n)
opencarp::local_index_t node_index_t
char * tokstr_r(char *s1, const char *s2, char **lasts)
void initialize_ts(Target target, ts *tstp, int ng, int *skp, double dt)
char * dupstr(const char *old_str)
int map
which plugin does this IMO match
bool compatible
does IM match stored IM
int nplug
number of plugins
saltatory list – memory is allocated in chunks
int nitems
number of items