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
422 std::vector<IonIfBase*>& IIF = MIIF->
IIF;
437 fprintf(fs,
"%4.10f\t", time);
438 if (IIF[ctrace->
region]->get_type().has_trace()) {
442 for (
auto& plugin : IIF[ctrace->
region]->plugins()) {
443 if (plugin->get_type().has_trace()) {
445 plugin->get_type().trace(
453 fprintf(ctrace->
file->
fd,
"%s", trace_buf);
495 std::vector<IonIfBase*>& pIF = this->
IIF;
496 for (
auto& IF : pIF) {
497 int ndmps = IF->dump_luts(zipped);
498 if (ndmps < IF->tables().size()) {
499 log_msg(
logger, 4, 0,
"LUT dump error %s: only %d out of %d LUTs dumped.\n",
500 IF->get_type().get_name().c_str(), ndmps, IF->tables().size());
502 for (
auto& plugin : IF->plugins()) {
503 ndmps = plugin->dump_luts(zipped);
504 if (ndmps < plugin->tables().size()) {
505 log_msg(
logger, 4, 0,
"LUT dump error %s: only %d out of %d LUTs dumped.\n",
506 plugin->get_type().get_name().c_str(), ndmps, IF->tables().size());
520 for (
int i = 0; i <
svd.
n; i++)
538 char *buf =
static_cast<char *
>(malloc(
static_cast<size_t>(n)*size));
540 char *p =
static_cast<char *
>(tab) + offset;
544 memcpy(bp, p, size * dlo_array_size);
545 bp += size * dlo_array_size;
561 if (iot->triggered) {
562 for (
int i = 0; i <
svd.
n; i++) {
567 nwr += SF::root_write<char>(fd, (
char*) buf,
568 static_cast<size_t>(
svd.
size[i]) *
static_cast<size_t>(
svd.
num[i]),
572 svd.
nwr +=
static_cast<long>(nwr);
590 vm[i] = vm[i] + (ion[i] * (-dt));
598 if (flag_send == 1) {
602 for (
int j = 0; j < this->
numSubDt; j++)
604 for (
int i = 0; i < this->
N_IIF; i++)
607 if (!this->
N_Nodes[i])
continue;
609 prepare_error_recovery(
this, i, pIF->
get_tstp().
cnt * this->dt);
621 fprintf(stderr,
"LIMPET compute fail in %s at node %jd (local %jd)! Aborting!\n",
627 }
while (current < this->
N_Nodes[i]);
629 for (
auto& plugin : pIF->
plugins()) {
635 plugin->compute(current, this->
N_Nodes[i], this->
ldata[i]);
638 if (plugin ==
nullptr)
644 fprintf(stderr,
"LIMPET plugin fail in %s at node %jd (local %jd)! Aborting!\n",
650 }
while (current < this->
N_Nodes[i]);
659 #if defined __CUDA__ || defined __HIP__
662 cudaDeviceSynchronize();
663 #elif defined __HIP__
664 hipDeviceSynchronize();
667 fprintf(stderr,
"GPU/CUDA not found");
672 if (flag_receive == 1) {
687 for (
auto& pIF : this->
IIF) {
688 pIF->get_type().destroy_ion_if(pIF);
699 for (
int i = 0; i < pMIIF->
N_IIF; i++) {
707 for (
int j = 0; j < NUM_IMP_DATA_TYPES; j++) {
715 allocate_on_target<GlobalData_t>(pMIIF->
IIF[i]->get_target(),
718 if (pMIIF->
gdata[j] == NULL) {
719 log_msg(pMIIF->
logger, 5,
LOCAL,
"IMP data type %s not supplied for region %d", imp_data_names[j], i);
737 for (
int j = 0; j < NUM_IMP_DATA_TYPES; j++) {
739 if (this->
gdata[j] != NULL) {
747 for (
int i = 0; i < this->
N_IIF; i++) {
756 this->
ldata[i][j][k] = rdata[ip[k]];
772 for (
int i = 0; i < this->
N_IIF; i++) {
773 if (!this->
N_Nodes[i])
continue;
776 if (
is_gpu(this->
IIF[i]->get_target())) {
777 for (
int j = 0; j < NUM_IMP_DATA_TYPES; j++) {
789 for (
int j = 0; j < NUM_IMP_DATA_TYPES; j++) {
790 if (this->
IIF[i]->get_moddat() & imp_data_flag[j]) {
800 for (
int j = 0; j < NUM_IMP_DATA_TYPES; j++)
801 if (this->
gdata[j] != NULL)
807 for (
int j = 0; j < NUM_IMP_DATA_TYPES; j++) {
808 if (pMIIF->
gdata[j] != NULL) {
809 for (
int i = 0; i < pMIIF->
N_IIF; i++)
811 deallocate_on_target<GlobalData_t>(pMIIF->
IIF[i]->get_target(),
814 delete pMIIF->
gdata[j];
831 if (plgstr == NULL) {
832 *out_num_plugins = 0;
838 char *plugspec =
dupstr(plgstr);
840 char *token =
tokstr_r(plugspec,
":", &saveptr);
842 *out_num_plugins = 0;
849 out_plugins.push_back(*type);
851 token =
tokstr_r(NULL,
":", &saveptr);
854 *out_num_plugins = out_plugins.size();
885 if (index(variable,
'.') == NULL) {
889 for (
int ii = 0; ii < NUM_IMP_DATA_TYPES; ii++) {
890 if (strcmp(variable, imp_data_names[ii]) == 0) {
896 log_msg(
logger, 5,
FLUSH,
"Error! No external variable named %s in this build of openCARP.", variable);
901 if (this->
gdata[data_id] == NULL) {
903 "External variable %s is not being used this processor.\n"
904 "Is this really what you meant to do?\n"
905 "Perhaps you don't have the correct Ionic models selected.",
906 imp_data_names[data_id]);
912 for (
size_t i = 0; i < indices.
size(); i++) {
913 raw_data[indices[i]] = values[i];
924 char *my_variable =
dupstr(variable);
925 char *IIF_name =
tokstr_r(my_variable,
".", &saveptr);
926 char *sv_name =
tokstr_r(NULL,
".", &saveptr);
930 log_msg(
logger, 5, 0,
"%s error: %s is not a valid IMP name.", __func__, IIF_name);
937 if (sv_get == NULL) {
938 log_msg(
logger, 5, 0,
"%s error: %s is not a valid state variable for the %s model.",
939 __func__, sv_name, IIF_name);
945 for (
int i_iif = 0; i_iif < this->
N_IIF; i_iif++) {
947 if (this->
IIF[i_iif]->get_type() == *type) {
948 lIIF = this->
IIF[i_iif];
952 for (
auto& plugin : this->
IIF[i_iif]->plugins()) {
953 if (plugin->get_type() == *type) {
964 for (
size_t ii = 0; ii < indices.
size(); ii++) {
973 sv_put(*lIIF, target - this->
NodeLists[i_iif], sv_offset, file_value);
981 MPI_Allreduce(MPI_IN_PLACE, &num_changed, 1, MPI_INT, MPI_SUM, PETSC_COMM_WORLD);
1010 long loff = offset[0];
1011 for (
int i = 0; i < N; i++)
1012 if (offset[i]-loff > bufsize) {
1019 *ranges = (
int *)r.data;
1022 MPI_Bcast(&nitems, 1, MPI_INT, 0, PETSC_COMM_WORLD);
1024 *ranges =
static_cast<int *
>(malloc( (nitems+1)*
sizeof(
int) ));
1025 MPI_Bcast(*ranges, nitems+1, MPI_INT, 0, PETSC_COMM_WORLD);
1068 bool append,
unsigned int revision)
1080 const bool elemwise = this->
gdata[Vm] && this->
gdata[Vm]->
layout == sf_vec::elemwise;
1083 log_msg(
logger, 0, 0,
"Saving state at time %f in file: %s", simtime, fname);
1086 out =
f_open(fname, append ?
"a" :
"w");
1089 fseek(out->fd, 0, SEEK_END);
1092 fwrite(&MIIF_Format,
sizeof(
unsigned int), 1, out->fd);
1093 fwrite(&revision,
sizeof(
unsigned int), 1, out->fd);
1094 time_t tm = time(NULL);
1095 fwrite(&tm,
sizeof(time_t), 1, out->fd);
1096 fwrite(&simtime,
sizeof(
float), 1, out->fd);
1100 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++)
1101 if (this->
gdata[i]) num_gdata++;
1103 fwrite(&num_gdata,
sizeof(
int), 1, out->fd);
1114 FILE* fd = rank == 0 ? out->fd : NULL;
1117 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++) {
1118 if (this->
gdata[i]) {
1122 log_msg(NULL, 0, 0,
"\tDumping %s at %d", imp_data_names[i], ftell(fd) );
1135 outVec->write_binary<
SF_real>(fd);
1147 int* imp_mem =
new int[this->
N_IIF];
1148 size_t *offset = NULL;
1153 log_msg(NULL, 0, 0,
"\tDumping IMP sizes at %d", ftell(fd) );
1157 fwrite(&this->
N_IIF,
sizeof(
int), 1, fd);
1159 for (
int i = 0; i < this->
N_IIF; i++) {
1165 fwrite(&sv_size,
sizeof(
int), 1, fd);
1169 fwrite(&sv_fp,
sizeof(uint64_t), 1, fd);
1170 unsigned long n_plugins = (
unsigned long) imp->
plugins().size();
1171 fwrite(&n_plugins,
sizeof(
int), 1, fd);
1172 imp_mem[i] = sv_size;
1174 for (
auto& plug : imp->
plugins()) {
1177 int plug_size = (int) plug->get_sv_per_node_size();
1178 fwrite(&plug_size,
sizeof(
int), 1, fd);
1179 uint64_t plug_fp = plug->sv_fingerprint();
1180 fwrite(&plug_fp,
sizeof(uint64_t), 1, fd);
1181 imp_mem[i] += plug_size;
1184 filepos = ftell(fd);
1187 MPI_Bcast(imp_mem, this->
N_IIF, MPI_INT, 0, PETSC_COMM_WORLD);
1200 for(
size_t i=0; i<canon_nbr.
size(); i++) loc2canon[i] = canon_nbr[i];
1207 for(
size_t i=0; i<alg_idx.
size(); i++) loc2canon[i] = canon_nbr[alg_idx[i]];
1214 layout, PETSC_COMM_WORLD);
1222 assert(loc2canon.
size() ==
static_cast<size_t>(this->numNode));
1227 canord[i] = loc2canon[i];
1230 log_msg(NULL, 0, 0,
"\tDumping IMP masks at %d", filepos);
1233 SF::root_write_ordered<global_node_index_t, IIF_Mask_t>(fd, canord,
IIFmask,
numNode, PETSC_COMM_WORLD);
1239 impsize[i] = imp_mem[(
int)
IIFmask[i]];
1243 size_t num_entr =
static_cast<size_t>(
SF::sum(impsize));
1252 for (
int imp_idx = 0; imp_idx < this->
N_IIF; imp_idx++)
1257 std::vector<std::pair<int, int>> main_fields;
1260 std::vector<std::vector<std::pair<int, int>>> plug_fields;
1261 for (
auto& plug : iif->
plugins()) {
1262 plug_fields.emplace_back();
1263 plug->get_sv_layout(plug_fields.back());
1269 char* write = impdata.
data() + impdsp[loc];
1270 auto gather = [&](
char* src, std::size_t sz) { memcpy(write, src, sz); write += sz; };
1273 for (
size_t p = 0; p < plug_fields.size(); p++)
1274 iif->
plugins()[p]->for_each_sv_field(imp_nod_idx, plug_fields[p], gather);
1279 SF::root_write_ordered<global_node_index_t, char>(fd, canord, impsize.data(), impdata.
data(),
1280 numNode, num_entr, PETSC_COMM_WORLD);
1286 double dump_time =
timing(t1, t0);
1315 static char *last_fn = NULL;
1325 const bool elemwise = this->
gdata[Vm] && this->
gdata[Vm]->
layout == sf_vec::elemwise;
1329 if (fname) in =
f_open(fname,
"r");
1332 if (fname)
log_msg(
logger, 5, 0,
"Error: cannot open file: %s\n", fname);
1333 else log_msg(
logger, 5, 0,
"Error: file stream not open yet");
1338 log_msg(
logger, 5, 0,
"%s is not a recognized MIIF dump file", fname);
1349 last_fn = strdup(fname);
1355 unsigned int format, version;
1358 f_read_par(&format,
sizeof(
unsigned int), 1, in);
1359 f_read_par(&version,
sizeof(
unsigned int), 1, in);
1360 f_read_par(&save_date,
sizeof(time_t), 1, in);
1362 log_msg(
logger, 0, 0,
"Restoring time %f from %s (format v%d) generated\n\tby calling "
1363 "program r%d on %s", time, fname, format, version, ctime(&save_date) );
1367 MPI_SUM, PETSC_COMM_WORLD);
1374 savedNum = savedNum32;
1376 if (savedNum != glob_numNode) {
1377 log_msg(
logger, 5, 0,
"expecting %jd nodes but read %jd nodes",
1386 for (
int g = 0; g < num_gdata; g++) {
1389 for (i = 0; i < NUM_IMP_DATA_TYPES; i++) {
1390 if (!strcmp(datatype, imp_data_names[i]) ) {
1391 if (this->
gdata[i]) {
1392 log_msg(
logger, 0, 0,
"\tRestoring global data %s", imp_data_names[i], datatype);
1394 FILE* fd = my_rank == 0 ? in->fd : NULL;
1397 petsc2canon(*this->
gdata[i], fwd);
1399 log_msg(
logger, 0, 0,
"\tGlobal data %s not used", datatype);
1404 if (i == NUM_IMP_DATA_TYPES)
1405 log_msg(
logger, 3, 0,
"\tSaved global data %s not recognized", datatype);
1410 if ( (my_rank == 0) && ((i == NUM_IMP_DATA_TYPES) || !this->
gdata[i]) )
1411 fseek(in->fd,
static_cast<long>(glob_numNode) *
sizeof(
SF_real), SEEK_CUR);
1424 if (
N_IIF != this->N_IIF) {
1425 log_msg(
logger, 5,
ECHO,
"Checkpoint was written with %d ionic region(s), this simulation has %d.",
1426 N_IIF, this->N_IIF);
1432 int *IMPsz =
static_cast<int *
>(malloc(
N_IIF *
sizeof(
int)));
1434 for (
int i = 0; i <
N_IIF; i++) {
1437 if (format >= 3)
f_read_par(&imps[i].fingerprint,
sizeof(uint64_t), 1, in);
1438 f_read_par(&imps[i].nplug,
sizeof(
int), 1, in);
1441 IMPsz[i] = imps[i].
sz;
1444 for (
int j = 0; j < imps[i].
nplug; j++) {
1447 f_read_par(&imps[i].plug[j].sz,
sizeof(
int), 1, in);
1448 if (format >= 3)
f_read_par(&imps[i].plug[j].fingerprint,
sizeof(uint64_t), 1, in);
1449 IMPsz[i] += imps[i].
plug[j].
sz;
1454 for (
int i = 0; i <
N_IIF; i++) {
1455 if (strcmp(imps[i].
name, this->
IIF[i]->get_type().get_name().c_str()) ) {
1456 log_msg(
logger, 5,
ECHO,
"Checkpoint holds ionic model %s for region %d, this simulation uses %s.",
1457 imps[i].
name, i, this->
IIF[i]->get_type().get_name().c_str());
1461 const bool per_node_fmt = format >= 3;
1462 const int exp_sz = per_node_fmt ? (int) this->
IIF[i]->get_sv_per_node_size()
1463 : (int) this->
IIF[i]->get_sv_size();
1464 if (imps[i].sz != exp_sz) {
1465 log_msg(
logger, 5,
ECHO,
"Checkpoint holds %d byte(s) of state for region %d (%s), this simulation needs %d.",
1466 imps[i].sz, i, imps[i].
name, exp_sz);
1472 if (per_node_fmt && imps[i].fingerprint != this->
IIF[i]->sv_fingerprint()) {
1473 log_msg(
logger, 5,
ECHO,
"Checkpoint state-variable layout of region %d (%s) does not match the model in this build.",
1482 const int cur_nplug = (int) this->
IIF[i]->plugins().size();
1483 if (imps[i].nplug != cur_nplug) {
1484 log_msg(
logger, 5,
ECHO,
"Checkpoint holds %d plugin(s) for region %d (%s), this simulation has %d.",
1485 imps[i].nplug, i, imps[i].
name, cur_nplug);
1492 std::vector<bool> matched(cur_nplug,
false);
1495 for (
int j = 0; j < imps[i].
nplug; j++) {
1496 for (
int k = 0; k < cur_nplug; k++) {
1500 const int exp_plug_sz = per_node_fmt ? (int) this->
IIF[i]->plugins()[k]->get_sv_per_node_size()
1501 : (int) this->
IIF[i]->plugins()[k]->get_sv_size();
1502 const bool plug_fp_ok = !per_node_fmt ||
1504 if (!strcmp(imps[i].plug[j].
name, this->
IIF[i]->plugins()[k]->get_type().get_name().c_str()) &&
1505 (imps[i].plug[j].sz == exp_plug_sz) && plug_fp_ok) {
1506 log_msg(
logger, 0, 0,
"Saved IMP region %d plugin %s compatible", i, imps[i].plug[j].
name);
1513 if (!imps[i].plug[j].compatible) {
1514 log_msg(
logger, 5,
ECHO,
"Checkpoint plugin %s of region %d (%s) has no counterpart in this simulation.",
1515 imps[i].plug[j].
name, i, imps[i].
name);
1522 const size_t global_node_count =
static_cast<size_t>(glob_numNode);
1523 IIF_Mask_t *canMask =
static_cast<char *
>(malloc(global_node_count*
sizeof(this->
IIFmask[0]) ));
1527 size_t *offset =
static_cast<size_t *
>(calloc(global_node_count+1,
sizeof(
size_t)));
1528 for (
size_t i = 1; i <= global_node_count; i++)
1529 offset[i] = offset[i-1] + IMPsz[
static_cast<int>(canMask[i-1])];
1537 SVstart = ftell(in->fd);
1541 MPI_Bcast(&SVstart,
sizeof(
long), MPI_BYTE, 0, PETSC_COMM_WORLD);
1551 for(
size_t i=0; i<canon_nbr.
size(); i++) loc2canon[i] = canon_nbr[i];
1558 for(
size_t i=0; i<alg_idx.
size(); i++) loc2canon[i] = canon_nbr[alg_idx[i]];
1563 assert(loc2canon.
size() ==
static_cast<size_t>(this->numNode));
1566 for (
int pid = 0; pid < mpi_size; pid++) {
1567 if (my_rank == pid) {
1571 for (
int i = 0; i <
N_IIF; i++) {
1572 fseek(in->fd, SVstart, SEEK_SET);
1575 canMask, offset, imps+i, loc2canon.
data());
1578 canMask, offset, imps+i, loc2canon.
data());
1583 MPI_Barrier(PETSC_COMM_WORLD);
1595 log_msg(
logger, 5,
ECHO,
"Checkpoint assigns a different ionic region than this simulation does at %jd node(s). "
1596 "The region layout must be identical to restore this checkpoint.",
1601 if ( (my_rank == 0) && (!close) ) {
1606 fseek(in->fd, SVstart+offset[global_node_count], SEEK_SET);
1610 for (
int i = 0; i <
N_IIF; i++)
1614 double restore_time =
timing(t1, t0);
1615 log_msg(
logger, 0, 0,
"State restored from file %s in %.3f seconds.\n", fname, restore_time);
1632 char *reg_name,
char *sv_lst,
char *plg_lst,
1633 char *plg_sv_lst,
double t,
double dump_dt) {
1634 char file[8000], svs[1024], plgs[1024], plgsvs[1024];
1635 char *e, *l, *p, *svnames, *plgnames, *plgsvnames;
1637 strcpy(svs, sv_lst);
1638 strcpy(plgs, plg_lst);
1639 strcpy(plgsvs, plg_sv_lst);
1641 plgnames = &plgs[0];
1642 plgsvnames = &plgsvs[0];
1652 snprintf(file,
sizeof file,
"%s.%s.bin", reg_name, svnames);
1666 snprintf(file,
sizeof file,
"%s_%s.%s.bin", reg_name, plgnames, plgsvnames);
1691 const char *
filename,
const char *regname) {
1693 int n = this->
svd.
n;
1698 for (i = 0; i < IF->
plugins().size(); i++)
1699 if (IF->
plugins()[i]->get_type() == type)
1701 if (i == IF->
plugins().size()) {
1702 log_msg(
logger, 2, 0,
"Warning: IMP %s not found in Region %s\n",
1713 this->
svd.
fn =
static_cast<char **
>(realloc(this->
svd.
fn, this->svd.n*
sizeof(
char *)));
1714 this->
svd.
reg =
static_cast<int *
>(realloc(this->
svd.
reg, this->svd.n*
sizeof(
int)));
1715 this->
svd.
svnames =
static_cast<char **
>(realloc(this->
svd.
svnames, this->svd.n*
sizeof(
char *)));
1718 this->
svd.
offset =
static_cast<int *
>(realloc(this->
svd.
offset, this->svd.n*
sizeof(
int)));
1719 this->
svd.
size =
static_cast<int *
>(realloc(this->
svd.
size, this->svd.n*
sizeof(
int)));
1720 this->
svd.
dlo_vs =
static_cast<int *
>(realloc(this->
svd.
dlo_vs, this->svd.n*
sizeof(
int)));
1721 this->
svd.
dtype =
static_cast<int *
>(realloc(this->
svd.
dtype, this->svd.n*
sizeof(
int)));
1722 this->
svd.
svtab =
static_cast<void **
>(realloc(this->
svd.
svtab, this->svd.n*
sizeof(
void *)));
1723 this->
svd.
svsize =
static_cast<size_t *
>(realloc(this->
svd.
svsize, this->svd.n*
sizeof(
size_t)));
1725 this->
svd.
reg =
static_cast<int *
>(realloc(this->
svd.
reg, this->svd.n*
sizeof(
int)));
1738 this->
svd.
reg[n] = region;
1760 char *svname,
char *regname,
char *
filename) {
1761 int offset, size, dtype, added = 0;
1762 char *svtypename = NULL;
1766 filename_bin = strcat(
filename,
".bin");
1768 assert(type != NULL);
1771 this->
sv_dump_add(region, *type, offset, size, dtype, filename_bin, regname);
1775 log_msg(NULL, 1, 0,
"No state variable added to dump list");
1794 assert(miif->
gdata[Vm] != NULL);
1796 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++) {
1797 for (
int n = 0; n < miif->
N_IIF; n++)
1798 if (
USED_DAT(miif->
IIF[n], imp_data_flag[i]) && (miif->
gdata[i] == NULL)) {
1813 int num_mech_data = 0;
1815 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++) {
1816 if ( (Lambda_DATA_FLAG == i) || (delLambda_DATA_FLAG == i) ||
1817 (Tension_DATA_FLAG == i) || (tension_component_DATA_FLAG == i) ) {
1818 for (
int n = 0; n < this->
N_IIF; n++)
1823 return static_cast<bool>(num_mech_data);
1844 float beta,
int *node,
int numnode) {
1846 if (strstr(species,
"Ca") != NULL) {
1849 }
else if (strstr(species,
"Na") != NULL) {
1851 }
else if (strstr(species,
"Cl") != NULL) {
1853 }
else if (strstr(species,
"K") != NULL) {
1856 log_msg(
logger, 5, 0,
"Unimplemented ion species: %s\n", species);
1862 static int warned = 0;
1867 int my_low_idx = layout[rank], my_high_idx = layout[rank+1];
1869 for (
int i = 0; i < numnode; i++) {
1870 if ((node[i] < my_low_idx) || (node[i] >= my_high_idx))
continue;
1872 for (
int j = 0; j < this->
N_IIF; j++) {
1873 if (this->
NodeLists[j] == NULL)
continue;
1875 if ((node[i] < this->
NodeLists[j][0]) ||
1879 ion_get = this->
IIF[j]->get_type().get_sv_offset(species, &offset, &sz);
1880 if (ion_get == NULL) {
1883 log_msg(
logger, 2, 0,
"Ion species not present in ionic model: %s\n",
1895 delta_conc = charge*g.
sl_i2c/z;
1898 delta_conc = 10*charge*beta/(
FARADAY*z);
1903 ion_put(*this->
IIF[j], k, offset, ion_get(*this->
IIF[j], k, offset)-delta_conc);
1916 for (
int i = 0; i < this->
N_IIF; i++) {
1917 this->
IIF[i]->destroy_luts();
1918 this->
IIF[i]->set_dt((
float) Dt);
1919 this->
iontypes[i].get().construct_tables(*this->
IIF[i]);
1921 for (
int j = 0; j < this->
IIF[i]->plugins().size(); j++) {
1922 auto& plugin = this->
IIF[i]->plugins()[j];
1923 plugin->destroy_luts();
1924 plugin->set_dt((
float) Dt);
1925 this->
plugtypes[i][j].get().construct_tables(*plugin);
1930 #define MEMFREE(A) free(A)
1941 for (
int i = 0; i < m->
N_IIF; i++) {
1942 m->
IIF[i]->get_type().destroy_ion_if(m->
IIF[i]);
1945 for (
int j = 0; j < NUM_IMP_DATA_TYPES; j++) {
1966 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++)
1970 for (
int i = 0; i < orig->
N_IIF; i++) {
1971 miif_doppel->
IIF[i]->copy_SVs_from(*orig->
IIF[i],
false);
1973 for (
int j = 0; j < orig->
IIF[i]->plugins().size(); j++)
1974 miif_doppel->
IIF[i]->plugins()[j]->copy_SVs_from(*orig->
IIF[i]->plugins()[j],
false);
1991 *miif_doppel = *orig;
1992 miif_doppel->
doppel =
true;
1995 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++)
2000 miif_doppel->
IIF = {};
2002 for (
int i = 0; i < orig->
N_IIF; i++) {
2004 miif_doppel->
IIF.push_back(orig->
IIF[i]->get_type().make_ion_if(orig->
IIF[i]->get_target(),
2006 miif_doppel->
IIF[i]->copy_SVs_from(*orig->
IIF[i],
true);
2007 miif_doppel->
IIF[i]->copy_plugins_from(*orig->
IIF[i]);
2030 int imp_data_id = -1;
2032 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++) {
2033 if (strcmp(sv, imp_data_names[i]) == 0) {
2048 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++)
2049 if (localdata && localdata[i])
2050 localdata[i][to] = localdata[i][from];
2054 int sv_list_size = imp.
get_type().get_sv_list(&sv_list);
2056 for (
int i = 0; i < sv_list_size; i++) {
2057 char *sv_name = sv_list[i];
2060 SVgetfcn sv_get = imp.
get_type().get_sv_offset(sv_name, &sv_offset, &sv_size);
2061 if (sv_get == NULL) {
2062 throw std::runtime_error(std::string(__func__) +
" error: " + sv_name +
" is not a valid state variable for the " + imp.
get_type().
get_name() +
" model.");
2067 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.
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()
@ 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