18 #include <sys/resource.h>
41 #include "build_info.h"
43 #include "petsc_utils.h"
49 namespace user_globals {
69 #define __FUNCT__ "main"
71 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;
121 double stim_charge = params.stim_curr_arg*dt;
122 double bcl = params.bcl_arg;
123 double stim_start = params.stim_start_arg;
124 double stim_dur = params.stim_dur_arg;
125 int nstim = params.numstim_arg ? params.numstim_arg : -1;
126 double dt_out = params.dt_out_arg;
127 double start_out = params.start_out_arg;
128 int numNode = params.num_arg;
129 int stim_assign = params.stim_assign_flag;
130 bool analyze_AP = params.APstatistics_given || params.restitute_given;
131 bool restitute = params.restitute_given;
132 bool validate = params.validate_given;
133 bool APclamp = params.AP_clamp_file_given;
134 bool do_trace = restitute ? params.res_trace_flag : (!params.no_trace_flag);
135 bool RRC = params.RRC_mode_counter;
139 io.
w2file = validate ? 1 : params.fout_given;
140 io.
wbin = validate ? 1 : params.bin_flag;
145 log_msg(NULL, 3, 0,
"Warning: Number of nodes is less than number of processes used!");
146 log_msg(NULL, 3, 0,
"Setting number of nodes to %d.", numNode);
151 bool tr_stim =
false;
152 if (params.stim_file_given) {
153 char *fname =
dupstr(params.stim_file_arg);
157 stim_dur = stim_trace.
dur;
158 if (bcl < stim_trace.
dur)
159 log_msg(NULL, 4, 0,
"BCL less than stimulus duration!");
163 mk_RRC_trace(&stim_trace, params.stim_curr_arg,params.RRC_delay_arg,
164 -1., params.RRC_clamp_dur_arg );
167 stim_dur = stim_trace.
dur;
170 duration = nstim*bcl;
175 bool tr_light =
false;
176 if(params.light_file_given) {
177 char* fname =
dupstr(params.light_file_arg);
182 int n_clipped_to_0 = 0;
183 for(
int i=0; i<light_trace.
N; i++) {
184 if( light_trace.
s[i] < 0.0 ) {
185 light_trace.
s[i] = 0.0;
189 if( n_clipped_to_0 ) {
190 FPRINTF(WORLD stderr,
"WARNING: %d irradiance values in %s were negative (clipped to 0.0)\n", n_clipped_to_0, fname);
196 int SVclamp =
process_sv_clamps(params.clamp_SVs_arg, params.SV_clamp_files_arg, &sv_cl, dt);
207 bool IsVclamp =
initialize_clamp(&cl, params.clamp_arg, params.clamp_ini_arg,
208 params.clamp_start_arg, params.clamp_dur_arg,
209 params.clamp_file_arg,
213 log_msg(NULL, 0, 0,
"info: cannot clamp voltage and have AP clamp at same time");
217 log_msg(NULL, 0, 0,
"info: Vm will be clamped to %f mV over the interval [%f, %f]",
218 params.clamp_arg, params.clamp_start_arg, params.clamp_start_arg + params.clamp_dur_arg);
220 log_msg(NULL, 0, 0,
"info: Vm will be clamped from %f to %f mV over the interval [%f, %f]",
221 params.clamp_ini_arg, params.clamp_arg, params.clamp_start_arg,
222 params.clamp_start_arg + params.clamp_dur_arg);
229 Regions =
static_cast<char *
>(calloc(numNode,
sizeof(
char) ));
234 int *stim_list =
static_cast<int *
>(malloc(numNode*
sizeof(
int) ));
235 for (
int i = 0; i < numNode; i++) {
240 for (
unsigned int i = 0; i < params.load_module_given; i++) {
243 if (!params.imp_given) {
245 char *imp = strdup(basename(params.load_module_arg[i]) );
246 char *
dot = strrchr(imp,
'.');
249 params.imp_arg = imp;
252 log_msg(NULL, 5, 0,
"Compile with USE_DLOPEN to support dynamic module loading.");
257 if (
get_ion_type(std::string(params.imp_arg)) == NULL) {
258 fprintf(stderr,
"Illegal IMP specified: %s\n", params.imp_arg);
263 if (!
get_plug_flag(params.plug_in_arg, &num_plugins, RegionPlug)) {
264 fprintf(stderr,
"Illegal plugin specified: %s\n", params.plug_in_arg);
275 fprintf(stderr,
"Unkown target: %s\n", params.target_arg);
281 fprintf(stderr,
"Model %s was not generated for target %s\n",
286 if (!RegionPlug.empty()) {
288 fprintf(stderr,
"Plugin %s was not generated for target %s\n",
297 bool doppel_created =
false;
299 MIIF.
N_IIF = num_region;
306 MIIF.
gdata[Vm] = Vmv;
307 MIIF.
gdata[Iion] = I_ion;
313 double setup_time =
timing(t2, t1);
318 if (params.list_imps_flag || params.plugin_outputs_flag) {
323 if (params.imp_info_flag) {
328 fprintf(stderr,
"\n*** GIT tag: %s\n", GIT_COMMIT_TAG);
329 fprintf(stderr,
"*** GIT hash: %s\n", GIT_COMMIT_HASH);
330 fprintf(stderr,
"*** GIT repo: %s\n", GIT_PATH);
331 fprintf(stderr,
"*** dependency commits: %s\n\n", SUBREPO_COMMITS);
333 if (params.buildinfo_flag) {
334 fprintf(stderr,
"\n*** -buildinfo flag is deprecated and will be removed.\n");
335 fprintf( stderr,
"\n*** The build information is printed by default. \n\n");
339 MIIF.
IIF[0]->tune(params.imp_par_arg, params.plug_in_arg, params.plug_par_arg);
350 char ap_stats_fname[1024];
351 snprintf(ap_stats_fname,
sizeof ap_stats_fname,
"%s_AP_stats.dat", params.fout_arg);
352 AP.
stats = fopen(ap_stats_fname,
"wt");
360 char *res_file =
dupstr(params.res_file_arg);
362 if (r.
dur > duration) duration = r.
dur;
365 char ap_rstats_fname[1024];
366 snprintf(ap_rstats_fname,
sizeof ap_rstats_fname,
"%s_APD_restitution.dat", params.fout_arg);
367 AP.
rstats = fopen(ap_rstats_fname,
"wt");
377 double light_irrad = params.light_irrad_arg;
378 double light_start = params.light_start_arg;
379 double light_end = params.duration_arg;
380 int light_nstim = params.light_numstim_arg;
381 double light_bcl = params.light_bcl_arg;
382 double light_dur = params.light_dur_arg;
384 if(light_irrad < 0) {
385 FPRINTF(WORLD stderr,
"WARNING: irradiance value %.3f makes no sense (clipped to 0.0)\n", light_irrad);
389 if(params.light_times_given)
392 if (params.SV_init_given)
393 initial_SVs(&MIIF, params.SV_init_arg, params.imp_arg, params.plug_in_arg, numNode);
400 if (params.save_time_arg)
403 if (params.save_ini_time_given)
410 if (params.restitute_given) {
411 std::vector<double> trg;
415 if (params.res_state_vector_given) {
420 if (!strcmp(params.restitute_arg,
"S1S2f") ) {
421 trg.assign(t_dopple, t_dopple + n_dopple);
425 else if (params.stim_times_given) {
426 std::vector<double> trg;
427 trg.assign(stim_lst.
lst, stim_lst.
lst + stim_lst.
n);
435 if (MIIF.
gdata[illum] != NULL && !tr_light) {
436 if (params.light_times_given) {
437 std::vector<double> trg;
438 trg.assign(light_lst.
lst, light_lst.
lst + light_lst.
n);
442 light_bcl, light_dur,
LIGHT_TM_IDX,
"LIGHT_TIMER", NULL);
450 if (!restitute && params.doppel_on_given) {
455 if (params.read_ini_file_given) {
456 if (
read_sv(&MIIF, R1, params.read_ini_file_arg) != 0) {
463 memset(&s, 0,
sizeof(
stretch));
466 params.strain_dur_arg, params.strain_rate_arg,
467 params.strain_rate_arg, &s);
470 MIIF.
gdata[Lambda] = lambdavec;
473 for (
int i = 0; i < lambdavec->
lsize(); i++)
480 std::stringstream stim_species(params.stim_species_arg);
481 std::stringstream stim_ratios(params.stim_ratios_arg);
482 std::string specie, ratio;
483 std::vector<std::string> species_list;
484 std::vector<float> ratios_list;
488 while(std::getline(stim_species, specie,
':'))
490 species_list.push_back(specie);
492 while(std::getline(stim_ratios, ratio,
':'))
494 ratios_list.push_back(std::stof(ratio));
496 if (species_list.size() != ratios_list.size()) {
497 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);
500 for (
auto i : ratios_list)
502 if (std::abs(ratio_sum - 1) >= 0.001)
503 log_msg(NULL, 3, 0,
"Warning: Sum of ion species ratios for stimulus assignement != 1. Normalizing to sum %.1f.", ratio_sum);
507 char sv_dump_names[1024];
508 if (!params.fout_given && !params.validate_flag)
509 snprintf(sv_dump_names,
sizeof sv_dump_names,
"%s_%s", params.fout_arg, params.imp_arg);
511 strcpy(sv_dump_names, params.fout_arg);
513 if (params.validate_flag) {
514 dump_all(&MIIF, R1, params.imp_arg, params.plug_in_arg, t, dt, sv_dump_names);
517 params.imp_sv_dump_arg, params.plug_in_arg,
518 params.plug_sv_dump_arg, t, dt_out);
522 if (params.dump_lut_flag)
526 int trace_nodes[] = {0};
528 open_trace(&MIIF,
sizeof(trace_nodes)/
sizeof(trace_nodes[0]), trace_nodes, ¶ms.trace_no_arg, NULL);
534 double ini_time =
timing(t3, t2);
538 doppel_created =
true;
541 int gpu_Vm_update = 1;
542 double counter = 0.0;
543 double epsilon = 0.0000001f;
544 Bisect RRC_find( 0, INFINITY, params.RRC_tol_arg );
545 float RRC_est = params.stim_curr_arg/10.;
553 fprintf(stderr,
"Running simulation on target %s\n",
562 printf(
"[%f] Switching to new ion structure\n", tmo.
time);
566 if( RRC_find.
update( RRC_est, !RRC_repol ) ){
567 std::cout <<
"\nRRC found: " << RRC_est << std::endl;
572 std::cout << RRC_est <<
" " << RRC_repol << std::endl;
588 for (
int i = 0; i < SVclamp; i++) {
590 if (params.SV_I_trigger_flag)
595 sv_clamp(sv_cl+i, &tmo, cMIIF, trigger);
608 save_sv(cMIIF, R1, params.save_ini_file_arg);
620 else if (params.stim_volt_given) {
623 stim_charge = (params.stim_volt_arg-d[0])/params.resistance_arg*dt;
628 *(cMIIF->
gdata[Vm]) += stim_charge;
633 for (
auto ion : species_list)
635 cMIIF->
transmem_stim_species(-stim_charge*(ratios_list[iIon]/ratio_sum), ion.c_str(), params.surface_to_volume_arg, stim_list, numNode);
636 FPRINTF(WORLD stderr,
"[stim_assign] @ t = %.3f ms; charge: %f pA/pF*ms; type: %s\n", tmo.
time, stim_charge, ion.c_str());
642 if (MIIF.
gdata[illum] != NULL) {
646 FPRINTF(WORLD stderr,
"[stim] illum ON @ t = %.3f ms; E_e = %.3f mW/mm^2\n", tmo.
time, light_irrad);
649 FPRINTF(WORLD stderr,
"[stim] illum OFF @ t = %.3f ms\n", tmo.
time);
666 if (gpu_Vm_update == 0) {
668 }
else if (gpu_Vm_update == 1) {
669 cMIIF->
compute_ionic_current(fabs(counter - 0.0) < epsilon || fabs(counter - 1.0) < epsilon , fabs((counter+dt) - 1.0) < epsilon);
676 double ode_time =
timing(t6, t5);
683 log_msg(NULL, 0, 0,
"[%f] Switching back to original ion structure\n", tmo.
time);
689 double loop_time =
timing(t7, t4);
693 counter = counter + dt;
694 if ( fabs(counter - 1.0) < epsilon ) {
700 auto data = cMIIF->
gdata[Vm]->
ptr();
701 if( *data <= params.RRC_repol_arg )
708 double main_time =
timing(t8, t3);
711 const char *ExpID = params.fout_arg;
725 log_msg(NULL, 0, 0,
"\n\n\nAll done!\n\n");
729 log_msg(NULL, 0, 0,
"setup time %.6f s", (
double)t_setup->
tot);
731 log_msg(NULL, 0, 0,
"initialization time %.6f s", (
double)t_init->
tot);
733 log_msg(NULL, 0, 0,
"main loop time %.6f s", (
double)t_loop->
tot);
735 log_msg(NULL, 0, 0,
"total ode time %.6f s\n", (
double)t_ode->
tot);
737 log_msg(NULL, 0, 0,
"mn/avg/mx loop time %.6f %.6f %.6f ms",
738 (
double)t_loop->
mn*1e3, (
double)t_loop->
avg*1e3, (
double)t_loop->
mx*1e3);
739 log_msg(NULL, 0, 0,
"mn/avg/mx ODE time %.6f %.6f %.6f ms",
740 (
double)t_ode->
mn*1e3, (
double)t_ode->
avg*1e3, (
double)t_ode->
mx*1e3);
742 log_msg(NULL, 0, 0,
"real time factor %.6f\n\n", duration/(t_ode->
tot*1e3) );
745 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
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...