29 #include "petsc_utils.h" 46 logger =
f_open(
"eikonal.log", param_globals::experiment != 4 ?
"w" :
"r");
70 param_globals::dt, 0,
"elec::ref_dt",
"TS");
93 if (param_globals::prepacing_bcl > 0)
104 m->
regions.resize(param_globals::num_gregions);
107 log_msg(logger, 0, 0,
"Setting up %s tissue poperties for %d regions ..", grid_name,
108 param_globals::num_gregions);
113 for (
size_t i = 0; i < m->
regions.size(); i++, reg++) {
114 if (!strcmp(param_globals::gregion[i].
name,
"")) {
115 snprintf(buf,
sizeof buf,
", gregion_%d",
int(i));
116 param_globals::gregion[i].name =
dupstr(buf);
119 reg->
regname = strdup(param_globals::gregion[i].name);
121 reg->
nsubregs = param_globals::gregion[i].num_IDs;
127 for (
int j = 0; j < reg->
nsubregs; j++)
128 reg->
subregtags[j] = param_globals::gregion[i].ID[j];
135 emat->
InVal[0] = param_globals::gregion[i].g_il;
136 emat->
InVal[1] = param_globals::gregion[i].g_it;
137 emat->
InVal[2] = param_globals::gregion[i].g_in;
139 emat->
ExVal[0] = param_globals::gregion[i].g_el;
140 emat->
ExVal[1] = param_globals::gregion[i].g_et;
141 emat->
ExVal[2] = param_globals::gregion[i].g_en;
143 emat->
BathVal[0] = param_globals::gregion[i].g_bath;
144 emat->
BathVal[1] = param_globals::gregion[i].g_bath;
145 emat->
BathVal[2] = param_globals::gregion[i].g_bath;
148 for (
int j = 0; j < 3; j++) {
149 emat->
InVal[j] *= 1e-3 * param_globals::gregion[i].g_mult;
150 emat->
ExVal[j] *= 1e-3 * param_globals::gregion[i].g_mult;
151 emat->
BathVal[j] *= 1e-3 * param_globals::gregion[i].g_mult;
160 const char* file = g ==
Eikonal::intra_grid ? param_globals::gi_scale_vec : param_globals::ge_scale_vec;
165 log_msg(0, 4, 0,
"%s warning: number of %s conductivity scaling entries does not match number of elements!",
189 void Eikonal::setup_mappings()
198 log_msg(logger, 0, 0,
"%s: Setting up intracellular algebraic-to-nodal scattering.", __func__);
202 log_msg(logger, 0, 0,
"%s: Setting up intracellular PETSc to canonical permutation.", __func__);
213 case EIKONAL: solve_EIKONAL();
break;
214 case DREAM: solve_DREAM();
break;
215 default: solve_RE();
break;
246 double curtime =
timing(t2, t1);
277 void Eikonal::setup_stimuli()
281 bool dumpTrace =
true;
285 stimuli.resize(param_globals::num_stim);
286 for (
int i = 0; i < param_globals::num_stim; i++) {
290 if (param_globals::stim[i].crct.type != 0 && param_globals::stim[i].crct.type != 9) {
293 log_msg(NULL, 5, 0,
"%s error: stimulus of type %i is incompatible with the eikonal model! Use I_tm or Vm_clmp instead. Aborting!", __func__, s.
phys.
type);
302 log_msg(NULL, 2, 0,
"Only geometry, start time, npls, and bcl of stim[%i] are used", i);
311 void Eikonal::stimulate_intracellular()
319 switch (s.phys.type) {
321 if (param_globals::operator_splitting) {
347 if (illum_vec == NULL) {
348 log_msg(0, 5, 0,
"Cannot apply illumination stim: global vector not present!");
363 void Eikonal::clamp_Vm()
366 if (s.phys.type ==
Vm_clmp && s.is_active())
371 void Eikonal::setup_output()
379 restr_i, param_globals::num_io_nodes > 0);
381 if (param_globals::dataout_i) {
390 if (strcmp(param_globals::dream.
output.idifffile,
"") != 0) {
397 if (strcmp(param_globals::dream.
output.idifffile,
"") != 0) {
405 if (param_globals::num_trace) {
407 open_trace(
ion.
miif, param_globals::num_trace, param_globals::trace_node, NULL, &imesh);
414 void Eikonal::dump_matrices()
416 std::string bsname = param_globals::dump_basename;
422 if (param_globals::parab_solve == 1) {
424 fn = bsname +
"_Ki_CN.bin";
427 fn = bsname +
"_Ki.bin";
430 fn = bsname +
"_Mi.bin";
444 val = std::nan(
"NaN");
458 s_unit =
stimuli[sidx].pulse.wave.f_unit;
463 void Eikonal::setup_solvers()
477 if (param_globals::dump2MatLab) dump_matrices();
481 void Eikonal::checkpointing()
490 snprintf(save_fnm,
sizeof save_fnm,
"%s.%s.roe", param_globals::write_statef, tsav_ext);
499 snprintf(save_fnm,
sizeof save_fnm,
"checkpoint.%.1f.roe", tm.
time);
504 void Eikonal::prepace()
511 log_msg(NULL, 0, 0,
"Using activation times from file %s to distribute prepacing states\n",
512 param_globals::prepacing_lats);
513 log_msg(NULL, 1, 0,
"Assuming stimulus strength %f uA/uF with duration %f ms for prepacing\n",
525 size_t numread = read_lats->
read_ascii(param_globals::prepacing_lats);
527 log_msg(NULL, 5, 0,
"Failed reading required LATs! Skipping prepacing!");
536 bool forward =
false;
537 (*sc)(*read_lats, forward);
541 SF_real* lp = read_lats->ptr();
542 for (
int i = 0; i < read_lats->lsize(); i++)
543 if (lp[i] < 0.0) lp[i] = param_globals::tend + 10.0;
545 read_lats->release_ptr(lp);
550 SF_real LATmin = read_lats->min();
553 log_msg(0, 3, 0,
"LAT data is not complete. Skipping prepacing.");
557 SF_real offset = floor(LATmin / param_globals::prepacing_bcl) * param_globals::prepacing_bcl;
558 SF_real last_tm = param_globals::prepacing_bcl * param_globals::prepacing_beats;
561 *read_lats += -offset;
563 *read_lats += last_tm;
566 SF_real* save_tm = read_lats->ptr();
569 for (
int ii = 0; ii < miif->
N_IIF; ii++) {
570 if (!miif->
N_Nodes[ii])
continue;
574 for (
int kk = 0; kk < miif->
N_Nodes[ii]; kk++) {
575 sorted_save[kk].v1 = save_tm[miif->
NodeLists[ii][kk]];
576 sorted_save[kk].v2 = kk;
578 std::sort(sorted_save.
begin(), sorted_save.
end());
580 size_t lastidx = sorted_save.
size() - 1;
581 int paced = sorted_save[lastidx].v2;
584 for (
double t = 0; t < sorted_save[lastidx].v1; t += param_globals::dt) {
585 if (fmod(t, param_globals::prepacing_bcl) < stimdur &&
586 t < param_globals::prepacing_bcl * param_globals::prepacing_beats - 1)
587 miif->
ldata[ii][limpet::Vm][paced] += stimstr * param_globals::dt;
592 miif->
ldata[ii][limpet::Vm][paced] -= miif->
ldata[ii][limpet::Iion][paced] * param_globals::dt;
593 vm[miif->
NodeLists[ii][paced]] = miif->
ldata[ii][limpet::Vm][paced];
595 while (csav < miif->N_Nodes[ii] - 1 && t >= sorted_save[csav].v1)
600 while (csav < miif->N_Nodes[ii] - 1)
603 for (
int k = 0; k < miif->
N_Nodes[ii]; k++) vm[miif->
NodeLists[ii][k]] = miif->
ldata[ii][limpet::Vm][k];
606 read_lats->release_ptr(save_tm);
611 void Eikonal::solve_EIKONAL()
621 void Eikonal::solve_RE()
632 void Eikonal::solve_DREAM()
650 void Eikonal::solve_RD()
688 if (param_globals::output_level > 1)
log_msg(0, 0, 0,
"\n *** Initializing Eikonal Solver ***\n");
691 log_msg(NULL, 5, 0,
"The DREAM does not run in parallel. Aborting!");
695 stats.init_logger(
"eik_stats.dat");
697 if (param_globals::dream.
output.debugNode >= 0) {
698 nodeData.idX = param_globals::dream.output.debugNode;
700 snprintf(buf,
sizeof buf,
"node_%d.dat", nodeData.idX);
701 nodeData.init_logger(buf);
715 elem_start = mesh.
dsp;
721 x_coord.resize(num_pts);
722 y_coord.resize(num_pts);
723 z_coord.resize(num_pts);
724 fiber_node.resize(num_pts * 3, 0);
725 sheet_node.resize(num_pts * 3, 0);
727 for (
int i = 0; i < ((mesh.
xyz.
size() + 1) / 3); i++) {
728 x_coord[i] = mesh.
xyz[3 * i + 0];
729 y_coord[i] = mesh.
xyz[3 * i + 1];
730 z_coord[i] = mesh.
xyz[3 * i + 2];
738 List.resize(num_pts, 0);
739 T_A.resize(num_pts, inf);
740 D_I.resize(num_pts, 0);
741 T_R.resize(num_pts, -400);
742 TA_old.resize(num_pts, inf);
743 num_changes.resize(num_pts, 0);
744 nReadded2List.resize(num_pts, 0);
745 stim_status.resize(num_pts, 0);
747 CVnodes.resize(num_pts, 0);
748 p_cvrest.resize(num_pts);
749 k_cvrest.resize(num_pts);
750 j_cvrest.resize(num_pts);
751 l_cvrest.resize(num_pts);
752 cv_ar_t.resize(num_pts, -1);
753 cv_ar_n.resize(num_pts, -1);
755 StimulusPoints.resize(num_pts * 10, -1);
756 StimulusTimes.resize(num_pts * 10, -1);
758 switch (mesh.
type[0]) {
772 log_msg(0, 5, 0,
"Error: Type of element is not compatible with this version of the eikonal model. Use tetrahedra or triangles");
777 if (strlen(param_globals::start_statef) > 0) load_state_file();
779 create_node_to_node_graph();
781 translate_stim_to_eikonal();
783 init_diffusion_current();
790 for (
int i = 0; i < length - 1; i++) {
791 for (
int j = 0; j < length - i - 1; j++) {
792 if (Array[j] > Array[j + 1]) {
794 Array[j] = Array[j + 1];
795 Array[j + 1] = Temp_a;
796 Temp_i = IndexArray[j];
797 IndexArray[j] = IndexArray[j + 1];
798 IndexArray[j + 1] = Temp_i;
806 bool act_is_in_safety_window, empty_list_and_illegal_stimulus, empty_stimulus, stimulus_is_in_safety_window;
808 act_is_in_safety_window = (actMIN > param_globals::dream.tau_s) && (actMIN - time > param_globals::dream.tau_s);
809 empty_stimulus = (StimulusPoints[Index_currStim] == -1);
810 stimulus_is_in_safety_window = (StimulusTimes[Index_currStim] - time > param_globals::dream.tau_s);
811 empty_list_and_illegal_stimulus = (
sum(
List) == 0) && (empty_stimulus || stimulus_is_in_safety_window);
813 return act_is_in_safety_window || empty_list_and_illegal_stimulus;
820 for (
int num_g = 0; num_g < param_globals::num_gregions; num_g++) {
821 for (
int num_id = 0; num_id <= param_globals::gregion[num_g].num_IDs; num_id++) {
823 for (
int i = 0; i < vertices.
size(); i++) {
824 CVnodes[vertices[i]] = param_globals::gregion[num_g].dream.vel_l;
825 cv_ar_t[vertices[i]] = param_globals::gregion[num_g].dream.vel_l / param_globals::gregion[num_g].dream.vel_t;
827 cv_ar_n[vertices[i]] = param_globals::gregion[num_g].dream.vel_l / param_globals::gregion[num_g].dream.vel_n;
832 CVnodes_mod = CVnodes;
834 for (
int num_i = 0; num_i < param_globals::num_imp_regions; num_i++) {
835 for (
int num_id = 0; num_id <= param_globals::imp_region[num_i].num_IDs; num_id++) {
837 for (
int i = 0; i < vertices.
size(); i++) {
838 p_cvrest[vertices[i]] = param_globals::imp_region[num_i].dream.CVrest.rho;
839 k_cvrest[vertices[i]] = param_globals::imp_region[num_i].dream.CVrest.kappa;
840 j_cvrest[vertices[i]] = param_globals::imp_region[num_i].dream.CVrest.theta;
841 l_cvrest[vertices[i]] = param_globals::imp_region[num_i].dream.CVrest.psi;
846 if (strlen(param_globals::cv_scale_vec)) {
848 const char* file = param_globals::cv_scale_vec;
852 if (num_file_entries != mesh.
g_numpts)
853 log_msg(0, 2, 0,
"%s warning: number of %s conductivity scaling entries does not match number of points!,%i,%i",
876 for (
int num_g = 0; num_g < param_globals::num_gregions; num_g++) {
877 for (
int num_id = 0; num_id < param_globals::gregion[num_g].num_IDs; num_id++) {
879 for (
int i = 0; i < vertices.
size(); i++) {
880 CVnodes[vertices[i]] *= nd_scale[vertices[i]];
884 CVnodes_mod = CVnodes;
888 void eikonal_solver::update_Ta_in_active_list()
890 bool First_in_List = 1;
892 for (
size_t j = 0; j <
List.size(); j++) {
893 if (T_A[j] < 0)
continue;
894 if (
List[j] == 1 && First_in_List) {
901 if (T_A[j] < actMIN) actMIN = T_A[j];
902 if (T_A[j] > actMAX) actMAX = T_A[j];
909 for (
size_t j = 0; j <
List.size(); j++) {
913 nReadded2List[j] = 0;
923 if (stim_status[indX] == 2) delay = 5;
925 if (T_A_indX == inf || (T_R[indX] + delay) == -400 || abs(T_A_indX - (TA_old[indX])) < 2) {
926 return CVnodes[indX];
927 }
else if ((T_R[indX]) > T_A_indX) {
928 return CVnodes[indX];
930 float DI_indX = T_A_indX - (T_R[indX] + delay);
934 float denom = log(p_cvrest[indX]) / l_cvrest[indX];
935 Factor_DI = 1 - p_cvrest[indX] * exp(-(DI_indX + k_cvrest[indX]) * denom);
938 if (DI_indX < j_cvrest[indX]) {
939 return -CVnodes[indX] * Factor_DI;
941 return CVnodes[indX] * Factor_DI;
953 SF_real q = compute_F(indX, p);
954 while (abs(p - q) >= param_globals::dream.fim.tol && iter_ch < param_globals::dream.fim.max_coh) {
956 q = compute_F(indX, p);
959 if (compute_H(indX, q) < 0)
return T_A[indX];
968 for (
size_t j = Index_currStim; j < StimulusTimes.size(); j++) {
969 if ((StimulusPoints[j] == -1) || (StimulusTimes[j] > StimulusTimes[Index_currStim])) {
975 SF_real TimeSt = StimulusTimes[j];
977 bool cond2add = add_node_neighbor_to_list(T_R[indNode], T_A[indNode], TimeSt);
978 if (cond2add && compute_H(indNode, TimeSt) > 0) {
979 if (T_A[indNode] < TimeSt) {
980 CVnodes_mod[indNode] = -CVnodes_mod[indNode];
982 T_A[indNode] = TimeSt;
983 stim_status[indNode] = 1;
984 stats.bc_status =
true;
986 if (param_globals::dream.
output.debugNode == indNode) {
987 nodeData.T_A = TimeSt;
991 for (
int ii = n2n_dsp[indNode]; ii < n2n_dsp[indNode + 1]; ii++) {
993 if (
List[indXNB] == 0) {
995 if (param_globals::dream.
output.debugNode == indXNB) {
997 nodeData.idXNB = indNode;
998 nodeData.nbn_T_A = TimeSt;
1004 if (cond2add && compute_H(indNode, TimeSt) <= 0) {
1005 stim_status[indNode] = 2;
1010 for (
size_t j = 0; j < StimulusPoints.size(); j++) {
1011 if ((StimulusPoints[j] == -1) && (StimulusTimes[j] > StimulusTimes[Index_currStim]))
continue;
1012 if (
List[StimulusPoints[j]] == 1) {
1013 List[StimulusPoints[j]] = 0;
1018 if (StimulusTimes[Index_currStim] != -1) actMAX = StimulusTimes[Index_currStim];
1020 for (
size_t i = Index_currStim; i < StimulusTimes.size(); i++) {
1022 SF_real TimeSt = StimulusTimes[i];
1024 if (indNode == -1)
continue;
1026 if (TimeSt <= actMAX) {
1027 bool cond2add = add_node_neighbor_to_list(T_R[indNode], T_A[indNode], TimeSt);
1028 if (cond2add && compute_H(indNode, TimeSt) > 0) {
1029 T_A[indNode] = TimeSt;
1030 stim_status[indNode] = 1;
1031 stats.bc_status =
true;
1033 if (param_globals::dream.
output.debugNode == indNode) {
1034 nodeData.T_A = TimeSt;
1038 for (
int ii = n2n_dsp[indNode]; ii < n2n_dsp[indNode + 1]; ii++) {
1040 if (
List[indXNB] == 0) {
1042 if (param_globals::dream.
output.debugNode == indXNB) {
1044 nodeData.idXNB = indNode;
1045 nodeData.nbn_T_A = TimeSt;
1050 for (
size_t j = 0; j < StimulusPoints.size(); j++) {
1051 if ((StimulusPoints[j] == -1) && (StimulusTimes[j] > StimulusTimes[Index_currStim]))
continue;
1052 if (
List[StimulusPoints[j]] == 1) {
1053 List[StimulusPoints[j]] = 0;
1058 if (cond2add && compute_H(indNode, TimeSt) <= 0) {
1059 stim_status[indNode] = 2;
1078 for (
size_t i = Index_currStim; i < StimulusTimes.size(); i++) {
1080 SF_real TimeSt = StimulusTimes[i];
1081 if (StimulusPoints[i] == -1)
break;
1083 T_A[indNode] = TimeSt;
1085 for (
size_t j = n2n_dsp[indNode]; j < n2n_dsp[indNode + 1]; j++) {
1086 if (T_A[n2n_connect[j]] == inf) {
1087 List[n2n_connect[j]] = 1;
1094 if (
List[indX] == 0)
continue;
1097 SF_real q = compute_F(indX, p);
1100 if (abs(p - q) < param_globals::dream.fim.tol) {
1101 for (
int ii = n2n_dsp[indX]; ii < n2n_dsp[indX + 1]; ii++) {
1103 if (
List[indXNB] == 1)
continue;
1105 q = compute_F(indXNB, p);
1115 update_Ta_in_active_list();
1118 if (niter > param_globals::dream.fim.max_iter)
break;
1123 double* atc = AT->ptr();
1125 if (T_A[i] == inf) {
1132 AT->release_ptr(atc);
1135 auto dur =
timing(t1, t0);
1136 stats.slvtime_A += dur;
1137 stats.update_iter(niter);
1138 stats.minAT = actMIN;
1139 stats.maxAT = actMAX;
1154 time2stop_eikonal = param_globals::dream.tau_inc;
1155 float maxadvance =
user_globals::tm_manager->
time + param_globals::dream.tau_s + param_globals::dream.tau_inc + param_globals::dream.tau_max;
1158 if (StimulusTimes[Index_currStim] <= maxadvance) {
1166 if (
List[indX] == 0)
continue;
1168 q = compute_coherence(indX);
1171 num_changes[indX] = num_changes[indX] + 1;
1173 if (q > maxadvance)
continue;
1175 if (abs(p - q) < param_globals::dream.fim.tol || (num_changes[indX] > param_globals::dream.fim.max_iter) || (q == inf || p == inf)) {
1176 for (
int ii = n2n_dsp[indX]; ii < n2n_dsp[indX + 1]; ii++) {
1179 if (
List[indXNB] == 1) {
1186 qNB = compute_coherence(indXNB);
1192 bool ignore_L2_if_valid = node_is_valid && qNB > pNB && nReadded2List[indXNB] >= param_globals::dream.fim.max_addpt;
1194 if (node_is_valid && (nReadded2List[indXNB] < param_globals::dream.fim.max_addpt) || ignore_L2_if_valid) {
1196 nReadded2List[indXNB] = 0;
1199 nReadded2List[indXNB]++;
1200 num_changes[indXNB] = 0;
1202 if (param_globals::dream.
output.debugNode == indXNB) {
1204 nodeData.idXNB = indX;
1205 nodeData.nbn_T_A = q;
1211 if (param_globals::dream.
output.debugNode == indX) {
1220 update_Ta_in_active_list();
1222 if (actMIN > actMIN_old) {
1223 progress_time = actMIN - actMIN_old;
1228 time2stop_eikonal -= progress_time;
1231 }
while (time2stop_eikonal > 0 &&
sum(
List) > 0);
1234 if (StimulusTimes[Index_currStim] != -1) actMIN = StimulusTimes[Index_currStim];
1238 double* atc = AT->ptr();
1239 double* rpt = RT->ptr();
1241 if (T_A[i] == inf) {
1249 AT->release_ptr(atc);
1250 RT->release_ptr(rpt);
1253 auto dur =
timing(t1, t0);
1254 stats.slvtime_A += dur;
1255 stats.update_iter(niter);
1256 stats.minAT = actMIN;
1257 stats.maxAT = actMAX;
1262 if (param_globals::dream.
output.debugNode >= 0) {
1263 nodeData.T_A = T_A[nodeData.idX];
1264 nodeData.T_R = T_R[nodeData.idX];
1265 nodeData.D_I = D_I[nodeData.idX];
1275 CVnodes_mod[indX] = compute_H(indX, T_A_indX);
1277 CV_l = abs(CVnodes_mod[indX]);
1286 fib.
x = fiber_node[3 * indX + 0];
1287 fib.
y = fiber_node[3 * indX + 1];
1288 fib.
z = fiber_node[3 * indX + 2];
1290 she.
x = sheet_node[3 * indX + 0];
1291 she.
y = sheet_node[3 * indX + 1];
1292 she.
z = sheet_node[3 * indX + 2];
1294 SF_real ani_ratio_t2 = cv_ar_t[indX] * cv_ar_t[indX];
1295 SF_real ani_ratio_n2 = cv_ar_n[indX] * cv_ar_n[indX];
1304 fib.
x = fiber_node[3 * indX + 0];
1305 fib.
y = fiber_node[3 * indX + 1];
1306 fib.
z = fiber_node[3 * indX + 2];
1308 SF_real ani_ratio2 = cv_ar_t[indX] * cv_ar_t[indX];
1310 D[0][0] += (1 / ani_ratio2), D[1][1] += (1 / ani_ratio2), D[2][2] += (1 / ani_ratio2);
1314 if (numPtsxElem == 4) {
1316 for (
int e_i = n2e_dsp[indX]; e_i < n2e_dsp[indX + 1]; e_i++) {
1317 int Elem_i = n2e_con[e_i];
1320 std::vector<mesh_int_t> Elem_cur = {e2n_con[indEle], e2n_con[indEle + 1], e2n_con[indEle + 2], e2n_con[indEle + 3]};
1321 std::remove(Elem_cur.begin(), Elem_cur.end(), indX);
1323 condign1 = T_A[Elem_cur[0]] == inf || T_A[Elem_cur[1]] == inf || T_A[Elem_cur[2]] == inf || (T_A[Elem_cur[0]] < time) || (T_A[Elem_cur[1]] < time) || (T_A[Elem_cur[2]] < time);
1324 condign2 = (T_A[Elem_cur[0]] < T_R[Elem_cur[0]]) || (T_A[Elem_cur[1]] < T_R[Elem_cur[1]]) || (T_A[Elem_cur[2]] < T_R[Elem_cur[2]]);
1325 condign3 = CV_l == 0;
1326 condign4 = stim_status[indX] == 2 && (stim_status[Elem_cur[0]] == 1 || stim_status[Elem_cur[1]] == 1 || stim_status[Elem_cur[2]] == 1);
1328 if (!(condign1 || condign2 || condign3 || condign4)) {
1329 SF_real temp3 = solve_tet(indX, Elem_cur);
1331 if (temp3 < TA && temp3 > T_R[indX] && compute_H(indX, temp3) > 0) {
1332 Winner_Element[0] = Elem_cur[0];
1333 Winner_Element[1] = Elem_cur[1];
1334 Winner_Element[2] = Elem_cur[2];
1339 std::vector<mesh_int_t> Triang = {-1, -1};
1341 for (
int cases = 0; cases < 3; cases++) {
1344 Triang[0] = Elem_cur[0];
1345 Triang[1] = Elem_cur[1];
1349 Triang[0] = Elem_cur[0];
1350 Triang[1] = Elem_cur[2];
1354 Triang[0] = Elem_cur[1];
1355 Triang[1] = Elem_cur[2];
1362 condign1 = T_A[Triang[0]] == inf || T_A[Triang[1]] == inf || (T_A[Triang[0]] < time) || (T_A[Triang[1]] < time);
1363 condign2 = (T_A[Triang[0]] < T_R[Triang[0]]) || (T_A[Triang[1]] < T_R[Triang[1]]);
1364 condign3 = CV_l == 0;
1365 condign4 = stim_status[indX] == 2 && (stim_status[Triang[0]] == 1 || stim_status[Triang[1]] == 1);
1367 if (!(condign1 || condign2 || condign3 || condign4)) {
1368 SF_real temp2 = solve_tri(indX, Triang);
1370 if (temp2 < TA && temp2 > T_R[indX] && compute_H(indX, temp2) > 0) {
1371 Winner_Element[0] = Triang[0];
1372 Winner_Element[1] = Triang[1];
1373 Winner_Element[2] = -1;
1381 if (numPtsxElem == 3) {
1382 for (
int e_i = n2e_dsp[indX]; e_i < n2e_dsp[indX + 1]; e_i++) {
1383 int Elem_i = n2e_con[e_i];
1386 std::vector<mesh_int_t> Elem_cur = {e2n_con[indEle], e2n_con[indEle + 1], e2n_con[indEle + 2]};
1387 std::remove(Elem_cur.begin(), Elem_cur.end(), indX);
1389 condign1 = T_A[Elem_cur[0]] == inf || T_A[Elem_cur[1]] == inf || (T_A[Elem_cur[0]] < time) || (T_A[Elem_cur[1]] < time);
1390 condign2 = (T_A[Elem_cur[0]] < T_R[Elem_cur[0]]) || (T_A[Elem_cur[1]] < T_R[Elem_cur[1]]);
1391 condign3 = CV_l == 0;
1392 condign4 = stim_status[indX] == 2 && (stim_status[Elem_cur[0]] == 1 || stim_status[Elem_cur[1]] == 1);
1394 if (condign1 || condign2 || condign3 || condign4)
continue;
1396 SF_real temp2 = solve_tri(indX, Elem_cur);
1398 if (TA > temp2 && temp2 > T_R[indX] && compute_H(indX, temp2) > 0) {
1405 for (
int ii = n2n_dsp[indX]; ii < n2n_dsp[indX + 1]; ii++) {
1407 condign4 = stim_status[indX] == 2 && (stim_status[indXNB] == 1);
1409 if (!(CV_l == 0 || T_A[indXNB] < T_R[indXNB] || T_A[indXNB] == inf || condign4 || T_A[indXNB] < time)) {
1410 SF_real temp1 = solve_edges(indX, indXNB);
1412 if (temp1 < TA && temp1 > T_R[indX] && compute_H(indX, temp1) > 0) {
1413 Winner_Element[0] = indXNB;
1414 Winner_Element[1] = -1;
1415 Winner_Element[2] = -1;
1422 Winner_Element[0] = -1;
1423 Winner_Element[1] = -1;
1424 Winner_Element[2] = -1;
1428 std::sort(Winner_Element.
begin(), Winner_Element.
end());
1429 if (compute_H(indX, TA) == 0) TA = inf;
1435 SF_real eikonal_solver::solve_tet(
mesh_int_t& indx3, std::vector<mesh_int_t>& Elem_cur)
1442 int indy3 = Elem_cur[0], indz3 = Elem_cur[1], indw3 = Elem_cur[2];
1444 X[0] = x_coord[indx3];
1445 X[1] = y_coord[indx3];
1446 X[2] = z_coord[indx3];
1448 Y[0] = x_coord[indy3];
1449 Y[1] = y_coord[indy3];
1450 Y[2] = z_coord[indy3];
1452 Z[0] = x_coord[indz3];
1453 Z[1] = y_coord[indz3];
1454 Z[2] = z_coord[indz3];
1456 W[0] = x_coord[indw3];
1457 W[1] = y_coord[indw3];
1458 W[2] = z_coord[indw3];
1460 XY[0] =
Y[0] -
X[0];
1461 XZ[0] =
Z[0] - X[0];
1462 XW[0] = W[0] - X[0];
1463 XY[1] =
Y[1] - X[1];
1464 XZ[1] =
Z[1] - X[1];
1465 XW[1] = W[1] - X[1];
1466 XY[2] =
Y[2] - X[2];
1467 XZ[2] =
Z[2] - X[2];
1468 XW[2] = W[2] - X[2];
1470 c1 = mult_VtMV(XY, iD, XY);
1471 c2 = mult_VtMV(XZ, iD, XZ);
1472 c3 = mult_VtMV(XW, iD, XW);
1473 c4 = 2 * (mult_VtMV(XY, iD, XZ));
1474 c5 = 2 * mult_VtMV(XY, iD, XW);
1475 c6 = 2 * mult_VtMV(XW, iD, XZ);
1477 a1 = 4 * c2 * c3 - 2 * c2 * c5 - 2 * c3 * c4 + c4 * c6 + c5 * c6 - c6 * c6;
1478 s1 = 4 * c1 * c2 + 4 * c1 * c3 + 4 * c2 * c3 - 4 * c1 * c6 - 4 * c2 * c5 - 4 * c3 * c4 + 2 * c4 * c5 + 2 * c4 * c6 + 2 * c5 * c6 - c4 * c4 - c5 * c5 - c6 * c6;
1480 s2 = c1 * c6 * c6 + c2 * c5 * c5 + c3 * c4 * c4 - 4 * c1 * c2 * c3 - c4 * c5 * c6;
1481 s3 = 4 * c1 * c6 - 4 * c1 * c3 - 4 * c2 * c3 - 4 * c1 * c2 + 4 * c2 * c5 + 4 * c3 * c4 - 2 * c4 * c5 - 2 * c4 * c6 - 2 * c5 * c6 + c4 * c4 + c5 * c5 + c6 * c6 + 4 * CV_l * CV_l * T_A[indy3] * T_A[indy3] * c2 + 4 * CV_l * CV_l * T_A[indy3] * T_A[indy3] * c3 - 4 * CV_l * CV_l * T_A[indy3] * T_A[indy3] * c6 + 4 * CV_l * CV_l * T_A[indz3] * T_A[indz3] * c1 + 4 * CV_l * CV_l * T_A[indz3] * T_A[indz3] * c3 - 4 * CV_l * CV_l * T_A[indz3] * T_A[indz3] * c5 + 4 * CV_l * CV_l * T_A[indw3] * T_A[indw3] * c1 + 4 * CV_l * CV_l * T_A[indw3] * T_A[indw3] * c2 - 4 * CV_l * CV_l * T_A[indw3] * T_A[indw3] * c4 - 8 * CV_l * CV_l * T_A[indy3] * T_A[indz3] * c3 - 4 * CV_l * CV_l * T_A[indy3] * T_A[indz3] * c4 + 4 * CV_l * CV_l * T_A[indy3] * T_A[indz3] * c5 + 4 * CV_l * CV_l * T_A[indy3] * T_A[indz3] * c6 - 8 * CV_l * CV_l * T_A[indy3] * T_A[indw3] * c2 + 4 * CV_l * CV_l * T_A[indy3] * T_A[indw3] * c4 - 4 * CV_l * CV_l * T_A[indy3] * T_A[indw3] * c5 + 4 * CV_l * CV_l * T_A[indy3] * T_A[indw3] * c6 - 8 * CV_l * CV_l * T_A[indz3] * T_A[indw3] * c1 + 4 * CV_l * CV_l * T_A[indz3] * T_A[indw3] * c4 + 4 * CV_l * CV_l * T_A[indz3] * T_A[indw3] * c5 - 4 * CV_l * CV_l * T_A[indz3] * T_A[indw3] * c6;
1482 a2 = 2 * CV_l * T_A[indy3] * c2 + 2 * CV_l * T_A[indy3] * c3 - 2 * CV_l * T_A[indy3] * c6 - 2 * CV_l * T_A[indz3] * c3 - CV_l * T_A[indz3] * c4 + CV_l * T_A[indz3] * c5 + CV_l * T_A[indz3] * c6 - 2 * CV_l * T_A[indw3] * c2 + CV_l * T_A[indw3] * c4 - CV_l * T_A[indw3] * c5 + CV_l * T_A[indw3] * c6;
1483 s4 = 4 * c1 * c2 + 4 * c1 * c3 + 4 * c2 * c3 - 4 * c1 * c6 - 4 * c2 * c5 - 4 * c3 * c4 + 2 * c4 * c5 + 2 * c4 * c6 + 2 * c5 * c6 - c4 * c4 - c5 * c5 - c6 * c6;
1484 b1 = 4 * c1 * c3 - 2 * c1 * c6 - 2 * c3 * c4 + c4 * c5 + c5 * c6 - c5 * c5;
1485 b2 = CV_l * T_A[indy3] * c5 - CV_l * T_A[indy3] * c4 - 2 * CV_l * T_A[indy3] * c3 + CV_l * T_A[indy3] * c6 + 2 * CV_l * T_A[indz3] * c1 + 2 * CV_l * T_A[indz3] * c3 - 2 * CV_l * T_A[indz3] * c5 - 2 * CV_l * T_A[indw3] * c1 + CV_l * T_A[indw3] * c4 + CV_l * T_A[indw3] * c5 - CV_l * T_A[indw3] * c6;
1491 SF_real RTa = (2 * sqrt(s2_s3) * (a2)) / (s4);
1492 SF_real RTb = (2 * sqrt(s2_s3) * (b2)) / (s4);
1496 if (abs(s1) > tol && abs(s3) > tol && abs(s4) > tol && (s2 / s3) > 0) {
1500 if ((a > 0) && (a < 1) && (b > 0) && (b < 1) && ((1 - a - b) > 0) && ((1 - a - b) < 1)) {
1501 TA_th =
std::min(TA_th, compute_AT_at_node_in_tet(a, b, indx3, indy3, indz3, indw3));
1507 if ((a > 0) && (a < 1) && (b > 0) && (b < 1) && ((1 - a - b) > 0) && ((1 - a - b) < 1)) {
1508 TA_th =
std::min(TA_th, compute_AT_at_node_in_tet(a, b, indx3, indy3, indz3, indw3));
1515 SF_real eikonal_solver::solve_tri(
mesh_int_t& indx, std::vector<mesh_int_t>& Elem_cur)
1522 int indy = Elem_cur[0], indz = Elem_cur[1];
1524 X[0] = x_coord[indx];
1525 X[1] = y_coord[indx];
1526 X[2] = z_coord[indx];
1528 Y[0] = x_coord[indy];
1529 Y[1] = y_coord[indy];
1530 Y[2] = z_coord[indy];
1532 Z[0] = x_coord[indz];
1533 Z[1] = y_coord[indz];
1534 Z[2] = z_coord[indz];
1536 XY[0] =
Y[0] -
X[0];
1537 XZ[0] = Z[0] - X[0];
1538 XY[1] =
Y[1] - X[1];
1539 XZ[1] = Z[1] - X[1];
1540 XY[2] =
Y[2] - X[2];
1541 XZ[2] = Z[2] - X[2];
1543 C = mult_VtMV(XZ, iD, XZ);
1544 A = mult_VtMV(XY, iD, XY) - 2 * mult_VtMV(XZ, iD, XY) + C;
1545 B = 2 * mult_VtMV(XY, iD, XZ) - 2 * C;
1547 if (abs(T_A[indy] - T_A[indz]) < 1e-5) {
1549 if (p1 > 0 && p1 < 1) {
1550 TA_tr =
std::min(compute_AT_at_node(p1, indx, indy, indz), TA_tr);
1554 lam = ((T_A[indz] - T_A[indy]) * (T_A[indz] - T_A[indy])) * 4 * (CV_l * CV_l);
1555 ae = (4 * (A * A)) - lam * A;
1556 be = 4 * A * B - lam * B;
1557 ce = (B * B) - lam * C;
1558 det = (be * be) - (4 * ae * ce);
1561 p1 = (-be + sqrt(det)) / (2 * ae);
1563 if (p1 > 0 && p1 < 1) {
1564 TA_tr =
std::min(compute_AT_at_node(p1, indx, indy, indz), TA_tr);
1568 p2 = (-be - sqrt(det)) / (2 * ae);
1570 if (p2 > 0 && p2 < 1) {
1571 TA_tr =
std::min(compute_AT_at_node(p2, indx, indy, indz), TA_tr);
1583 X[0] = x_coord[indX];
1584 X[1] = y_coord[indX];
1585 X[2] = z_coord[indX];
1586 Y[0] = x_coord[indY];
1587 Y[1] = y_coord[indY];
1588 Y[2] = z_coord[indY];
1590 XY[0] =
Y[0] -
X[0];
1591 XY[1] =
Y[1] - X[1];
1592 XY[2] =
Y[2] - X[2];
1594 Num = mult_VtMV(XY, iD, XY);
1598 SF_real TAn = T_A[indY] + Frac;
1605 bool isNewTABetweenRTAndOldTA = (RT < newTA) && (newTA < oldTA);
1606 bool isNewTABiggerRTBiggerOldTA = (oldTA < RT) && (RT < newTA);
1608 return (isNewTABetweenRTAndOldTA) || (isNewTABiggerRTBiggerOldTA);
1615 if (X[0] == Y[0] && X[1] == Y[1] && X[2] == Y[2]) {
1616 result = iD[0][0] * X[0] * X[0] + 2 * iD[0][1] * X[0] * X[1] + iD[1][1] * X[1] * X[1] + 2 * iD[0][2] * X[0] * X[2] + iD[2][2] * X[2] * X[2] + 2 * iD[1][2] * X[1] * X[2];
1618 result = iD[0][0] * X[0] * Y[0] + iD[0][1] * (X[0] * Y[1] + X[1] * Y[0]) + iD[1][1] * X[1] * Y[1] + iD[0][2] * (X[0] * Y[2] + X[2] * Y[0]) + iD[2][2] * X[2] * Y[2] + iD[1][2] * (X[1] * X[2] + X[2] * Y[1]);
1630 return T_A[indzf1] + Frac;
1632 }
else if (pp == 1) {
1633 Num = sqrt(A + B + C);
1635 return T_A[indyf1] + Frac;
1638 Num = sqrt(A * pp * pp + B * pp + C);
1640 TA_ori = T_A[indyf1] * pp + T_A[indzf1] * (1 - pp);
1641 return TA_ori + Frac;
1647 Num = c1 * (pf2 * pf2) + c2 * (qf2 * qf2) + c3 * ((1 - pf2 - qf2) * (1 - pf2 - qf2)) + c4 * (pf2 * qf2) + c5 * (pf2 * (1 - pf2 - qf2)) + c6 * (qf2 * (1 - pf2 - qf2));
1650 TA_ori = T_A[indyf2] * pf2 + T_A[indzf2] * qf2 + T_A[indwf2] * (1 - pf2 - qf2);
1651 return TA_ori + Frac;
1657 FILE* file_writestate;
1658 char buffer_writestate[1024];
1659 snprintf(buffer_writestate,
sizeof buffer_writestate,
"%s.%s.roe.dat", param_globals::write_statef, tsav_ext);
1660 file_writestate = fopen(buffer_writestate,
"w");
1661 for (
size_t jjj = 0; jjj <
List.size(); jjj++) {
1662 fprintf(file_writestate,
"%d %d %d %f %f %f %f \n",
List[jjj], num_changes[jjj], nReadded2List[jjj], T_A[jjj], T_R[jjj], TA_old[jjj], D_I[jjj]);
1665 fclose(file_writestate);
1674 for (
int ind_nodes = 0; ind_nodes < num_pts; ind_nodes++) {
1675 double prev_R = T_R[ind_nodes];
1677 if (old_ptr[ind_nodes] >= param_globals::dream.repol_time_thresh && new_ptr[ind_nodes] < param_globals::dream.repol_time_thresh) {
1678 T_R[ind_nodes] = time;
1691 int max_threads = omp_get_max_threads();
1692 omp_set_num_threads(1);
1700 for (
int i = 0; i < miif->
N_IIF; i++) {
1701 if (!miif->
N_Nodes[i])
continue;
1710 int ind_gb = (miif->
NodeLists[i][current]);
1713 double Vm_old = miif->
ldata[i][limpet::Vm][current];
1714 double Iion_old = miif->
ldata[i][limpet::Iion][current];
1715 double prev_R = T_R[ind_gb];
1717 bool cond_2upd = T_R[ind_gb] <= T_A[ind_gb] && T_A[ind_gb] != inf && Vm_old > param_globals::dream.repol_time_thresh;
1720 double elapsed_time = 0;
1721 double prev_Vm = miif->
ldata[i][limpet::Vm][current];
1726 miif->
ldata[i][limpet::Vm][current] -= miif->
ldata[i][limpet::Iion][current] * param_globals::dt;
1727 if (miif->
ldata[i][limpet::Vm][current] < param_globals::dream.repol_time_thresh) {
1728 T_R[ind_gb] = time + elapsed_time;
1731 }
while (elapsed_time < 600);
1734 miif->
ldata[i][limpet::Vm][current] = Vm_old;
1735 miif->
ldata[i][limpet::Iion][current] = Iion_old;
1738 }
while (current < miif->N_Nodes[i]);
1743 omp_set_num_threads(max_threads);
1747 auto dur =
timing(t1, t0);
1748 stats.slvtime_D += dur;
1765 for (
size_t j = 0; j < alg_nod.
size(); j++) {
1769 if ((time >= T_A[loc_nodal_idx]) && ((T_A[loc_nodal_idx] + 5) >= time) && (
List[loc_nodal_idx] == 0)) {
1770 dT = time - T_A[loc_nodal_idx];
1772 switch (diff_cur[loc_nodal_idx].model) {
1774 c[loc_petsc_idx] = diff_cur[loc_nodal_idx].alpha_1 * exp(-((dT - diff_cur[loc_nodal_idx].beta_1) / diff_cur[loc_nodal_idx].gamma_1) * ((dT - diff_cur[loc_nodal_idx].beta_1) / diff_cur[loc_nodal_idx].gamma_1))
1775 + diff_cur[loc_nodal_idx].alpha_2 * exp(-((dT - diff_cur[loc_nodal_idx].beta_2) / diff_cur[loc_nodal_idx].gamma_2) * ((dT - diff_cur[loc_nodal_idx].beta_2) / diff_cur[loc_nodal_idx].gamma_2))
1776 + diff_cur[loc_nodal_idx].alpha_3 * exp(-((dT - diff_cur[loc_nodal_idx].beta_3) / diff_cur[loc_nodal_idx].gamma_3) * ((dT - diff_cur[loc_nodal_idx].beta_3) / diff_cur[loc_nodal_idx].gamma_3));
1779 e_on = (dT >= 0) ? 1.0 : 0.0;
1780 e_off = (v[loc_petsc_idx] < diff_cur[loc_nodal_idx].V_th) ? 1.0 : 0.0;
1781 c[loc_petsc_idx] = diff_cur[loc_nodal_idx].A_F / diff_cur[loc_nodal_idx].tau_F * exp(dT / diff_cur[loc_nodal_idx].tau_F) * e_on * e_off;
1786 Idiff->release_ptr(c);
1790 auto dur =
timing(t1, t0);
1791 stats.slvtime_B += dur;
1794 void eikonal_solver::load_state_file()
1797 FILE* file_startstate;
1798 char buffer_startstate[strlen(param_globals::start_statef) + 10];
1800 snprintf(buffer_startstate,
sizeof buffer_startstate,
"%s.dat", param_globals::start_statef);
1801 file_startstate = fopen(buffer_startstate,
"r");
1803 if (file_startstate == NULL) {
1804 log_msg(NULL, 5, 0,
"Not able to open state file: %s", buffer_startstate);
1805 }
else if (param_globals::output_level) {
1806 log_msg(NULL, 0, 0,
"Open state file for eikonal model: %s", buffer_startstate);
1809 int ListVal, numChangesVal, numChanges2Val;
1810 float T_AVal, T_RVal, TA_oldVal, D_IVal, PCLVal;
1813 while (fscanf(file_startstate,
"%d %d %d %f %f %f %f", &ListVal, &numChangesVal, &numChanges2Val, &T_AVal, &T_RVal, &TA_oldVal, &D_IVal) == 7) {
1814 List[index] = ListVal;
1815 num_changes[index] = numChangesVal;
1816 nReadded2List[index] = numChanges2Val;
1817 T_A[index] = T_AVal;
1818 T_R[index] = T_RVal;
1819 TA_old[index] = TA_oldVal;
1820 D_I[index] = D_IVal;
1823 if (param_globals::output_level)
log_msg(NULL, 0, 0,
"Number of nodes in active list: %i",
sum(
List));
1825 fclose(file_startstate);
1828 void eikonal_solver::init_diffusion_current()
1833 for (
int num_i = 0; num_i < param_globals::num_imp_regions; num_i++) {
1834 for (
int num_id = 0; num_id <= param_globals::imp_region[num_i].num_IDs; num_id++) {
1836 for (
int i = 0; i < vertices.
size(); i++) {
1837 diff_cur[vertices[i]].model =
static_cast<eikonal_solver::Idiff_t>(param_globals::imp_region[num_i].dream.Idiff.model);
1838 switch (diff_cur[vertices[i]].model) {
1840 diff_cur[vertices[i]].alpha_1 = param_globals::imp_region[num_i].dream.Idiff.alpha_i[0];
1841 diff_cur[vertices[i]].alpha_2 = param_globals::imp_region[num_i].dream.Idiff.alpha_i[1];
1842 diff_cur[vertices[i]].alpha_3 = param_globals::imp_region[num_i].dream.Idiff.alpha_i[2];
1843 diff_cur[vertices[i]].beta_1 = param_globals::imp_region[num_i].dream.Idiff.beta_i[0];
1844 diff_cur[vertices[i]].beta_2 = param_globals::imp_region[num_i].dream.Idiff.beta_i[1];
1845 diff_cur[vertices[i]].beta_3 = param_globals::imp_region[num_i].dream.Idiff.beta_i[2];
1846 diff_cur[vertices[i]].gamma_1 = param_globals::imp_region[num_i].dream.Idiff.gamma_i[0];
1847 diff_cur[vertices[i]].gamma_2 = param_globals::imp_region[num_i].dream.Idiff.gamma_i[1];
1848 diff_cur[vertices[i]].gamma_3 = param_globals::imp_region[num_i].dream.Idiff.gamma_i[2];
1851 diff_cur[vertices[i]].A_F = param_globals::imp_region[num_i].dream.Idiff.A_F;
1852 diff_cur[vertices[i]].tau_F = param_globals::imp_region[num_i].dream.Idiff.tau_F;
1853 diff_cur[vertices[i]].V_th = param_globals::imp_region[num_i].dream.Idiff.V_th;
1860 void eikonal_solver::translate_stim_to_eikonal()
1863 if (param_globals::output_level)
log_msg(NULL, 0, 0,
"Initializing stimuli for eikonal model ...");
1867 int number_stimulus = param_globals::num_stim;
1868 int total_stimuli = 0;
1874 total_stimuli += s.ptcl.npls;
1875 for (
int idx_pls = 0; idx_pls < s.ptcl.npls; idx_pls++) {
1876 SF_real start_time = s.ptcl.start + s.ptcl.pcl * idx_pls;
1883 bubble_sort(StartStimulus, IndexStimulus, total_stimuli);
1885 for (
int ind_stim = 0; ind_stim < total_stimuli; ind_stim++) {
1886 stimulus s = (*stimuliRef)[IndexStimulus[ind_stim]];
1890 StimulusTimes[
count] = StartStimulus[ind_stim];
1895 StimulusPoints.
resize(count + 2, -1);
1896 StimulusTimes.resize(count + 2, -1);
1899 void eikonal_solver::create_node_to_node_graph()
1902 n2n_dsp.resize(num_pts + 1, 0);
1906 for (
int point_idx = 0; point_idx < num_pts; point_idx++) {
1907 int numNBElem = n2e_dsp[point_idx + 1] - n2e_dsp[point_idx];
1908 std::vector<mesh_int_t> NNNodesxNodes(numNBElem * numPtsxElem);
1910 for (
int eedsp = 0; eedsp < numNBElem; eedsp++) {
1911 int currElem = n2e_con[n2e_dsp[point_idx] + eedsp];
1914 fiber_node[3 * point_idx] = mesh.
fib[3 * currElem];
1915 fiber_node[3 * point_idx + 1] = mesh.
fib[3 * currElem + 1];
1916 fiber_node[3 * point_idx + 2] = mesh.
fib[3 * currElem + 2];
1918 sheet_node[3 * point_idx] = mesh.
she[3 * currElem];
1919 sheet_node[3 * point_idx + 1] = mesh.
she[3 * currElem + 1];
1920 sheet_node[3 * point_idx + 2] = mesh.
she[3 * currElem + 2];
1923 fiber_node[3 * point_idx] = mesh.
fib[3 * currElem];
1924 fiber_node[3 * point_idx + 1] = mesh.
fib[3 * currElem + 1];
1925 fiber_node[3 * point_idx + 2] = mesh.
fib[3 * currElem + 2];
1928 for (
int nndsp = 0; nndsp < numPtsxElem; nndsp++) {
1929 NNNodesxNodes[eedsp * numPtsxElem + nndsp] = e2n_con[elem_start[currElem] + nndsp];
1933 std::sort(NNNodesxNodes.begin(), NNNodesxNodes.end());
1934 auto it = std::unique(NNNodesxNodes.begin(), NNNodesxNodes.end());
1935 NNNodesxNodes.erase(it, NNNodesxNodes.end());
1936 it = std::remove(NNNodesxNodes.begin(), NNNodesxNodes.end(), point_idx);
1937 NNNodesxNodes.erase(it, NNNodesxNodes.end());
1938 int max = NNNodesxNodes.size();
1940 n2n_dsp[point_idx + 1] = n2n_dsp[point_idx] + NNNodesxNodes.size();
1942 n2n_connect.insert(n2n_connect.end(), NNNodesxNodes.begin(), NNNodesxNodes.end());
1945 n2n_dsp[num_pts] = n2n_connect.size();
1950 logger =
f_open(filename,
"w");
1952 const char* h1 =
" ------ ---------- ---------- ------- ------- | List logic ----- -------- | Neighbor node ---- |";
1953 const char* h2 =
" cycle AT old AT RT DI | Status Entry Exit | ID AT |";
1956 log_msg(NULL, 3, 0,
"%s error: Could not open file %s in %s. Turning off logging.\n",
1957 __func__, filename);
1959 log_msg(logger, 0, 0,
"%s", h1);
1960 log_msg(logger, 0, 0,
"%s", h2);
1966 if (!this->logger)
return;
1973 std::ostringstream oss_TA, oss_TA_, oss_TR, oss_DI, oss_nbnTA;
1974 oss_TA << this->T_A;
1975 oss_TA_ << this->T_A_;
1976 oss_TR << this->T_R;
1977 oss_DI << this->D_I;
1978 oss_nbnTA << this->nbn_T_A;
1981 snprintf(cbuf,
sizeof cbuf,
"%7s %10s",
"-",
"-");
1983 snprintf(cbuf,
sizeof cbuf,
"%7d %10s", this->idXNB, oss_nbnTA.str().c_str());
1986 snprintf(abuf,
sizeof abuf,
"%6d %10s %10s %7s %7s", this->cycle, oss_TA.str().c_str(), oss_TA_.str().c_str(), oss_TR.str().c_str(), oss_DI.str().c_str());
1987 snprintf(bbuf,
sizeof bbuf,
"%7s %8s %8s", this->
status, this->reasonIn, this->reasonOut);
1989 unsigned char flag = cflg ?
ECHO : 0;
1990 log_msg(this->logger, 0, flag |
FLUSH |
NONL,
"%9.3f %s | %s | %s |\n", time, abuf, bbuf, cbuf);
1992 this->reasonIn =
"-";
1993 this->reasonOut =
"-";
1994 this->T_A_ = this->T_A;
1995 this->T_A = std::numeric_limits<double>::quiet_NaN();
1996 this->T_R = std::numeric_limits<double>::quiet_NaN();
1997 this->D_I = std::numeric_limits<double>::quiet_NaN();
1999 this->nbn_T_A = std::numeric_limits<double>::quiet_NaN();
2006 const char* stat_str;
2007 const char* reas_str;
2022 this->reasonIn = reas_str;
2024 this->reasonOut = reas_str;
constexpr T min(T a, T b)
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.
int ** NodeLists
local partitioned node lists for each IMP stored
stim_electrode electrode
electrode geometry
void init()
Initialize vectors and variables in the eikonal_solver class.
int * subregtags
FEM tags forming this region.
char * regname
name of region
void log_stats(double tm, bool cflg)
virtual void release_ptr(S *&p)=0
void FIM()
Standard fast iterative method to solve eikonal equation with active list approach.
stim_pulse pulse
stimulus wave form
char * dupstr(const char *old_str)
description of materal properties in a mesh
virtual void add_scaled(const abstract_vector< T, S > &vec, S k)=0
physMaterial * material
material parameter description
sf_vec * Irhs
weighted transmembrane currents
eikonal_solver eik_solver
Solver for the eikonal equation.
LAT_detector lat
the activation time detector
MPI_Comm comm
the parallel mesh is defined on a MPI world
void set_stimuli(SF::vector< stimulus > &stimuli)
Simple setter for stimulus vector.
igb_output_manager output_manager_cycle
constexpr T max(T a, T b)
parabolic_solver parab_solver
Solver for the parabolic bidomain equation.
#define PETSC_TO_CANONICAL
Permute algebraic data from PETSC to canonical ordering.
const IonType & get_type() const
Gets this IMP's model type.
physMat_t material_type
ID of physics material.
vector< T > dsp
connectivity starting index of each element
sf_vec * phie_dummy
no elliptic solver needed, but we need a dummy for phie to use parabolic solver
overlapping_layout< T > pl
nodal parallel layout
vector< S > fib
fiber direction
int calls
# calls for this interval, this is incremented externally
virtual void set(const vector< T > &idx, const vector< S > &vals, const bool additive=false, const bool local=false)=0
void update_status(enum status s, enum reason r)
void cnt_from_dsp(const std::vector< T > &dsp, std::vector< T > &cnt)
Compute counts from displacements.
void compute_diffusion_current(const double &time, sf_vec &vm)
Compute the diffusion current approximation I_diff in all activated nodes. Only converged nodes are c...
eikonal_solver_stats stats
void solve(sf_vec &phie_i)
virtual T lsize() const =0
FILE_SPEC logger
The logger of the physic, each physic should have one.
timer_manager * tm_manager
a manager for the various physics timers
double ExVal[3]
extracellular conductivity eigenvalues
const char * name
The name of the physic, each physic should have one.
sf_mat * lhs_parab
lhs matrix (CN) to solve parabolic
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.
SF::vector< mesh_int_t > vertices
size_t read_ascii(FILE *fd)
double time_step
global reference time step
void cycFIM()
Implementation of the cyclical fast iterative method used in step A of the DREAM model.
void count(const vector< T > &data, vector< S > &cnt)
Count number of occurrences of indices.
const char * get_mesh_type_name(mesh_t t)
get a char* to the name of a mesh type
vector< S > xyz
node cooridnates
Target get_target() const
sf_vec * tmp_i1
scratch vector for i-grid
void log_stats(double tm, bool cflg)
mesh_t
The enum identifying the different meshes we might want to load.
std::vector< IonTypeList > plugtypes
plugins types for each region
bool trigger(int ID) const
double InVal[3]
intracellular conductivity eigenvalues
int N_IIF
how many different IIF's
void init_stim_info(void)
uses voltage for stimulation
double timer_val(const int timer_id)
figure out current value of a signal linked to a given timer
void close_files_and_cleanup()
close file descriptors
void init_logger(const char *filename)
void init_vector(SF::abstract_vector< T, S > **vec)
virtual void copy_SVs_from(IonIfBase &other, bool alloc)=0
Copies the state variables of an IMP.
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
std::vector< IonIfBase * > IIF
array of IIF's
#define ELEM_PETSC_TO_CANONICAL
Permute algebraic element data from PETSC to canonical ordering.
bool determine_model_to_run(double &time)
Determine the next model to run in the alternation between RD and Eikonal.
const T * end() const
Pointer to the vector's end.
void initialize()
Initialize the Eikonal class.
generic_timing_stats IO_stats
vec3< V > cross(const vec3< V > &a, const vec3< V > &b)
void compute_IIF(limpet::IonIfBase &pIF, limpet::GlobalData_t **impdata, int n)
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 indices_from_region_tag(SF::vector< mesh_int_t > &idx, const sf_mesh &mesh, const int tag)
Populate vertex data with the vertices of a given tag region.
bool using_legacy_stimuli
flag storing whether legacy stimuli are used
void init(sf_vec &vm, sf_vec &phie, int offset, enum physic_t=elec_phys)
initializes all datastructs after electric solver setup
virtual void mult(const abstract_vector< T, S > &x, abstract_vector< T, S > &b) const =0
void dump_state(char *, float, opencarp::mesh_t gid, bool, unsigned int)
void transpose_connectivity(const vector< T > &a_cnt, const vector< T > &a_con, vector< T > &b_cnt, vector< T > &b_con)
Transpose CRS matrix graph A into B.
sf_vec * Vmv
global Vm vector
double tot_time
total time, this is incremented externally
void log_stats(double time, bool cflg)
void clean_list()
Clean the list of nodes by resetting their status and tracking changes based on the time step of the ...
virtual void write(const char *filename) const =0
void assemble_sv_gvec(gvec_data &gvecs, limpet::MULTI_IF *miif)
Represents the ionic model and plug-in (IMP) data structure.
virtual IonIfBase * make_ion_if(Target target, int num_node, const std::vector< std::reference_wrapper< IonType >> &plugins) const =0
Generate an IonIf object from this type.
void destroy()
Currently we only need to close the file logger.
region based variations of arbitrary material parameters
GlobalData_t *** ldata
data local to each IMP
int check_acts(double tm)
check activations at sim time tm
double BathVal[3]
bath conductivity eigenvalues
std::string name
label stimulus
int timer_idx
the timer index received from the timer manager
MaterialType mtype[2]
the material types of intra_grid and extra_grid grids.
void write_data()
write registered data to disk
void compute(int start, int end, GlobalData_t **data)
Perform ionic model computation for 1 time step.
sf_mesh & get_mesh(const mesh_t gt)
Get a mesh by specifying the gridID.
SF::scattering * register_permutation(const int mesh_id, const int perm_id, const int dpn)
Register a permutation between two orderings for a mesh.
void set_initial_cv()
Set the initial conduction velocity (CV) parameters for the nodes in the mesh.
SF::vector< stimulus > stimuli
the electrical stimuli
const char * get_tsav_ext(double time)
#define ALG_TO_NODAL
Scatter algebraic to nodal.
gvec_data gvec
datastruct holding global IMP state variable output
SF::vector< double > el_scale
optionally provided per-element params scale
void dsp_from_cnt(const std::vector< T > &cnt, std::vector< T > &dsp)
Compute displacements from counts.
void get_time(double &tm)
Basic_physic * get_physics(physic_t p, bool error_if_missing)
Convinience function to get a physics.
int write_trace()
write traces to file
T sum(const vector< T > &vec)
Compute sum of a vector's entries.
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.
int * N_Nodes
#nodes for each IMP
sf_vec * old_vm
older Vm needed for 2nd order dT
size_t root_count_ascii_lines(std::string file, MPI_Comm comm)
count the lines in a ascii file
int check_quiescence(double tm, double dt)
check for quiescence
V timing(V &t2, const V &t1)
sig::time_trace wave
wave form of stimulus pulse
void setup(int idx)
Setup from a param stimulus index.
void rebuild_matrices(MaterialType *mtype, limpet::MULTI_IF &miif, FILE_SPEC logger)
void outer_prod(const Point &a, const Point &b, const double s, double *buff, const bool add=false)
opencarp::sf_vec * gdata[NUM_IMP_DATA_TYPES]
data used by all IMPs
void update_repolarization_times_from_rd(sf_vec &Vmv, sf_vec &Vmv_old, double time)
Checks if Vm crosses the repolarization threshold during each time step of the parabolic solver and u...
void dup_IMP_node_state(IonIfBase &IF, int from, int to, GlobalData_t **localdata)
size_t size() const
The current size of the vector.
void log_stats(double tm, bool cflg)
int nsubregs
#subregions forming this region
Electrical stimulation functions.
void log_msg(FILE_SPEC out, int level, unsigned char flag, const char *fmt,...)
void init_sv_gvec(gvec_data &GVs, limpet::MULTI_IF *miif, sf_vec &tmpl, igb_output_manager &output_manager)
int get_num_node() const
Gets the number of nodes handled by this IMP.
bool mesh_is_registered(const mesh_t gt)
check wheter a SF mesh is set
stim_t type
type of stimulus
void save_eikonal_state(const char *tsav_ext)
Save the current state of variables related to the Eikonal simulation to a file to initialize a futur...
size_t l_numpts
local number of points
void output_initial_activations()
output one nodal vector of initial activation time
void dump_trace(MULTI_IF *MIIF, limpet::Real time)
size_t g_numpts
global number of points
igb_output_manager output_manager_time
class handling the igb output
const T * begin() const
Pointer to the vector's start.
void f_close(FILE_SPEC &f)
Close a FILE_SPEC.
sf_mat * mass_i
lumped for parabolic problem
sf_vec * IIon
ionic currents
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.
void assign(InputIterator s, InputIterator e)
Assign a memory range.
const vector< T > & algebraic_nodes() const
Getter function for the local indices forming the local algebraic node set.
vector< S > she
sheet direction
Diffusion Reaction Eikonal Alternant Model (DREAM) based on the electrics physics class...
size_t g_numelem
global number of elements
double SF_real
Use the general double as real type.
Basic utility structs and functions, mostly IO related.
std::string timer_unit(const int timer_id)
figure out units of a signal linked to a given timer
void translate(int id)
convert legacy definitions to new format
stim_physics phys
physics of stimulus
void apply_stim_to_vector(const stimulus &s, sf_vec &vec, bool add)
SF::vector< RegionSpecs > regions
array with region params
void init_logger(const char *filename)
void setup_dataout(const int dataout, std::string dataout_vtx, mesh_t grid, SF::vector< mesh_int_t > *&restr, bool async)
void resize(size_t n)
Resize a vector.
vector< elem_t > type
element type
int get_size(MPI_Comm comm=PETSC_COMM_WORLD)
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 ...
void invert_3x3(S *ele, S &det)
int stimidx_from_timeridx(const SF::vector< stimulus > &stimuli, const int timer_id)
determine link between timer and stimulus
void update_repolarization_times(const Ionics &ion)
Estimates initial repolarization times (T_R) in Step D of DREAM.
sf_mat * rhs_parab
rhs matrix to solve parabolic
centralize time managment and output triggering
int get_rank(MPI_Comm comm=PETSC_COMM_WORLD)
T local_nodal_to_local_petsc(const meshdata< T, S > &mesh, int rank, T local_nodal)
void compute_bc()
Computes and updates boundary counditions in cycFIM.
grid_t
An electrics grid identifier to distinguish between intra and extra grids.
FILE_SPEC f_open(const char *fname, const char *mode)
Open a FILE_SPEC.
Container for a PETSc VecScatter.