18 #include <sys/resource.h>
43 #include "build_info.h"
45 #include "petsc_utils.h"
51 namespace user_globals {
71 #define __FUNCT__ "main"
73 int main(
int argc,
char *argv[]) {
76 const int num_region = 1;
91 struct gengetopt_args_info params;
97 FILE *fhdls[NUM_IMP_DATA_TYPES+1];
101 char *PetscDBfile = COMPAT_PETSC_NULLPTR;
102 char *help_msg = COMPAT_PETSC_NULLPTR;
103 initialize_PETSc(&argc, argv, PetscDBfile, help_msg);
104 COMPAT_PetscOptionsInsertString(
"-options_left no");
106 if (cmdline_parser(argc, argv, ¶ms) != 0)
110 double t1, t2, t3, t4, t5, t6, t7, t8;
120 bool RRC = params.RRC_mode_counter;
121 bool Lapicque_crv = params.StimThresh_mode_counter;
122 bool restitute = params.restitute_given;
125 double dt = params.dt_arg;
126 double bcl = Lapicque_crv ? params.Lap_bcl_arg : params.bcl_arg;
127 double stim_start = Lapicque_crv ? 0. : params.stim_start_arg;
128 int nstim = Lapicque_crv ? params.Lap_numstim_arg : params.bcl_arg;
129 double stim_dur = params.stim_dur_arg;
130 double stim_charge = params.stim_curr_arg*dt;
131 double dt_out = params.dt_out_arg;
132 double start_out = params.start_out_arg;
133 int numNode = params.num_arg;
134 int stim_assign = params.stim_assign_flag;
135 bool analyze_AP = params.APstatistics_given || params.restitute_given;
136 bool validate = params.validate_given;
137 bool APclamp = params.AP_clamp_file_given;
138 bool do_trace = restitute ? params.res_trace_flag : (!params.no_trace_flag);
142 nstim = nstim ? nstim : -1;
143 io.
w2file = validate ? 1 : params.fout_given;
144 io.
wbin = validate ? 1 : params.bin_flag;
149 log_msg(NULL, 3, 0,
"Warning: Number of nodes is less than number of processes used!");
150 log_msg(NULL, 3, 0,
"Setting number of nodes to %d.", numNode);
155 bool tr_stim =
false;
156 if (params.stim_file_given) {
157 char *fname =
dupstr(params.stim_file_arg);
161 stim_dur = stim_trace.
dur;
162 if (bcl < stim_trace.
dur)
163 log_msg(NULL, 4, 0,
"BCL less than stimulus duration!");
167 mk_RRC_trace(&stim_trace, params.stim_curr_arg,params.RRC_delay_arg,
168 -1., params.RRC_clamp_dur_arg );
171 stim_dur = stim_trace.
dur;
174 duration = nstim*bcl;
179 bool tr_light =
false;
180 if(params.light_file_given) {
181 char* fname =
dupstr(params.light_file_arg);
186 int n_clipped_to_0 = 0;
187 for(
int i=0; i<light_trace.
N; i++) {
188 if( light_trace.
s[i] < 0.0 ) {
189 light_trace.
s[i] = 0.0;
193 if( n_clipped_to_0 ) {
194 FPRINTF(WORLD stderr,
"WARNING: %d irradiance values in %s were negative (clipped to 0.0)\n", n_clipped_to_0, fname);
200 int SVclamp =
process_sv_clamps(params.clamp_SVs_arg, params.SV_clamp_files_arg, &sv_cl, dt);
211 bool IsVclamp =
initialize_clamp(&cl, params.clamp_arg, params.clamp_ini_arg,
212 params.clamp_start_arg, params.clamp_dur_arg,
213 params.clamp_file_arg,
217 log_msg(NULL, 0, 0,
"info: cannot clamp voltage and have AP clamp at same time");
221 log_msg(NULL, 0, 0,
"info: Vm will be clamped to %f mV over the interval [%f, %f]",
222 params.clamp_arg, params.clamp_start_arg, params.clamp_start_arg + params.clamp_dur_arg);
224 log_msg(NULL, 0, 0,
"info: Vm will be clamped from %f to %f mV over the interval [%f, %f]",
225 params.clamp_ini_arg, params.clamp_arg, params.clamp_start_arg,
226 params.clamp_start_arg + params.clamp_dur_arg);
233 Regions =
static_cast<char *
>(calloc(numNode,
sizeof(
char) ));
238 int *stim_list =
static_cast<int *
>(malloc(numNode*
sizeof(
int) ));
239 for (
int i = 0; i < numNode; i++) {
244 for (
unsigned int i = 0; i < params.load_module_given; i++) {
247 if (!params.imp_given) {
249 char *imp = strdup(basename(params.load_module_arg[i]) );
250 char *
dot = strrchr(imp,
'.');
253 params.imp_arg = imp;
256 log_msg(NULL, 5, 0,
"Compile with USE_DLOPEN to support dynamic module loading.");
261 if (
get_ion_type(std::string(params.imp_arg)) == NULL) {
262 fprintf(stderr,
"Illegal IMP specified: %s\n", params.imp_arg);
267 if (!
get_plug_flag(params.plug_in_arg, &num_plugins, RegionPlug)) {
268 fprintf(stderr,
"Illegal plugin specified: %s\n", params.plug_in_arg);
279 fprintf(stderr,
"Unkown target: %s\n", params.target_arg);
285 fprintf(stderr,
"Model %s was not generated for target %s\n",
290 if (!RegionPlug.empty()) {
292 fprintf(stderr,
"Plugin %s was not generated for target %s\n",
301 bool doppel_created =
false;
303 MIIF.
N_IIF = num_region;
310 MIIF.
gdata[Vm] = Vmv;
311 MIIF.
gdata[Iion] = I_ion;
317 double setup_time =
timing(t2, t1);
322 if (params.list_imps_flag || params.plugin_outputs_flag) {
327 if (params.imp_info_flag) {
332 fprintf(stderr,
"\n*** GIT tag: %s\n", GIT_COMMIT_TAG);
333 fprintf(stderr,
"*** GIT hash: %s\n", GIT_COMMIT_HASH);
334 fprintf(stderr,
"*** GIT repo: %s\n", GIT_PATH);
335 fprintf(stderr,
"*** dependency commits: %s\n\n", SUBREPO_COMMITS);
337 if (params.buildinfo_flag) {
338 fprintf(stderr,
"\n*** -buildinfo flag is deprecated and will be removed.\n");
339 fprintf( stderr,
"\n*** The build information is printed by default. \n\n");
343 MIIF.
IIF[0]->tune(params.imp_par_arg, params.plug_in_arg, params.plug_par_arg);
354 char ap_stats_fname[1024];
355 snprintf(ap_stats_fname,
sizeof ap_stats_fname,
"%s_AP_stats.dat", params.fout_arg);
356 AP.
stats = fopen(ap_stats_fname,
"wt");
364 char *res_file =
dupstr(params.res_file_arg);
366 if (r.
dur > duration) duration = r.
dur;
369 char ap_rstats_fname[1024];
370 snprintf(ap_rstats_fname,
sizeof ap_rstats_fname,
"%s_APD_restitution.dat", params.fout_arg);
371 AP.
rstats = fopen(ap_rstats_fname,
"wt");
381 double light_irrad = params.light_irrad_arg;
382 double light_start = params.light_start_arg;
383 double light_end = params.duration_arg;
384 int light_nstim = params.light_numstim_arg;
385 double light_bcl = params.light_bcl_arg;
386 double light_dur = params.light_dur_arg;
388 if(light_irrad < 0) {
389 FPRINTF(WORLD stderr,
"WARNING: irradiance value %.3f makes no sense (clipped to 0.0)\n", light_irrad);
393 if(params.light_times_given)
396 if (params.SV_init_given)
397 initial_SVs(&MIIF, params.SV_init_arg, params.imp_arg, params.plug_in_arg, numNode);
404 if (params.save_time_arg)
407 if (params.save_ini_time_given)
416 if (params.restitute_given) {
417 std::vector<double> trg;
421 if (params.res_state_vector_given) {
426 if (!strcmp(params.restitute_arg,
"S1S2f") ) {
427 trg.assign(t_dopple, t_dopple + n_dopple);
431 else if (params.stim_times_given) {
432 std::vector<double> trg;
433 trg.assign(stim_lst.
lst, stim_lst.
lst + stim_lst.
n);
441 if (MIIF.
gdata[illum] != NULL && !tr_light) {
442 if (params.light_times_given) {
443 std::vector<double> trg;
444 trg.assign(light_lst.
lst, light_lst.
lst + light_lst.
n);
448 light_bcl, light_dur,
LIGHT_TM_IDX,
"LIGHT_TIMER", NULL);
456 if (!restitute && params.doppel_on_given) {
461 if (params.read_ini_file_given) {
462 if (
read_sv(&MIIF, R1, params.read_ini_file_arg) != 0) {
469 memset(&s, 0,
sizeof(
stretch));
472 params.strain_dur_arg, params.strain_rate_arg,
473 params.strain_rate_arg, &s);
476 MIIF.
gdata[Lambda] = lambdavec;
479 for (
int i = 0; i < lambdavec->
lsize(); i++)
487 if( Lapicque_crv ) lapicque =
new Lapicque(&tmo,params.Lap_min_arg,params.Lap_max_arg,
488 params.Lapicque_arg, params.thresh_tol_arg, params.thresh_tm_arg );
491 std::stringstream stim_species(params.stim_species_arg);
492 std::stringstream stim_ratios(params.stim_ratios_arg);
493 std::string specie, ratio;
494 std::vector<std::string> species_list;
495 std::vector<float> ratios_list;
499 while(std::getline(stim_species, specie,
':'))
501 species_list.push_back(specie);
503 while(std::getline(stim_ratios, ratio,
':'))
505 ratios_list.push_back(std::stof(ratio));
507 if (species_list.size() != ratios_list.size()) {
508 fprintf(stderr,
"Number of ion species for which stimulus should be assigned does not match number of ratio entries: %s | %s\n", params.stim_species_arg, params.stim_ratios_arg);
511 for (
auto i : ratios_list)
513 if (std::abs(ratio_sum - 1) >= 0.001)
514 log_msg(NULL, 3, 0,
"Warning: Sum of ion species ratios for stimulus assignement != 1. Normalizing to sum %.1f.", ratio_sum);
518 char sv_dump_names[1024];
519 if (!params.fout_given && !params.validate_flag)
520 snprintf(sv_dump_names,
sizeof sv_dump_names,
"%s_%s", params.fout_arg, params.imp_arg);
522 strcpy(sv_dump_names, params.fout_arg);
524 if (params.validate_flag) {
525 dump_all(&MIIF, R1, params.imp_arg, params.plug_in_arg, t, dt, sv_dump_names);
528 params.imp_sv_dump_arg, params.plug_in_arg,
529 params.plug_sv_dump_arg, t, dt_out);
533 if (params.dump_lut_flag)
537 int trace_nodes[] = {0};
539 open_trace(&MIIF,
sizeof(trace_nodes)/
sizeof(trace_nodes[0]), trace_nodes, ¶ms.trace_no_arg, NULL);
545 double ini_time =
timing(t3, t2);
549 doppel_created =
true;
552 int gpu_Vm_update = 1;
553 double counter = 0.0;
554 double epsilon = 0.0000001f;
555 Bisect RRC_find( 0, INFINITY, params.RRC_tol_arg );
556 float RRC_est = params.stim_curr_arg/10.;
564 fprintf(stderr,
"Running simulation on target %s\n",
573 printf(
"[%f] Switching to new ion structure\n", tmo.
time);
577 if( RRC_find.
update( RRC_est, !RRC_repol ) ){
578 std::cout <<
"\nRRC found: " << RRC_est << std::endl;
583 std::cout << RRC_est <<
" " << RRC_repol << std::endl;
585 }
else if( Lapicque_crv ) {
587 bool fire = cMIIF->
gdata[Vm]->
get(0) >= params.vthreshold_arg;
588 float stimcurr = stim_charge/dt;
591 stim_charge = stimcurr*dt;
610 for (
int i = 0; i < SVclamp; i++) {
612 if (params.SV_I_trigger_flag)
617 sv_clamp(sv_cl+i, &tmo, cMIIF, trigger);
630 save_sv(cMIIF, R1, params.save_ini_file_arg);
642 else if (params.stim_volt_given) {
645 stim_charge = (params.stim_volt_arg-d[0])/params.resistance_arg*dt;
650 *(cMIIF->
gdata[Vm]) += stim_charge;
655 for (
auto ion : species_list)
657 cMIIF->
transmem_stim_species(-stim_charge*(ratios_list[iIon]/ratio_sum), ion.c_str(), params.surface_to_volume_arg, stim_list, numNode);
658 FPRINTF(WORLD stderr,
"[stim_assign] @ t = %.3f ms; charge: %f pA/pF*ms; type: %s\n", tmo.
time, stim_charge, ion.c_str());
664 if (MIIF.
gdata[illum] != NULL) {
668 FPRINTF(WORLD stderr,
"[stim] illum ON @ t = %.3f ms; E_e = %.3f mW/mm^2\n", tmo.
time, light_irrad);
671 FPRINTF(WORLD stderr,
"[stim] illum OFF @ t = %.3f ms\n", tmo.
time);
688 if (gpu_Vm_update == 0) {
690 }
else if (gpu_Vm_update == 1) {
691 cMIIF->
compute_ionic_current(fabs(counter - 0.0) < epsilon || fabs(counter - 1.0) < epsilon , fabs((counter+dt) - 1.0) < epsilon);
698 double ode_time =
timing(t6, t5);
705 log_msg(NULL, 0, 0,
"[%f] Switching back to original ion structure\n", tmo.
time);
711 double loop_time =
timing(t7, t4);
715 counter = counter + dt;
716 if ( fabs(counter - 1.0) < epsilon ) {
722 auto data = cMIIF->
gdata[Vm]->
ptr();
723 if( *data <= params.RRC_repol_arg )
730 double main_time =
timing(t8, t3);
733 const char *ExpID = params.fout_arg;
738 if( params.Lap_file_given ) {
739 std::ofstream ofs(params.Lap_file_arg);
740 lapicque->
print(ofs);
742 lapicque->
print(std::cout);
754 log_msg(NULL, 0, 0,
"\n\n\nAll done!\n\n");
758 log_msg(NULL, 0, 0,
"setup time %.6f s", (
double)t_setup->
tot);
760 log_msg(NULL, 0, 0,
"initialization time %.6f s", (
double)t_init->
tot);
762 log_msg(NULL, 0, 0,
"main loop time %.6f s", (
double)t_loop->
tot);
764 log_msg(NULL, 0, 0,
"total ode time %.6f s\n", (
double)t_ode->
tot);
766 log_msg(NULL, 0, 0,
"mn/avg/mx loop time %.6f %.6f %.6f ms",
767 (
double)t_loop->
mn*1e3, (
double)t_loop->
avg*1e3, (
double)t_loop->
mx*1e3);
768 log_msg(NULL, 0, 0,
"mn/avg/mx ODE time %.6f %.6f %.6f ms",
769 (
double)t_ode->
mn*1e3, (
double)t_ode->
avg*1e3, (
double)t_ode->
mx*1e3);
771 log_msg(NULL, 0, 0,
"real time factor %.6f\n\n", duration/(t_ode->
tot*1e3) );
774 CHKERRQ(PetscFinalize());
Define multiple ionic models to be used in different regions.
opencarp::real_t SF_real
Global scalar type.
Basic utility structs and functions, mostly IO related.
int main(int argc, char *argv[])
bool update(float &val, bool success)
update search
void print(std::ostream &)
bool init(int, int)
initial first step
bool check(bool fire, float &, int, int)
check if the Lapicque curve is finished and update current
virtual void get(const vector< T > &idx, S *out)=0
virtual void release_ptr(S *&p)=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
The scatterer registry class.
Abstract class representing an ionic model type.
virtual Target select_target(Target target) const =0
Gets a supported target from the given target.
bool extUpdateVm
flag indicating update function for Vm
std::vector< IonIfBase * > IIF
array of IIF's
opencarp::sf_vec * gdata[NUM_IMP_DATA_TYPES]
data used by all IMPs
void sv_dump_add_by_name_list(int, char *, char *, char *, char *, char *, double, double)
node_count_t numNode
local number of nodes
size_t dump_svs(opencarp::base_timer *)
int * numplugs
number of plugins for each region
std::vector< Target > targets
target for each region
std::vector< IonTypeList > plugtypes
plugins types for each region
IonTypeList iontypes
type for each region
void dump_state(char *, float, opencarp::mesh_t gid, bool, unsigned int)
SV_DUMP svd
state variable dump
void transmem_stim_species(float, const char *, float, int *, int)
void initialize_currents(double, int)
int N_IIF
how many different IIF's
void compute_ionic_current(bool flag_send=1, bool flag_receive=1)
GPU kernel to emulate the add_scaled call made to adjust the Vm values when the update to Vm is not m...
void dump_luts_MIIF(bool)
IIF_Mask_t * IIFmask
region for each node
centralize time managment and output triggering
void initialize_neq_timer(const std::vector< double > &itrig, double idur, int ID, const char *iname, const char *poolname=nullptr)
long d_time
current time instance index
bool trigger(int ID) const
void initialize_eq_timer(double istart, double iend, int ntrig, double iintv, double idur, int ID, const char *iname, const char *poolname=nullptr)
double time_step
global reference time step
void initialize_singlestep_timer(double tg, double idur, int ID, const char *iname, const char *poolname=nullptr)
int trigger_elapse(int ID) const
bool trigger_end(int ID) const
std::vector< base_timer * > timers
vector containing individual timers
bool triggered_now(int ID) const
void init_vector(SF::abstract_vector< T, S > **vec)
int mk_RRC_trace(trace *tr, float st, float delay, float clamp, float dur)
make a trace for a repolarization reserve current calculation
void initial_SVs(MULTI_IF *miif, char *SVs, char *imp, char *plgins, int num)
void doppel_MIIF(MULTI_IF *orig, MULTI_IF *miif_doppel)
int write_dump_header(GVEC_DUMP *gvd, SV_DUMP *svd, const char *ExpID)
int get_plug_flag(char *plgstr, int *out_num_plugins, IonTypeList &out_plugins)
void doppel_update(MULTI_IF *orig, MULTI_IF *miif_doppel)
void globalvec_dump(FILE **fhdls, GVEC_DUMP *gvd, MULTI_IF *pMIIF, timer_manager *tmo, IOCtrl *io, int numNode)
void resample_trace(trace *tr, double dt)
int load_ionic_module(const char *)
void free_trace(trace *tr)
void clamp_signal(MULTI_IF *pMIIF, Clamp *cl, timer_manager *tm)
Target
enum that represents different targets to run ionic models on.
@ UNKNOWN
special value to handle unknown targets
void set_trace_amp(trace *tr, float val, float whenceforth)
change the amplitude of part of a trace
void sv_clamp(Clamp *cl, timer_manager *tm, MULTI_IF *miif, bool trigger)
@ LOOP_IDX
timing for main loop (including IO and ODE solve)
@ ODE_IDX
timing for ODE solve
@ INIT_IDX
timing for initialization
@ N_TIMINGS
number of benchmark timings we use
@ SETUP_IDX
timing for setup phase
std::string get_string_from_target(Target const target)
Get a string representation of a given target.
void dump_all(MULTI_IF *MIIF, int reg, char *imp, char *plugs, double t, double ddt, char *fout)
void close_globalvec_dump(FILE **fhdls, GVEC_DUMP *gvd, IOCtrl *io)
IonType * get_ion_type(const std::string &name)
int initialize_AP_analysis(action_potential *AP)
void restitution_trigger_list(char *r_file, restitution *r, char *protocol, int *n_dop, double **t_dop)
void save_sv(MULTI_IF *, int, const char *)
double getCellVal(sf_vec *v, int ind)
std::string get_target_list_string()
Returns a string containing the list of available targets.
void apply_stretch(MULTI_IF *miif, stretch *s, timer_manager *tm)
bool is_gpu(Target const target)
Checks if this is a GPU target.
void restitution_save_sv(MULTI_IF *miif, int R1, restitution *r, action_potential *AP)
void print_AP_stats_header(action_potential *AP, FILE *outbuf)
void initialize_timings(event_timing *t)
bool initialize_clamp(Clamp *cl, double cl_val, double ini_val, double start, double dur, const char *f, int trans, float *duration)
void initializePulseStretch(float strain, float onset, float duration, float rise, float fall, stretch *s)
void determine_stim_list(char *stl, TrgList *trg, bool DIAs)
void cleanup_AP_analysis(action_potential *AP)
std::vector< std::reference_wrapper< IonType > > IonTypeList
float determine_duration(struct gengetopt_args_info *p, TrgList *stim_lst)
determine time of last stimulus
int process_sv_clamps(char *SVs, char *files, Clamp **clamps, double dt)
int read_trace(trace *tr, const char *name)
void open_globalvec_dump(FILE **fhdls, GVEC_DUMP *gvd, MULTI_IF *pMIIF, char *base_name, IOCtrl *io)
int read_sv(MULTI_IF *, int, const char *)
void close_trace(MULTI_IF *MIIF)
void dump_trace(MULTI_IF *MIIF, limpet::Real time)
void update_timing(event_timing *t, double event_duration)
void open_trace(MULTI_IF *MIIF, int n_traceNodes, int *traceNodes, int *label, opencarp::sf_mesh *imesh)
Set up ionic model traces at some global node numbers.
void free_doppel(MULTI_IF *m)
void initialize_sv_clamp(Clamp *cl, const char *sv, char *file, double dt)
bool check_events(double vm, action_potential *AP, timer_manager *tm)
void print_param_help(IonType *im, IonTypeList &plugs)
Target get_target_from_string(std::string const str)
Returns a value from the Target enum from a given string.
void AP_clamp(Clamp *cl, timer_manager *tm, sf_vec *v, bool trigger)
timer_manager * tm_manager
a manager for the various physics timers
std::map< SF::quadruple< int >, SF::index_mapping< mesh_int_t > > map_reg
Registriy for the inter domain mappings.
SF::scatter_registry scatter_reg
Registry for the different scatter objects.
std::map< mesh_t, sf_mesh > mesh_reg
Registry for the different meshes used in a multi-physics simulation.
V dot(const vec3< V > &p1, const vec3< V > &p2)
char * dupstr(const char *old_str)
void log_msg(FILE_SPEC out, int level, unsigned char flag, const char *fmt,...)
void get_time(double &tm)
int get_size(MPI_Comm comm=PETSC_COMM_WORLD)
V timing(V &t2, const V &t1)
char wbin
write to file in binary format
int n
number of pulses required for protocol
double * lst
store instants of pulse delivery
bool * pmat
store flag to indicate prematurity
bool pmat
indiacte premature AP
FILE * rstats
output restitution statistics only
FILE * stats
output statistics for each AP
double vm_trc[VM_HIST_LEN]
double avg
average duration of event
double mx
maximum duration of event
double mn
minimum duration of event
double tot
total duration of all events
TrgList saveState
instants at wich we save state vectors
double dur
total duration of protocol
TrgList trigs
trigger list for defining stim sequence
manage input, output, resampling of traces
Defines valid targets for an ionic model to run on and an allocator for allocating memory on a specif...