61 #include <cuda_runtime.h>
63 #if defined HAS_ROCM_MODEL && defined __HIP__
64 #include <hip/hip_runtime.h>
68 #include "petsc_utils.h"
72 using ::opencarp::base_timer;
83 using ::opencarp::Salt_list;
88 #ifdef USE_FMEM_WRAPPER
107 static MULTI_IF *gMIIF_Error_Recovery;
108 static int current_IIF_index;
109 static float current_time = 0;
110 static float start_time = 0;
112 static void prepare_error_recovery(
MULTI_IF *MIIF,
int IIF_index,
float time) {
113 gMIIF_Error_Recovery = MIIF;
114 current_IIF_index = IIF_index;
115 current_time = start_time+time;
119 return gMIIF_Error_Recovery->
NodeLists[current_IIF_index][local_node];
126 static int g_print_bounds_exceeded = 1;
129 return g_print_bounds_exceeded;
133 int oldval = g_print_bounds_exceeded;
135 g_print_bounds_exceeded = newval;
158 int ***NodeLists,
int numNode)
164 int *NodeNum =
static_cast<int *
>(calloc(N_IIF,
sizeof(
int)));
165 int **NodeLst =
static_cast<int **
>(calloc(N_IIF,
sizeof(
int *)));
168 for (
int i = 0; i < numNode; i++)
169 NodeNum[
static_cast<int>(IIF_Mask[i])]++;
174 for (
int i = 0; i < N_IIF; i++) {
176 NodeLst[i] =
static_cast<int *
>(malloc(
sizeof(
int *) * NodeNum[i]));
182 for (
int j = 0; j < N_IIF; j++) {
184 for (
int i = 0; i < numNode; i++)
185 if (IIF_Mask[i] == j)
186 NodeLst[j][hcount++] = i;
189 for(
int j=0; j<N_IIF; j++)
190 std::sort(NodeLst[j], NodeLst[j]+NodeNum[j]);
193 *NodeLists = NodeLst;
222 int N_IIF = pMIIF->
N_IIF;
224 pMIIF->
contiguous =
static_cast<bool *
>(calloc(N_IIF,
sizeof(
bool)));
229 for (std::size_t i = 0; i < pMIIF->
N_IIF; i++) {
230 pMIIF->
ldata[i] = allocate_on_target<GlobalData_t*>(pMIIF->
iontypes[i].get().select_target(pMIIF->
targets[i]), NUM_IMP_DATA_TYPES);
234 for (
int i = 0; i < pMIIF->
N_IIF; i++) {
253 for (
auto& imp : pMIIF->
IIF) {
254 imp->initialize_params();
263 for (
int i = 0; i < pMIIF->
IIF.size(); i++)
264 pMIIF->
IIF[i]->initialize(pMIIF->
dt, pMIIF->
ldata[i]);
278 unsigned int *moddat =
static_cast<unsigned int *
>(calloc(this->
N_IIF,
sizeof(
unsigned int)));
280 for (
int i = 0; i < this->
N_IIF; i++) {
281 moddat[i] = this->
IIF[i]->get_moddat();
282 this->
IIF[i]->set_moddat(moddat[i] | this->
IIF[i]->get_reqdat());
285 for (
int i = 0; i < this->
N_IIF; i++) {
286 this->
IIF[i]->set_moddat(moddat[i]);
306 #define FILENAME_BUF 1024
310 return *(
int *)a - *(
int *)b;
342 if (!n_traceNodes)
return;
344 if (n_traceNodes > 1000)
345 log_msg(0, 4, 0,
"%s warning: %d trace nodes may impact performance", __func__, n_traceNodes);
355 for (
int iTrace = 0; iTrace < n_traceNodes; iTrace++) {
356 mesh_int_t lnode = imesh ? imesh->
pl.localize(traceNodes[iTrace]) : traceNodes[iTrace];
361 if(petsc2nod.
in_b(lnode) ==
false)
continue;
367 for (
int iRegion = 0; iRegion < MIIF->
N_IIF; iRegion++)
369 auto target =
static_cast<int *
>(bsearch(&lnode, MIIF->
NodeLists[iRegion],
372 if (target != NULL ) {
373 int idx = target - MIIF->
NodeLists[iRegion];
375 trace_info->
found =
true;
376 trace_info->
region = iRegion;
382 for (
int iTrace = 0; iTrace < n_traceNodes; iTrace++) {
385 log_msg(0,4,0,
"trace node %d not found", traceNodes[iTrace]);
390 snprintf(traceName,
sizeof traceName,
"Trace_%d.dat", label ? label[iTrace] : traceNodes[iTrace]);
415 #define MAX_TRACE_LINE_LEN 8196
419 std::vector<IonIfBase*>& IIF = MIIF->
IIF;
430 fprintf(fs,
"%4.10f\t", time);
431 if (IIF[ctrace->
region]->get_type().has_trace()) {
435 for (
auto& plugin : IIF[ctrace->
region]->plugins()) {
436 if (plugin->get_type().has_trace()) {
438 plugin->get_type().trace(
446 fprintf(ctrace->
file->
fd,
"%s", trace_buf);
488 std::vector<IonIfBase*>& pIF = this->
IIF;
489 for (
auto& IF : pIF) {
490 int ndmps = IF->dump_luts(zipped);
491 if (ndmps < IF->tables().size()) {
492 log_msg(
logger, 4, 0,
"LUT dump error %s: only %d out of %d LUTs dumped.\n",
493 IF->get_type().get_name().c_str(), ndmps, IF->tables().size());
495 for (
auto& plugin : IF->plugins()) {
496 ndmps = plugin->dump_luts(zipped);
497 if (ndmps < plugin->tables().size()) {
498 log_msg(
logger, 4, 0,
"LUT dump error %s: only %d out of %d LUTs dumped.\n",
499 plugin->get_type().get_name().c_str(), ndmps, IF->tables().size());
513 for (
int i = 0; i <
svd.
n; i++)
530 char *
get_sv(
void *tab,
int offset,
int n,
int svSize,
int size,
int dlo_vector_size) {
531 char *buf =
static_cast<char *
>(malloc(n*size));
533 char *p =
static_cast<char *
>(tab) + offset;
535 for (
int i = 0; i < n; i += dlo_vector_size) {
536 int dlo_array_size =
min(dlo_vector_size, n - i);
537 memcpy(bp, p, size * dlo_array_size);
538 bp += size * dlo_array_size;
554 if (iot->triggered) {
555 for (
int i = 0; i <
svd.
n; i++) {
560 nwr += SF::root_write<char>(fd, (
char*) buf,
svd.
size[i]*
svd.
num[i], PETSC_COMM_WORLD);
577 void update_vm(
int start,
int end,
double *vm,
double *ion,
double dt)
579 int i = blockIdx.x*blockDim.x + threadIdx.x;
581 vm[i] = vm[i] + (ion[i] * (-dt));
589 if (flag_send == 1) {
593 for (
int j = 0; j < this->
numSubDt; j++)
595 for (
int i = 0; i < this->
N_IIF; i++)
598 if (!this->
N_Nodes[i])
continue;
600 prepare_error_recovery(
this, i, pIF->
get_tstp().
cnt * this->dt);
612 fprintf(stderr,
"LIMPET compute fail in %s at node %d (local %d)! Aborting!\n",
613 this->
name.c_str(), this->NodeLists[i][j], j);
618 }
while (current < this->
N_Nodes[i]);
620 for (
auto& plugin : pIF->
plugins()) {
626 plugin->compute(current, this->
N_Nodes[i], this->
ldata[i]);
629 if (plugin ==
nullptr)
635 fprintf(stderr,
"LIMPET plugin fail in %s at node %d (local %d)! Aborting!\n",
636 this->
name.c_str(), this->NodeLists[i][j], j);
641 }
while (current < this->
N_Nodes[i]);
650 #if defined __CUDA__ || defined __HIP__
653 cudaDeviceSynchronize();
654 #elif defined __HIP__
655 hipDeviceSynchronize();
658 fprintf(stderr,
"GPU/CUDA not found");
663 if (flag_receive == 1) {
678 for (
auto& pIF : this->
IIF) {
679 pIF->get_type().destroy_ion_if(pIF);
690 for (
int i = 0; i < pMIIF->
N_IIF; i++) {
698 for (
int j = 0; j < NUM_IMP_DATA_TYPES; j++) {
706 allocate_on_target<GlobalData_t>(pMIIF->
IIF[i]->get_target(),
709 if (pMIIF->
gdata[j] == NULL) {
710 log_msg(pMIIF->
logger, 5,
LOCAL,
"IMP data type %s not supplied for region %d", imp_data_names[j], i);
728 for (
int j = 0; j < NUM_IMP_DATA_TYPES; j++) {
730 if (this->
gdata[j] != NULL) {
738 for (
int i = 0; i < this->
N_IIF; i++) {
746 for (
int k = 0; k < this->
N_Nodes[i]; k++)
747 this->
ldata[i][j][k] = rdata[ip[k]];
763 for (
int i = 0; i < this->
N_IIF; i++) {
764 if (!this->
N_Nodes[i])
continue;
767 if (
is_gpu(this->
IIF[i]->get_target())) {
768 for (
int j = 0; j < NUM_IMP_DATA_TYPES; j++) {
774 for (
int k = 0; k < this->
N_Nodes[i]; k++)
780 for (
int j = 0; j < NUM_IMP_DATA_TYPES; j++) {
781 if (this->
IIF[i]->get_moddat() & imp_data_flag[j]) {
783 for (
int k = 0; k < this->
N_Nodes[i]; k++)
791 for (
int j = 0; j < NUM_IMP_DATA_TYPES; j++)
792 if (this->
gdata[j] != NULL)
798 for (
int j = 0; j < NUM_IMP_DATA_TYPES; j++) {
799 if (pMIIF->
gdata[j] != NULL) {
800 for (
int i = 0; i < pMIIF->
N_IIF; i++)
802 deallocate_on_target<GlobalData_t>(pMIIF->
IIF[i]->get_target(),
805 delete pMIIF->
gdata[j];
822 if (plgstr == NULL) {
823 *out_num_plugins = 0;
829 char *plugspec =
dupstr(plgstr);
831 char *token =
tokstr_r(plugspec,
":", &saveptr);
833 *out_num_plugins = 0;
840 out_plugins.push_back(*type);
842 token =
tokstr_r(NULL,
":", &saveptr);
845 *out_num_plugins = out_plugins.size();
876 if (index(variable,
'.') == NULL) {
880 for (
int ii = 0; ii < NUM_IMP_DATA_TYPES; ii++) {
881 if (strcmp(variable, imp_data_names[ii]) == 0) {
887 log_msg(
logger, 5,
FLUSH,
"Error! No external variable named %s in this build of openCARP.", variable);
892 if (this->
gdata[data_id] == NULL) {
894 "External variable %s is not being used this processor.\n"
895 "Is this really what you meant to do?\n"
896 "Perhaps you don't have the correct Ionic models selected.",
897 imp_data_names[data_id]);
903 for (
size_t i = 0; i < indices.
size(); i++) {
904 raw_data[indices[i]] = values[i];
915 char *my_variable =
dupstr(variable);
916 char *IIF_name =
tokstr_r(my_variable,
".", &saveptr);
917 char *sv_name =
tokstr_r(NULL,
".", &saveptr);
921 log_msg(
logger, 5, 0,
"%s error: %s is not a valid IMP name.", __func__, IIF_name);
928 if (sv_get == NULL) {
929 log_msg(
logger, 5, 0,
"%s error: %s is not a valid state variable for the %s model.",
930 __func__, sv_name, IIF_name);
936 for (
int i_iif = 0; i_iif < this->
N_IIF; i_iif++) {
938 if (this->
IIF[i_iif]->get_type() == *type) {
939 lIIF = this->
IIF[i_iif];
943 for (
auto& plugin : this->
IIF[i_iif]->plugins()) {
944 if (plugin->get_type() == *type) {
955 for (
size_t ii = 0; ii < indices.
size(); ii++) {
958 int *target =
static_cast<int*
>(bsearch(&indices[ii], this->
NodeLists[i_iif],
963 sv_put(*lIIF, (
int)(target - this->
NodeLists[i_iif]), sv_offset, file_value);
971 MPI_Allreduce(MPI_IN_PLACE, &num_changed, 1, MPI_INT, MPI_SUM, PETSC_COMM_WORLD);
1000 long loff = offset[0];
1001 for (
int i = 0; i < N; i++)
1002 if (offset[i]-loff > bufsize) {
1009 *ranges = (
int *)r.data;
1012 MPI_Bcast(&nitems, 1, MPI_INT, 0, PETSC_COMM_WORLD);
1014 *ranges =
static_cast<int *
>(malloc( (nitems+1)*
sizeof(
int) ));
1015 MPI_Bcast(*ranges, nitems+1, MPI_INT, 0, PETSC_COMM_WORLD);
1058 bool append,
unsigned int revision)
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);
1082 fwrite(&miif_node_gsize,
sizeof(
int), 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++) {
1149 fwrite(&sv_size,
sizeof(
int), 1, fd);
1150 unsigned long n_plugins = (
unsigned long) imp->
plugins().size();
1151 fwrite(&n_plugins,
sizeof(
int), 1, fd);
1154 for (
auto& plug : imp->
plugins()) {
1157 fwrite(&sv_size,
sizeof(
int), 1, fd);
1158 imp_mem[i] += plug->get_sv_size();
1161 filepos = ftell(fd);
1164 MPI_Bcast(imp_mem, this->
N_IIF, MPI_INT, 0, PETSC_COMM_WORLD);
1177 for(
size_t i=0; i<alg_idx.
size(); i++) loc2canon[i] = canon_nbr[alg_idx[i]];
1185 for (
int i = 0; i < this->
numNode; i++) loc2canon[i] = layout[rank] + i;
1189 int *canord =
new int[this->
numNode];
1190 for (
int i = 0; i < this->
numNode; i++)
1191 canord[i] = loc2canon[i];
1194 log_msg(NULL, 0, 0,
"\tDumping IMP masks at %d", filepos);
1197 SF::root_write_ordered<int, IIF_Mask_t>(fd, canord,
IIFmask,
numNode, PETSC_COMM_WORLD);
1203 impsize[i] = imp_mem[(
int)
IIFmask[i]];
1207 size_t num_entr =
SF::sum(impsize);
1211 for (
int imp_idx = 0; imp_idx < this->
N_IIF; imp_idx++)
1217 for (
int imp_nod_idx = 0; imp_nod_idx < this->
N_Nodes[imp_idx]; imp_nod_idx+=vec_size) {
1218 int index = imp_nod_idx / vec_size;
1219 int loc = this->
NodeLists[imp_idx][imp_nod_idx];
1222 char* write = impdata.
data() + impdsp[loc];
1224 memcpy(write, read, svSize);
1227 for (
auto& plug : iif->
plugins()) {
1228 int plugsize = plug->get_sv_size();
1230 write = impdata.
data() + impdsp[loc] + shift;
1231 read = (
char*) plug->get_sv_address() + index * plugsize;
1232 memcpy(write, read, plugsize);
1239 SF::root_write_ordered<int, char>(fd, canord, impsize.data(), impdata.
data(),
1240 numNode, num_entr, PETSC_COMM_WORLD);
1246 double dump_time =
timing(t1, t0);
1275 static char *last_fn = NULL;
1284 if (fname) in =
f_open(fname,
"r");
1287 if (fname)
log_msg(
logger, 5, 0,
"Error: cannot open file: %s\n", fname);
1288 else log_msg(
logger, 5, 0,
"Error: file stream not open yet");
1293 log_msg(
logger, 5, 0,
"%s is not a recognized MIIF dump file", fname);
1304 last_fn = strdup(fname);
1310 unsigned int format, version;
1313 f_read_par(&format,
sizeof(
unsigned int), 1, in);
1314 f_read_par(&version,
sizeof(
unsigned int), 1, in);
1315 f_read_par(&save_date,
sizeof(time_t), 1, in);
1317 log_msg(
logger, 0, 0,
"Restoring time %f from %s (format v%d) generated\n\tby calling "
1318 "program r%d on %s", time, fname, format, version, ctime(&save_date) );
1320 int savedNum, glob_numNode;
1321 MPI_Allreduce(&this->
numNode, &glob_numNode, 1, MPI_INT, MPI_SUM, PETSC_COMM_WORLD);
1324 if (savedNum != glob_numNode) {
1325 log_msg(
logger, 5, 0,
"expecting %d nodes but read %d nodes", glob_numNode, savedNum);
1333 for (
int g = 0; g < num_gdata; g++) {
1336 for (i = 0; i < NUM_IMP_DATA_TYPES; i++) {
1337 if (!strcmp(datatype, imp_data_names[i]) ) {
1338 if (this->
gdata[i]) {
1339 log_msg(
logger, 0, 0,
"\tRestoring global data %s", imp_data_names[i], datatype);
1341 FILE* fd = my_rank == 0 ? in->fd : NULL;
1344 petsc2canon(*this->
gdata[i], fwd);
1346 log_msg(
logger, 0, 0,
"\tGlobal data %s not used", datatype);
1351 if (i == NUM_IMP_DATA_TYPES)
1352 log_msg(
logger, 3, 0,
"\tSaved global data %s not recognized", datatype);
1354 if ( (my_rank == 0) && ((i == NUM_IMP_DATA_TYPES) || !this->
gdata[i]) )
1355 fseek(in->fd, this->gdata[i]->gsize() *
sizeof(
SF_real), SEEK_CUR);
1365 int *IMPsz =
static_cast<int *
>(malloc(
N_IIF *
sizeof(
int)));
1367 for (
int i = 0; i <
N_IIF; i++) {
1370 f_read_par(&imps[i].nplug,
sizeof(
int), 1, in);
1373 IMPsz[i] = imps[i].
sz;
1376 for (
int j = 0; j < imps[i].
nplug; j++) {
1379 f_read_par(&imps[i].plug[j].sz,
sizeof(
int), 1, in);
1380 IMPsz[i] += imps[i].
plug[j].
sz;
1385 for (
int i = 0; i <
N_IIF; i++) {
1386 if (i >= this->N_IIF) {
1387 log_msg(NULL, 3, 0,
"Saved IMP region %d out of range", i);
1390 if (strcmp(imps[i].
name, this->
IIF[i]->get_type().get_name().c_str()) ) {
1391 log_msg(NULL, 3, 0,
"Saved IMP region %d ionic model does not match that of IMP region %d", i, i);
1394 if (imps[i].sz != this->
IIF[i]->get_sv_size()) {
1395 log_msg(NULL, 3, 0,
"Saved IMP region %d size does not match current IMP size", i);
1401 for (
int j = 0; j < imps[i].
nplug; j++)
1402 for (
int k = 0; k < this->
IIF[i]->plugins().size(); k++)
1403 if (!strcmp(imps[i].plug[j].
name, this->
IIF[i]->plugins()[k]->get_type().get_name().c_str()) &&
1404 (imps[i].plug[j].sz == this->
IIF[i]->plugins()[k]->get_sv_size()) ) {
1405 log_msg(NULL, 3, 0,
"Saved IMP region %d plugin %s compatible", i, imps[i].plug[j].
name);
1414 IIF_Mask_t *canMask =
static_cast<char *
>(malloc(glob_numNode*
sizeof(this->
IIFmask[0]) ));
1418 size_t *offset =
static_cast<size_t *
>(calloc(glob_numNode+1,
sizeof(
size_t)));
1419 for (
int i = 1; i <= glob_numNode; i++)
1420 offset[i] = offset[i-1] + IMPsz[
static_cast<int>(canMask[i-1])];
1428 SVstart = ftell(in->fd);
1432 MPI_Bcast(&SVstart,
sizeof(
long), MPI_BYTE, 0, PETSC_COMM_WORLD);
1441 for(
size_t i=0; i<alg_idx.
size(); i++) loc2canon[i] = canon_nbr[alg_idx[i]];
1444 for (
int pid = 0; pid < mpi_size; pid++) {
1445 if (my_rank == pid) {
1449 for (
int i = 0; i <
N_IIF; i++) {
1450 fseek(in->fd, SVstart, SEEK_SET);
1452 canMask, offset, imps+i, loc2canon.
data());
1457 MPI_Barrier(PETSC_COMM_WORLD);
1462 MPI_Reduce(my_rank ? &mismatch : MPI_IN_PLACE, &mismatch, 1, MPI_INT, MPI_SUM, 0, PETSC_COMM_WORLD);
1463 if ( (my_rank == 0) && mismatch)
1464 log_msg(NULL, 3, 0,
"Number of nonmatching nodes: %d", mismatch);
1466 if ( (my_rank == 0) && (!close) ) {
1471 fseek(in->fd, SVstart+offset[glob_numNode], SEEK_SET);
1475 for (
int i = 0; i <
N_IIF; i++)
1479 double restore_time =
timing(t1, t0);
1480 log_msg(
logger, 0, 0,
"State restored from file %s in %.3f seconds.\n", fname, restore_time);
1497 char *reg_name,
char *sv_lst,
char *plg_lst,
1498 char *plg_sv_lst,
double t,
double dump_dt) {
1499 char file[8000], svs[1024], plgs[1024], plgsvs[1024];
1500 char *e, *l, *p, *svnames, *plgnames, *plgsvnames;
1502 strcpy(svs, sv_lst);
1503 strcpy(plgs, plg_lst);
1504 strcpy(plgsvs, plg_sv_lst);
1506 plgnames = &plgs[0];
1507 plgsvnames = &plgsvs[0];
1517 snprintf(file,
sizeof file,
"%s.%s.bin", reg_name, svnames);
1531 snprintf(file,
sizeof file,
"%s_%s.%s.bin", reg_name, plgnames, plgsvnames);
1556 const char *
filename,
const char *regname) {
1558 int n = this->
svd.
n;
1563 for (i = 0; i < IF->
plugins().size(); i++)
1564 if (IF->
plugins()[i]->get_type() == type)
1566 if (i == IF->
plugins().size()) {
1567 log_msg(
logger, 2, 0,
"Warning: IMP %s not found in Region %s\n",
1578 this->
svd.
fn =
static_cast<char **
>(realloc(this->
svd.
fn, this->svd.n*
sizeof(
char *)));
1579 this->
svd.
reg =
static_cast<int *
>(realloc(this->
svd.
reg, this->svd.n*
sizeof(
int)));
1580 this->
svd.
svnames =
static_cast<char **
>(realloc(this->
svd.
svnames, this->svd.n*
sizeof(
char *)));
1583 this->
svd.
offset =
static_cast<int *
>(realloc(this->
svd.
offset, this->svd.n*
sizeof(
int)));
1584 this->
svd.
size =
static_cast<int *
>(realloc(this->
svd.
size, this->svd.n*
sizeof(
int)));
1585 this->
svd.
dlo_vs =
static_cast<int *
>(realloc(this->
svd.
dlo_vs, this->svd.n*
sizeof(
int)));
1586 this->
svd.
dtype =
static_cast<int *
>(realloc(this->
svd.
dtype, this->svd.n*
sizeof(
int)));
1587 this->
svd.
svtab =
static_cast<void **
>(realloc(this->
svd.
svtab, this->svd.n*
sizeof(
void *)));
1588 this->
svd.
svsize =
static_cast<size_t *
>(realloc(this->
svd.
svsize, this->svd.n*
sizeof(
size_t)));
1589 this->
svd.
num =
static_cast<int *
>(realloc(this->
svd.
num, this->svd.n*
sizeof(
int)));
1590 this->
svd.
reg =
static_cast<int *
>(realloc(this->
svd.
reg, this->svd.n*
sizeof(
int)));
1603 this->
svd.
reg[n] = region;
1625 char *svname,
char *regname,
char *
filename) {
1626 int offset, size, dtype, added = 0;
1627 char *svtypename = NULL;
1631 filename_bin = strcat(
filename,
".bin");
1633 assert(type != NULL);
1636 this->
sv_dump_add(region, *type, offset, size, dtype, filename_bin, regname);
1640 log_msg(NULL, 1, 0,
"No state variable added to dump list");
1659 assert(miif->
gdata[Vm] != NULL);
1661 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++) {
1662 for (
int n = 0; n < miif->
N_IIF; n++)
1663 if (
USED_DAT(miif->
IIF[n], imp_data_flag[i]) && (miif->
gdata[i] == NULL)) {
1678 int num_mech_data = 0;
1680 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++) {
1681 if ( (Lambda_DATA_FLAG == i) || (delLambda_DATA_FLAG == i) ||
1682 (Tension_DATA_FLAG == i) || (tension_component_DATA_FLAG == i) ) {
1683 for (
int n = 0; n < this->
N_IIF; n++)
1688 return static_cast<bool>(num_mech_data);
1709 float beta,
int *node,
int numnode) {
1711 if (strstr(species,
"Ca") != NULL) {
1714 }
else if (strstr(species,
"Na") != NULL) {
1716 }
else if (strstr(species,
"Cl") != NULL) {
1718 }
else if (strstr(species,
"K") != NULL) {
1721 log_msg(
logger, 5, 0,
"Unimplemented ion species: %s\n", species);
1727 static int warned = 0;
1732 int my_low_idx = layout[rank], my_high_idx = layout[rank+1];
1734 for (
int i = 0; i < numnode; i++) {
1735 if ((node[i] < my_low_idx) || (node[i] >= my_high_idx))
continue;
1737 for (
int j = 0; j < this->
N_IIF; j++) {
1738 if (this->
NodeLists[j] == NULL)
continue;
1740 if ((node[i] < this->
NodeLists[j][0]) ||
1744 ion_get = this->
IIF[j]->get_type().get_sv_offset(species, &offset, &sz);
1745 if (ion_get == NULL) {
1748 log_msg(
logger, 2, 0,
"Ion species not present in ionic model: %s\n",
1760 delta_conc = charge*g.
sl_i2c/z;
1763 delta_conc = 10*charge*beta/(
FARADAY*z);
1766 for (
int k = 0; k < this->
N_Nodes[j]; k++)
1768 ion_put(*this->
IIF[j], k, offset, ion_get(*this->
IIF[j], k, offset)-delta_conc);
1781 for (
int i = 0; i < this->
N_IIF; i++) {
1782 this->
IIF[i]->destroy_luts();
1783 this->
IIF[i]->set_dt((
float) Dt);
1784 this->
iontypes[i].get().construct_tables(*this->
IIF[i]);
1786 for (
int j = 0; j < this->
IIF[i]->plugins().size(); j++) {
1787 auto& plugin = this->
IIF[i]->plugins()[j];
1788 plugin->destroy_luts();
1789 plugin->set_dt((
float) Dt);
1790 this->
plugtypes[i][j].get().construct_tables(*plugin);
1795 #define MEMFREE(A) free(A)
1806 for (
int i = 0; i < m->
N_IIF; i++) {
1807 m->
IIF[i]->get_type().destroy_ion_if(m->
IIF[i]);
1810 for (
int j = 0; j < NUM_IMP_DATA_TYPES; j++) {
1831 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++)
1835 for (
int i = 0; i < orig->
N_IIF; i++) {
1836 miif_doppel->
IIF[i]->copy_SVs_from(*orig->
IIF[i],
false);
1838 for (
int j = 0; j < orig->
IIF[i]->plugins().size(); j++)
1839 miif_doppel->
IIF[i]->plugins()[j]->copy_SVs_from(*orig->
IIF[i]->plugins()[j],
false);
1856 *miif_doppel = *orig;
1857 miif_doppel->
doppel =
true;
1860 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++)
1865 miif_doppel->
IIF = {};
1867 for (
int i = 0; i < orig->
N_IIF; i++) {
1869 miif_doppel->
IIF.push_back(orig->
IIF[i]->get_type().make_ion_if(orig->
IIF[i]->get_target(),
1871 miif_doppel->
IIF[i]->copy_SVs_from(*orig->
IIF[i],
true);
1872 miif_doppel->
IIF[i]->copy_plugins_from(*orig->
IIF[i]);
1895 int imp_data_id = -1;
1897 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++) {
1898 if (strcmp(sv, imp_data_names[i]) == 0) {
1913 for (
int i = 0; i < NUM_IMP_DATA_TYPES; i++)
1914 if (localdata && localdata[i])
1915 localdata[i][to] = localdata[i][from];
1919 int sv_list_size = imp.
get_type().get_sv_list(&sv_list);
1921 for (
int i = 0; i < sv_list_size; i++) {
1922 char *sv_name = sv_list[i];
1925 SVgetfcn sv_get = imp.
get_type().get_sv_offset(sv_name, &sv_offset, &sv_size);
1926 if (sv_get == NULL) {
1927 throw std::runtime_error(std::string(__func__) +
" error: " + sv_name +
" is not a valid state variable for the " + imp.
get_type().
get_name() +
" model.");
1932 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.
double SF_real
Use the general double as real type.
#define SLIST_APPEND(S, P)
virtual void release_ptr(S *&p)=0
size_t read_binary(FILE *fd)
virtual void add_scaled(const abstract_vector< T, S > &vec, S k)=0
size_t write_binary(FILE *fd)
Write a vector to HD in binary. File descriptor is already set up.
virtual void set(const vector< T > &idx, const vector< S > &vals, const bool additive=false, const bool local=false)=0
bool in_b(const T idx)
return whether idx is in set B
T backward_map(T idx) const
Map one index from b to a.
overlapping_layout< T > pl
nodal parallel layout
Container for a PETSc VecScatter.
void forward(abstract_vector< T, S > &in, abstract_vector< T, S > &out, bool add=false)
Forward scattering.
size_t size() const
The current size of the vector.
void resize(size_t n)
Resize a vector.
T * data()
Pointer to the vector's start.
Represents the ionic model and plug-in (IMP) data structure.
const IonType & get_type() const
Gets this IMP's model type.
std::vector< IonIfBase * > & plugins()
Returns a vector containing the plugins of this IMP.
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 get_num_node() const
Gets the number of nodes handled by this 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.
void compute(int start, int end, GlobalData_t **data)
Perform ionic model computation for 1 time step.
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).
int numNode
local number of nodes
bool extUpdateVm
flag indicating update function for Vm
int dump_svs(opencarp::base_timer *)
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)
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.
int * N_Nodes
#nodes for each IMP
int ** NodeLists
local partitioned node lists for each IMP stored
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
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()
void dsp_from_cnt(const vector< T > &cnt, vector< T > &dsp)
Compute displacements from counts.
T sum(const vector< T > &vec)
Compute sum of a vector's entries.
void local_petsc_to_nodal_mapping(const meshdata< T, S > &mesh, index_mapping< T > &petsc_to_nodal)
void layout_from_count(const T count, vector< T > &layout, MPI_Comm comm)
void init_vector(SF::abstract_vector< T, S > **vec)
@ NBR_SUBMESH
Submesh nodal numbering: The globally ascending sorted reference indices are reindexed.
void doppel_MIIF(MULTI_IF *orig, MULTI_IF *miif_doppel)
int getGlobalNodalIndex(IonIfBase &pIF, int relIdx)
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)
GlobalData_t(* SVgetfcn)(IonIfBase &, int, int)
SVputfcn getPutSV(SVgetfcn)
void doppel_update(MULTI_IF *orig, MULTI_IF *miif_doppel)
void dup_IMP_node_state(IonIfBase &IF, int from, int to, GlobalData_t **localdata)
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.
int current_global_node(int local_node)
void initialize_params_MIIF(MULTI_IF *pMIIF)
void(* SVputfcn)(IonIfBase &, int, int, GlobalData_t)
constexpr T min(T a, T b)
void alloc_MIIF(MULTI_IF *pMIIF)
void freeIMPData(MULTI_IF *pMIIF)
std::vector< std::reference_wrapper< IonType > > IonTypeList
constexpr T max(T a, T b)
void deallocate_on_target(Target target, T *ptr)
Utility function for deallocating memory on a target. See TargetAllocator.
void CreateIIFNodeLsts_(int, char *, int **, int ***, int)
void CreateIIFLocalNodeLsts(MULTI_IF *pMIIF)
void initialize_ionic_IF(MULTI_IF *pMIIF)
void update_ts(ts *ptstp)
char * get_sv(void *tab, int offset, int n, int svSize, int size, int dlo_vector_size)
float current_global_time()
void close_trace(MULTI_IF *MIIF)
void dump_trace(MULTI_IF *MIIF, limpet::Real time)
char * get_next_list(char *lst, char delimiter)
int int_cmp(const void *a, const void *b)
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)
char * tokstr_r(char *s1, const char *s2, char **lasts)
int set_print_bounds_exceeded_messages(int newval)
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)
void log_msg(FILE_SPEC out, int level, unsigned char flag, const char *fmt,...)
mesh_t
The enum identifying the different meshes we might want to load.
void get_time(double &tm)
SF::abstract_vector< SF_int, SF_real > sf_vec
int get_size(MPI_Comm comm=PETSC_COMM_WORLD)
V timing(V &t2, const V &t1)
void f_close(FILE_SPEC &f)
Close a FILE_SPEC.
#define PETSC_TO_CANONICAL
Permute algebraic data from PETSC to canonical ordering.
int offset
offset into node data
int map
which plugin does this IMO match
bool compatible
does IM match stored IM
int nplug
number of plugins
data structure to manage state variable file dumps
size_t * svsize
state variable sizes
char ** fn
array to store file names
double intv
time interval for sv dumps
int n_dumps
keep track of number of dumped time slices
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
bool found
found on this node
int node_idx
local node number
float sl_i2c
convert sl-currents in uA/cm^2 to mM/L without valence