62 #include <cuda_runtime.h>
64 #if defined HAS_ROCM_MODEL && defined __HIP__
65 #include <hip/hip_runtime.h>
69 #include "petsc_utils.h"
73 using ::opencarp::base_timer;
85 using ::opencarp::Salt_list;
90 #ifdef USE_FMEM_WRAPPER
109 static MULTI_IF *gMIIF_Error_Recovery;
110 static int current_IIF_index;
111 static float current_time = 0;
112 static float start_time = 0;
114 static void prepare_error_recovery(
MULTI_IF *MIIF,
int IIF_index,
float time) {
115 gMIIF_Error_Recovery = MIIF;
116 current_IIF_index = IIF_index;
117 current_time = start_time+time;
121 return gMIIF_Error_Recovery->
NodeLists[current_IIF_index][local_node];
128 static int g_print_bounds_exceeded = 1;
131 return g_print_bounds_exceeded;
135 int oldval = g_print_bounds_exceeded;
137 g_print_bounds_exceeded = newval;
171 NodeNum[
static_cast<int>(IIF_Mask[i])]++;
176 for (
int i = 0; i < N_IIF; i++) {
184 for (
int j = 0; j < N_IIF; j++) {
187 if (IIF_Mask[i] == j)
188 NodeLst[j][hcount++] = i;
191 for(
int j=0; j<N_IIF; j++)
192 std::sort(NodeLst[j], NodeLst[j]+NodeNum[j]);
195 *NodeLists = NodeLst;
224 int N_IIF = pMIIF->
N_IIF;
226 pMIIF->
contiguous =
static_cast<bool *
>(calloc(N_IIF,
sizeof(
bool)));
231 for (std::size_t i = 0; i < pMIIF->
N_IIF; i++) {
232 pMIIF->
ldata[i] = allocate_on_target<GlobalData_t*>(pMIIF->
iontypes[i].get().select_target(pMIIF->
targets[i]), NUM_IMP_DATA_TYPES);
236 for (
int i = 0; i < pMIIF->
N_IIF; i++) {
255 for (
auto& imp : pMIIF->
IIF) {
256 imp->initialize_params();
265 for (
int i = 0; i < pMIIF->
IIF.size(); i++)
266 pMIIF->
IIF[i]->initialize(pMIIF->
dt, pMIIF->
ldata[i]);
280 unsigned int *moddat =
static_cast<unsigned int *
>(calloc(this->
N_IIF,
sizeof(
unsigned int)));
282 for (
int i = 0; i < this->
N_IIF; i++) {
283 moddat[i] = this->
IIF[i]->get_moddat();
284 this->
IIF[i]->set_moddat(moddat[i] | this->
IIF[i]->get_reqdat());
287 for (
int i = 0; i < this->
N_IIF; i++) {
288 this->
IIF[i]->set_moddat(moddat[i]);
308 #define FILENAME_BUF 1024
314 return (lhs > rhs) - (lhs < rhs);
346 if (!n_traceNodes)
return;
348 if (n_traceNodes > 1000)
349 log_msg(0, 4, 0,
"%s warning: %d trace nodes may impact performance", __func__, n_traceNodes);
359 for (
int iTrace = 0; iTrace < n_traceNodes; iTrace++) {
360 mesh_int_t lnode = imesh ? imesh->
pl.localize(traceNodes[iTrace]) : traceNodes[iTrace];
365 if(petsc2nod.
in_b(lnode) ==
false)
continue;
371 for (
int iRegion = 0; iRegion < MIIF->
N_IIF; iRegion++)
377 if (target != NULL ) {
380 trace_info->
found =
true;
381 trace_info->
region = iRegion;
387 for (
int iTrace = 0; iTrace < n_traceNodes; iTrace++) {
390 log_msg(0,4,0,
"trace node %d not found", traceNodes[iTrace]);
395 snprintf(traceName,
sizeof traceName,
"Trace_%d.dat", label ? label[iTrace] : traceNodes[iTrace]);
420 #define MAX_TRACE_LINE_LEN 8196
424 std::vector<IonIfBase*>& IIF = MIIF->
IIF;
435 fprintf(fs,
"%4.10f\t", time);
436 if (IIF[ctrace->
region]->get_type().has_trace()) {
440 for (
auto& plugin : IIF[ctrace->
region]->plugins()) {
441 if (plugin->get_type().has_trace()) {
443 plugin->get_type().trace(
451 fprintf(ctrace->
file->
fd,
"%s", trace_buf);
493 std::vector<IonIfBase*>& pIF = this->
IIF;
494 for (
auto& IF : pIF) {
495 int ndmps = IF->dump_luts(zipped);
496 if (ndmps < IF->tables().size()) {
497 log_msg(
logger, 4, 0,
"LUT dump error %s: only %d out of %d LUTs dumped.\n",
498 IF->get_type().get_name().c_str(), ndmps, IF->tables().size());
500 for (
auto& plugin : IF->plugins()) {
501 ndmps = plugin->dump_luts(zipped);
502 if (ndmps < plugin->tables().size()) {
503 log_msg(
logger, 4, 0,
"LUT dump error %s: only %d out of %d LUTs dumped.\n",
504 plugin->get_type().get_name().c_str(), ndmps, IF->tables().size());
518 for (
int i = 0; i <
svd.
n; i++)
536 char *buf =
static_cast<char *
>(malloc(
static_cast<size_t>(n)*size));
538 char *p =
static_cast<char *
>(tab) + offset;
542 memcpy(bp, p, size * dlo_array_size);
543 bp += size * dlo_array_size;
559 if (iot->triggered) {
560 for (
int i = 0; i <
svd.
n; i++) {
565 nwr += SF::root_write<char>(fd, (
char*) buf,
566 static_cast<size_t>(
svd.
size[i]) *
static_cast<size_t>(
svd.
num[i]),
570 svd.
nwr +=
static_cast<long>(nwr);
588 vm[i] = vm[i] + (ion[i] * (-dt));
596 if (flag_send == 1) {
600 for (
int j = 0; j < this->
numSubDt; j++)
602 for (
int i = 0; i < this->
N_IIF; i++)
605 if (!this->
N_Nodes[i])
continue;
607 prepare_error_recovery(
this, i, pIF->
get_tstp().
cnt * this->dt);
619 fprintf(stderr,
"LIMPET compute fail in %s at node %jd (local %jd)! Aborting!\n",
625 }
while (current < this->
N_Nodes[i]);
627 for (
auto& plugin : pIF->
plugins()) {
633 plugin->compute(current, this->
N_Nodes[i], this->
ldata[i]);
636 if (plugin ==
nullptr)
642 fprintf(stderr,
"LIMPET plugin fail in %s at node %jd (local %jd)! Aborting!\n",
648 }
while (current < this->
N_Nodes[i]);
657 #if defined __CUDA__ || defined __HIP__
660 cudaDeviceSynchronize();
661 #elif defined __HIP__
662 hipDeviceSynchronize();
665 fprintf(stderr,
"GPU/CUDA not found");
670 if (flag_receive == 1) {
685 for (
auto& pIF : this->
IIF) {
686 pIF->get_type().destroy_ion_if(pIF);
697 for (
int i = 0; i < pMIIF->
N_IIF; i++) {
705 for (
int j = 0; j < NUM_IMP_DATA_TYPES; j++) {
713 allocate_on_target<GlobalData_t>(pMIIF->
IIF[i]->get_target(),
716 if (pMIIF->
gdata[j] == NULL) {
717 log_msg(pMIIF->
logger, 5,
LOCAL,
"IMP data type %s not supplied for region %d", imp_data_names[j], i);
735 for (
int j = 0; j < NUM_IMP_DATA_TYPES; j++) {
737 if (this->
gdata[j] != NULL) {
745 for (
int i = 0; i < this->
N_IIF; i++) {
754 this->
ldata[i][j][k] = rdata[ip[k]];
770 for (
int i = 0; i < this->
N_IIF; i++) {
771 if (!this->
N_Nodes[i])
continue;
774 if (
is_gpu(this->
IIF[i]->get_target())) {
775 for (
int j = 0; j < NUM_IMP_DATA_TYPES; j++) {
787 for (
int j = 0; j < NUM_IMP_DATA_TYPES; j++) {
788 if (this->
IIF[i]->get_moddat() & imp_data_flag[j]) {
798 for (
int j = 0; j < NUM_IMP_DATA_TYPES; j++)
799 if (this->
gdata[j] != NULL)
805 for (
int j = 0; j < NUM_IMP_DATA_TYPES; j++) {
806 if (pMIIF->
gdata[j] != NULL) {
807 for (
int i = 0; i < pMIIF->
N_IIF; i++)
809 deallocate_on_target<GlobalData_t>(pMIIF->
IIF[i]->get_target(),
812 delete pMIIF->
gdata[j];
829 if (plgstr == NULL) {
830 *out_num_plugins = 0;
836 char *plugspec =
dupstr(plgstr);
838 char *token =
tokstr_r(plugspec,
":", &saveptr);
840 *out_num_plugins = 0;
847 out_plugins.push_back(*type);
849 token =
tokstr_r(NULL,
":", &saveptr);
852 *out_num_plugins = out_plugins.size();
883 if (index(variable,
'.') == NULL) {
887 for (
int ii = 0; ii < NUM_IMP_DATA_TYPES; ii++) {
888 if (strcmp(variable, imp_data_names[ii]) == 0) {
894 log_msg(
logger, 5,
FLUSH,
"Error! No external variable named %s in this build of openCARP.", variable);
899 if (this->
gdata[data_id] == NULL) {
901 "External variable %s is not being used this processor.\n"
902 "Is this really what you meant to do?\n"
903 "Perhaps you don't have the correct Ionic models selected.",
904 imp_data_names[data_id]);
910 for (
size_t i = 0; i < indices.
size(); i++) {
911 raw_data[indices[i]] = values[i];
922 char *my_variable =
dupstr(variable);
923 char *IIF_name =
tokstr_r(my_variable,
".", &saveptr);
924 char *sv_name =
tokstr_r(NULL,
".", &saveptr);
928 log_msg(
logger, 5, 0,
"%s error: %s is not a valid IMP name.", __func__, IIF_name);
935 if (sv_get == NULL) {
936 log_msg(
logger, 5, 0,
"%s error: %s is not a valid state variable for the %s model.",
937 __func__, sv_name, IIF_name);
943 for (
int i_iif = 0; i_iif < this->
N_IIF; i_iif++) {
945 if (this->
IIF[i_iif]->get_type() == *type) {
946 lIIF = this->
IIF[i_iif];
950 for (
auto& plugin : this->
IIF[i_iif]->plugins()) {
951 if (plugin->get_type() == *type) {
962 for (
size_t ii = 0; ii < indices.
size(); ii++) {
971 sv_put(*lIIF, target - this->
NodeLists[i_iif], sv_offset, file_value);
979 MPI_Allreduce(MPI_IN_PLACE, &num_changed, 1, MPI_INT, MPI_SUM, PETSC_COMM_WORLD);
1008 long loff = offset[0];
1009 for (
int i = 0; i < N; i++)
1010 if (offset[i]-loff > bufsize) {
1017 *ranges = (
int *)r.data;
1020 MPI_Bcast(&nitems, 1, MPI_INT, 0, PETSC_COMM_WORLD);
1022 *ranges =
static_cast<int *
>(malloc( (nitems+1)*
sizeof(
int) ));
1023 MPI_Bcast(*ranges, nitems+1, MPI_INT, 0, PETSC_COMM_WORLD);
1066 bool append,
unsigned int revision)
1076 log_msg(
logger, 0, 0,
"Saving state at time %f in file: %s", simtime, fname);
1079 out =
f_open(fname, append ?
"a" :
"w");
1082 fseek(out->fd, 0, SEEK_END);
1085 fwrite(&MIIF_Format,
sizeof(
unsigned int), 1, out->fd);
1086 fwrite(&revision,
sizeof(
unsigned int), 1, out->fd);
1087 time_t tm = time(NULL);
1088 fwrite(&tm,
sizeof(time_t), 1, out->fd);
1089 fwrite(&simtime,
sizeof(
float), 1, out->fd);
1093 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++)
1094 if (this->
gdata[i]) num_gdata++;
1096 fwrite(&num_gdata,
sizeof(
int), 1, out->fd);
1107 FILE* fd = rank == 0 ? out->fd : NULL;
1110 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++) {
1111 if (this->
gdata[i]) {
1115 log_msg(NULL, 0, 0,
"\tDumping %s at %d", imp_data_names[i], ftell(fd) );
1128 outVec->write_binary<
SF_real>(fd);
1140 int* imp_mem =
new int[this->
N_IIF];
1141 size_t *offset = NULL;
1146 log_msg(NULL, 0, 0,
"\tDumping IMP sizes at %d", ftell(fd) );
1150 fwrite(&this->
N_IIF,
sizeof(
int), 1, fd);
1152 for (
int i = 0; i < this->
N_IIF; i++) {
1157 fwrite(&sv_size,
sizeof(
int), 1, fd);
1158 unsigned long n_plugins = (
unsigned long) imp->
plugins().size();
1159 fwrite(&n_plugins,
sizeof(
int), 1, fd);
1162 for (
auto& plug : imp->
plugins()) {
1165 fwrite(&sv_size,
sizeof(
int), 1, fd);
1166 imp_mem[i] += plug->get_sv_size();
1169 filepos = ftell(fd);
1172 MPI_Bcast(imp_mem, this->
N_IIF, MPI_INT, 0, PETSC_COMM_WORLD);
1185 for(
size_t i=0; i<alg_idx.
size(); i++) loc2canon[i] = canon_nbr[alg_idx[i]];
1191 layout, PETSC_COMM_WORLD);
1200 canord[i] = loc2canon[i];
1203 log_msg(NULL, 0, 0,
"\tDumping IMP masks at %d", filepos);
1206 SF::root_write_ordered<global_node_index_t, IIF_Mask_t>(fd, canord,
IIFmask,
numNode, PETSC_COMM_WORLD);
1212 impsize[i] = imp_mem[(
int)
IIFmask[i]];
1216 size_t num_entr =
static_cast<size_t>(
SF::sum(impsize));
1220 for (
int imp_idx = 0; imp_idx < this->
N_IIF; imp_idx++)
1226 for (
node_index_t imp_nod_idx = 0; imp_nod_idx < this->
N_Nodes[imp_idx]; imp_nod_idx+=vec_size) {
1231 char* write = impdata.
data() + impdsp[loc];
1233 memcpy(write, read, svSize);
1236 for (
auto& plug : iif->
plugins()) {
1237 int plugsize = plug->get_sv_size();
1239 write = impdata.
data() + impdsp[loc] + shift;
1240 read = (
char*) plug->get_sv_address() + index * plugsize;
1241 memcpy(write, read, plugsize);
1248 SF::root_write_ordered<global_node_index_t, char>(fd, canord, impsize.data(), impdata.
data(),
1249 numNode, num_entr, PETSC_COMM_WORLD);
1255 double dump_time =
timing(t1, t0);
1284 static char *last_fn = NULL;
1293 if (fname) in =
f_open(fname,
"r");
1296 if (fname)
log_msg(
logger, 5, 0,
"Error: cannot open file: %s\n", fname);
1297 else log_msg(
logger, 5, 0,
"Error: file stream not open yet");
1302 log_msg(
logger, 5, 0,
"%s is not a recognized MIIF dump file", fname);
1313 last_fn = strdup(fname);
1319 unsigned int format, version;
1322 f_read_par(&format,
sizeof(
unsigned int), 1, in);
1323 f_read_par(&version,
sizeof(
unsigned int), 1, in);
1324 f_read_par(&save_date,
sizeof(time_t), 1, in);
1326 log_msg(
logger, 0, 0,
"Restoring time %f from %s (format v%d) generated\n\tby calling "
1327 "program r%d on %s", time, fname, format, version, ctime(&save_date) );
1331 MPI_SUM, PETSC_COMM_WORLD);
1338 savedNum = savedNum32;
1340 if (savedNum != glob_numNode) {
1341 log_msg(
logger, 5, 0,
"expecting %jd nodes but read %jd nodes",
1350 for (
int g = 0; g < num_gdata; g++) {
1353 for (i = 0; i < NUM_IMP_DATA_TYPES; i++) {
1354 if (!strcmp(datatype, imp_data_names[i]) ) {
1355 if (this->
gdata[i]) {
1356 log_msg(
logger, 0, 0,
"\tRestoring global data %s", imp_data_names[i], datatype);
1358 FILE* fd = my_rank == 0 ? in->fd : NULL;
1361 petsc2canon(*this->
gdata[i], fwd);
1363 log_msg(
logger, 0, 0,
"\tGlobal data %s not used", datatype);
1368 if (i == NUM_IMP_DATA_TYPES)
1369 log_msg(
logger, 3, 0,
"\tSaved global data %s not recognized", datatype);
1371 if ( (my_rank == 0) && ((i == NUM_IMP_DATA_TYPES) || !this->
gdata[i]) )
1372 fseek(in->fd, this->gdata[i]->gsize() *
sizeof(
SF_real), SEEK_CUR);
1382 int *IMPsz =
static_cast<int *
>(malloc(
N_IIF *
sizeof(
int)));
1384 for (
int i = 0; i <
N_IIF; i++) {
1387 f_read_par(&imps[i].nplug,
sizeof(
int), 1, in);
1390 IMPsz[i] = imps[i].
sz;
1393 for (
int j = 0; j < imps[i].
nplug; j++) {
1396 f_read_par(&imps[i].plug[j].sz,
sizeof(
int), 1, in);
1397 IMPsz[i] += imps[i].
plug[j].
sz;
1402 for (
int i = 0; i <
N_IIF; i++) {
1403 if (i >= this->N_IIF) {
1404 log_msg(NULL, 3, 0,
"Saved IMP region %d out of range", i);
1407 if (strcmp(imps[i].
name, this->
IIF[i]->get_type().get_name().c_str()) ) {
1408 log_msg(NULL, 3, 0,
"Saved IMP region %d ionic model does not match that of IMP region %d", i, i);
1411 if (imps[i].sz != this->
IIF[i]->get_sv_size()) {
1412 log_msg(NULL, 3, 0,
"Saved IMP region %d size does not match current IMP size", i);
1418 for (
int j = 0; j < imps[i].
nplug; j++)
1419 for (
int k = 0; k < this->
IIF[i]->plugins().size(); k++)
1420 if (!strcmp(imps[i].plug[j].
name, this->
IIF[i]->plugins()[k]->get_type().get_name().c_str()) &&
1421 (imps[i].plug[j].sz == this->
IIF[i]->plugins()[k]->get_sv_size()) ) {
1422 log_msg(NULL, 3, 0,
"Saved IMP region %d plugin %s compatible", i, imps[i].plug[j].
name);
1431 const size_t global_node_count =
static_cast<size_t>(glob_numNode);
1432 IIF_Mask_t *canMask =
static_cast<char *
>(malloc(global_node_count*
sizeof(this->
IIFmask[0]) ));
1436 size_t *offset =
static_cast<size_t *
>(calloc(global_node_count+1,
sizeof(
size_t)));
1437 for (
size_t i = 1; i <= global_node_count; i++)
1438 offset[i] = offset[i-1] + IMPsz[
static_cast<int>(canMask[i-1])];
1446 SVstart = ftell(in->fd);
1450 MPI_Bcast(&SVstart,
sizeof(
long), MPI_BYTE, 0, PETSC_COMM_WORLD);
1459 for(
size_t i=0; i<alg_idx.
size(); i++) loc2canon[i] = canon_nbr[alg_idx[i]];
1462 for (
int pid = 0; pid < mpi_size; pid++) {
1463 if (my_rank == pid) {
1467 for (
int i = 0; i <
N_IIF; i++) {
1468 fseek(in->fd, SVstart, SEEK_SET);
1470 canMask, offset, imps+i, loc2canon.
data());
1475 MPI_Barrier(PETSC_COMM_WORLD);
1480 MPI_Reduce(my_rank ? &mismatch : MPI_IN_PLACE, &mismatch, 1,
1481 opencarp::mpi_datatype<global_node_index_t>(), MPI_SUM, 0, PETSC_COMM_WORLD);
1482 if ( (my_rank == 0) && mismatch)
1485 if ( (my_rank == 0) && (!close) ) {
1490 fseek(in->fd, SVstart+offset[global_node_count], SEEK_SET);
1494 for (
int i = 0; i <
N_IIF; i++)
1498 double restore_time =
timing(t1, t0);
1499 log_msg(
logger, 0, 0,
"State restored from file %s in %.3f seconds.\n", fname, restore_time);
1516 char *reg_name,
char *sv_lst,
char *plg_lst,
1517 char *plg_sv_lst,
double t,
double dump_dt) {
1518 char file[8000], svs[1024], plgs[1024], plgsvs[1024];
1519 char *e, *l, *p, *svnames, *plgnames, *plgsvnames;
1521 strcpy(svs, sv_lst);
1522 strcpy(plgs, plg_lst);
1523 strcpy(plgsvs, plg_sv_lst);
1525 plgnames = &plgs[0];
1526 plgsvnames = &plgsvs[0];
1536 snprintf(file,
sizeof file,
"%s.%s.bin", reg_name, svnames);
1550 snprintf(file,
sizeof file,
"%s_%s.%s.bin", reg_name, plgnames, plgsvnames);
1575 const char *
filename,
const char *regname) {
1577 int n = this->
svd.
n;
1582 for (i = 0; i < IF->
plugins().size(); i++)
1583 if (IF->
plugins()[i]->get_type() == type)
1585 if (i == IF->
plugins().size()) {
1586 log_msg(
logger, 2, 0,
"Warning: IMP %s not found in Region %s\n",
1597 this->
svd.
fn =
static_cast<char **
>(realloc(this->
svd.
fn, this->svd.n*
sizeof(
char *)));
1598 this->
svd.
reg =
static_cast<int *
>(realloc(this->
svd.
reg, this->svd.n*
sizeof(
int)));
1599 this->
svd.
svnames =
static_cast<char **
>(realloc(this->
svd.
svnames, this->svd.n*
sizeof(
char *)));
1602 this->
svd.
offset =
static_cast<int *
>(realloc(this->
svd.
offset, this->svd.n*
sizeof(
int)));
1603 this->
svd.
size =
static_cast<int *
>(realloc(this->
svd.
size, this->svd.n*
sizeof(
int)));
1604 this->
svd.
dlo_vs =
static_cast<int *
>(realloc(this->
svd.
dlo_vs, this->svd.n*
sizeof(
int)));
1605 this->
svd.
dtype =
static_cast<int *
>(realloc(this->
svd.
dtype, this->svd.n*
sizeof(
int)));
1606 this->
svd.
svtab =
static_cast<void **
>(realloc(this->
svd.
svtab, this->svd.n*
sizeof(
void *)));
1607 this->
svd.
svsize =
static_cast<size_t *
>(realloc(this->
svd.
svsize, this->svd.n*
sizeof(
size_t)));
1609 this->
svd.
reg =
static_cast<int *
>(realloc(this->
svd.
reg, this->svd.n*
sizeof(
int)));
1622 this->
svd.
reg[n] = region;
1644 char *svname,
char *regname,
char *
filename) {
1645 int offset, size, dtype, added = 0;
1646 char *svtypename = NULL;
1650 filename_bin = strcat(
filename,
".bin");
1652 assert(type != NULL);
1655 this->
sv_dump_add(region, *type, offset, size, dtype, filename_bin, regname);
1659 log_msg(NULL, 1, 0,
"No state variable added to dump list");
1678 assert(miif->
gdata[Vm] != NULL);
1680 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++) {
1681 for (
int n = 0; n < miif->
N_IIF; n++)
1682 if (
USED_DAT(miif->
IIF[n], imp_data_flag[i]) && (miif->
gdata[i] == NULL)) {
1697 int num_mech_data = 0;
1699 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++) {
1700 if ( (Lambda_DATA_FLAG == i) || (delLambda_DATA_FLAG == i) ||
1701 (Tension_DATA_FLAG == i) || (tension_component_DATA_FLAG == i) ) {
1702 for (
int n = 0; n < this->
N_IIF; n++)
1707 return static_cast<bool>(num_mech_data);
1728 float beta,
int *node,
int numnode) {
1730 if (strstr(species,
"Ca") != NULL) {
1733 }
else if (strstr(species,
"Na") != NULL) {
1735 }
else if (strstr(species,
"Cl") != NULL) {
1737 }
else if (strstr(species,
"K") != NULL) {
1740 log_msg(
logger, 5, 0,
"Unimplemented ion species: %s\n", species);
1746 static int warned = 0;
1751 int my_low_idx = layout[rank], my_high_idx = layout[rank+1];
1753 for (
int i = 0; i < numnode; i++) {
1754 if ((node[i] < my_low_idx) || (node[i] >= my_high_idx))
continue;
1756 for (
int j = 0; j < this->
N_IIF; j++) {
1757 if (this->
NodeLists[j] == NULL)
continue;
1759 if ((node[i] < this->
NodeLists[j][0]) ||
1763 ion_get = this->
IIF[j]->get_type().get_sv_offset(species, &offset, &sz);
1764 if (ion_get == NULL) {
1767 log_msg(
logger, 2, 0,
"Ion species not present in ionic model: %s\n",
1779 delta_conc = charge*g.
sl_i2c/z;
1782 delta_conc = 10*charge*beta/(
FARADAY*z);
1787 ion_put(*this->
IIF[j], k, offset, ion_get(*this->
IIF[j], k, offset)-delta_conc);
1800 for (
int i = 0; i < this->
N_IIF; i++) {
1801 this->
IIF[i]->destroy_luts();
1802 this->
IIF[i]->set_dt((
float) Dt);
1803 this->
iontypes[i].get().construct_tables(*this->
IIF[i]);
1805 for (
int j = 0; j < this->
IIF[i]->plugins().size(); j++) {
1806 auto& plugin = this->
IIF[i]->plugins()[j];
1807 plugin->destroy_luts();
1808 plugin->set_dt((
float) Dt);
1809 this->
plugtypes[i][j].get().construct_tables(*plugin);
1814 #define MEMFREE(A) free(A)
1825 for (
int i = 0; i < m->
N_IIF; i++) {
1826 m->
IIF[i]->get_type().destroy_ion_if(m->
IIF[i]);
1829 for (
int j = 0; j < NUM_IMP_DATA_TYPES; j++) {
1850 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++)
1854 for (
int i = 0; i < orig->
N_IIF; i++) {
1855 miif_doppel->
IIF[i]->copy_SVs_from(*orig->
IIF[i],
false);
1857 for (
int j = 0; j < orig->
IIF[i]->plugins().size(); j++)
1858 miif_doppel->
IIF[i]->plugins()[j]->copy_SVs_from(*orig->
IIF[i]->plugins()[j],
false);
1875 *miif_doppel = *orig;
1876 miif_doppel->
doppel =
true;
1879 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++)
1884 miif_doppel->
IIF = {};
1886 for (
int i = 0; i < orig->
N_IIF; i++) {
1888 miif_doppel->
IIF.push_back(orig->
IIF[i]->get_type().make_ion_if(orig->
IIF[i]->get_target(),
1890 miif_doppel->
IIF[i]->copy_SVs_from(*orig->
IIF[i],
true);
1891 miif_doppel->
IIF[i]->copy_plugins_from(*orig->
IIF[i]);
1914 int imp_data_id = -1;
1916 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++) {
1917 if (strcmp(sv, imp_data_names[i]) == 0) {
1932 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++)
1933 if (localdata && localdata[i])
1934 localdata[i][to] = localdata[i][from];
1938 int sv_list_size = imp.
get_type().get_sv_list(&sv_list);
1940 for (
int i = 0; i < sv_list_size; i++) {
1941 char *sv_name = sv_list[i];
1944 SVgetfcn sv_get = imp.
get_type().get_sv_offset(sv_name, &sv_offset, &sv_size);
1945 if (sv_get == NULL) {
1946 throw std::runtime_error(std::string(__func__) +
" error: " + sv_name +
" is not a valid state variable for the " + imp.
get_type().
get_name() +
" model.");
1951 sv_put(imp, to, sv_offset, sv_val);
#define NDEF
definition of cell geometry
#define MAX_TRACE_LINE_LEN
Define multiple ionic models to be used in different regions.
#define FARADAY
Faraday's constant.
opencarp::local_index_t mesh_int_t
opencarp::real_t SF_real
Global scalar type.
#define SLIST_APPEND(S, P)
virtual void release_ptr(S *&p)=0
size_t read_binary(FILE *fd)
virtual void add_scaled(const abstract_vector< T, S > &vec, S k)=0
size_t write_binary(FILE *fd)
Write a vector to HD in binary. File descriptor is already set up.
virtual void set(const vector< T > &idx, const vector< S > &vals, const bool additive=false, const bool local=false)=0
bool in_b(const T idx)
return whether idx is in set B
T backward_map(T idx) const
Map one index from b to a.
overlapping_layout< T > pl
nodal parallel layout
Container for a PETSc VecScatter.
void forward(abstract_vector< T, S > &in, abstract_vector< T, S > &out, bool add=false)
Forward scattering.
size_t size() const
The current size of the vector.
void resize(size_t n)
Resize a vector.
T * data()
Pointer to the vector's start.
Represents the ionic model and plug-in (IMP) data structure.
const IonType & get_type() const
Gets this IMP's model type.
std::vector< IonIfBase * > & plugins()
Returns a vector containing the plugins of this IMP.
void compute(node_index_t start, node_index_t end, GlobalData_t **data)
Perform ionic model computation for 1 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.
IonIfBase * parent() const
Gets the parent IMP.
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.
virtual void * get_sv_address()=0
Gets the raw address of the state variables for this IMP.
node_count_t get_num_node() const
Gets the number of nodes handled by this IMP.
Abstract class representing an ionic model type.
bool is_plugin() const
Returns whether this model is a plugin or not.
const std::string & get_name() const
Gets the model name.
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_type(const char *svname, int *type, char **type_name) const =0
Determines the type of a SV.
virtual size_t dlo_vector_size() const =0
Gets the vector size when using data layout optimization (DLO).
bool extUpdateVm
flag indicating update function for Vm
std::vector< IonIfBase * > IIF
array of IIF's
opencarp::sf_vec * gdata[NUM_IMP_DATA_TYPES]
data used by all IMPs
void sv_dump_add_by_name_list(int, char *, char *, char *, char *, char *, double, double)
node_count_t numNode
local number of nodes
size_t dump_svs(opencarp::base_timer *)
std::vector< Target > targets
target for each region
std::vector< IonTypeList > plugtypes
plugins types for each region
IonTypeList iontypes
type for each region
void dump_state(char *, float, opencarp::mesh_t gid, bool, unsigned int)
SV_DUMP svd
state variable dump
void sv_dump_add(int, const IonType &, int, int, int, const char *, const char *)
void transmem_stim_species(float, const char *, float, int *, int)
void initialize_currents(double, int)
GlobalData_t *** ldata
data local to each IMP
float restore_state(const char *, opencarp::mesh_t gid, bool)
int N_IIF
how many different IIF's
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...
int sv_dump_add_by_name(int, char *, char *, char *, char *)
Trace_Info * trace_info
Information about traces.
node_count_t * N_Nodes
#nodes for each IMP
GlobalData_t * procdata[NUM_IMP_DATA_TYPES]
data for this processor
void dump_luts_MIIF(bool)
bool * contiguous
whether a region is contiguously numbered
opencarp::FILE_SPEC logger
int numSubDt
number of sub-dt time steps
node_index_t ** NodeLists
local partitioned node lists for each IMP stored
void MIIF_change_dt(double)
IIF_Mask_t * IIFmask
region for each node
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
bool doppel
is this a shallow clone?
void releaseRealDataDuringInit()
#define log_msg(F, L, O,...)
void dsp_from_cnt(const vector< T > &cnt, vector< T > &dsp)
Compute displacements from counts.
T sum(const vector< T > &vec)
Compute sum of a vector's entries.
void local_petsc_to_nodal_mapping(const meshdata< T, S > &mesh, index_mapping< T > &petsc_to_nodal)
void layout_from_count(const T count, vector< T > &layout, MPI_Comm comm)
void init_vector(SF::abstract_vector< T, S > **vec)
@ NBR_SUBMESH
Submesh nodal numbering: The globally ascending sorted reference indices are reindexed.
void(* SVputfcn)(IonIfBase &, node_index_t, int, GlobalData_t)
void CreateIIFNodeLsts_(int, IIF_Mask_t *, node_count_t **, node_index_t ***, node_count_t)
void doppel_MIIF(MULTI_IF *orig, MULTI_IF *miif_doppel)
void initializeIMPData(MULTI_IF *pMIIF)
int determine_write_ranges(int N, size_t *offset, size_t bufsize, int **ranges)
int get_plug_flag(char *plgstr, int *out_num_plugins, IonTypeList &out_plugins)
SVputfcn getPutSV(SVgetfcn)
void doppel_update(MULTI_IF *orig, MULTI_IF *miif_doppel)
node_index_t getGlobalNodalIndex(IonIfBase &pIF, node_index_t relIdx)
int should_print_bounds_exceeded_messages()
@ CPU
baseline CPU model generated with the original opencarp code generator
IonType * get_ion_type(const std::string &name)
int IMPdataLabel2Index(const char *sv)
void CreateIIFGlobalNodeLsts(MULTI_IF *pMIIF)
void allocate_shared_data(MULTI_IF *)
bool isIMPdata(const char *)
bool is_gpu(Target const target)
Checks if this is a GPU target.
void initialize_params_MIIF(MULTI_IF *pMIIF)
constexpr T min(T a, T b)
void alloc_MIIF(MULTI_IF *pMIIF)
void freeIMPData(MULTI_IF *pMIIF)
GlobalData_t(* SVgetfcn)(IonIfBase &, node_index_t, int)
std::vector< std::reference_wrapper< IonType > > IonTypeList
void dup_IMP_node_state(IonIfBase &IF, node_index_t from, node_index_t to, GlobalData_t **localdata)
constexpr T max(T a, T b)
char * get_sv(void *tab, int offset, node_count_t n, int svSize, int size, int dlo_vector_size)
void deallocate_on_target(Target target, T *ptr)
Utility function for deallocating memory on a target. See TargetAllocator.
void CreateIIFLocalNodeLsts(MULTI_IF *pMIIF)
void initialize_ionic_IF(MULTI_IF *pMIIF)
void update_ts(ts *ptstp)
float current_global_time()
opencarp::local_index_t node_count_t
void close_trace(MULTI_IF *MIIF)
int node_index_cmp(const void *a, const void *b)
void dump_trace(MULTI_IF *MIIF, limpet::Real time)
char * get_next_list(char *lst, char delimiter)
void open_trace(MULTI_IF *MIIF, int n_traceNodes, int *traceNodes, int *label, opencarp::sf_mesh *imesh)
Set up ionic model traces at some global node numbers.
void free_doppel(MULTI_IF *m)
opencarp::global_index_t global_node_index_t
node_index_t current_global_node(node_index_t local_node)
opencarp::local_index_t node_index_t
char * tokstr_r(char *s1, const char *s2, char **lasts)
int set_print_bounds_exceeded_messages(int newval)
std::intmax_t printable_int(T value)
sf_mesh & get_mesh(const mesh_t gt)
Get a mesh by specifying the gridID.
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
char * read_bin_string(FILE_SPEC in)
void f_read_par(void *ptr, size_t size, size_t nmemb, FILE_SPEC stream, MPI_Comm comm)
Parallel fread. Root reads, then broadcasts.
int get_rank(MPI_Comm comm=PETSC_COMM_WORLD)
T get_global(T in, MPI_Op OP, MPI_Comm comm=PETSC_COMM_WORLD)
Do a global reduction on a variable.
void write_bin_string(FILE_SPEC out, const char *s)
FILE_SPEC f_open(const char *fname, const char *mode)
Open a FILE_SPEC.
char * read_bin_string_par(FILE_SPEC in)
char * dupstr(const char *old_str)
mesh_t
The enum identifying the different meshes we might want to load.
void get_time(double &tm)
SF::abstract_vector< SF_int, SF_real > sf_vec
int get_size(MPI_Comm comm=PETSC_COMM_WORLD)
V timing(V &t2, const V &t1)
void f_close(FILE_SPEC &f)
Close a FILE_SPEC.
#define PETSC_TO_CANONICAL
Permute algebraic data from PETSC to canonical ordering.
int offset
offset into node data
int map
which plugin does this IMO match
bool compatible
does IM match stored IM
int nplug
number of plugins
data structure to manage state variable file dumps
size_t * svsize
state variable sizes
char ** fn
array to store file names
double intv
time interval for sv dumps
int n_dumps
keep track of number of dumped time slices
node_count_t * num
number of nodes
long nwr
keep track of number of written tokens
int * size
sizes of SV to dump
void ** svtab
state variable tables
int * reg
array to store region ids
double t_dump
next instant for sv dump
char ** svnames
array to store sv names
int n
#state variables we want to dump
int * offset
offsets into structure for SV
opencarp::FILE_SPEC * hdls
array of file handles to sv output files
data structure to manage trace dumps. Should eventually be combined with the state variable dumps,...
bool ignored
globally not found
node_index_t node_idx
local node number
bool found
found on this node
float sl_i2c
convert sl-currents in uA/cm^2 to mM/L without valence