18 #include <sys/resource.h>
43 #include "build_info.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 =
nullptr;
102 char *help_msg =
nullptr;
105 if (
petsc_active()) petsc_insert_options(
"-options_left no");
108 if (cmdline_parser(argc, argv, ¶ms) != 0)
112 double t1, t2, t3, t4, t5, t6, t7, t8;
122 bool RRC = params.RRC_mode_counter;
123 bool Lapicque_crv = params.StimThresh_mode_counter;
124 bool restitute = params.restitute_given;
127 double dt = params.dt_arg;
128 double bcl = Lapicque_crv ? params.Lap_bcl_arg : params.bcl_arg;
129 double stim_start = Lapicque_crv ? 0. : params.stim_start_arg;
130 int nstim = Lapicque_crv ? params.Lap_numstim_arg : params.numstim_arg;
131 double stim_dur = params.stim_dur_arg;
132 double stim_charge = params.stim_curr_arg*dt;
133 double dt_out = params.dt_out_arg;
134 double start_out = params.start_out_arg;
135 int numNode = params.num_arg;
136 int stim_assign = params.stim_assign_flag;
137 bool analyze_AP = params.APstatistics_given || params.restitute_given;
138 bool validate = params.validate_given;
139 bool APclamp = params.AP_clamp_file_given;
140 bool do_trace = restitute ? params.res_trace_flag : (!params.no_trace_flag);
144 nstim = nstim ? nstim : -1;
145 io.
w2file = validate ? 1 : params.fout_given;
146 io.
wbin = validate ? 1 : params.bin_flag;
151 log_msg(NULL, 3, 0,
"Warning: Number of nodes is less than number of processes used!");
152 log_msg(NULL, 3, 0,
"Setting number of nodes to %d.", numNode);
157 bool tr_stim =
false;
158 if (params.stim_file_given) {
159 char *fname =
dupstr(params.stim_file_arg);
163 stim_dur = stim_trace.
dur;
164 if (bcl < stim_trace.
dur)
165 log_msg(NULL, 4, 0,
"BCL less than stimulus duration!");
169 mk_RRC_trace(&stim_trace, params.stim_curr_arg,params.RRC_delay_arg,
170 -1., params.RRC_clamp_dur_arg );
173 stim_dur = stim_trace.
dur;
176 duration = nstim*bcl;
181 bool tr_light =
false;
182 if(params.light_file_given) {
183 char* fname =
dupstr(params.light_file_arg);
188 int n_clipped_to_0 = 0;
189 for(
int i=0; i<light_trace.
N; i++) {
190 if( light_trace.
s[i] < 0.0 ) {
191 light_trace.
s[i] = 0.0;
195 if( n_clipped_to_0 ) {
196 if (!
get_rank()) fprintf(stderr,
"WARNING: %d irradiance values in %s were negative (clipped to 0.0)\n", n_clipped_to_0, fname);
202 int SVclamp =
process_sv_clamps(params.clamp_SVs_arg, params.SV_clamp_files_arg, &sv_cl, dt);
213 bool IsVclamp =
initialize_clamp(&cl, params.clamp_arg, params.clamp_ini_arg,
214 params.clamp_start_arg, params.clamp_dur_arg,
215 params.clamp_file_arg,
219 log_msg(NULL, 0, 0,
"info: cannot clamp voltage and have AP clamp at same time");
223 log_msg(NULL, 0, 0,
"info: Vm will be clamped to %f mV over the interval [%f, %f]",
224 params.clamp_arg, params.clamp_start_arg, params.clamp_start_arg + params.clamp_dur_arg);
226 log_msg(NULL, 0, 0,
"info: Vm will be clamped from %f to %f mV over the interval [%f, %f]",
227 params.clamp_ini_arg, params.clamp_arg, params.clamp_start_arg,
228 params.clamp_start_arg + params.clamp_dur_arg);
235 Regions =
static_cast<char *
>(calloc(numNode,
sizeof(
char) ));
240 int *stim_list =
static_cast<int *
>(malloc(numNode*
sizeof(
int) ));
241 for (
int i = 0; i < numNode; i++) {
246 for (
unsigned int i = 0; i < params.load_module_given; i++) {
249 if (!params.imp_given) {
251 char *imp = strdup(basename(params.load_module_arg[i]) );
252 char *
dot = strrchr(imp,
'.');
255 params.imp_arg = imp;
258 log_msg(NULL, 5, 0,
"Compile with USE_DLOPEN to support dynamic module loading.");
263 if (
get_ion_type(std::string(params.imp_arg)) == NULL) {
264 fprintf(stderr,
"Illegal IMP specified: %s\n", params.imp_arg);
269 if (!
get_plug_flag(params.plug_in_arg, &num_plugins, RegionPlug)) {
270 fprintf(stderr,
"Illegal plugin specified: %s\n", params.plug_in_arg);
281 fprintf(stderr,
"Unkown target: %s\n", params.target_arg);
287 fprintf(stderr,
"Model %s was not generated for target %s\n",
292 if (!RegionPlug.empty()) {
294 fprintf(stderr,
"Plugin %s was not generated for target %s\n",
303 bool doppel_created =
false;
305 MIIF.
N_IIF = num_region;
312 MIIF.
gdata[Vm] = Vmv;
313 MIIF.
gdata[Iion] = I_ion;
319 double setup_time =
timing(t2, t1);
324 if (params.list_imps_flag || params.plugin_outputs_flag) {
329 if (params.imp_info_flag) {
334 fprintf(stderr,
"\n*** GIT tag: %s\n", GIT_COMMIT_TAG);
335 fprintf(stderr,
"*** GIT hash: %s\n", GIT_COMMIT_HASH);
336 fprintf(stderr,
"*** GIT repo: %s\n", GIT_PATH);
337 fprintf(stderr,
"*** dependency commits: %s\n\n", SUBREPO_COMMITS);
339 if (params.buildinfo_flag) {
340 fprintf(stderr,
"\n*** -buildinfo flag is deprecated and will be removed.\n");
341 fprintf( stderr,
"\n*** The build information is printed by default. \n\n");
345 MIIF.
IIF[0]->tune(params.imp_par_arg, params.plug_in_arg, params.plug_par_arg);
356 char ap_stats_fname[1024];
357 snprintf(ap_stats_fname,
sizeof ap_stats_fname,
"%s_AP_stats.dat", params.fout_arg);
358 AP.
stats = fopen(ap_stats_fname,
"wt");
366 char *res_file =
dupstr(params.res_file_arg);
368 if (r.
dur > duration) duration = r.
dur;
371 char ap_rstats_fname[1024];
372 snprintf(ap_rstats_fname,
sizeof ap_rstats_fname,
"%s_APD_restitution.dat", params.fout_arg);
373 AP.
rstats = fopen(ap_rstats_fname,
"wt");
383 double light_irrad = params.light_irrad_arg;
384 double light_start = params.light_start_arg;
385 double light_end = params.duration_arg;
386 int light_nstim = params.light_numstim_arg;
387 double light_bcl = params.light_bcl_arg;
388 double light_dur = params.light_dur_arg;
390 if(light_irrad < 0) {
391 if (!
get_rank()) fprintf(stderr,
"WARNING: irradiance value %.3f makes no sense (clipped to 0.0)\n", light_irrad);
395 if(params.light_times_given)
398 if (params.SV_init_given)
399 initial_SVs(&MIIF, params.SV_init_arg, params.imp_arg, params.plug_in_arg, numNode);
406 if (params.save_time_arg)
409 if (params.save_ini_time_given)
418 if (params.restitute_given) {
419 std::vector<double> trg;
423 if (params.res_state_vector_given) {
428 if (!strcmp(params.restitute_arg,
"S1S2f") ) {
429 trg.assign(t_dopple, t_dopple + n_dopple);
433 else if (params.stim_times_given) {
434 std::vector<double> trg;
435 trg.assign(stim_lst.
lst, stim_lst.
lst + stim_lst.
n);
443 if (MIIF.
gdata[illum] != NULL && !tr_light) {
444 if (params.light_times_given) {
445 std::vector<double> trg;
446 trg.assign(light_lst.
lst, light_lst.
lst + light_lst.
n);
450 light_bcl, light_dur,
LIGHT_TM_IDX,
"LIGHT_TIMER", NULL);
458 if (!restitute && params.doppel_on_given) {
463 if (params.read_ini_file_given) {
464 if (
read_sv(&MIIF, R1, params.read_ini_file_arg) != 0) {
471 memset(&s, 0,
sizeof(
stretch));
474 params.strain_dur_arg, params.strain_rate_arg,
475 params.strain_rate_arg, &s);
478 MIIF.
gdata[Lambda] = lambdavec;
481 for (
int i = 0; i < lambdavec->
lsize(); i++)
489 if( Lapicque_crv ) lapicque =
new Lapicque(&tmo,params.Lap_min_arg,params.Lap_max_arg,
490 params.Lapicque_arg, params.thresh_tol_arg, params.thresh_tm_arg );
493 std::stringstream stim_species(params.stim_species_arg);
494 std::stringstream stim_ratios(params.stim_ratios_arg);
495 std::string specie, ratio;
496 std::vector<std::string> species_list;
497 std::vector<float> ratios_list;
501 while(std::getline(stim_species, specie,
':'))
503 species_list.push_back(specie);
505 while(std::getline(stim_ratios, ratio,
':'))
507 ratios_list.push_back(std::stof(ratio));
509 if (species_list.size() != ratios_list.size()) {
510 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);
513 for (
auto i : ratios_list)
515 if (std::abs(ratio_sum - 1) >= 0.001)
516 log_msg(NULL, 3, 0,
"Warning: Sum of ion species ratios for stimulus assignement != 1. Normalizing to sum %.1f.", ratio_sum);
520 char sv_dump_names[1024];
521 if (!params.fout_given && !params.validate_flag)
522 snprintf(sv_dump_names,
sizeof sv_dump_names,
"%s_%s", params.fout_arg, params.imp_arg);
524 strcpy(sv_dump_names, params.fout_arg);
526 if (params.validate_flag) {
527 dump_all(&MIIF, R1, params.imp_arg, params.plug_in_arg, t, dt, sv_dump_names);
530 params.imp_sv_dump_arg, params.plug_in_arg,
531 params.plug_sv_dump_arg, t, dt_out);
535 if (params.dump_lut_flag)
539 int trace_nodes[] = {0};
541 open_trace(&MIIF,
sizeof(trace_nodes)/
sizeof(trace_nodes[0]), trace_nodes, ¶ms.trace_no_arg, NULL);
547 double ini_time =
timing(t3, t2);
551 doppel_created =
true;
554 int gpu_Vm_update = 1;
555 double counter = 0.0;
556 double epsilon = 0.0000001f;
557 Bisect RRC_find( 0, INFINITY, params.RRC_tol_arg );
558 float RRC_est = params.stim_curr_arg/10.;
566 fprintf(stderr,
"Running simulation on target %s\n",
575 printf(
"[%f] Switching to new ion structure\n", tmo.
time);
579 if( RRC_find.
update( RRC_est, !RRC_repol ) ){
580 std::cout <<
"\nRRC found: " << RRC_est << std::endl;
585 std::cout << RRC_est <<
" " << RRC_repol << std::endl;
587 }
else if( Lapicque_crv ) {
589 bool fire = cMIIF->
gdata[Vm]->
get(0) >= params.vthreshold_arg;
590 float stimcurr = stim_charge/dt;
593 stim_charge = stimcurr*dt;
612 for (
int i = 0; i < SVclamp; i++) {
614 if (params.SV_I_trigger_flag)
619 sv_clamp(sv_cl+i, &tmo, cMIIF, trigger);
632 save_sv(cMIIF, R1, params.save_ini_file_arg);
644 else if (params.stim_volt_given) {
647 stim_charge = (params.stim_volt_arg-d[0])/params.resistance_arg*dt;
652 *(cMIIF->
gdata[Vm]) += stim_charge;
657 for (
auto ion : species_list)
659 cMIIF->
transmem_stim_species(-stim_charge*(ratios_list[iIon]/ratio_sum), ion.c_str(), params.surface_to_volume_arg, stim_list, numNode);
660 if (!
get_rank()) fprintf(stderr,
"[stim_assign] @ t = %.3f ms; charge: %f pA/pF*ms; type: %s\n", tmo.
time, stim_charge, ion.c_str());
666 if (MIIF.
gdata[illum] != NULL) {
670 if (!
get_rank()) fprintf(stderr,
"[stim] illum ON @ t = %.3f ms; E_e = %.3f mW/mm^2\n", tmo.
time, light_irrad);
673 if (!
get_rank()) fprintf(stderr,
"[stim] illum OFF @ t = %.3f ms\n", tmo.
time);
690 if (gpu_Vm_update == 0) {
692 }
else if (gpu_Vm_update == 1) {
693 cMIIF->
compute_ionic_current(fabs(counter - 0.0) < epsilon || fabs(counter - 1.0) < epsilon , fabs((counter+dt) - 1.0) < epsilon);
700 double ode_time =
timing(t6, t5);
707 log_msg(NULL, 0, 0,
"[%f] Switching back to original ion structure\n", tmo.
time);
713 double loop_time =
timing(t7, t4);
717 counter = counter + dt;
718 if ( fabs(counter - 1.0) < epsilon ) {
724 auto data = cMIIF->
gdata[Vm]->
ptr();
725 if( *data <= params.RRC_repol_arg )
732 double main_time =
timing(t8, t3);
735 const char *ExpID = params.fout_arg;
740 if( params.Lap_file_given ) {
741 std::ofstream ofs(params.Lap_file_arg);
742 lapicque->
print(ofs);
744 lapicque->
print(std::cout);
756 log_msg(NULL, 0, 0,
"\n\n\nAll done!\n\n");
760 log_msg(NULL, 0, 0,
"setup time %.6f s", (
double)t_setup->
tot);
762 log_msg(NULL, 0, 0,
"initialization time %.6f s", (
double)t_init->
tot);
764 log_msg(NULL, 0, 0,
"main loop time %.6f s", (
double)t_loop->
tot);
766 log_msg(NULL, 0, 0,
"total ode time %.6f s\n", (
double)t_ode->
tot);
768 log_msg(NULL, 0, 0,
"mn/avg/mx loop time %.6f %.6f %.6f ms",
769 (
double)t_loop->
mn*1e3, (
double)t_loop->
avg*1e3, (
double)t_loop->
mx*1e3);
770 log_msg(NULL, 0, 0,
"mn/avg/mx ODE time %.6f %.6f %.6f ms",
771 (
double)t_ode->
mn*1e3, (
double)t_ode->
avg*1e3, (
double)t_ode->
mx*1e3);
773 log_msg(NULL, 0, 0,
"real time factor %.6f\n\n", duration/(t_ode->
tot*1e3) );
Define multiple ionic models to be used in different regions.
opencarp::real_t SF_real
Global scalar type.
Starts and stops the linear algebra backend the flavor parameter selects.
#define EXIT(A)
finalize the backend, if it runs, and exit
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)
int get_size(MPI_Comm comm=SF_COMM)
void initialize_backend(int *argc, char **argv, char *rc, char *help_msg)
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_rank(MPI_Comm comm=SF_COMM)
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...