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);
1421 int *IMPsz =
static_cast<int *
>(malloc(
N_IIF *
sizeof(
int)));
1423 for (
int i = 0; i <
N_IIF; i++) {
1426 if (format >= 3)
f_read_par(&imps[i].fingerprint,
sizeof(uint64_t), 1, in);
1427 f_read_par(&imps[i].nplug,
sizeof(
int), 1, in);
1430 IMPsz[i] = imps[i].
sz;
1433 for (
int j = 0; j < imps[i].
nplug; j++) {
1436 f_read_par(&imps[i].plug[j].sz,
sizeof(
int), 1, in);
1437 if (format >= 3)
f_read_par(&imps[i].plug[j].fingerprint,
sizeof(uint64_t), 1, in);
1438 IMPsz[i] += imps[i].
plug[j].
sz;
1443 for (
int i = 0; i <
N_IIF; i++) {
1444 if (i >= this->N_IIF) {
1445 log_msg(NULL, 3, 0,
"Saved IMP region %d out of range", i);
1448 if (strcmp(imps[i].
name, this->
IIF[i]->get_type().get_name().c_str()) ) {
1449 log_msg(NULL, 3, 0,
"Saved IMP region %d ionic model does not match that of IMP region %d", i, i);
1453 const bool per_node_fmt = format >= 3;
1454 const int exp_sz = per_node_fmt ? (int) this->
IIF[i]->get_sv_per_node_size()
1455 : (int) this->
IIF[i]->get_sv_size();
1456 if (imps[i].sz != exp_sz) {
1457 log_msg(NULL, 3, 0,
"Saved IMP region %d size does not match current IMP size", i);
1462 if (per_node_fmt && imps[i].fingerprint != this->
IIF[i]->sv_fingerprint()) {
1463 log_msg(NULL, 3, 0,
"Saved IMP region %d state-variable layout does not match current model", i);
1469 for (
int j = 0; j < imps[i].
nplug; j++)
1470 for (
int k = 0; k < this->
IIF[i]->plugins().size(); k++) {
1471 const int exp_plug_sz = per_node_fmt ? (int) this->
IIF[i]->plugins()[k]->get_sv_per_node_size()
1472 : (int) this->
IIF[i]->plugins()[k]->get_sv_size();
1473 const bool plug_fp_ok = !per_node_fmt ||
1475 if (!strcmp(imps[i].plug[j].
name, this->
IIF[i]->plugins()[k]->get_type().get_name().c_str()) &&
1476 (imps[i].plug[j].sz == exp_plug_sz) && plug_fp_ok) {
1477 log_msg(NULL, 3, 0,
"Saved IMP region %d plugin %s compatible", i, imps[i].plug[j].
name);
1486 const size_t global_node_count =
static_cast<size_t>(glob_numNode);
1487 IIF_Mask_t *canMask =
static_cast<char *
>(malloc(global_node_count*
sizeof(this->
IIFmask[0]) ));
1491 size_t *offset =
static_cast<size_t *
>(calloc(global_node_count+1,
sizeof(
size_t)));
1492 for (
size_t i = 1; i <= global_node_count; i++)
1493 offset[i] = offset[i-1] + IMPsz[
static_cast<int>(canMask[i-1])];
1501 SVstart = ftell(in->fd);
1505 MPI_Bcast(&SVstart,
sizeof(
long), MPI_BYTE, 0, PETSC_COMM_WORLD);
1515 for(
size_t i=0; i<canon_nbr.
size(); i++) loc2canon[i] = canon_nbr[i];
1522 for(
size_t i=0; i<alg_idx.
size(); i++) loc2canon[i] = canon_nbr[alg_idx[i]];
1527 assert(loc2canon.
size() ==
static_cast<size_t>(this->numNode));
1530 for (
int pid = 0; pid < mpi_size; pid++) {
1531 if (my_rank == pid) {
1535 for (
int i = 0; i <
N_IIF; i++) {
1536 fseek(in->fd, SVstart, SEEK_SET);
1539 canMask, offset, imps+i, loc2canon.
data());
1542 canMask, offset, imps+i, loc2canon.
data());
1547 MPI_Barrier(PETSC_COMM_WORLD);
1552 MPI_Reduce(my_rank ? &mismatch : MPI_IN_PLACE, &mismatch, 1,
1553 opencarp::mpi_datatype<global_node_index_t>(), MPI_SUM, 0, PETSC_COMM_WORLD);
1554 if ( (my_rank == 0) && mismatch)
1557 if ( (my_rank == 0) && (!close) ) {
1562 fseek(in->fd, SVstart+offset[global_node_count], SEEK_SET);
1566 for (
int i = 0; i <
N_IIF; i++)
1570 double restore_time =
timing(t1, t0);
1571 log_msg(
logger, 0, 0,
"State restored from file %s in %.3f seconds.\n", fname, restore_time);
1588 char *reg_name,
char *sv_lst,
char *plg_lst,
1589 char *plg_sv_lst,
double t,
double dump_dt) {
1590 char file[8000], svs[1024], plgs[1024], plgsvs[1024];
1591 char *e, *l, *p, *svnames, *plgnames, *plgsvnames;
1593 strcpy(svs, sv_lst);
1594 strcpy(plgs, plg_lst);
1595 strcpy(plgsvs, plg_sv_lst);
1597 plgnames = &plgs[0];
1598 plgsvnames = &plgsvs[0];
1608 snprintf(file,
sizeof file,
"%s.%s.bin", reg_name, svnames);
1622 snprintf(file,
sizeof file,
"%s_%s.%s.bin", reg_name, plgnames, plgsvnames);
1647 const char *
filename,
const char *regname) {
1649 int n = this->
svd.
n;
1654 for (i = 0; i < IF->
plugins().size(); i++)
1655 if (IF->
plugins()[i]->get_type() == type)
1657 if (i == IF->
plugins().size()) {
1658 log_msg(
logger, 2, 0,
"Warning: IMP %s not found in Region %s\n",
1669 this->
svd.
fn =
static_cast<char **
>(realloc(this->
svd.
fn, this->svd.n*
sizeof(
char *)));
1670 this->
svd.
reg =
static_cast<int *
>(realloc(this->
svd.
reg, this->svd.n*
sizeof(
int)));
1671 this->
svd.
svnames =
static_cast<char **
>(realloc(this->
svd.
svnames, this->svd.n*
sizeof(
char *)));
1674 this->
svd.
offset =
static_cast<int *
>(realloc(this->
svd.
offset, this->svd.n*
sizeof(
int)));
1675 this->
svd.
size =
static_cast<int *
>(realloc(this->
svd.
size, this->svd.n*
sizeof(
int)));
1676 this->
svd.
dlo_vs =
static_cast<int *
>(realloc(this->
svd.
dlo_vs, this->svd.n*
sizeof(
int)));
1677 this->
svd.
dtype =
static_cast<int *
>(realloc(this->
svd.
dtype, this->svd.n*
sizeof(
int)));
1678 this->
svd.
svtab =
static_cast<void **
>(realloc(this->
svd.
svtab, this->svd.n*
sizeof(
void *)));
1679 this->
svd.
svsize =
static_cast<size_t *
>(realloc(this->
svd.
svsize, this->svd.n*
sizeof(
size_t)));
1681 this->
svd.
reg =
static_cast<int *
>(realloc(this->
svd.
reg, this->svd.n*
sizeof(
int)));
1694 this->
svd.
reg[n] = region;
1716 char *svname,
char *regname,
char *
filename) {
1717 int offset, size, dtype, added = 0;
1718 char *svtypename = NULL;
1722 filename_bin = strcat(
filename,
".bin");
1724 assert(type != NULL);
1727 this->
sv_dump_add(region, *type, offset, size, dtype, filename_bin, regname);
1731 log_msg(NULL, 1, 0,
"No state variable added to dump list");
1750 assert(miif->
gdata[Vm] != NULL);
1752 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++) {
1753 for (
int n = 0; n < miif->
N_IIF; n++)
1754 if (
USED_DAT(miif->
IIF[n], imp_data_flag[i]) && (miif->
gdata[i] == NULL)) {
1769 int num_mech_data = 0;
1771 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++) {
1772 if ( (Lambda_DATA_FLAG == i) || (delLambda_DATA_FLAG == i) ||
1773 (Tension_DATA_FLAG == i) || (tension_component_DATA_FLAG == i) ) {
1774 for (
int n = 0; n < this->
N_IIF; n++)
1779 return static_cast<bool>(num_mech_data);
1800 float beta,
int *node,
int numnode) {
1802 if (strstr(species,
"Ca") != NULL) {
1805 }
else if (strstr(species,
"Na") != NULL) {
1807 }
else if (strstr(species,
"Cl") != NULL) {
1809 }
else if (strstr(species,
"K") != NULL) {
1812 log_msg(
logger, 5, 0,
"Unimplemented ion species: %s\n", species);
1818 static int warned = 0;
1823 int my_low_idx = layout[rank], my_high_idx = layout[rank+1];
1825 for (
int i = 0; i < numnode; i++) {
1826 if ((node[i] < my_low_idx) || (node[i] >= my_high_idx))
continue;
1828 for (
int j = 0; j < this->
N_IIF; j++) {
1829 if (this->
NodeLists[j] == NULL)
continue;
1831 if ((node[i] < this->
NodeLists[j][0]) ||
1835 ion_get = this->
IIF[j]->get_type().get_sv_offset(species, &offset, &sz);
1836 if (ion_get == NULL) {
1839 log_msg(
logger, 2, 0,
"Ion species not present in ionic model: %s\n",
1851 delta_conc = charge*g.
sl_i2c/z;
1854 delta_conc = 10*charge*beta/(
FARADAY*z);
1859 ion_put(*this->
IIF[j], k, offset, ion_get(*this->
IIF[j], k, offset)-delta_conc);
1872 for (
int i = 0; i < this->
N_IIF; i++) {
1873 this->
IIF[i]->destroy_luts();
1874 this->
IIF[i]->set_dt((
float) Dt);
1875 this->
iontypes[i].get().construct_tables(*this->
IIF[i]);
1877 for (
int j = 0; j < this->
IIF[i]->plugins().size(); j++) {
1878 auto& plugin = this->
IIF[i]->plugins()[j];
1879 plugin->destroy_luts();
1880 plugin->set_dt((
float) Dt);
1881 this->
plugtypes[i][j].get().construct_tables(*plugin);
1886 #define MEMFREE(A) free(A)
1897 for (
int i = 0; i < m->
N_IIF; i++) {
1898 m->
IIF[i]->get_type().destroy_ion_if(m->
IIF[i]);
1901 for (
int j = 0; j < NUM_IMP_DATA_TYPES; j++) {
1922 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++)
1926 for (
int i = 0; i < orig->
N_IIF; i++) {
1927 miif_doppel->
IIF[i]->copy_SVs_from(*orig->
IIF[i],
false);
1929 for (
int j = 0; j < orig->
IIF[i]->plugins().size(); j++)
1930 miif_doppel->
IIF[i]->plugins()[j]->copy_SVs_from(*orig->
IIF[i]->plugins()[j],
false);
1947 *miif_doppel = *orig;
1948 miif_doppel->
doppel =
true;
1951 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++)
1956 miif_doppel->
IIF = {};
1958 for (
int i = 0; i < orig->
N_IIF; i++) {
1960 miif_doppel->
IIF.push_back(orig->
IIF[i]->get_type().make_ion_if(orig->
IIF[i]->get_target(),
1962 miif_doppel->
IIF[i]->copy_SVs_from(*orig->
IIF[i],
true);
1963 miif_doppel->
IIF[i]->copy_plugins_from(*orig->
IIF[i]);
1986 int imp_data_id = -1;
1988 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++) {
1989 if (strcmp(sv, imp_data_names[i]) == 0) {
2004 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++)
2005 if (localdata && localdata[i])
2006 localdata[i][to] = localdata[i][from];
2010 int sv_list_size = imp.
get_type().get_sv_list(&sv_list);
2012 for (
int i = 0; i < sv_list_size; i++) {
2013 char *sv_name = sv_list[i];
2016 SVgetfcn sv_get = imp.
get_type().get_sv_offset(sv_name, &sv_offset, &sv_size);
2017 if (sv_get == NULL) {
2018 throw std::runtime_error(std::string(__func__) +
" error: " + sv_name +
" is not a valid state variable for the " + imp.
get_type().
get_name() +
" model.");
2023 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