13 #include "petsc_utils.h"
21 #include "caliper/cali.h"
38 logger =
f_open(
"electrics.log", param_globals::experiment != 4 ?
"w" :
"a");
53 if (param_globals::bidomain || param_globals::extracell_monodomain_stim) {
62 param_globals::dt, 0,
"elec::ref_dt",
"TS");
82 if(strlen(param_globals::phie_rec_ptf) > 0)
89 if (param_globals::prepacing_bcl > 0)
99 m->
regions.resize(param_globals::num_gregions);
102 log_msg(logger, 0, 0,
"Setting up %s tissue properties for %d regions ..", grid_name,
103 param_globals::num_gregions);
108 for (
size_t i=0; i<m->
regions.size(); i++, reg++) {
109 if(!strcmp(param_globals::gregion[i].name,
"")) {
110 snprintf(buf,
sizeof buf,
", gregion_%d",
int(i));
111 param_globals::gregion[i].name =
dupstr(buf);
114 reg->
regname = strdup(param_globals::gregion[i].name);
116 reg->
nsubregs = param_globals::gregion[i].num_IDs;
122 reg->
subregtags[j] = param_globals::gregion[i].ID[j];
124 log_msg(NULL,3,
ECHO,
"Warning: not all %u IDs provided for gregion[%u]!\n", reg->
nsubregs, i);
132 emat->
InVal[0] = param_globals::gregion[i].g_il;
133 emat->
InVal[1] = param_globals::gregion[i].g_it;
134 emat->
InVal[2] = param_globals::gregion[i].g_in;
136 emat->
ExVal[0] = param_globals::gregion[i].g_el;
137 emat->
ExVal[1] = param_globals::gregion[i].g_et;
138 emat->
ExVal[2] = param_globals::gregion[i].g_en;
140 emat->
BathVal[0] = param_globals::gregion[i].g_bath;
141 emat->
BathVal[1] = param_globals::gregion[i].g_bath;
142 emat->
BathVal[2] = param_globals::gregion[i].g_bath;
145 for (
int j=0; j<3; j++) {
146 emat->
InVal[j] *= 1e-3 * param_globals::gregion[i].g_mult;
147 emat->
ExVal[j] *= 1e-3 * param_globals::gregion[i].g_mult;
148 emat->
BathVal[j] *= 1e-3 * param_globals::gregion[i].g_mult;
155 const char* file = g ==
Electrics::intra_grid ? param_globals::gi_scale_vec : param_globals::ge_scale_vec;
161 void Electrics::setup_mappings()
171 log_msg(
logger, 0, 0,
"%s: Setting up intracellular algebraic-to-nodal scattering.", __func__);
175 log_msg(
logger, 0, 0,
"%s: Setting up intracellular PETSc to canonical permutation.", __func__);
181 log_msg(
logger, 0, 0,
"%s: Setting up extracellular algebraic-to-nodal scattering.", __func__);
183 log_msg(
logger, 0, 0,
"%s: Setting up extracellular PETSc to canonical permutation.", __func__);
185 log_msg(
logger, 0, 0,
"%s: Setting up intra-to-extra scattering.", __func__);
189 bool check_i2e =
false;
190 if(check_i2e && extra_exists) {
208 SF_real*
id = intra_testvec->ptr();
209 for(
size_t i=0; i<intra_alg_nod.
size(); i++) {
211 id[lpidx] = intra_ref_nbr[intra_alg_nod[i]];
213 intra_testvec->release_ptr(
id);
215 SF_real* ed = extra_testvec->ptr();
216 for(
size_t i=0; i<extra_alg_nod.
size(); i++) {
218 ed[lpidx] = extra_ref_nbr[extra_alg_nod[i]];
220 extra_testvec->release_ptr(ed);
222 i2e_testvec->set(-1.0);
223 i2e.
forward(*intra_testvec, *i2e_testvec);
226 for(
size_t i=0; i<extra_alg_nod.
size(); i++) {
227 auto id = i2e_testvec->get(i);
228 auto ed = extra_testvec->get(i);
229 if(
id > -1 &&
id != ed)
234 log_msg(0,5,0,
"Electrics mapping test failed!");
236 log_msg(0,5,0,
"Electrics mapping test succeeded!");
261 stimulate_extracellular();
263 if(param_globals::bidomain ==
BIDOMAIN)
271 stimulate_intracellular();
274 if(param_globals::dump_data &
DUMP_IC)
285 if(param_globals::bidomain ==
BIDOMAIN)
315 if(param_globals::bidomain && (param_globals::dump_data &
DUMP_IACT)) {
319 if(param_globals::dump_data &
DUMP_IC) {
322 if (time <= time_step) {
324 Ic[i] = (Vmv[i] - Vmv[i]) / (-time_step);
328 Ic[i] = (Ic[i] - Vmv[i]) / (-time_step);
343 double curtime =
timing(t2, t1);
374 log_msg( NULL, 0, 0,
"Balancing stimulus %d with %d %s-wise.",balance_from, balance_to,
375 is_current(stimuli[balance_from].phys.type) ?
"current" :
"voltage" );
377 stimulus & from = stimuli[balance_from];
378 stimulus & to = stimuli[balance_to];
400 void Electrics::balance_electrodes()
402 for(
int i=0; i<param_globals::num_stim; i++) {
403 if(param_globals::stim[i].crct.balance != -1) {
404 int from = param_globals::stim[i].crct.balance;
412 void Electrics::setup_stimuli()
417 stimuli.resize(param_globals::num_stim);
418 for(
int i=0; i<param_globals::num_stim; i++)
428 if (s.electrode.dump_vtx)
431 if(param_globals::stim[i].pulse.dumpTrace &&
get_rank() == 0) {
433 s.pulse.wave.write_trace(s.name+
".trc");
440 double val; s.
value(val);
444 for (
size_t i = 0; i < idx.
size(); i++) {
447 vec.
set(local_idx, val, add,
true);
450 void Electrics::stimulate_intracellular()
461 if(param_globals::operator_splitting) {
472 *ps.tmp_i1 = *ps.IIon;
473 *ps.tmp_i1 -= *ps.Irhs;
478 ps.mass_i->mult(*ps.tmp_i1, *ps.Irhs);
480 *ps.Irhs = *ps.tmp_i1;
488 if(illum_vec == NULL) {
489 log_msg(0,5,0,
"Cannot apply illumination stim: global vector not present!");
504 void Electrics::clamp_Vm() {
506 if(s.phys.type ==
Vm_clmp && s.is_active())
511 void Electrics::stimulate_extracellular()
513 if(param_globals::bidomain) {
518 if(dbcs_have_updated && time_not_final)
523 for(
const stimulus & s :
stimuli) {
524 if(s.is_active() && s.phys.type ==
I_ex)
542 for(
int pid=0; pid < mpi_size; pid++) {
543 if(mpi_rank == pid) {
545 buffsize = sndbuff.
size();
548 MPI_Bcast(&buffsize,
sizeof(
size_t), MPI_BYTE, pid, PETSC_COMM_WORLD);
550 MPI_Bcast(sndbuff.
data(), buffsize*
sizeof(
mesh_int_t), MPI_BYTE, pid, PETSC_COMM_WORLD);
552 mesh_int_t start = layout[mpi_rank], stop = layout[mpi_rank+1];
555 if(i >= start && i < stop)
579 for(
int pid=0; pid < mpi_size; pid++) {
580 if(mpi_rank == pid) {
582 buffsize = sndbuff.
size();
585 MPI_Bcast(&buffsize,
sizeof(
size_t), MPI_BYTE, pid, PETSC_COMM_WORLD);
587 MPI_Bcast(sndbuff.
data(), buffsize*
sizeof(
mesh_int_t), MPI_BYTE, pid, PETSC_COMM_WORLD);
674 const char* dataout_name)
676 const bool restricted_before = restr != NULL;
677 const long int num_dataout = restricted_before ?
678 get_global(
static_cast<long int>(restr->
size()), MPI_SUM, PETSC_COMM_WORLD) : 0;
682 const long int num_kept =
get_global(
static_cast<long int>(restr->
size()), MPI_SUM, PETSC_COMM_WORLD);
684 log_msg(0, 5,
ECHO,
"gridout_tags and %s select no common %s output nodes.",
685 dataout_name, domain);
689 if(restricted_before && num_kept < num_dataout)
691 "Warning: gridout_tags keeps %ld of the %ld %s output nodes selected by %s, %ld are dropped.",
692 num_kept, num_dataout, domain, dataout_name, num_dataout - num_kept);
697 void Electrics::setup_output()
704 if(restrict_gridout) {
706 if(param_globals::dataout_i || param_globals::dump_data)
708 if(param_globals::bidomain && param_globals::dataout_e)
716 restr_i, param_globals::num_io_nodes > 0,
717 restrict_gridout ? &output_tags : NULL);
719 if(restrict_gridout && (param_globals::dataout_i || param_globals::dump_data)) {
723 param_globals::num_io_nodes > 0);
724 if(
get_global(
static_cast<long int>(tag_restr_i.
size()), MPI_SUM, PETSC_COMM_WORLD) == 0) {
725 log_msg(0, 5,
ECHO,
"gridout_tags selected no intracellular output nodes.");
728 restrict_output_to_tags(restr_i, tag_restr_i,
"intracellular",
"dataout_i");
731 if(param_globals::dataout_i)
734 if(param_globals::bidomain) {
736 restr_e, param_globals::num_io_nodes > 0,
737 restrict_gridout ? &output_tags : NULL);
739 if(restrict_gridout && param_globals::dataout_e) {
743 param_globals::num_io_nodes > 0);
744 if(
get_global(
static_cast<long int>(tag_restr_e.
size()), MPI_SUM, PETSC_COMM_WORLD) == 0) {
745 log_msg(0, 5,
ECHO,
"gridout_tags selected no extracellular output nodes.");
748 restrict_output_to_tags(restr_e, tag_restr_e,
"extracellular",
"dataout_e");
751 if(param_globals::dataout_i)
753 if(param_globals::dataout_e)
757 if(param_globals::dump_data &
DUMP_IC) {
772 if(param_globals::num_trace) {
774 open_trace(
ion.
miif, param_globals::num_trace, param_globals::trace_node, NULL, &imesh);
781 void Electrics::dump_matrices()
783 std::string bsname = param_globals::dump_basename;
789 if ( param_globals::parab_solve==1 ) {
791 fn = bsname +
"_Ki_CN.bin";
794 fn = bsname +
"_Ki.bin";
797 fn = bsname +
"_Mi.bin";
800 if ( param_globals::bidomain ) {
801 fn = bsname +
"_Kie.bin";
804 fn = bsname +
"_Me.bin";
821 val = std::nan(
"NaN");
835 s_unit =
stimuli[sidx].pulse.wave.f_unit;
848 for(
size_t i = 0; i<stimuli.
size(); i++)
872 double* reg_kappa =
new double[miif.
N_IIF];
874 for(
int i=0; i<miif.
N_IIF; i++)
875 reg_kappa[i] = k * miif.
IIF[i]->cgeom().SVratio * ir[i].volFrac;
877 double *kd = kappa.
ptr();
879 for(
int i = 0; i < miif.
numNode; i++)
880 kd[i] = reg_kappa[(
int) miif.
IIFmask[i]];
896 for(
size_t i=0; i < m.
regions.size(); i++) {
902 void Electrics::setup_solvers()
908 if (param_globals::bidomain) {
913 if(param_globals::dump2MatLab)
931 double min_diff = 1e100;
933 for(
int i=0; i<param_globals::num_tsav; i++)
935 double diff = fabs(param_globals::tsav[i] - time);
936 if(min_diff > diff) {
945 return param_globals::tsav_ext[min_idx];
948 void Electrics::checkpointing()
957 snprintf(save_fnm,
sizeof save_fnm,
"%s.%s.roe", param_globals::write_statef, tsav_ext);
965 snprintf(save_fnm,
sizeof save_fnm,
"checkpoint.%.1f.roe", tm.time);
1000 mass_e ->
init(extra_mesh, dpn, dpn, param_globals::mass_lumping ? 1 : max_row_entries);
1022 int log_flag = param_globals::output_level > 1 ?
ECHO : 0;
1043 log_msg(logger,0,log_flag,
"Computed ellipitc stiffness matrix in %.3f seconds.", dur);
1047 log_msg(logger,0,log_flag,
"Elliptic lhs matrix enforcing Dirichlet boundaries.");
1058 log_msg(logger,0,log_flag,
"Elliptic lhs matrix Dirichlet enforcing done in %.3f seconds.", dur);
1061 log_msg(logger,1,
ECHO,
"Elliptic lhs matrix is singular!");
1070 setup_linear_solver(logger);
1073 log_msg(logger,0,log_flag,
"Initializing elliptic solver in %.5f seconds.", dur);
1080 int log_flag = param_globals::output_level > 1 ?
ECHO : 0;
1089 if(param_globals::mass_lumping) {
1096 log_msg(logger,0,log_flag,
"Computed elliptic mass matrix in %.3f seconds.", dur);
1099 void elliptic_solver::setup_linear_solver(
FILE_SPEC logger)
1103 tol = param_globals::cg_tol_ellip;
1104 max_it = param_globals::cg_maxit_ellip;
1106 std::string default_opts;
1107 std::string solver_file;
1108 solver_file = param_globals::ellip_options_file;
1109 if (param_globals::flavor == std::string(
"ginkgo")) {
1110 default_opts = std::string(
1112 "type": "solver::Cg",
1115 "type": "Iteration",
1119 "type": "ResidualNorm",
1120 "reduction_factor": 1e-4
1124 "type": "solver::Multigrid",
1127 "type": "multigrid::Pgm",
1128 "deterministic": true
1133 "type": "Iteration",
1137 "coarsest_solver": {
1138 "type": "preconditioner::Schwarz",
1140 "type": "preconditioner::Ilu"
1144 "min_coarse_rows": 8,
1145 "default_initial_guess": "zero"
1148 } else if (param_globals::flavor == std::string(
"petsc")) {
1149 default_opts = std::string(
"-ksp_type cg -pc_type hypre -pc_hypre_type boomeramg -pc_hypre_boomeramg_max_iter 1 -pc_hypre_boomeramg_strong_threshold 0.0 -options_left");
1154 logger, solver_file.c_str(), default_opts.c_str());
1168 Ki.mult(Vmv, tmp_i);
1180 auto dur =
timing(t1, t0);
1206 auto dur =
timing(t1, t0);
1238 if(!(vm_ptr != NULL && iion_ptr != NULL)) {
1239 log_msg(0,5,0,
"%s error: global Vm and Iion vectors not properly set up! Ionics seem invalid! Aborting!",
1265 if(!param_globals::operator_splitting)
1276 mass_i ->
init(intra_mesh, dpn, dpn, param_globals::mass_lumping ? 1 : max_row_entries);
1285 double start, end, period;
1291 int log_flag = param_globals::output_level > 1 ?
ECHO : 0;
1300 if( (param_globals::bidomain ==
MONODOMAIN && param_globals::bidm_eqv_mono) ||
1315 log_msg(logger,0,log_flag,
"Computed parabolic stiffness matrix in %.3f seconds.", dur);
1318 if(param_globals::mass_lumping)
1327 log_msg(logger,0,log_flag,
"Computed parabolic mass matrix in %.3f seconds.", dur);
1335 bool same_nonzero = param_globals::mass_lumping ==
false;
1365 setup_linear_solver(logger);
1368 log_msg(logger,0,log_flag,
"Initializing parabolic solver in %.5f seconds.", dur);
1371 period =
timing(end, start);
1375 void parabolic_solver::setup_linear_solver(
FILE_SPEC logger)
1378 tol = param_globals::cg_tol_parab;
1379 max_it = param_globals::cg_maxit_parab;
1381 std::string default_opts;
1382 std::string solver_file;
1383 solver_file = param_globals::parab_options_file;
1384 if (param_globals::flavor == std::string(
"ginkgo")) {
1385 default_opts = std::string(
1388 "type": "solver::Cg",
1391 "type": "Iteration",
1395 "type": "ResidualNorm",
1396 "reduction_factor": 1e-4
1400 "type": "preconditioner::Schwarz",
1402 "type": "preconditioner::Ilu"
1407 } else if (param_globals::flavor == std::string(
"petsc")) {
1408 default_opts = std::string(
"-pc_type bjacobi -sub_pc_type ilu -ksp_type cg");
1412 "parabolic PDE",
false, logger, solver_file.c_str(),
1413 default_opts.c_str());
1420 case CN: solve_CN(phie_i);
break;
1421 case O2dT: solve_O2dT(phie_i);
break;
1422 default: solve_EF(phie_i);
break;
1426 void parabolic_solver::solve_CN(
sf_vec & phie_i)
1431 if (param_globals::bidomain ==
BIDOMAIN) {
1438 *
tmp_i2 *= 1.0 - param_globals::theta;
1445 if(!param_globals::operator_splitting)
1459 auto dur =
timing(t1, t0);
1465 void parabolic_solver::solve_O2dT(
sf_vec & phie_i)
1470 if (param_globals::bidomain ==
BIDOMAIN) {
1497 void parabolic_solver::solve_EF(
sf_vec & phie_i)
1504 if (param_globals::bidomain ==
BIDOMAIN) {
1516 if(param_globals::operator_splitting ==
false)
1525 char* prvSimDir = strlen(param_globals::start_statef) ?
1528 const char* extn =
".dat";
1531 int addLATs = param_globals::compute_APD ? 2 : 0;
1533 bool have_sentinel = param_globals::t_sentinel > 0.0;
1534 bool need_to_add_sentinel = have_sentinel && (param_globals::sentinel_ID < 0);
1536 addLATs += need_to_add_sentinel ? 1 : 0;
1537 acts.resize(param_globals::num_LATs + addLATs);
1540 for (
int i = 0; i < param_globals::num_LATs; i++ )
1543 if (param_globals::lats[i].method <= 0 || (param_globals::lats[i].measurand ==
PHIE && !param_globals::bidomain)) {
1544 log_msg(NULL, 3, 0,
"Phie-based LAT measurement requires bidomain >=1 Ignoring lats[%d].", i);
1549 acts[j].threshold = param_globals::lats[i].threshold;
1550 acts[j].start = param_globals::lats[i].start;
1551 acts[j].mode = param_globals::lats[i].mode;
1552 acts[j].all = param_globals::lats[i].all;
1553 acts[j].measurand = (
PotType)param_globals::lats[i].measurand;
1554 acts[j].ID = param_globals::lats[i].ID;
1555 acts[j].fout = NULL;
1557 if(param_globals::lats[i].all) {
1558 acts[j].fname = (
char*) malloc((strlen(param_globals::lats[i].ID)+strlen(extn)+1)*
sizeof(
char));
1559 snprintf(
acts[j].fname, strlen(param_globals::lats[i].ID)+strlen(extn)+1,
"%s%s", param_globals::lats[i].ID, extn);
1562 char prfx[] =
"init_acts_";
1563 int max_len = strlen(prfx) + strlen(param_globals::lats[i].ID) + strlen(extn) + 1;
1565 acts[j].fname = (
char*) malloc(max_len*
sizeof(
char));
1566 snprintf(
acts[j].fname, max_len,
"%s%s%s", prfx, param_globals::lats[i].ID, extn);
1570 if(prvSimDir != NULL) {
1571 int len_fname = strlen(prvSimDir)+strlen(
acts[j].fname)+2;
1572 acts[j].prv_fname = (
char*) malloc(len_fname*
sizeof(
char));
1573 snprintf(
acts[j].prv_fname, len_fname,
"%s/%s", prvSimDir,
acts[j].fname);
1579 if(param_globals::compute_APD) {
1581 acts[j].threshold = param_globals::actthresh;
1586 acts[j].fout = NULL;
1591 acts[j].threshold = param_globals::recovery_thresh;
1596 acts[j].fout = NULL;
1597 acts[j].fname =
dupstr(
"vm_repolarisation.dat");
1607 sntl.
ID = param_globals::sentinel_ID;
1609 if(need_to_add_sentinel) {
1612 acts[j].threshold = param_globals::actthresh;
1617 acts[j].fout = NULL;
1624 if(prvSimDir) free(prvSimDir);
1629 const Activation & act = acts[idx];
1632 log_msg(logger, 0, 0,
"LAT detector [%2d]", idx);
1633 log_msg(logger, 0, 0,
"-----------------\n");
1635 log_msg(logger, 0, 0,
"Measurand: %s", act.measurand ?
"Phie" :
"Vm");
1636 log_msg(logger, 0, 0,
"All: %s", act.all ?
"All" :
"Only first");
1637 log_msg(logger, 0, 0,
"Method: %s", act.method==
ACT_DT ?
"Derivative" :
"Threshold crossing");
1639 char buf[64], gt[2], sgn[2];
1640 snprintf(sgn,
sizeof sgn,
"%s", act.mode?
"-":
"+");
1641 snprintf(gt,
sizeof gt,
"%s", act.mode?
"<":
">");
1643 const char* unit = act.method==
ACT_DT ?
"mV/ms" :
"mV";
1646 snprintf(buf,
sizeof buf,
"Maximum %sdf/dt %s %.2f %s", sgn, gt, act.threshold, unit);
1648 snprintf(buf,
sizeof buf,
"Intersection %sdf/dt with %.2f", sgn, act.threshold);
1650 log_msg(logger, 0, 0,
"Mode: %s", buf);
1651 log_msg(logger, 0, 0,
"Threshold: %.2f %s", act.threshold, unit);
1652 log_msg(logger, 0, 0,
"Start: %.2f ms\n", act.start);
1658 log_msg(0,0,5,
"There seems to be no EP is defined. LAT detector requires active EP! Aborting LAT setup!");
1667 for(
size_t i = 0; i <
acts.size(); ++i) {
1670 acts[i].phi->shallow_copy(!
acts[i].measurand ? vm : phie);
1671 acts[i].offset = offset;
1683 acts[i].ibuf = (
int *)malloc(
acts[i].phi->lsize()*
sizeof(int));
1684 acts[i].actbuf = (
double *)malloc(
acts[i].phi->lsize()*
sizeof(double));
1688 acts[i].tm->set(-1.);
1691 if(
acts[i].prv_fname != NULL) {
1693 size_t nread =
acts[i].tm->read_ascii(
acts[i].prv_fname);
1697 log_msg(NULL,2,
ECHO,
"Warning: Initialization of LAT[%2d] failed.", i);
1702 (*sc)(*
acts[i].tm,
false);
1709 if(
acts[i].prv_fname!=NULL) {
1713 log_msg(NULL,2,0,
"Copying over of previous activation file not implemented.\n");
f_close(in);
1716 log_msg(NULL,3,0,
"Warning: Initialization in %s - \n"
1717 "Failed to read activation file %s.\n", __func__,
acts[i].prv_fname);
1738 for (
int i=0; i<nlacts; i++)
1739 fprintf(fp->fd,
"%d\t%.6f\n", ibuf[i], act_tbuf[i]);
1746 for (
int j=1; j<numProc; j++) {
1749 MPI_Recv(&acts, 1, MPI_INT, j, 110, PETSC_COMM_WORLD, &status);
1755 MPI_Recv(buf_inds.
data(), acts, MPI_INT, j, 110, PETSC_COMM_WORLD, &status);
1756 MPI_Recv(buf_acts.
data(), acts, MPI_DOUBLE, j, 110, PETSC_COMM_WORLD, &status);
1758 for(
int ii=0; ii<acts; ii++)
1759 fprintf(fp->fd,
"%d\t%.6f\n", buf_inds[ii], buf_acts[ii]);
1767 MPI_Send(&nlacts, 1, MPI_INT, 0, 110, PETSC_COMM_WORLD);
1769 MPI_Send(ibuf, nlacts, MPI_INT, 0, 110, PETSC_COMM_WORLD);
1770 MPI_Send(act_tbuf, nlacts, MPI_DOUBLE, 0, 110, PETSC_COMM_WORLD);
1774 MPI_Bcast(&gacts, 1, MPI_INT, 0, PETSC_COMM_WORLD);
1783 for(Activation* aptr =
acts.data(); aptr !=
acts.end(); aptr++)
1786 switch (aptr->method) {
1788 lacts = check_cross_threshold(*aptr->phi, *aptr->phip, tm,
1789 aptr->ibuf, aptr->actbuf, aptr->threshold, aptr->mode);
1793 lacts = check_mx_derivative (*aptr->phi, *aptr->phip, tm,
1794 aptr->ibuf, aptr->actbuf, *aptr->dvp0, *aptr->dvp1,
1795 aptr->threshold, aptr->mode);
1803 if (aptr->start > 0.0) {
1805 for (
int j = 0; j < lacts; j++) {
1806 if (aptr->actbuf[j] >= aptr->start) {
1807 aptr->ibuf[kept] = aptr->ibuf[j];
1808 aptr->actbuf[kept] = aptr->actbuf[j];
1816 a = aptr->tm->ptr();
1820 for(
int j=0; j<lacts; j++) {
1823 aptr->ibuf[j] = canon_nbr[nodal_idx] + aptr->offset;
1826 if(a[aptr->ibuf[j]] == -1)
1827 a[aptr->ibuf[j]] = aptr->actbuf[j];
1834 aptr->tm->release_ptr(a);
1836 MPI_Allreduce(MPI_IN_PLACE, &lacts, 1, MPI_INT, MPI_SUM, PETSC_COMM_WORLD);
1839 aptr->nacts = nacts;
1848 static int savequitFlag = 0;
1849 int numNodesActivated = -1;
1854 log_msg(0,0,
ECHO |
NONL,
"================================================================================================\n");
1855 log_msg(0,0,
ECHO |
NONL,
"%s() WARNING: simulation is configured to savequit() after %.2f ms of quiescence\n", __func__,
sntl.
t_window);
1856 log_msg(0,0,
ECHO |
NONL,
"================================================================================================\n");
1874 return numNodesActivated;
1880 int LAT_detector::check_cross_threshold(
sf_vec & vm,
sf_vec & vmp,
double tm,
1881 int *ibuf,
double *actbuf,
float threshold,
int mode)
1885 int lsize = vm.lsize();
1886 int nacts = 0, gnacts = 0;
1888 for (
int i=0; i<lsize; i++) {
1890 bool triggered =
false;
1892 triggered = p[i] <= threshold && c[i] > threshold; }
1894 triggered = p[i] >= threshold && c[i] < threshold;
1899 double tact = tm - param_globals::dt + (threshold-p[i])/(c[i]-p[i])*sgn*param_globals::dt;
1901 actbuf[nacts] = tact;
1912 int LAT_detector::check_mx_derivative(
sf_vec & vm,
sf_vec & vmp,
double tm,
1913 int *ibuf,
double *actbuf,
sf_vec & dvp0,
sf_vec & dvp1,
1914 float threshold,
int mode)
1916 int nacts = 0, gnacts = 0;
1917 double tact, dt2 = 2 * param_globals::dt;
1918 int lsize = vm.lsize();
1927 for (
int i=0; i<lsize; i++ ) {
1929 dvdt = dv/param_globals::dt;
1930 ddv0 = pd1[i]-pd0[i];
1935 triggered = dvdt >= threshold && ddv0 > 0 && ddv1 < 0;
1937 triggered = dvdt <= threshold && ddv0 < 0 && ddv1 > 0;
1940 tact = tm-dt2+(ddv0/(ddv0-ddv1))*param_globals::dt;
1942 actbuf[nacts] = tact;
1951 vmp .release_ptr(p);
1952 dvp0.release_ptr(pd0);
1953 dvp1.release_ptr(pd1);
1966 bool forward =
true;
1968 for (
size_t i = 0; i <
acts.size(); i++) {
1970 (*sc)(*
acts[i].tm, forward);
1971 acts[i].tm->write_ascii(
acts[i].fname,
false);
1976 void Electrics::prepace() {
1977 log_msg(NULL, 0, 0,
"Using activation times from file %s to distribute prepacing states\n",
1978 param_globals::prepacing_lats);
1979 log_msg(NULL, 0, 0,
"Assuming stimulus strength %f uA/uF with duration %f ms for prepacing\n",
1980 param_globals::prepacing_stimstr, param_globals::prepacing_stimdur);
1989 size_t numread = read_lats->read_ascii(param_globals::prepacing_lats);
1991 log_msg(NULL, 5, 0,
"Failed reading required LATs! Skipping prepacing!");
2000 bool forward =
false;
2001 (*sc)(*read_lats, forward);
2005 PetscReal* lp = read_lats->ptr();
2006 for(
int i=0; i<read_lats->lsize(); i++)
2007 if(lp[i] < 0.0) lp[i] = param_globals::tend + 10.0;
2009 read_lats->release_ptr(lp);
2014 SF_real LATmin = read_lats->min();
2017 log_msg(0,3,0,
"LAT data is not complete. Skipping prepacing.");
2021 SF_real offset = floor(LATmin / param_globals::prepacing_bcl) * param_globals::prepacing_bcl;
2022 SF_real last_tm = param_globals::prepacing_bcl * param_globals::prepacing_beats;
2025 *read_lats += -offset;
2027 *read_lats += last_tm;
2030 SF_real *save_tm = read_lats->ptr();
2033 for (
int ii = 0; ii < miif->
N_IIF; ii++) {
2034 if (!miif->
N_Nodes[ii])
continue;
2039 sorted_save[kk].v1 = save_tm[miif->
NodeLists[ii][kk]];
2040 sorted_save[kk].v2 = kk;
2042 std::sort(sorted_save.
begin(), sorted_save.
end());
2044 size_t lastidx = sorted_save.
size() - 1;
2048 for (
double t = 0; t < sorted_save[lastidx].v1; t += param_globals::dt) {
2049 if (fmod(t, param_globals::prepacing_bcl) < param_globals::prepacing_stimdur &&
2050 t < param_globals::prepacing_bcl * param_globals::prepacing_beats - 1)
2051 miif->
ldata[ii][limpet::Vm][paced] += param_globals::prepacing_stimstr * param_globals::dt;
2056 miif->
ldata[ii][limpet::Vm][paced] -= miif->
ldata[ii][limpet::Iion][paced] * param_globals::dt;
2057 vm[miif->
NodeLists[ii][paced]] = miif->
ldata[ii][limpet::Vm][paced];
2059 while (csav < miif->N_Nodes[ii] - 1 && t >= sorted_save[csav].v1)
2064 while (csav < miif->N_Nodes[ii] - 1)
2070 read_lats->release_ptr(save_tm);
2079 if (!rcv.pts.size())
2085 log_msg(0,0,5,
"There seems to be no EP is defined. Phie recovery requires active EP! Aborting!");
2090 sf_mat & Ki = *elec->parab_solver.rhs_parab;
2096 vm.get_ownership_range(start, end);
2104 rcv.phie_rec->get_ownership_range(r_start, r_end);
2106 SF_real *ph_r = rcv.phie_rec->ptr();
2111 float minDist = 2. / param_globals::imp_region[0].cellSurfVolRatio;
2113 Ki.mult(vm, *rcv.Im);
2114 int numpts = rcv.pts.size() / 3;
2117 for (
int j=0; j<numpts; j++) {
2118 fpt = rcv.pts.data() + j*3;
2120 *rcv.dphi = *rcv.Im;
2121 SF_real* dp = rcv.dphi->ptr();
2123 for (
size_t i = 0; i<alg_nod.
size(); i++)
2127 cpt = imesh.xyz.data()+loc_nodal_idx*3;
2129 double r =
dist(fpt, cpt) + minDist;
2130 dp[loc_petsc_idx] /= r;
2133 rcv.dphi->release_ptr(dp);
2135 SF_real phi = rcv.dphi->sum() / 4. /
M_PI / rcv.gBath;
2136 if ( (j>=r_start) && (j<r_end) )
2137 ph_r[j-r_start] = phi;
2140 rcv.phie_rec->release_ptr(ph_r);
2148 log_msg(0,0,5,
"There seems to be no EP is defined. Phie recovery requires active EP! Aborting!");
2154 phie_recovery_data & phie_rcv = elec->phie_rcv;
2157 elec->output_manager.close_files_and_cleanup();
2161 igb_output_manager phie_rec_out;
2162 phie_rec_out.register_output(phie_rcv.phie_rec,
phie_recv_msh, 1,
2163 param_globals::phie_recovery_file,
"mV");
2177 if(vm_igb.
x() != vm->gsize()) {
2178 log_msg(0,4,0,
"%s error: Vm dimension does not fit to %s file. Aborting recovery! \n",
2179 __func__, param_globals::vofile);
2191 FILE* fd =
static_cast<FILE*
>(vm_igb.
fileptr());
2198 assert(petsc_to_canonical != NULL);
2201 for(
int i=0; i<num_io; i++) {
2203 size_t nread = vm->read_binary<
float>(fd);
2205 if(nread !=
size_t(vm->gsize())) {
2206 log_msg(0,3,0,
"%s warning: read incomplete data slice! Aborting!", __func__);
2212 bool forward =
false;
2213 (*petsc_to_canonical)(*vm, forward);
2218 phie_rec_out.write_data();
2221 phie_rec_out.close_files_and_cleanup();
2230 log_msg(0,0,5,
"There seems to be no EP is defined. Phie recovery requires active EP! Aborting!");
2238 const std::string basename = param_globals::phie_rec_ptf;
2254 data.gBath =
static_cast<elecMaterial*
>(intra_regions[0].material)->BathVal[0];
2263 assert(param_globals::bidomain ==
BIDOMAIN);
2288 stimuli.resize(param_globals::num_stim);
2290 for(
int i=0; i<param_globals::num_stim; i++) {
2310 if(param_globals::dump2MatLab) {
2311 std::string bsname = param_globals::dump_basename;
2315 fn = bsname +
"_Kie.bin";
2326 restr_e, param_globals::num_io_nodes > 0);
2327 if(param_globals::dataout_e)
2332 restr_i, param_globals::num_io_nodes > 0);
2333 if(param_globals::dataout_i)
2352 log_msg(0,0,0,
"Solving Laplace problem ..");
2358 log_msg(0,0,0,
"Done in %.5f seconds.", dur);
2381 if(sidx != -1)
stimuli[sidx].value(val);
2382 else val = std::nan(
"NaN");
2390 if(sidx != -1) s_unit =
stimuli[sidx].pulse.wave.f_unit;
2402 for(stimulus & s : stimuli) {
2403 if(
is_current(s.phys.type) && s.phys.total_current) {
2405 if (s.phys.type ==
I_ex) {
2414 float scale = 1.e12/vol;
2416 s.pulse.strength *= scale;
2419 "%s [Stimulus %d]: current density scaled to %.4g uA/cm^3\n",
2420 s.name.c_str(), s.idx, s.pulse.strength);
2422 else if (s.phys.type ==
I_tm) {
2428 if(alg_idx_map.
size() == 0) {
2431 alg_idx_map[n] = lidx;
2438 if(alg_idx_map.
count(n)) {
2442 surf = vol * miif->
IIF[r]->cgeom().SVratio * param_globals::imp_region[r].volFrac;
2448 surf =
get_global(surf, MPI_MAX, PETSC_COMM_WORLD);
2451 s.pulse.strength /= surf;
2453 "%s [Stimulus %d]: current density scaled to %.4g uA/cm^2\n",
2454 s.name.c_str(), s.idx, s.pulse.strength);
opencarp::local_index_t mesh_int_t
opencarp::real_t SF_real
Global scalar type.
opencarp::global_index_t SF_int
Global algebraic index type.
#define CALI_CXX_MARK_FUNCTION
virtual void mult(const abstract_vector< T, S > &x, abstract_vector< T, S > &b) const =0
virtual void scale(S s)=0
virtual void get_diagonal(abstract_vector< T, S > &vec) const =0
virtual void mult_LR(const abstract_vector< T, S > &L, const abstract_vector< T, S > &R)=0
virtual void init(T iNRows, T iNCols, T ilrows, T ilcols, T loc_offset, T mxent)
virtual void duplicate(const abstract_matrix< T, S > &M)=0
virtual void add_scaled_matrix(const abstract_matrix< T, S > &A, const S s, const bool same_nnz)=0
virtual void write(const char *filename) const =0
virtual void release_ptr(S *&p)=0
virtual void deep_copy(const abstract_vector< T, S > &v)=0
virtual void shallow_copy(const abstract_vector< T, S > &v)=0
virtual void add_scaled(const abstract_vector< T, S > &vec, S k)=0
virtual T lsize() const =0
virtual void set(const vector< T > &idx, const vector< S > &vals, const bool additive=false, const bool local=false)=0
const meshdata< mesh_int_t, mesh_real_t > * mesh
the connected mesh
T forward_map(T idx) const
Map one index from a to b.
overlapping_layout< T > pl
nodal parallel layout
vector< T > & get_numbering(SF_nbr nbr_type)
Get the vector defining a certain numbering.
Container for a PETSc VecScatter.
void forward(abstract_vector< T, S > &in, abstract_vector< T, S > &out, bool add=false)
Forward scattering.
void backward(abstract_vector< T, S > &in, abstract_vector< T, S > &out, bool add=false)
Backward scattering.
size_t size() const
The current size of the vector.
void resize(size_t n)
Resize a vector.
const T * end() const
Pointer to the vector's end.
const T * begin() const
Pointer to the vector's start.
T * data()
Pointer to the vector's start.
hm_int count(const K &key) const
Check if key exists.
void insert(InputIterator first, InputIterator last)
std::vector< IonIfBase * > IIF
array of IIF's
opencarp::sf_vec * gdata[NUM_IMP_DATA_TYPES]
data used by all IMPs
node_count_t numNode
local number of nodes
void dump_state(char *, float, opencarp::mesh_t gid, bool, unsigned int)
GlobalData_t *** ldata
data local to each IMP
int N_IIF
how many different IIF's
node_count_t * N_Nodes
#nodes for each IMP
node_index_t ** NodeLists
local partitioned node lists for each IMP stored
IIF_Mask_t * IIFmask
region for each node
int timer_idx
the timer index received from the timer manager
FILE_SPEC logger
The logger of the physic, each physic should have one.
SF::vector< stimulus > stimuli
the electrical stimuli
LAT_detector lat
the activation time detector
grid_t
An electrics grid identifier to distinguish between intra and extra grids.
phie_recovery_data phie_rcv
struct holding helper data for phie recovery
generic_timing_stats IO_stats
void destroy()
Currently we only need to close the file logger.
gvec_data gvec
datastruct holding global IMP state variable output
elliptic_solver ellip_solver
Solver for the elliptic bidomain equation.
MaterialType mtype[2]
the material types of intra_grid and extra_grid grids.
std::string timer_unit(const int timer_id)
figure out units of a signal linked to a given timer
parabolic_solver parab_solver
Solver for the parabolic bidomain equation.
double timer_val(const int timer_id)
figure out current value of a signal linked to a given timer
void initialize()
Initialize the Electrics.
igb_output_manager output_manager
class handling the igb output
SF::index_mapping< mesh_int_t > petsc_to_nodal
int check_quiescence(double tm, double dt)
check for quiescence
void output_initial_activations()
output one nodal vector of initial activation time
void init(sf_vec &vm, sf_vec &phie, int offset, enum physic_t=elec_phys)
initializes all datastructs after electric solver setup
int check_acts(double tm)
check activations at sim time tm
SF::vector< Activation > acts
LAT_detector()
constructor, sets up basic datastructs from global_params
SF::vector< stimulus > stimuli
the electrical stimuli
elliptic_solver ellip_solver
Solver for the elliptic bidomain equation.
double timer_val(const int timer_id)
figure out current value of a signal linked to a given timer
std::string timer_unit(const int timer_id)
figure out units of a signal linked to a given timer
MaterialType mtype[2]
the material types of intra_grid and extra_grid grids.
igb_output_manager output_manager
class handling the igb output
manager for dirichlet boundary conditions
void enforce_dbc_rhs(sf_vec &rhs)
void recompute_dbcs()
recompute the dbc data.
bool dbc_update()
check if dbcs have updated
sf_mat * phie_mat
lhs matrix to solve elliptic
void rebuild_stiffness(MaterialType *mtype, SF::vector< stimulus > &stimuli, FILE_SPEC logger)
void rebuild_matrices(MaterialType *mtype, SF::vector< stimulus > &stimuli, FILE_SPEC logger)
sf_vec * phie_i
phi_e on intracellular grid
void solve(sf_mat &Ki, sf_vec &Vmv, sf_vec &tmp_i)
sf_sol * lin_solver
petsc or ginkgo lin_solver
sf_mat * mass_e
mass matrix for RHS elliptic calc
double tol
CG stopping tolerance.
bool phie_mat_has_nullspace
sf_vec * currtmp
temp vector for phiesrc
dbc_manager * dbc
dbcs require a dbc manager
int max_it
maximum number of iterations
void rebuild_mass(FILE_SPEC logger)
void write_data()
write registered data to disk
void register_output_sync(sf_vec *inp_data, const mesh_t inp_meshid, const int dpn, const char *name, const char *units, const SF::vector< mesh_int_t > *idx=NULL, bool elem_data=false)
void close_files_and_cleanup()
close file descriptors
void register_output(sf_vec *inp_data, const mesh_t inp_meshid, const int dpn, const char *name, const char *units, const SF::vector< mesh_int_t > *idx=NULL, bool elem_data=false)
Register a data vector for output.
sf_vec * Ivol
global Vm vector
double tol
CG stopping tolerance.
sf_vec * Iact
global Vm vector
sf_vec * Diff_term
Diffusion current.
sf_mat * rhs_parab
rhs matrix to solve parabolic
sf_vec * kappa_i
scaling vector for intracellular mass matrix, M
void rebuild_matrices(MaterialType *mtype, limpet::MULTI_IF &miif, FILE_SPEC logger)
parabolic_t parab_tech
manner in which parabolic equations are solved
void solve(sf_vec &phie_i)
sf_vec * inv_mass_diag
inverse diagonal of mass matrix, for EXPLICIT solving
sf_mat * mass_i
lumped for parabolic problem
sf_vec * Ic
global Vm vector
sf_vec * tmp_i2
scratch vector for i-grid
int max_it
maximum number of iterations
sf_vec * tmp_i1
scratch vector for i-grid
sf_mat * lhs_parab
lhs matrix (CN) to solve parabolic
sf_vec * Vmv
global Vm vector
sf_vec * Irhs
weighted transmembrane currents
sf_vec * old_vm
older Vm needed for 2nd order dT
sf_sol * lin_solver
petsc or ginkgo lin_solver
sf_vec * IIon
ionic currents
SF::vector< mesh_int_t > vertices
bool total_current
whether we apply total current scaling
stim_t type
type of stimulus
int timer_id
timer for stimulus
waveform_t wform
wave form of stimulus
double strength
strength of stimulus
stim_protocol ptcl
applied stimulation protocol used
int idx
index in global input stimulus array
stim_electrode electrode
electrode geometry
stim_pulse pulse
stimulus wave form
void translate(int id)
convert legacy definitions to new format
void setup(int idx)
Setup from a param stimulus index.
stim_physics phys
physics of stimulus
bool value(double &v) const
Get the current value if the stimulus is active.
long d_time
current time instance index
double time_step
global reference time step
int add_eq_timer(double istart, double iend, int ntrig, double iintv, double idur, const char *iname, const char *poolname=nullptr)
Add a equidistant step timer to the array of timers.
int add_singlestep_timer(double tg, double idur, const char *iname, const char *poolname=nullptr)
long d_end
final index in multiples of dt
std::vector< base_timer * > timers
vector containing individual timers
Tissue level electrics, main Electrics physics class.
void init_solver(SF::abstract_linear_solver< T, S > **sol)
void compute_surface_mesh(const meshdata< T, S > &mesh, const SF_nbr numbering, const hashmap::unordered_set< T > &tags, meshdata< T, S > &surfmesh)
Compute the surface of a given mesh.
void read_points(const std::string basename, const MPI_Comm comm, vector< S > &pts, vector< T > &ptsidx)
Read the points and insert them into a list of meshes.
void make_global(const vector< T > &vec, vector< T > &out, MPI_Comm comm)
make a parallel vector global
void unique_resize(vector< T > &_P)
void assemble_matrix(abstract_matrix< T, S > &mat, meshdata< mesh_int_t, mesh_real_t > &domain, matrix_integrator< mesh_int_t, mesh_real_t > &integrator)
Generalized matrix assembly.
int max_nodal_edgecount(const meshdata< T, S > &mesh)
Compute the maximum number of node-to-node edges for a mesh.
void local_petsc_to_nodal_mapping(const meshdata< T, S > &mesh, index_mapping< T > &petsc_to_nodal)
T local_nodal_to_local_petsc(const meshdata< T, S > &mesh, int rank, T local_nodal)
void assemble_lumped_matrix(abstract_matrix< T, S > &mat, meshdata< mesh_int_t, mesh_real_t > &domain, matrix_integrator< mesh_int_t, mesh_real_t > &integrator)
bool is_init(const abstract_vector< T, S > *v)
void layout_from_count(const T count, vector< T > &layout, MPI_Comm comm)
void init_vector(SF::abstract_vector< T, S > **vec)
void binary_sort(vector< T > &_V)
void init_matrix(SF::abstract_matrix< T, S > **mat)
@ NBR_PETSC
PETSc numbering of nodes.
@ NBR_REF
The nodal numbering of the reference mesh (the one stored on HD).
@ NBR_SUBMESH
Submesh nodal numbering: The globally ascending sorted reference indices are reindexed.
void dup_IMP_node_state(IonIfBase &IF, node_index_t from, node_index_t to, GlobalData_t **localdata)
void dump_trace(MULTI_IF *MIIF, limpet::Real time)
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.
opencarp::local_index_t node_index_t
timer_manager * tm_manager
a manager for the various physics timers
bool using_legacy_stimuli
flag storing whether legacy stimuli are used
void get_kappa(sf_vec &kappa, IMPregion *ir, limpet::MULTI_IF &miif, double k)
compute the vector
void compute_IIF(limpet::IonIfBase &pIF, limpet::GlobalData_t **impdata, limpet::node_index_t n)
physic_t
Identifier for the different physics we want to set up.
int stimidx_from_timeridx(const SF::vector< stimulus > &stimuli, const int timer_id)
determine link between timer and stimulus
sf_vec * get_data(datavec_t d)
Retrieve a petsc data vector from the data registry.
SF::scattering * get_scattering(const int from, const int to, const SF::SF_nbr nbr, const int dpn)
Get a scattering from the global scatter registry.
void set_cond_type(MaterialType &m, cond_t type)
void sample_wave_form(stim_pulse &sp, int idx)
sample a signal given in analytic form
void read_el_scale_vec(const char *file, mesh_t mt, SF::vector< double > &el_scale, int &el_scale_dpn)
SF_real get_volume_from_nodes(sf_mat &mass, SF::vector< mesh_int_t > &local_idx)
sf_mesh & get_mesh(const mesh_t gt)
Get a mesh by specifying the gridID.
SF::scattering * register_scattering(const int from, const int to, const SF::SF_nbr nbr, const int dpn)
Register a scattering between to grids, or between algebraic and nodal representation of data on the ...
cond_t
description of electrical tissue properties
void print_act_log(FILE_SPEC logger, const SF::vector< Activation > &acts, int idx)
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.
void region_mask(mesh_t meshspec, SF::vector< RegionSpecs > ®spec, SF::vector< int > ®ionIDs, bool mask_elem, const char *reglist, bool warn_on_default_tags)
classify elements/points as belonging to a region
bool is_dbc(stim_t type)
whether stimulus is a dirichlet type. implies boundary conditions on matrix
SF::meshdata< mesh_int_t, mesh_real_t > sf_mesh
void compute_restr_idx_async(sf_mesh &mesh, SF::vector< mesh_int_t > &inp_idx, SF::vector< mesh_int_t > &idx)
void apply_stim_to_vector(const stimulus &s, sf_vec &vec, bool add)
void recover_phie_std(sf_vec &vm, phie_recovery_data &rcv)
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.
V dist(const vec3< V > &p1, const vec3< V > &p2)
void init_stim_info(void)
uses potential for stimulation
int output_all_activations(FILE_SPEC fp, int *ibuf, double *act_tbuf, int nlacts)
FILE_SPEC f_open(const char *fname, const char *mode)
Open a FILE_SPEC.
void savequit()
save state and quit simulator
bool have_dbc_stims(const SF::vector< stimulus > &stimuli)
return wheter any stimuli require dirichlet boundary conditions
SF::scattering * register_permutation(const int mesh_id, const int perm_id, const int dpn)
Register a permutation between two orderings for a mesh.
bool is_current(stim_t type)
uses current as stimulation
char * get_file_dir(const char *file)
void init_sv_gvec(gvec_data &GVs, limpet::MULTI_IF *miif, sf_vec &tmpl, igb_output_manager &output_manager)
void assemble_sv_gvec(gvec_data &gvecs, limpet::MULTI_IF *miif)
void constant_total_stimulus_current(SF::vector< stimulus > &stimuli, sf_mat &mass_i, sf_mat &mass_e, limpet::MULTI_IF *miif, FILE_SPEC logger)
Scales stimulus current to maintain constant total current across affected regions.
void intersect_output_restriction(SF::vector< mesh_int_t > *&restr, const SF::vector< mesh_int_t > &selected_idx)
Intersect an existing output restriction with another local index set.
int postproc_recover_phie()
char * dupstr(const char *old_str)
void balance_electrode(elliptic_solver &ellip, SF::vector< stimulus > &stimuli, int balance_from, int balance_to)
void set_elec_tissue_properties(MaterialType *mtype, Electrics::grid_t g, FILE_SPEC logger)
Fill the RegionSpec of an electrics grid with the associated inputs from the param parameters.
void compute_restr_idx(sf_mesh &mesh, SF::vector< mesh_int_t > &inp_idx, SF::vector< mesh_int_t > &idx)
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)
bool mesh_is_registered(const mesh_t gt)
check wheter a SF mesh is set
bool parse_gridout_tags(hashmap::unordered_set< int > &output_tags)
Parse the gridout_tags idset into a unique set of region IDs.
void validate_gridout_tags(hashmap::unordered_set< int > &output_tags, const SF::vector< mesh_t > &mesh_ids)
Warn about selected gridout tags that are absent from the relevant meshes.
void setup_phie_recovery_data(phie_recovery_data &data)
SF::abstract_vector< SF_int, SF_real > sf_vec
int get_size(MPI_Comm comm=PETSC_COMM_WORLD)
Basic_physic * get_physics(physic_t p, bool error_if_missing)
Convinience function to get a physics.
void setup_dataout(const int dataout, std::string dataout_vtx, mesh_t grid, SF::vector< mesh_int_t > *&restr, bool async, const hashmap::unordered_set< int > *output_tags)
const char * get_tsav_ext(double time)
SF::abstract_matrix< SF_int, SF_real > sf_mat
V timing(V &t2, const V &t1)
void read_indices(SF::vector< T > &idx, const std::string filename, const hashmap::unordered_map< mesh_int_t, mesh_int_t > &dd_map, MPI_Comm comm)
Read indices from a file.
void build_tagged_nodal_output_restriction(sf_mesh &mesh, const hashmap::unordered_set< int > &output_tags, SF::vector< mesh_int_t > &output_idx, bool async)
Build a local output-vector restriction from mesh element tags.
void update_cwd()
save the current working directory to curdir so that we can switch back to it if needed.
void f_close(FILE_SPEC &f)
Close a FILE_SPEC.
#define UM2_to_CM2
convert um^2 to cm^2
#define PETSC_TO_CANONICAL
Permute algebraic data from PETSC to canonical ordering.
#define ALG_TO_NODAL
Scatter algebraic to nodal.
Electrical stimulation functions.
SF_int niter
number of iterations
SF_real time
solver runtime
SF_int reason
number of iterations
std::string name
the solver name
virtual void setup_solver(abstract_matrix< T, S > &mat, double tol, int max_it, short norm, std::string name, bool has_nullspace, void *logger, const char *solver_opts_file, const char *default_opts)=0
description of materal properties in a mesh
SF::vector< RegionSpecs > regions
array with region params
SF::vector< double > el_scale
optionally provided per-element params scale
int el_scale_dpn
0=disabled, 1=isotropic scalar, 3=anisotropic (sl, st, sn) per element
region based variations of arbitrary material parameters
physMaterial * material
material parameter description
int nsubregs
#subregions forming this region
int * subregtags
FEM tags forming this region.
char * regname
name of region
bool activated
flag sentinel activation
int ID
ID of LAT detector used as sentinel.
double t_start
start of observation window
double t_window
duration of observation window
double t_quiesc
measure current duration of quiescence
double ExVal[3]
extracellular conductivity eigenvalues
cond_t g
rule to build conductivity tensor
double InVal[3]
intracellular conductivity eigenvalues
double BathVal[3]
bath conductivity eigenvalues
void log_stats(double tm, bool cflg)
void init_logger(const char *filename)
int calls
# calls for this interval, this is incremented externally
double tot_time
total time, this is incremented externally
void init_logger(const char *filename)
void log_stats(double tm, bool cflg)
void update_iter(const int curiter)
double slvtime
total solver time
sf_vec * phie_rec
The phie recovery output vector buffer.
SF::vector< mesh_real_t > pts
The phie recovery locations.
physMat_t material_type
ID of physics material.