47 #include <cuda_runtime.h>
49 #if defined HAS_ROCM_MODEL && defined __HIP__
50 #include <hip/hip_runtime.h>
54 #include "petsc_utils.h"
58 using ::opencarp::base_timer;
70 using ::opencarp::Salt_list;
75 #ifdef USE_FMEM_WRAPPER
94 static MULTI_IF *gMIIF_Error_Recovery;
95 static int current_IIF_index;
96 static float current_time = 0;
97 static float start_time = 0;
99 static void prepare_error_recovery(
MULTI_IF *MIIF,
int IIF_index,
float time) {
100 gMIIF_Error_Recovery = MIIF;
101 current_IIF_index = IIF_index;
102 current_time = start_time+time;
106 return gMIIF_Error_Recovery->
NodeLists[current_IIF_index][local_node];
113 static int g_print_bounds_exceeded = 1;
116 return g_print_bounds_exceeded;
120 int oldval = g_print_bounds_exceeded;
122 g_print_bounds_exceeded = newval;
156 NodeNum[
static_cast<int>(IIF_Mask[i])]++;
161 for (
int i = 0; i < N_IIF; i++) {
169 for (
int j = 0; j < N_IIF; j++) {
172 if (IIF_Mask[i] == j)
173 NodeLst[j][hcount++] = i;
176 for(
int j=0; j<N_IIF; j++)
177 std::sort(NodeLst[j], NodeLst[j]+NodeNum[j]);
180 *NodeLists = NodeLst;
209 int N_IIF = pMIIF->
N_IIF;
211 pMIIF->
contiguous =
static_cast<bool *
>(calloc(N_IIF,
sizeof(
bool)));
216 for (std::size_t i = 0; i < pMIIF->
N_IIF; i++) {
217 pMIIF->
ldata[i] = allocate_on_target<GlobalData_t*>(pMIIF->
iontypes[i].get().select_target(pMIIF->
targets[i]), NUM_IMP_DATA_TYPES);
221 for (
int i = 0; i < pMIIF->
N_IIF; i++) {
240 for (
auto& imp : pMIIF->
IIF) {
241 imp->initialize_params();
250 for (
int i = 0; i < pMIIF->
IIF.size(); i++)
251 pMIIF->
IIF[i]->initialize(pMIIF->
dt, pMIIF->
ldata[i]);
265 unsigned int *moddat =
static_cast<unsigned int *
>(calloc(this->
N_IIF,
sizeof(
unsigned int)));
267 for (
int i = 0; i < this->
N_IIF; i++) {
268 moddat[i] = this->
IIF[i]->get_moddat();
269 this->
IIF[i]->set_moddat(moddat[i] | this->
IIF[i]->get_reqdat());
272 for (
int i = 0; i < this->
N_IIF; i++) {
273 this->
IIF[i]->set_moddat(moddat[i]);
293 #define FILENAME_BUF 1024
299 return (lhs > rhs) - (lhs < rhs);
331 if (!n_traceNodes)
return;
333 if (n_traceNodes > 1000)
334 log_msg(0, 4, 0,
"%s warning: %d trace nodes may impact performance", __func__, n_traceNodes);
344 for (
int iTrace = 0; iTrace < n_traceNodes; iTrace++) {
345 mesh_int_t lnode = imesh ? imesh->
pl.localize(traceNodes[iTrace]) : traceNodes[iTrace];
350 if(petsc2nod.
in_b(lnode) ==
false)
continue;
356 for (
int iRegion = 0; iRegion < MIIF->
N_IIF; iRegion++)
362 if (target != NULL ) {
365 trace_info->
found =
true;
366 trace_info->
region = iRegion;
372 for (
int iTrace = 0; iTrace < n_traceNodes; iTrace++) {
375 log_msg(0,4,0,
"trace node %d not found", traceNodes[iTrace]);
380 snprintf(traceName,
sizeof traceName,
"Trace_%d.dat", label ? label[iTrace] : traceNodes[iTrace]);
405 #define MAX_TRACE_LINE_LEN 8196
407 std::vector<IonIfBase*>& IIF = MIIF->
IIF;
422 fprintf(fs,
"%4.10f\t", time);
423 if (IIF[ctrace->
region]->get_type().has_trace()) {
427 for (
auto& plugin : IIF[ctrace->
region]->plugins()) {
428 if (plugin->get_type().has_trace()) {
430 plugin->get_type().trace(
438 fprintf(ctrace->
file->
fd,
"%s", trace_buf);
480 std::vector<IonIfBase*>& pIF = this->
IIF;
481 for (
auto& IF : pIF) {
482 int ndmps = IF->dump_luts(zipped);
483 if (ndmps < IF->tables().size()) {
484 log_msg(
logger, 4, 0,
"LUT dump error %s: only %d out of %d LUTs dumped.\n",
485 IF->get_type().get_name().c_str(), ndmps, IF->tables().size());
487 for (
auto& plugin : IF->plugins()) {
488 ndmps = plugin->dump_luts(zipped);
489 if (ndmps < plugin->tables().size()) {
490 log_msg(
logger, 4, 0,
"LUT dump error %s: only %d out of %d LUTs dumped.\n",
491 plugin->get_type().get_name().c_str(), ndmps, IF->tables().size());
505 for (
int i = 0; i <
svd.
n; i++)
523 char *buf =
static_cast<char *
>(malloc(
static_cast<size_t>(n)*size));
525 char *p =
static_cast<char *
>(tab) + offset;
529 memcpy(bp, p, size * dlo_array_size);
530 bp += size * dlo_array_size;
546 if (iot->triggered) {
547 for (
int i = 0; i <
svd.
n; i++) {
552 nwr += SF::root_write<char>(fd, (
char*) buf,
553 static_cast<size_t>(
svd.
size[i]) *
static_cast<size_t>(
svd.
num[i]),
557 svd.
nwr +=
static_cast<long>(nwr);
575 vm[i] = vm[i] + (ion[i] * (-dt));
583 if (flag_send == 1) {
587 for (
int j = 0; j < this->
numSubDt; j++)
589 for (
int i = 0; i < this->
N_IIF; i++)
592 if (!this->
N_Nodes[i])
continue;
594 prepare_error_recovery(
this, i, pIF->
get_tstp().
cnt * this->dt);
606 fprintf(stderr,
"LIMPET compute fail in %s at node %jd (local %jd)! Aborting!\n",
612 }
while (current < this->
N_Nodes[i]);
614 for (
auto& plugin : pIF->
plugins()) {
620 plugin->compute(current, this->
N_Nodes[i], this->
ldata[i]);
623 if (plugin ==
nullptr)
629 fprintf(stderr,
"LIMPET plugin fail in %s at node %jd (local %jd)! Aborting!\n",
635 }
while (current < this->
N_Nodes[i]);
644 #if defined __CUDA__ || defined __HIP__
647 cudaDeviceSynchronize();
648 #elif defined __HIP__
649 hipDeviceSynchronize();
652 fprintf(stderr,
"GPU/CUDA not found");
657 if (flag_receive == 1) {
672 for (
auto& pIF : this->
IIF) {
673 pIF->get_type().destroy_ion_if(pIF);
684 for (
int i = 0; i < pMIIF->
N_IIF; i++) {
692 for (
int j = 0; j < NUM_IMP_DATA_TYPES; j++) {
700 allocate_on_target<GlobalData_t>(pMIIF->
IIF[i]->get_target(),
703 if (pMIIF->
gdata[j] == NULL) {
704 log_msg(pMIIF->
logger, 5,
LOCAL,
"IMP data type %s not supplied for region %d", imp_data_names[j], i);
722 for (
int j = 0; j < NUM_IMP_DATA_TYPES; j++) {
724 if (this->
gdata[j] != NULL) {
732 for (
int i = 0; i < this->
N_IIF; i++) {
741 this->
ldata[i][j][k] = rdata[ip[k]];
757 for (
int i = 0; i < this->
N_IIF; i++) {
758 if (!this->
N_Nodes[i])
continue;
761 if (
is_gpu(this->
IIF[i]->get_target())) {
762 for (
int j = 0; j < NUM_IMP_DATA_TYPES; j++) {
774 for (
int j = 0; j < NUM_IMP_DATA_TYPES; j++) {
775 if (this->
IIF[i]->get_moddat() & imp_data_flag[j]) {
785 for (
int j = 0; j < NUM_IMP_DATA_TYPES; j++)
786 if (this->
gdata[j] != NULL)
792 for (
int j = 0; j < NUM_IMP_DATA_TYPES; j++) {
793 if (pMIIF->
gdata[j] != NULL) {
794 for (
int i = 0; i < pMIIF->
N_IIF; i++)
796 deallocate_on_target<GlobalData_t>(pMIIF->
IIF[i]->get_target(),
799 delete pMIIF->
gdata[j];
816 if (plgstr == NULL) {
817 *out_num_plugins = 0;
823 char *plugspec =
dupstr(plgstr);
825 char *token =
tokstr_r(plugspec,
":", &saveptr);
827 *out_num_plugins = 0;
834 out_plugins.push_back(*type);
836 token =
tokstr_r(NULL,
":", &saveptr);
839 *out_num_plugins = out_plugins.size();
870 if (index(variable,
'.') == NULL) {
874 for (
int ii = 0; ii < NUM_IMP_DATA_TYPES; ii++) {
875 if (strcmp(variable, imp_data_names[ii]) == 0) {
881 log_msg(
logger, 5,
FLUSH,
"Error! No external variable named %s in this build of openCARP.", variable);
886 if (this->
gdata[data_id] == NULL) {
888 "External variable %s is not being used this processor.\n"
889 "Is this really what you meant to do?\n"
890 "Perhaps you don't have the correct Ionic models selected.",
891 imp_data_names[data_id]);
897 for (
size_t i = 0; i < indices.
size(); i++) {
898 raw_data[indices[i]] = values[i];
909 char *my_variable =
dupstr(variable);
910 char *IIF_name =
tokstr_r(my_variable,
".", &saveptr);
911 char *sv_name =
tokstr_r(NULL,
".", &saveptr);
915 log_msg(
logger, 5, 0,
"%s error: %s is not a valid IMP name.", __func__, IIF_name);
922 if (sv_get == NULL) {
923 log_msg(
logger, 5, 0,
"%s error: %s is not a valid state variable for the %s model.",
924 __func__, sv_name, IIF_name);
930 for (
int i_iif = 0; i_iif < this->
N_IIF; i_iif++) {
932 if (this->
IIF[i_iif]->get_type() == *type) {
933 lIIF = this->
IIF[i_iif];
937 for (
auto& plugin : this->
IIF[i_iif]->plugins()) {
938 if (plugin->get_type() == *type) {
949 for (
size_t ii = 0; ii < indices.
size(); ii++) {
958 sv_put(*lIIF, target - this->
NodeLists[i_iif], sv_offset, file_value);
966 MPI_Allreduce(MPI_IN_PLACE, &num_changed, 1, MPI_INT, MPI_SUM, PETSC_COMM_WORLD);
995 long loff = offset[0];
996 for (
int i = 0; i < N; i++)
997 if (offset[i]-loff > bufsize) {
1004 *ranges = (
int *)r.data;
1007 MPI_Bcast(&nitems, 1, MPI_INT, 0, PETSC_COMM_WORLD);
1009 *ranges =
static_cast<int *
>(malloc( (nitems+1)*
sizeof(
int) ));
1010 MPI_Bcast(*ranges, nitems+1, MPI_INT, 0, PETSC_COMM_WORLD);
1053 bool append,
unsigned int revision)
1065 const bool elemwise = this->
gdata[Vm] && this->
gdata[Vm]->
layout == sf_vec::elemwise;
1068 log_msg(
logger, 0, 0,
"Saving state at time %f in file: %s", simtime, fname);
1071 out =
f_open(fname, append ?
"a" :
"w");
1074 fseek(out->fd, 0, SEEK_END);
1077 fwrite(&MIIF_Format,
sizeof(
unsigned int), 1, out->fd);
1078 fwrite(&revision,
sizeof(
unsigned int), 1, out->fd);
1079 time_t tm = time(NULL);
1080 fwrite(&tm,
sizeof(time_t), 1, out->fd);
1081 fwrite(&simtime,
sizeof(
float), 1, out->fd);
1085 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++)
1086 if (this->
gdata[i]) num_gdata++;
1088 fwrite(&num_gdata,
sizeof(
int), 1, out->fd);
1099 FILE* fd = rank == 0 ? out->fd : NULL;
1102 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++) {
1103 if (this->
gdata[i]) {
1107 log_msg(NULL, 0, 0,
"\tDumping %s at %d", imp_data_names[i], ftell(fd) );
1120 outVec->write_binary<
SF_real>(fd);
1132 int* imp_mem =
new int[this->
N_IIF];
1133 size_t *offset = NULL;
1138 log_msg(NULL, 0, 0,
"\tDumping IMP sizes at %d", ftell(fd) );
1142 fwrite(&this->
N_IIF,
sizeof(
int), 1, fd);
1144 for (
int i = 0; i < this->
N_IIF; i++) {
1150 fwrite(&sv_size,
sizeof(
int), 1, fd);
1154 fwrite(&sv_fp,
sizeof(uint64_t), 1, fd);
1155 unsigned long n_plugins = (
unsigned long) imp->
plugins().size();
1156 fwrite(&n_plugins,
sizeof(
int), 1, fd);
1157 imp_mem[i] = sv_size;
1159 for (
auto& plug : imp->
plugins()) {
1162 int plug_size = (int) plug->get_sv_per_node_size();
1163 fwrite(&plug_size,
sizeof(
int), 1, fd);
1164 uint64_t plug_fp = plug->sv_fingerprint();
1165 fwrite(&plug_fp,
sizeof(uint64_t), 1, fd);
1166 imp_mem[i] += plug_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<canon_nbr.
size(); i++) loc2canon[i] = canon_nbr[i];
1192 for(
size_t i=0; i<alg_idx.
size(); i++) loc2canon[i] = canon_nbr[alg_idx[i]];
1199 layout, PETSC_COMM_WORLD);
1207 assert(loc2canon.
size() ==
static_cast<size_t>(this->numNode));
1212 canord[i] = loc2canon[i];
1215 log_msg(NULL, 0, 0,
"\tDumping IMP masks at %d", filepos);
1218 SF::root_write_ordered<global_node_index_t, IIF_Mask_t>(fd, canord,
IIFmask,
numNode, PETSC_COMM_WORLD);
1224 impsize[i] = imp_mem[(
int)
IIFmask[i]];
1228 size_t num_entr =
static_cast<size_t>(
SF::sum(impsize));
1237 for (
int imp_idx = 0; imp_idx < this->
N_IIF; imp_idx++)
1242 std::vector<std::pair<int, int>> main_fields;
1245 std::vector<std::vector<std::pair<int, int>>> plug_fields;
1246 for (
auto& plug : iif->
plugins()) {
1247 plug_fields.emplace_back();
1248 plug->get_sv_layout(plug_fields.back());
1254 char* write = impdata.
data() + impdsp[loc];
1255 auto gather = [&](
char* src, std::size_t sz) { memcpy(write, src, sz); write += sz; };
1258 for (
size_t p = 0; p < plug_fields.size(); p++)
1259 iif->
plugins()[p]->for_each_sv_field(imp_nod_idx, plug_fields[p], gather);
1264 SF::root_write_ordered<global_node_index_t, char>(fd, canord, impsize.data(), impdata.
data(),
1265 numNode, num_entr, PETSC_COMM_WORLD);
1271 double dump_time =
timing(t1, t0);
1300 static char *last_fn = NULL;
1310 const bool elemwise = this->
gdata[Vm] && this->
gdata[Vm]->
layout == sf_vec::elemwise;
1314 if (fname) in =
f_open(fname,
"r");
1317 if (fname)
log_msg(
logger, 5, 0,
"Error: cannot open file: %s\n", fname);
1318 else log_msg(
logger, 5, 0,
"Error: file stream not open yet");
1323 log_msg(
logger, 5, 0,
"%s is not a recognized MIIF dump file", fname);
1334 last_fn = strdup(fname);
1340 unsigned int format, version;
1343 f_read_par(&format,
sizeof(
unsigned int), 1, in);
1344 f_read_par(&version,
sizeof(
unsigned int), 1, in);
1345 f_read_par(&save_date,
sizeof(time_t), 1, in);
1347 log_msg(
logger, 0, 0,
"Restoring time %f from %s (format v%d) generated\n\tby calling "
1348 "program r%d on %s", time, fname, format, version, ctime(&save_date) );
1352 MPI_SUM, PETSC_COMM_WORLD);
1359 savedNum = savedNum32;
1361 if (savedNum != glob_numNode) {
1362 log_msg(
logger, 5, 0,
"expecting %jd nodes but read %jd nodes",
1371 for (
int g = 0; g < num_gdata; g++) {
1374 for (i = 0; i < NUM_IMP_DATA_TYPES; i++) {
1375 if (!strcmp(datatype, imp_data_names[i]) ) {
1376 if (this->
gdata[i]) {
1377 log_msg(
logger, 0, 0,
"\tRestoring global data %s", imp_data_names[i], datatype);
1379 FILE* fd = my_rank == 0 ? in->fd : NULL;
1382 petsc2canon(*this->
gdata[i], fwd);
1384 log_msg(
logger, 0, 0,
"\tGlobal data %s not used", datatype);
1389 if (i == NUM_IMP_DATA_TYPES)
1390 log_msg(
logger, 3, 0,
"\tSaved global data %s not recognized", datatype);
1395 if ( (my_rank == 0) && ((i == NUM_IMP_DATA_TYPES) || !this->
gdata[i]) )
1396 fseek(in->fd,
static_cast<long>(glob_numNode) *
sizeof(
SF_real), SEEK_CUR);
1409 if (
N_IIF != this->N_IIF) {
1410 log_msg(
logger, 5,
ECHO,
"Checkpoint was written with %d ionic region(s), this simulation has %d.",
1411 N_IIF, this->N_IIF);
1417 int *IMPsz =
static_cast<int *
>(malloc(
N_IIF *
sizeof(
int)));
1419 for (
int i = 0; i <
N_IIF; i++) {
1422 if (format >= 3)
f_read_par(&imps[i].fingerprint,
sizeof(uint64_t), 1, in);
1423 f_read_par(&imps[i].nplug,
sizeof(
int), 1, in);
1426 IMPsz[i] = imps[i].
sz;
1429 for (
int j = 0; j < imps[i].
nplug; j++) {
1432 f_read_par(&imps[i].plug[j].sz,
sizeof(
int), 1, in);
1433 if (format >= 3)
f_read_par(&imps[i].plug[j].fingerprint,
sizeof(uint64_t), 1, in);
1434 IMPsz[i] += imps[i].
plug[j].
sz;
1439 for (
int i = 0; i <
N_IIF; i++) {
1440 if (strcmp(imps[i].
name, this->
IIF[i]->get_type().get_name().c_str()) ) {
1441 log_msg(
logger, 5,
ECHO,
"Checkpoint holds ionic model %s for region %d, this simulation uses %s.",
1442 imps[i].
name, i, this->
IIF[i]->get_type().get_name().c_str());
1446 const bool per_node_fmt = format >= 3;
1447 const int exp_sz = per_node_fmt ? (int) this->
IIF[i]->get_sv_per_node_size()
1448 : (int) this->
IIF[i]->get_sv_size();
1449 if (imps[i].sz != exp_sz) {
1450 log_msg(
logger, 5,
ECHO,
"Checkpoint holds %d byte(s) of state for region %d (%s), this simulation needs %d.",
1451 imps[i].sz, i, imps[i].
name, exp_sz);
1457 if (per_node_fmt && imps[i].fingerprint != this->
IIF[i]->sv_fingerprint()) {
1458 log_msg(
logger, 5,
ECHO,
"Checkpoint state-variable layout of region %d (%s) does not match the model in this build.",
1467 const int cur_nplug = (int) this->
IIF[i]->plugins().size();
1468 if (imps[i].nplug != cur_nplug) {
1469 log_msg(
logger, 5,
ECHO,
"Checkpoint holds %d plugin(s) for region %d (%s), this simulation has %d.",
1470 imps[i].nplug, i, imps[i].
name, cur_nplug);
1477 std::vector<bool> matched(cur_nplug,
false);
1480 for (
int j = 0; j < imps[i].
nplug; j++) {
1481 for (
int k = 0; k < cur_nplug; k++) {
1485 const int exp_plug_sz = per_node_fmt ? (int) this->
IIF[i]->plugins()[k]->get_sv_per_node_size()
1486 : (int) this->
IIF[i]->plugins()[k]->get_sv_size();
1487 const bool plug_fp_ok = !per_node_fmt ||
1489 if (!strcmp(imps[i].plug[j].
name, this->
IIF[i]->plugins()[k]->get_type().get_name().c_str()) &&
1490 (imps[i].plug[j].sz == exp_plug_sz) && plug_fp_ok) {
1491 log_msg(
logger, 0, 0,
"Saved IMP region %d plugin %s compatible", i, imps[i].plug[j].
name);
1498 if (!imps[i].plug[j].compatible) {
1499 log_msg(
logger, 5,
ECHO,
"Checkpoint plugin %s of region %d (%s) has no counterpart in this simulation.",
1500 imps[i].plug[j].
name, i, imps[i].
name);
1507 const size_t global_node_count =
static_cast<size_t>(glob_numNode);
1508 IIF_Mask_t *canMask =
static_cast<char *
>(malloc(global_node_count*
sizeof(this->
IIFmask[0]) ));
1512 size_t *offset =
static_cast<size_t *
>(calloc(global_node_count+1,
sizeof(
size_t)));
1513 for (
size_t i = 1; i <= global_node_count; i++)
1514 offset[i] = offset[i-1] + IMPsz[
static_cast<int>(canMask[i-1])];
1522 SVstart = ftell(in->fd);
1526 MPI_Bcast(&SVstart,
sizeof(
long), MPI_BYTE, 0, PETSC_COMM_WORLD);
1536 for(
size_t i=0; i<canon_nbr.
size(); i++) loc2canon[i] = canon_nbr[i];
1543 for(
size_t i=0; i<alg_idx.
size(); i++) loc2canon[i] = canon_nbr[alg_idx[i]];
1548 assert(loc2canon.
size() ==
static_cast<size_t>(this->numNode));
1551 for (
int pid = 0; pid < mpi_size; pid++) {
1552 if (my_rank == pid) {
1556 for (
int i = 0; i <
N_IIF; i++) {
1557 fseek(in->fd, SVstart, SEEK_SET);
1560 canMask, offset, imps+i, loc2canon.
data());
1563 canMask, offset, imps+i, loc2canon.
data());
1568 MPI_Barrier(PETSC_COMM_WORLD);
1580 log_msg(
logger, 5,
ECHO,
"Checkpoint assigns a different ionic region than this simulation does at %jd node(s). "
1581 "The region layout must be identical to restore this checkpoint.",
1586 if ( (my_rank == 0) && (!close) ) {
1591 fseek(in->fd, SVstart+offset[global_node_count], SEEK_SET);
1595 for (
int i = 0; i <
N_IIF; i++)
1599 double restore_time =
timing(t1, t0);
1600 log_msg(
logger, 0, 0,
"State restored from file %s in %.3f seconds.\n", fname, restore_time);
1617 char *reg_name,
char *sv_lst,
char *plg_lst,
1618 char *plg_sv_lst,
double t,
double dump_dt) {
1619 char file[8000], svs[1024], plgs[1024], plgsvs[1024];
1620 char *e, *l, *p, *svnames, *plgnames, *plgsvnames;
1622 strcpy(svs, sv_lst);
1623 strcpy(plgs, plg_lst);
1624 strcpy(plgsvs, plg_sv_lst);
1626 plgnames = &plgs[0];
1627 plgsvnames = &plgsvs[0];
1637 snprintf(file,
sizeof file,
"%s.%s.bin", reg_name, svnames);
1651 snprintf(file,
sizeof file,
"%s_%s.%s.bin", reg_name, plgnames, plgsvnames);
1676 const char *
filename,
const char *regname) {
1678 int n = this->
svd.
n;
1683 for (i = 0; i < IF->
plugins().size(); i++)
1684 if (IF->
plugins()[i]->get_type() == type)
1686 if (i == IF->
plugins().size()) {
1687 log_msg(
logger, 2, 0,
"Warning: IMP %s not found in Region %s\n",
1698 this->
svd.
fn =
static_cast<char **
>(realloc(this->
svd.
fn, this->svd.n*
sizeof(
char *)));
1699 this->
svd.
reg =
static_cast<int *
>(realloc(this->
svd.
reg, this->svd.n*
sizeof(
int)));
1700 this->
svd.
svnames =
static_cast<char **
>(realloc(this->
svd.
svnames, this->svd.n*
sizeof(
char *)));
1703 this->
svd.
offset =
static_cast<int *
>(realloc(this->
svd.
offset, this->svd.n*
sizeof(
int)));
1704 this->
svd.
size =
static_cast<int *
>(realloc(this->
svd.
size, this->svd.n*
sizeof(
int)));
1705 this->
svd.
dlo_vs =
static_cast<int *
>(realloc(this->
svd.
dlo_vs, this->svd.n*
sizeof(
int)));
1706 this->
svd.
dtype =
static_cast<int *
>(realloc(this->
svd.
dtype, this->svd.n*
sizeof(
int)));
1707 this->
svd.
svtab =
static_cast<void **
>(realloc(this->
svd.
svtab, this->svd.n*
sizeof(
void *)));
1708 this->
svd.
svsize =
static_cast<size_t *
>(realloc(this->
svd.
svsize, this->svd.n*
sizeof(
size_t)));
1710 this->
svd.
reg =
static_cast<int *
>(realloc(this->
svd.
reg, this->svd.n*
sizeof(
int)));
1723 this->
svd.
reg[n] = region;
1745 char *svname,
char *regname,
char *
filename) {
1746 int offset, size, dtype, added = 0;
1747 char *svtypename = NULL;
1751 filename_bin = strcat(
filename,
".bin");
1753 assert(type != NULL);
1756 this->
sv_dump_add(region, *type, offset, size, dtype, filename_bin, regname);
1760 log_msg(NULL, 1, 0,
"No state variable added to dump list");
1779 assert(miif->
gdata[Vm] != NULL);
1781 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++) {
1782 for (
int n = 0; n < miif->
N_IIF; n++)
1783 if (
USED_DAT(miif->
IIF[n], imp_data_flag[i]) && (miif->
gdata[i] == NULL)) {
1798 int num_mech_data = 0;
1800 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++) {
1801 if ( (Lambda_DATA_FLAG == i) || (delLambda_DATA_FLAG == i) ||
1802 (Tension_DATA_FLAG == i) || (tension_component_DATA_FLAG == i) ) {
1803 for (
int n = 0; n < this->
N_IIF; n++)
1808 return static_cast<bool>(num_mech_data);
1829 float beta,
int *node,
int numnode) {
1831 if (strstr(species,
"Ca") != NULL) {
1834 }
else if (strstr(species,
"Na") != NULL) {
1836 }
else if (strstr(species,
"Cl") != NULL) {
1838 }
else if (strstr(species,
"K") != NULL) {
1841 log_msg(
logger, 5, 0,
"Unimplemented ion species: %s\n", species);
1847 static int warned = 0;
1852 int my_low_idx = layout[rank], my_high_idx = layout[rank+1];
1854 for (
int i = 0; i < numnode; i++) {
1855 if ((node[i] < my_low_idx) || (node[i] >= my_high_idx))
continue;
1857 for (
int j = 0; j < this->
N_IIF; j++) {
1858 if (this->
NodeLists[j] == NULL)
continue;
1860 if ((node[i] < this->
NodeLists[j][0]) ||
1864 ion_get = this->
IIF[j]->get_type().get_sv_offset(species, &offset, &sz);
1865 if (ion_get == NULL) {
1868 log_msg(
logger, 2, 0,
"Ion species not present in ionic model: %s\n",
1880 delta_conc = charge*g.
sl_i2c/z;
1883 delta_conc = 10*charge*beta/(
FARADAY*z);
1888 ion_put(*this->
IIF[j], k, offset, ion_get(*this->
IIF[j], k, offset)-delta_conc);
1901 for (
int i = 0; i < this->
N_IIF; i++) {
1902 this->
IIF[i]->set_dt((
float) Dt);
1903 this->
IIF[i]->rebuild_lookup_tables();
1905 for (
int j = 0; j < this->
IIF[i]->plugins().size(); j++) {
1906 auto& plugin = this->
IIF[i]->plugins()[j];
1907 plugin->set_dt((
float) Dt);
1908 plugin->rebuild_lookup_tables();
1913 #define MEMFREE(A) free(A)
1925 for (
size_t i = 0; i < m->
IIF.size(); i++) {
1929 Target target = m->
IIF[i]->get_target();
1930 for (
int j = 0; j < NUM_IMP_DATA_TYPES; j++)
1933 deallocate_on_target<GlobalData_t>(target, m->
ldata[i][j]);
1934 deallocate_on_target<GlobalData_t*>(target, m->
ldata[i]);
1939 for (
auto& iif : m->
IIF)
1940 iif->get_type().destroy_ion_if(iif);
1942 for (
int j = 0; j < NUM_IMP_DATA_TYPES; j++) {
1953 static void copy_IIF_configuration_tree(IonIfBase& dst, IonIfBase& src) {
1954 dst.copy_configuration_from(src);
1956 auto& dst_plugins = dst.plugins();
1957 auto& src_plugins = src.plugins();
1958 if (dst_plugins.size() != src_plugins.size())
1959 throw std::logic_error(
"cannot copy IMP configuration between different plugin layouts");
1961 for (
size_t i = 0; i < src_plugins.size(); i++)
1962 copy_IIF_configuration_tree(*dst_plugins[i], *src_plugins[i]);
1965 static void copy_IIF_state_tree(IonIfBase& dst, IonIfBase& src) {
1966 dst.copy_SVs_from(src,
false);
1968 auto& dst_plugins = dst.plugins();
1969 auto& src_plugins = src.plugins();
1970 if (dst_plugins.size() != src_plugins.size())
1971 throw std::logic_error(
"cannot copy IMP state between different plugin layouts");
1973 for (
size_t i = 0; i < src_plugins.size(); i++)
1974 copy_IIF_state_tree(*dst_plugins[i], *src_plugins[i]);
1977 static void share_IIF_lookup_tables_tree(IonIfBase& dst, IonIfBase& src) {
1978 dst.share_lookup_tables_from(src);
1980 auto& dst_plugins = dst.plugins();
1981 auto& src_plugins = src.plugins();
1982 if (dst_plugins.size() != src_plugins.size())
1983 throw std::logic_error(
"cannot share LUTs between different plugin layouts");
1985 for (
size_t i = 0; i < src_plugins.size(); i++)
1986 share_IIF_lookup_tables_tree(*dst_plugins[i], *src_plugins[i]);
1989 static void copy_global_data_values(MULTI_IF& dst, MULTI_IF& src) {
1990 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++) {
1994 throw std::logic_error(
"cannot copy missing IMP global data vector");
1995 *dst.gdata[i] = *src.gdata[i];
1999 static void allocate_doppel_local_data(MULTI_IF& doppel) {
2000 doppel.ldata = allocate_on_target<GlobalData_t**>(
Target::CPU, doppel.N_IIF);
2001 for (
int i = 0; i < doppel.N_IIF; i++) {
2002 Target target = doppel.IIF[i]->get_target();
2003 doppel.ldata[i] = allocate_on_target<GlobalData_t*>(target, NUM_IMP_DATA_TYPES);
2005 for (
int j = 0; j < NUM_IMP_DATA_TYPES; j++)
2006 if ((!doppel.contiguous[i] ||
is_gpu(target)) &&
2007 USED_DAT(doppel.IIF[i], imp_data_flag[j]) && doppel.N_Nodes[i] > 0)
2008 doppel.ldata[i][j] = allocate_on_target<GlobalData_t>(target, doppel.N_Nodes[i]);
2022 copy_global_data_values(*miif_doppel, *orig);
2024 for (
int i = 0; i < orig->
N_IIF; i++)
2025 copy_IIF_state_tree(*miif_doppel->
IIF[i], *orig->
IIF[i]);
2038 *miif_doppel = *orig;
2039 miif_doppel->
doppel =
true;
2040 miif_doppel->
IIF.clear();
2041 miif_doppel->
ldata =
nullptr;
2042 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++)
2043 miif_doppel->
gdata[i] =
nullptr;
2046 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++)
2049 copy_global_data_values(*miif_doppel, *orig);
2051 miif_doppel->
IIF.reserve(orig->
N_IIF);
2052 for (
int i = 0; i < orig->
N_IIF; i++) {
2053 IonIfBase* doppel_iif = orig->
IIF[i]->get_type().make_ion_if(
2054 orig->
IIF[i]->get_target(), orig->
IIF[i]->get_num_node(), orig->
plugtypes[i]);
2055 miif_doppel->
IIF.push_back(doppel_iif);
2058 for (
int i = 0; i < orig->
N_IIF; i++) {
2062 copy_IIF_configuration_tree(*doppel_iif, *orig->
IIF[i]);
2063 share_IIF_lookup_tables_tree(*doppel_iif, *orig->
IIF[i]);
2066 allocate_doppel_local_data(*miif_doppel);
2069 for (
int i = 0; i < orig->
N_IIF; i++)
2070 miif_doppel->
IIF[i]->initialize_state(miif_doppel->
dt, miif_doppel->
ldata[i]);
2080 copy_global_data_values(*miif_doppel, *orig);
2081 for (
int i = 0; i < orig->
N_IIF; i++)
2082 copy_IIF_state_tree(*miif_doppel->
IIF[i], *orig->
IIF[i]);
2109 int imp_data_id = -1;
2111 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++) {
2112 if (strcmp(sv, imp_data_names[i]) == 0) {
2127 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++)
2128 if (localdata && localdata[i])
2129 localdata[i][to] = localdata[i][from];
2133 int sv_list_size = imp.
get_type().get_sv_list(&sv_list);
2135 for (
int i = 0; i < sv_list_size; i++) {
2136 char *sv_name = sv_list[i];
2139 SVgetfcn sv_get = imp.
get_type().get_sv_offset(sv_name, &sv_offset, &sv_size);
2140 if (sv_get == NULL) {
2141 throw std::runtime_error(std::string(__func__) +
" error: " + sv_name +
" is not a valid state variable for the " + imp.
get_type().
get_name() +
" model.");
2146 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)
ltype layout
used vector layout (nodal, algebraic, unset)
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.
void set_parent(IonIfBase *parent)
const IonType & get_type() const
Gets this IMP's model type.
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< IonIfBase * > & plugins()
Returns a vector containing the plugins of this IMP.
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.
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.
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.
@ NBR_ELEM_SUBMESH
Submesh element 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()
Target
enum that represents different targets to run ionic models on.
@ 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.
#define ELEM_PETSC_TO_CANONICAL
Permute algebraic element 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
uint64_t fingerprint
saved SV-layout fingerprint (format >= 3; 0 otherwise)
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