27 #include "petsc_utils.h"
35 #include "caliper/cali.h"
52 logger =
f_open(
"electrics.log", param_globals::experiment != 4 ?
"w" :
"r");
67 if (param_globals::bidomain || param_globals::extracell_monodomain_stim) {
76 param_globals::dt, 0,
"elec::ref_dt",
"TS");
96 if(strlen(param_globals::phie_rec_ptf) > 0)
103 if (param_globals::prepacing_bcl > 0)
113 m->
regions.resize(param_globals::num_gregions);
116 log_msg(logger, 0, 0,
"Setting up %s tissue properties for %d regions ..", grid_name,
117 param_globals::num_gregions);
122 for (
size_t i=0; i<m->
regions.size(); i++, reg++) {
123 if(!strcmp(param_globals::gregion[i].name,
"")) {
124 snprintf(buf,
sizeof buf,
", gregion_%d",
int(i));
125 param_globals::gregion[i].name =
dupstr(buf);
128 reg->
regname = strdup(param_globals::gregion[i].name);
130 reg->
nsubregs = param_globals::gregion[i].num_IDs;
136 reg->
subregtags[j] = param_globals::gregion[i].ID[j];
138 log_msg(NULL,3,
ECHO,
"Warning: not all %u IDs provided for gregion[%u]!\n", reg->
nsubregs, i);
146 emat->
InVal[0] = param_globals::gregion[i].g_il;
147 emat->
InVal[1] = param_globals::gregion[i].g_it;
148 emat->
InVal[2] = param_globals::gregion[i].g_in;
150 emat->
ExVal[0] = param_globals::gregion[i].g_el;
151 emat->
ExVal[1] = param_globals::gregion[i].g_et;
152 emat->
ExVal[2] = param_globals::gregion[i].g_en;
154 emat->
BathVal[0] = param_globals::gregion[i].g_bath;
155 emat->
BathVal[1] = param_globals::gregion[i].g_bath;
156 emat->
BathVal[2] = param_globals::gregion[i].g_bath;
159 for (
int j=0; j<3; j++) {
160 emat->
InVal[j] *= 1e-3 * param_globals::gregion[i].g_mult;
161 emat->
ExVal[j] *= 1e-3 * param_globals::gregion[i].g_mult;
162 emat->
BathVal[j] *= 1e-3 * param_globals::gregion[i].g_mult;
169 const char* file = g ==
Electrics::intra_grid ? param_globals::gi_scale_vec : param_globals::ge_scale_vec;
175 void Electrics::setup_mappings()
185 log_msg(
logger, 0, 0,
"%s: Setting up intracellular algebraic-to-nodal scattering.", __func__);
189 log_msg(
logger, 0, 0,
"%s: Setting up intracellular PETSc to canonical permutation.", __func__);
195 log_msg(
logger, 0, 0,
"%s: Setting up extracellular algebraic-to-nodal scattering.", __func__);
197 log_msg(
logger, 0, 0,
"%s: Setting up extracellular PETSc to canonical permutation.", __func__);
199 log_msg(
logger, 0, 0,
"%s: Setting up intra-to-extra scattering.", __func__);
203 bool check_i2e =
false;
204 if(check_i2e && extra_exists) {
222 SF_real*
id = intra_testvec->ptr();
223 for(
size_t i=0; i<intra_alg_nod.
size(); i++) {
225 id[lpidx] = intra_ref_nbr[intra_alg_nod[i]];
227 intra_testvec->release_ptr(
id);
229 SF_real* ed = extra_testvec->ptr();
230 for(
size_t i=0; i<extra_alg_nod.
size(); i++) {
232 ed[lpidx] = extra_ref_nbr[extra_alg_nod[i]];
234 extra_testvec->release_ptr(ed);
236 i2e_testvec->set(-1.0);
237 i2e.
forward(*intra_testvec, *i2e_testvec);
240 for(
size_t i=0; i<extra_alg_nod.
size(); i++) {
241 auto id = i2e_testvec->get(i);
242 auto ed = extra_testvec->get(i);
243 if(
id > -1 &&
id != ed)
248 log_msg(0,5,0,
"Electrics mapping test failed!");
250 log_msg(0,5,0,
"Electrics mapping test succeeded!");
275 stimulate_extracellular();
277 if(param_globals::bidomain ==
BIDOMAIN)
285 stimulate_intracellular();
288 if(param_globals::dump_data &
DUMP_IC)
299 if(param_globals::bidomain ==
BIDOMAIN)
329 if(param_globals::bidomain && (param_globals::dump_data &
DUMP_IACT)) {
333 if(param_globals::dump_data &
DUMP_IC) {
336 if (time <= time_step) {
338 Ic[i] = (Vmv[i] - Vmv[i]) / (-time_step);
342 Ic[i] = (Ic[i] - Vmv[i]) / (-time_step);
357 double curtime =
timing(t2, t1);
388 log_msg( NULL, 0, 0,
"Balancing stimulus %d with %d %s-wise.",balance_from, balance_to,
389 is_current(stimuli[balance_from].phys.type) ?
"current" :
"voltage" );
391 stimulus & from = stimuli[balance_from];
392 stimulus & to = stimuli[balance_to];
414 void Electrics::balance_electrodes()
416 for(
int i=0; i<param_globals::num_stim; i++) {
417 if(param_globals::stim[i].crct.balance != -1) {
418 int from = param_globals::stim[i].crct.balance;
426 void Electrics::setup_stimuli()
431 stimuli.resize(param_globals::num_stim);
432 for(
int i=0; i<param_globals::num_stim; i++)
442 if (s.electrode.dump_vtx)
445 if(param_globals::stim[i].pulse.dumpTrace &&
get_rank() == 0) {
447 s.pulse.wave.write_trace(s.name+
".trc");
454 double val; s.
value(val);
458 for (
size_t i = 0; i < idx.
size(); i++) {
461 vec.
set(local_idx, val, add,
true);
464 void Electrics::stimulate_intracellular()
475 if(param_globals::operator_splitting) {
486 *ps.tmp_i1 = *ps.IIon;
487 *ps.tmp_i1 -= *ps.Irhs;
492 ps.mass_i->mult(*ps.tmp_i1, *ps.Irhs);
494 *ps.Irhs = *ps.tmp_i1;
502 if(illum_vec == NULL) {
503 log_msg(0,5,0,
"Cannot apply illumination stim: global vector not present!");
518 void Electrics::clamp_Vm() {
520 if(s.phys.type ==
Vm_clmp && s.is_active())
525 void Electrics::stimulate_extracellular()
527 if(param_globals::bidomain) {
532 if(dbcs_have_updated && time_not_final)
537 for(
const stimulus & s :
stimuli) {
538 if(s.is_active() && s.phys.type ==
I_ex)
556 for(
int pid=0; pid < mpi_size; pid++) {
557 if(mpi_rank == pid) {
559 buffsize = sndbuff.
size();
562 MPI_Bcast(&buffsize,
sizeof(
size_t), MPI_BYTE, pid, PETSC_COMM_WORLD);
564 MPI_Bcast(sndbuff.
data(), buffsize*
sizeof(
mesh_int_t), MPI_BYTE, pid, PETSC_COMM_WORLD);
566 mesh_int_t start = layout[mpi_rank], stop = layout[mpi_rank+1];
569 if(i >= start && i < stop)
593 for(
int pid=0; pid < mpi_size; pid++) {
594 if(mpi_rank == pid) {
596 buffsize = sndbuff.
size();
599 MPI_Bcast(&buffsize,
sizeof(
size_t), MPI_BYTE, pid, PETSC_COMM_WORLD);
601 MPI_Bcast(sndbuff.
data(), buffsize*
sizeof(
mesh_int_t), MPI_BYTE, pid, PETSC_COMM_WORLD);
673 void Electrics::setup_output()
681 restr_i, param_globals::num_io_nodes > 0);
683 if(param_globals::dataout_i)
686 if(param_globals::bidomain) {
688 restr_e, param_globals::num_io_nodes > 0);
690 if(param_globals::dataout_i)
692 if(param_globals::dataout_e)
696 if(param_globals::dump_data &
DUMP_IC) {
711 if(param_globals::num_trace) {
713 open_trace(
ion.
miif, param_globals::num_trace, param_globals::trace_node, NULL, &imesh);
720 void Electrics::dump_matrices()
722 std::string bsname = param_globals::dump_basename;
728 if ( param_globals::parab_solve==1 ) {
730 fn = bsname +
"_Ki_CN.bin";
733 fn = bsname +
"_Ki.bin";
736 fn = bsname +
"_Mi.bin";
739 if ( param_globals::bidomain ) {
740 fn = bsname +
"_Kie.bin";
743 fn = bsname +
"_Me.bin";
760 val = std::nan(
"NaN");
774 s_unit =
stimuli[sidx].pulse.wave.f_unit;
787 for(
size_t i = 0; i<stimuli.
size(); i++)
811 double* reg_kappa =
new double[miif.
N_IIF];
813 for(
int i=0; i<miif.
N_IIF; i++)
814 reg_kappa[i] = k * miif.
IIF[i]->cgeom().SVratio * ir[i].volFrac;
816 double *kd = kappa.
ptr();
818 for(
int i = 0; i < miif.
numNode; i++)
819 kd[i] = reg_kappa[(
int) miif.
IIFmask[i]];
835 for(
size_t i=0; i < m.
regions.size(); i++) {
841 void Electrics::setup_solvers()
847 if (param_globals::bidomain) {
852 if(param_globals::dump2MatLab)
868 double min_diff = 1e100;
870 for(
int i=0; i<param_globals::num_tsav; i++)
872 double diff = fabs(param_globals::tsav[i] - time);
873 if(min_diff > diff) {
882 return param_globals::tsav_ext[min_idx];
885 void Electrics::checkpointing()
894 snprintf(save_fnm,
sizeof save_fnm,
"%s.%s.roe", param_globals::write_statef, tsav_ext);
902 snprintf(save_fnm,
sizeof save_fnm,
"checkpoint.%.1f.roe", tm.time);
937 mass_e ->
init(extra_mesh, dpn, dpn, param_globals::mass_lumping ? 1 : max_row_entries);
959 int log_flag = param_globals::output_level > 1 ?
ECHO : 0;
980 log_msg(logger,0,log_flag,
"Computed ellipitc stiffness matrix in %.3f seconds.", dur);
984 log_msg(logger,0,log_flag,
"Elliptic lhs matrix enforcing Dirichlet boundaries.");
995 log_msg(logger,0,log_flag,
"Elliptic lhs matrix Dirichlet enforcing done in %.3f seconds.", dur);
998 log_msg(logger,1,
ECHO,
"Elliptic lhs matrix is singular!");
1007 setup_linear_solver(logger);
1010 log_msg(logger,0,log_flag,
"Initializing elliptic solver in %.5f seconds.", dur);
1017 int log_flag = param_globals::output_level > 1 ?
ECHO : 0;
1026 if(param_globals::mass_lumping) {
1033 log_msg(logger,0,log_flag,
"Computed elliptic mass matrix in %.3f seconds.", dur);
1036 void elliptic_solver::setup_linear_solver(
FILE_SPEC logger)
1040 tol = param_globals::cg_tol_ellip;
1041 max_it = param_globals::cg_maxit_ellip;
1043 std::string default_opts;
1044 std::string solver_file;
1045 solver_file = param_globals::ellip_options_file;
1046 if (param_globals::flavor == std::string(
"ginkgo")) {
1047 default_opts = std::string(
1049 "type": "solver::Cg",
1052 "type": "Iteration",
1056 "type": "ResidualNorm",
1057 "reduction_factor": 1e-4
1061 "type": "solver::Multigrid",
1064 "type": "multigrid::Pgm",
1065 "deterministic": true
1070 "type": "Iteration",
1074 "coarsest_solver": {
1075 "type": "preconditioner::Schwarz",
1077 "type": "preconditioner::Ilu"
1081 "min_coarse_rows": 8,
1082 "default_initial_guess": "zero"
1085 } else if (param_globals::flavor == std::string(
"petsc")) {
1086 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");
1091 logger, solver_file.c_str(), default_opts.c_str());
1105 Ki.mult(Vmv, tmp_i);
1117 auto dur =
timing(t1, t0);
1143 auto dur =
timing(t1, t0);
1175 if(!(vm_ptr != NULL && iion_ptr != NULL)) {
1176 log_msg(0,5,0,
"%s error: global Vm and Iion vectors not properly set up! Ionics seem invalid! Aborting!",
1202 if(!param_globals::operator_splitting)
1213 mass_i ->
init(intra_mesh, dpn, dpn, param_globals::mass_lumping ? 1 : max_row_entries);
1222 double start, end, period;
1228 int log_flag = param_globals::output_level > 1 ?
ECHO : 0;
1237 if( (param_globals::bidomain ==
MONODOMAIN && param_globals::bidm_eqv_mono) ||
1252 log_msg(logger,0,log_flag,
"Computed parabolic stiffness matrix in %.3f seconds.", dur);
1255 if(param_globals::mass_lumping)
1264 log_msg(logger,0,log_flag,
"Computed parabolic mass matrix in %.3f seconds.", dur);
1272 bool same_nonzero = param_globals::mass_lumping ==
false;
1302 setup_linear_solver(logger);
1305 log_msg(logger,0,log_flag,
"Initializing parabolic solver in %.5f seconds.", dur);
1308 period =
timing(end, start);
1311 void parabolic_solver::setup_linear_solver(
FILE_SPEC logger)
1314 tol = param_globals::cg_tol_parab;
1315 max_it = param_globals::cg_maxit_parab;
1317 std::string default_opts;
1318 std::string solver_file;
1319 solver_file = param_globals::parab_options_file;
1320 if (param_globals::flavor == std::string(
"ginkgo")) {
1321 default_opts = std::string(
1324 "type": "solver::Cg",
1327 "type": "Iteration",
1331 "type": "ResidualNorm",
1332 "reduction_factor": 1e-4
1336 "type": "preconditioner::Schwarz",
1338 "type": "preconditioner::Ilu"
1343 } else if (param_globals::flavor == std::string(
"petsc")) {
1344 default_opts = std::string(
"-pc_type bjacobi -sub_pc_type ilu -ksp_type cg");
1348 "parabolic PDE",
false, logger, solver_file.c_str(),
1349 default_opts.c_str());
1356 case CN: solve_CN(phie_i);
break;
1357 case O2dT: solve_O2dT(phie_i);
break;
1358 default: solve_EF(phie_i);
break;
1362 void parabolic_solver::solve_CN(
sf_vec & phie_i)
1367 if (param_globals::bidomain ==
BIDOMAIN) {
1374 *
tmp_i2 *= 1.0 - param_globals::theta;
1381 if(!param_globals::operator_splitting)
1395 auto dur =
timing(t1, t0);
1401 void parabolic_solver::solve_O2dT(
sf_vec & phie_i)
1406 if (param_globals::bidomain ==
BIDOMAIN) {
1433 void parabolic_solver::solve_EF(
sf_vec & phie_i)
1440 if (param_globals::bidomain ==
BIDOMAIN) {
1452 if(param_globals::operator_splitting ==
false)
1461 char* prvSimDir = strlen(param_globals::start_statef) ?
1464 const char* extn =
".dat";
1467 int addLATs = param_globals::compute_APD ? 2 : 0;
1469 bool have_sentinel = param_globals::t_sentinel > 0.0;
1470 bool need_to_add_sentinel = have_sentinel && (param_globals::sentinel_ID < 0);
1472 addLATs += need_to_add_sentinel ? 1 : 0;
1473 acts.resize(param_globals::num_LATs + addLATs);
1476 for (
int i = 0; i < param_globals::num_LATs; i++ )
1479 if (param_globals::lats[i].method <= 0 || (param_globals::lats[i].measurand ==
PHIE && !param_globals::bidomain)) {
1480 log_msg(NULL, 3, 0,
"Phie-based LAT measurement requires bidomain >=1 Ignoring lats[%d].", i);
1485 acts[j].threshold = param_globals::lats[i].threshold;
1486 acts[j].mode = param_globals::lats[i].mode;
1487 acts[j].all = param_globals::lats[i].all;
1488 acts[j].measurand = (
PotType)param_globals::lats[i].measurand;
1489 acts[j].ID = param_globals::lats[i].ID;
1490 acts[j].fout = NULL;
1492 if(param_globals::lats[i].all) {
1493 acts[j].fname = (
char*) malloc((strlen(param_globals::lats[i].ID)+strlen(extn)+1)*
sizeof(
char));
1494 snprintf(
acts[j].fname, strlen(param_globals::lats[i].ID)+strlen(extn)+1,
"%s%s", param_globals::lats[i].ID, extn);
1497 char prfx[] =
"init_acts_";
1498 int max_len = strlen(prfx) + strlen(param_globals::lats[i].ID) + strlen(extn) + 1;
1500 acts[j].fname = (
char*) malloc(max_len*
sizeof(
char));
1501 snprintf(
acts[j].fname, max_len,
"%s%s%s", prfx, param_globals::lats[i].ID, extn);
1505 if(prvSimDir != NULL) {
1506 int len_fname = strlen(prvSimDir)+strlen(
acts[j].fname)+2;
1507 acts[j].prv_fname = (
char*) malloc(len_fname*
sizeof(
char));
1508 snprintf(
acts[j].prv_fname, len_fname,
"%s/%s", prvSimDir,
acts[j].fname);
1514 if(param_globals::compute_APD) {
1516 acts[j].threshold = param_globals::actthresh;
1521 acts[j].fout = NULL;
1526 acts[j].threshold = param_globals::recovery_thresh;
1532 acts[j].fname =
dupstr(
"vm_repolarisation.dat");
1542 sntl.
ID = param_globals::sentinel_ID;
1544 if(need_to_add_sentinel) {
1547 acts[j].threshold = param_globals::actthresh;
1552 acts[j].fout = NULL;
1559 if(prvSimDir) free(prvSimDir);
1564 const Activation & act = acts[idx];
1567 log_msg(logger, 0, 0,
"LAT detector [%2d]", idx);
1568 log_msg(logger, 0, 0,
"-----------------\n");
1570 log_msg(logger, 0, 0,
"Measurand: %s", act.measurand ?
"Phie" :
"Vm");
1571 log_msg(logger, 0, 0,
"All: %s", act.all ?
"All" :
"Only first");
1572 log_msg(logger, 0, 0,
"Method: %s", act.method==
ACT_DT ?
"Derivative" :
"Threshold crossing");
1574 char buf[64], gt[2], sgn[2];
1575 snprintf(sgn,
sizeof sgn,
"%s", act.mode?
"-":
"+");
1576 snprintf(gt,
sizeof gt,
"%s", act.mode?
"<":
">");
1579 snprintf(buf,
sizeof buf,
"Maximum %sdf/dt %s %.2f mV", sgn, gt, act.threshold);
1581 snprintf(buf,
sizeof buf,
"Intersection %sdf/dt with %.2f", sgn, act.threshold);
1583 log_msg(logger, 0, 0,
"Mode: %s", buf);
1584 log_msg(logger, 0, 0,
"Threshold: %.2f mV\n", act.threshold);
1590 log_msg(0,0,5,
"There seems to be no EP is defined. LAT detector requires active EP! Aborting LAT setup!");
1599 for(
size_t i = 0; i <
acts.size(); ++i) {
1602 acts[i].phi->shallow_copy(!
acts[i].measurand ? vm : phie);
1603 acts[i].offset = offset;
1613 log_msg(NULL,2,0,
"Detection of -df/dt|max not implemented, +df/dt|max will be detected.");
1617 acts[i].ibuf = (
int *)malloc(
acts[i].phi->lsize()*
sizeof(int));
1618 acts[i].actbuf = (
double *)malloc(
acts[i].phi->lsize()*
sizeof(double));
1622 acts[i].tm->set(-1.);
1625 if(
acts[i].prv_fname != NULL) {
1627 size_t nread =
acts[i].tm->read_ascii(
acts[i].prv_fname);
1631 log_msg(NULL,2,
ECHO,
"Warning: Initialization of LAT[%2d] failed.", i);
1636 (*sc)(*
acts[i].tm,
false);
1643 if(
acts[i].prv_fname!=NULL) {
1647 log_msg(NULL,2,0,
"Copying over of previous activation file not implemented.\n");
f_close(in);
1650 log_msg(NULL,3,0,
"Warning: Initialization in %s - \n"
1651 "Failed to read activation file %s.\n", __func__,
acts[i].prv_fname);
1672 for (
int i=0; i<nlacts; i++)
1673 fprintf(fp->fd,
"%d\t%.6f\n", ibuf[i], act_tbuf[i]);
1680 for (
int j=1; j<numProc; j++) {
1683 MPI_Recv(&acts, 1, MPI_INT, j, 110, PETSC_COMM_WORLD, &status);
1689 MPI_Recv(buf_inds.
data(), acts, MPI_INT, j, 110, PETSC_COMM_WORLD, &status);
1690 MPI_Recv(buf_acts.
data(), acts, MPI_DOUBLE, j, 110, PETSC_COMM_WORLD, &status);
1692 for(
int ii=0; ii<acts; ii++)
1693 fprintf(fp->fd,
"%d\t%.6f\n", buf_inds[ii], buf_acts[ii]);
1701 MPI_Send(&nlacts, 1, MPI_INT, 0, 110, PETSC_COMM_WORLD);
1703 MPI_Send(ibuf, nlacts, MPI_INT, 0, 110, PETSC_COMM_WORLD);
1704 MPI_Send(act_tbuf, nlacts, MPI_DOUBLE, 0, 110, PETSC_COMM_WORLD);
1708 MPI_Bcast(&gacts, 1, MPI_INT, 0, PETSC_COMM_WORLD);
1720 switch (aptr->method) {
1722 lacts = check_cross_threshold(*aptr->phi, *aptr->phip, tm,
1723 aptr->ibuf, aptr->actbuf, aptr->threshold, aptr->mode);
1727 lacts = check_mx_derivative (*aptr->phi, *aptr->phip, tm,
1728 aptr->ibuf, aptr->actbuf, *aptr->dvp0, *aptr->dvp1,
1729 aptr->threshold, aptr->mode);
1737 a = aptr->tm->ptr();
1741 for(
int j=0; j<lacts; j++) {
1744 aptr->ibuf[j] = canon_nbr[nodal_idx] + aptr->offset;
1747 if(a[aptr->ibuf[j]] == -1)
1748 a[aptr->ibuf[j]] = aptr->actbuf[j];
1755 aptr->tm->release_ptr(a);
1757 MPI_Allreduce(MPI_IN_PLACE, &lacts, 1, MPI_INT, MPI_SUM, PETSC_COMM_WORLD);
1760 aptr->nacts = nacts;
1769 static int savequitFlag = 0;
1770 int numNodesActivated = -1;
1775 log_msg(0,0,
ECHO |
NONL,
"================================================================================================\n");
1776 log_msg(0,0,
ECHO |
NONL,
"%s() WARNING: simulation is configured to savequit() after %.2f ms of quiescence\n", __func__,
sntl.
t_window);
1777 log_msg(0,0,
ECHO |
NONL,
"================================================================================================\n");
1795 return numNodesActivated;
1801 int LAT_detector::check_cross_threshold(
sf_vec & vm,
sf_vec & vmp,
double tm,
1802 int *ibuf,
double *actbuf,
float threshold,
int mode)
1806 int lsize = vm.lsize();
1807 int nacts = 0, gnacts = 0;
1809 for (
int i=0; i<lsize; i++) {
1811 bool triggered =
false;
1813 triggered = p[i] <= threshold && c[i] > threshold; }
1815 triggered = p[i] >= threshold && c[i] < threshold;
1820 double tact = tm - param_globals::dt + (threshold-p[i])/(c[i]-p[i])*sgn*param_globals::dt;
1822 actbuf[nacts] = tact;
1833 int LAT_detector::check_mx_derivative(
sf_vec & vm,
sf_vec & vmp,
double tm,
1834 int *ibuf,
double *actbuf,
sf_vec & dvp0,
sf_vec & dvp1,
1835 float threshold,
int mode)
1837 int nacts = 0, gnacts = 0;
1838 double tact, dt2 = 2 * param_globals::dt;
1839 int lsize = vm.lsize();
1848 for (
int i=0; i<lsize; i++ ) {
1850 dvdt = dv/param_globals::dt;
1851 ddv0 = pd1[i]-pd0[i];
1854 if (dvdt>=threshold && ddv0>0 && ddv1<0) {
1855 tact = tm-dt2+(ddv0/(ddv0-ddv1))*param_globals::dt;
1857 actbuf[nacts] = tact;
1866 vmp .release_ptr(p);
1867 dvp0.release_ptr(pd0);
1868 dvp1.release_ptr(pd1);
1881 bool forward =
true;
1883 for (
size_t i = 0; i <
acts.size(); i++) {
1885 (*sc)(*
acts[i].tm, forward);
1886 acts[i].tm->write_ascii(
acts[i].fname,
false);
1891 void Electrics::prepace() {
1892 log_msg(NULL, 0, 0,
"Using activation times from file %s to distribute prepacing states\n",
1893 param_globals::prepacing_lats);
1894 log_msg(NULL, 0, 0,
"Assuming stimulus strength %f uA/uF with duration %f ms for prepacing\n",
1895 param_globals::prepacing_stimstr, param_globals::prepacing_stimdur);
1904 size_t numread = read_lats->read_ascii(param_globals::prepacing_lats);
1906 log_msg(NULL, 5, 0,
"Failed reading required LATs! Skipping prepacing!");
1915 bool forward =
false;
1916 (*sc)(*read_lats, forward);
1920 PetscReal* lp = read_lats->ptr();
1921 for(
int i=0; i<read_lats->lsize(); i++)
1922 if(lp[i] < 0.0) lp[i] = param_globals::tend + 10.0;
1924 read_lats->release_ptr(lp);
1929 SF_real LATmin = read_lats->min();
1932 log_msg(0,3,0,
"LAT data is not complete. Skipping prepacing.");
1936 SF_real offset = floor(LATmin / param_globals::prepacing_bcl) * param_globals::prepacing_bcl;
1937 SF_real last_tm = param_globals::prepacing_bcl * param_globals::prepacing_beats;
1940 *read_lats += -offset;
1942 *read_lats += last_tm;
1945 SF_real *save_tm = read_lats->ptr();
1948 for (
int ii = 0; ii < miif->
N_IIF; ii++) {
1949 if (!miif->
N_Nodes[ii])
continue;
1953 for (
int kk = 0; kk < miif->
N_Nodes[ii]; kk++) {
1954 sorted_save[kk].v1 = save_tm[miif->
NodeLists[ii][kk]];
1955 sorted_save[kk].v2 = kk;
1957 std::sort(sorted_save.
begin(), sorted_save.
end());
1959 size_t lastidx = sorted_save.
size() - 1;
1960 int paced = sorted_save[lastidx].v2;
1963 for (
double t = 0; t < sorted_save[lastidx].v1; t += param_globals::dt) {
1964 if (fmod(t, param_globals::prepacing_bcl) < param_globals::prepacing_stimdur &&
1965 t < param_globals::prepacing_bcl * param_globals::prepacing_beats - 1)
1966 miif->
ldata[ii][limpet::Vm][paced] += param_globals::prepacing_stimstr * param_globals::dt;
1971 miif->
ldata[ii][limpet::Vm][paced] -= miif->
ldata[ii][limpet::Iion][paced] * param_globals::dt;
1972 vm[miif->
NodeLists[ii][paced]] = miif->
ldata[ii][limpet::Vm][paced];
1974 while (csav < miif->N_Nodes[ii] - 1 && t >= sorted_save[csav].v1)
1979 while (csav < miif->N_Nodes[ii] - 1)
1982 for (
int k = 0; k < miif->
N_Nodes[ii]; k++) vm[miif->
NodeLists[ii][k]] = miif->
ldata[ii][limpet::Vm][k];
1985 read_lats->release_ptr(save_tm);
1994 if (!rcv.pts.size())
2000 log_msg(0,0,5,
"There seems to be no EP is defined. Phie recovery requires active EP! Aborting!");
2005 sf_mat & Ki = *elec->parab_solver.rhs_parab;
2011 vm.get_ownership_range(start, end);
2019 rcv.phie_rec->get_ownership_range(r_start, r_end);
2021 SF_real *ph_r = rcv.phie_rec->ptr();
2026 float minDist = 2. / param_globals::imp_region[0].cellSurfVolRatio;
2028 Ki.mult(vm, *rcv.Im);
2029 int numpts = rcv.pts.size() / 3;
2032 for (
int j=0; j<numpts; j++) {
2033 fpt = rcv.pts.data() + j*3;
2035 *rcv.dphi = *rcv.Im;
2036 SF_real* dp = rcv.dphi->ptr();
2038 for (
size_t i = 0; i<alg_nod.
size(); i++)
2042 cpt = imesh.xyz.data()+loc_nodal_idx*3;
2044 double r =
dist(fpt, cpt) + minDist;
2045 dp[loc_petsc_idx] /= r;
2048 rcv.dphi->release_ptr(dp);
2050 SF_real phi = rcv.dphi->sum() / 4. /
M_PI / rcv.gBath;
2051 if ( (j>=r_start) && (j<r_end) )
2052 ph_r[j-r_start] = phi;
2055 rcv.phie_rec->release_ptr(ph_r);
2063 log_msg(0,0,5,
"There seems to be no EP is defined. Phie recovery requires active EP! Aborting!");
2069 phie_recovery_data & phie_rcv = elec->phie_rcv;
2072 elec->output_manager.close_files_and_cleanup();
2076 igb_output_manager phie_rec_out;
2077 phie_rec_out.register_output(phie_rcv.phie_rec,
phie_recv_msh, 1,
2078 param_globals::phie_recovery_file,
"mV");
2092 if(vm_igb.
x() != vm->gsize()) {
2093 log_msg(0,4,0,
"%s error: Vm dimension does not fit to %s file. Aborting recovery! \n",
2094 __func__, param_globals::vofile);
2106 FILE* fd =
static_cast<FILE*
>(vm_igb.
fileptr());
2113 assert(petsc_to_canonical != NULL);
2116 for(
int i=0; i<num_io; i++) {
2117 log_msg(0,0,0,
"Step %d / %d", i+1, num_io);
2118 size_t nread = vm->read_binary<
float>(fd);
2120 if(nread !=
size_t(vm->gsize())) {
2121 log_msg(0,3,0,
"%s warning: read incomplete data slice! Aborting!", __func__);
2127 bool forward =
false;
2128 (*petsc_to_canonical)(*vm, forward);
2133 phie_rec_out.write_data();
2136 phie_rec_out.close_files_and_cleanup();
2145 log_msg(0,0,5,
"There seems to be no EP is defined. Phie recovery requires active EP! Aborting!");
2153 const std::string basename = param_globals::phie_rec_ptf;
2169 data.gBath =
static_cast<elecMaterial*
>(intra_regions[0].material)->BathVal[0];
2177 assert(param_globals::bidomain ==
BIDOMAIN);
2202 stimuli.resize(param_globals::num_stim);
2204 for(
int i=0; i<param_globals::num_stim; i++) {
2224 if(param_globals::dump2MatLab) {
2225 std::string bsname = param_globals::dump_basename;
2229 fn = bsname +
"_Kie.bin";
2240 restr_e, param_globals::num_io_nodes > 0);
2241 if(param_globals::dataout_e)
2246 restr_i, param_globals::num_io_nodes > 0);
2247 if(param_globals::dataout_i)
2266 log_msg(0,0,0,
"Solving Laplace problem ..");
2272 log_msg(0,0,0,
"Done in %.5f seconds.", dur);
2295 if(sidx != -1)
stimuli[sidx].value(val);
2296 else val = std::nan(
"NaN");
2304 if(sidx != -1) s_unit =
stimuli[sidx].pulse.wave.f_unit;
2316 for(stimulus & s : stimuli) {
2317 if(
is_current(s.phys.type) && s.phys.total_current) {
2319 if (s.phys.type ==
I_ex) {
2328 float scale = 1.e12/vol;
2330 s.pulse.strength *= scale;
2333 "%s [Stimulus %d]: current density scaled to %.4g uA/cm^3\n",
2334 s.name.c_str(), s.idx, s.pulse.strength);
2336 else if (s.phys.type ==
I_tm) {
2342 if(alg_idx_map.
size() == 0) {
2345 alg_idx_map[n] = lidx;
2352 if(alg_idx_map.
count(n)) {
2356 surf = vol * miif->
IIF[r]->cgeom().SVratio * param_globals::imp_region[r].volFrac;
2362 surf =
get_global(surf, MPI_MAX, PETSC_COMM_WORLD);
2365 s.pulse.strength /= surf;
2367 "%s [Stimulus %d]: current density scaled to %.4g uA/cm^2\n",
2368 s.name.c_str(), s.idx, s.pulse.strength);
double SF_real
Use the general double as real type.
std::int32_t SF_int
Use the general std::int32_t as int 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.
int numNode
local number of nodes
std::vector< IonIfBase * > IIF
array of IIF's
opencarp::sf_vec * gdata[NUM_IMP_DATA_TYPES]
data used by all IMPs
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
int * N_Nodes
#nodes for each IMP
int ** 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, int from, int 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.
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
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.
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 region_mask(mesh_t meshspec, SF::vector< RegionSpecs > ®spec, SF::vector< int > ®ionIDs, bool mask_elem, const char *reglist)
classify elements/points as belonging to a region
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
void setup_dataout(const int dataout, std::string dataout_vtx, mesh_t grid, SF::vector< mesh_int_t > *&restr, bool async)
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.
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
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.
const char * get_tsav_ext(double time)
SF::abstract_matrix< SF_int, SF_real > sf_mat
void compute_IIF(limpet::IonIfBase &pIF, limpet::GlobalData_t **impdata, int n)
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 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
event detection data structures
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.