openCARP
Doxygen code documentation for the open cardiac electrophysiology simulator openCARP
stimulate.cc
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // openCARP is an open cardiac electrophysiology simulator.
3 //
4 // Copyright (C) 2020 openCARP project
5 //
6 // This program is licensed under the openCARP Academic Public License (APL)
7 // v1.0: You can use and redistribute it and/or modify it in non-commercial
8 // academic environments under the terms of APL as published by the openCARP
9 // project v1.0, or (at your option) any later version. Commercial use requires
10 // a commercial license (info@opencarp.org).
11 //
12 // This program is distributed without any warranty; see the openCARP APL for
13 // more details.
14 //
15 // You should have received a copy of the openCARP APL along with this program
16 // and can find it online: http://www.opencarp.org/license
17 // ----------------------------------------------------------------------------
18 
27 #include "stimulate.h"
28 #include "electrics.h"
29 
30 #include "SF_init.h" // for SF::init_xxx()
31 #include "petsc_utils.h" // TODO for EXIT
32 
33 namespace opencarp {
34 
35 // stimulus convenience functions
36 // group stimulus types
37 namespace stim_info {
39  std::set<int> current_stim {I_tm, I_ex, I_in};
41  std::map<int,std::string> units;
42 } // namespace stim_info
43 
44 namespace user_globals {
45 
46  extern timer_manager* tm_manager;
47 } // namespace user_globals
48 
49 void init_stim_info(void)
50 {
51  stim_info::units[I_tm] = "uA/cm^2";
52  stim_info::units[I_ex] = "uA/cm^3";
53  stim_info::units[Phi_ex] = "mV";
54  stim_info::units[GND_ex] = "mV";
55  stim_info::units[I_in] = "uA/cm^3";
56  stim_info::units[Phi_ex_ol] = "mV";
57  // stim_info::units[I_tm_grad] = ""; //!<
58  // stim_info::units[I_lat] = "uA/cm^2"; //!< acts as transmembrane current stimulus
59  stim_info::units[Vm_clmp] = "mV";
60  stim_info::units[Phi_in] = "mV";
61  stim_info::units[Phi_in_ol] = "mV";
62 }
63 
64 
66 bool is_potential(stim_t type)
67 {
68  return stim_info::potential_stim.count(type);
69 }
70 
72 bool is_current(stim_t type)
73 {
74  return stim_info::current_stim.count(type);
75 }
76 
77 bool is_dbc(stim_t type)
78 {
79  return stim_info::dbc_stim.count(type);
80 }
81 
82 bool is_extra(stim_t type)
83 {
84  switch(type) {
85  default:
86  case Illum:
87  case I_tm:
88  case Vm_clmp:
89  case Phi_in:
90  case Phi_in_ol:
91  case I_in:
92  return false;
93 
94  case I_ex:
95  case Phi_ex:
96  case Phi_ex_ol:
97  case GND_ex:
98  return true;
99  }
100 }
101 
102 
105 void stimulus::translate(int iidx)
106 {
107  idx = iidx;
108 
109  // translate protocol
110  Stim & s = param_globals::stim[idx];
111  Stimulus & curstim = param_globals::stimulus[idx];
112 
113  s.ptcl.bcl = curstim.bcl;
114  s.ptcl.npls = curstim.npls;
115  s.ptcl.start = curstim.start;
116  s.ptcl.duration = curstim.duration;
117 
118  // translate pulse
119  // create a name, old stimulus structure lacks this feature, no naming of pulse waveforms
120  std::string pulse_name;
121  pulse_name = "pulse_" + std::to_string(idx);
122  s.pulse.name = (char*) calloc(pulse_name.length()+1, sizeof(char));
123  strcpy(s.pulse.name, pulse_name.c_str());
124 
125  // old stimulus treats any pulse as truncated exponential shape
126  s.pulse.shape = truncExpPulse;
127  s.pulse.file = strdup(curstim.pulse_file);
128  s.pulse.bias = curstim.bias;
129  s.pulse.tau_plateau = curstim.tau_plateau;
130  s.pulse.tau_edge = curstim.tau_edge;
131  s.pulse.s2 = curstim.s2;
132  s.pulse.d1 = curstim.d1;
133  s.pulse.strength = curstim.strength;
134 
135  // strength is not a scalar, we prescribe a different strength at every node
136  s.elec.vtx_fcn = curstim.vtx_fcn;
137 
138  // translate circuit
139  s.crct.type = curstim.stimtype;
140  s.crct.balance = curstim.balance;
141  s.crct.total_current = curstim.total_current;
142 
143  // translate electrode
144  s.elec.geomID = curstim.geometry;
145  // s.elec.domain = curstim.domain;
146  s.elec.vtx_file = strdup(curstim.vtx_file);
147  s.elec.dump_vtx_file = curstim.dump_vtx_file;
148 
149  // check whether we have a sound electrode geometry definition
150  s.elec.geom_type = 2; // should be region_t block;
151  s.elec.p0[0] = curstim.x0 - (curstim.ctr_def?curstim.xd/2.:0.);
152  s.elec.p0[1] = curstim.y0 - (curstim.ctr_def?curstim.yd/2.:0.);
153  s.elec.p0[2] = curstim.z0 - (curstim.ctr_def?curstim.zd/2.:0.);
154  s.elec.p1[0] = s.elec.p0[0] + curstim.xd;
155  s.elec.p1[1] = s.elec.p0[1] + curstim.yd;
156  s.elec.p1[2] = s.elec.p0[2] + curstim.zd;
157 
158  // cp overall electrode name
159  s.name = strdup(curstim.name);
160 }
161 
166 void stimulus::setup(int iidx)
167 {
168  idx = iidx;
169  const Stim & cur_stim = param_globals::stim[idx];
170 
171  // label stimulus
172  if(cur_stim.name != std::string(""))
173  name = cur_stim.name;
174  else
175  name = "Stimulus_" + std::to_string(idx);
176 
177  // set up physics of applied stimulus
179 
180  // set up stimulus pulse
181  pulse.setup(idx);
182 
183  // set up the spatial region of the stimulus
185 
186  // set up stimulation protocol
187  ptcl.setup(idx,name);
188 }
189 
191 {
192  // closed loop intra-/extracellular potential stimuli are always active
193  if(this->phys.type == Phi_ex || this->phys.type == Phi_in)
194  return true;
195 
197 }
198 
199 
202 void stim_pulse::setup(int idx)
203 {
204  const Stim & cur_stim = param_globals::stim[idx];
205  const Pulse & pulse = cur_stim.pulse;
206 
207  // assign waveform type and parameters
208  waveform_t wvt;
209  // set waveform based on circuit type/file/param
210  switch (cur_stim.crct.type) {
211  case Vm_clmp:
212  case GND_ex:
213  wvt = constPulse;
214  break;
215 
216  default:
217  if (pulse.file && strlen(pulse.file))
218  wvt = arbPulse;
219  else
220  wvt = static_cast<waveform_t>(pulse.shape);
221  break;
222  }
223 
224  assign(pulse.strength, cur_stim.ptcl.duration, param_globals::dt, wvt);
225  sample_wave_form(*this, idx);
226 
227  // add unit labels
228  std::string sUnit = stim_info::units[(stim_t)cur_stim.crct.type];
229  std::string tUnit = "ms";
230  this->wave.setUnits(tUnit,sUnit);
231 }
232 
233 
234 void get_stim_list(const char* str_list, std::vector<double> & stlist)
235 {
236  std::string tstim = str_list;
237  std::vector<std::string> stims;
238  split_string(tstim, ',', stims);
239 
240  stlist.resize(stims.size());
241  size_t widx = 0, err = 0;
242 
243  for(size_t i=0; i<stims.size(); i++) {
244  std::string & stim = stims[i];
245 
246  if(stim.size()) {
247  if(stim[0] == '+') {
248  double last = widx == 0 ? 0.0 : stlist[widx-1];
249  stim.erase(0, 1); // erase first char
250 
251  // we use sscanf so that we can actually determine if the string was converted
252  // into a double. atof does not allow for error-checking
253  double cur = -1.0;
254  size_t nread = sscanf(stim.c_str(), "%lf", &cur);
255  if(nread)
256  stlist[widx++] = cur + last;
257  } else {
258  double cur = -1.0;
259  size_t nread = sscanf(stim.c_str(), "%lf", &cur);
260  if(nread)
261  stlist[widx++] = cur;
262  }
263  }
264  }
265 
266  stlist.resize(widx);
267 
268  if(widx != stims.size())
269  log_msg(0, 4, 0, "%s warning: Some values of %s could not be converted in stim times!",
270  __func__, str_list);
271 }
272 
273 
276 void stim_protocol::setup(int idx, std::string name)
277 {
278  const Stim & cur_stim = param_globals::stim[idx];
279  const Protocol & ptcl = cur_stim.ptcl;
280 
281  if(strlen(ptcl.stimlist) == 0) {
282  start = ptcl.start, npls = ptcl.npls, pcl = ptcl.bcl;
283 
284  // add timer
286  param_globals::tend, npls, pcl, ptcl.duration, name.c_str());
287  } else {
288  std::vector<double> stims;
289  get_stim_list(ptcl.stimlist, stims);
290 
291  log_msg(0,0,ECHO | NONL, "stim %d: stimulating at times: ", idx);
292  for(double t : stims)
293  log_msg(0,0, ECHO | NONL, "%.2lf ", t);
294  log_msg(0,0,0, "");
295  log_msg(0,0,0, "stim %d: .bcl and .npls values will be ignored.", idx);
296 
297  timer_id = user_globals::tm_manager->add_neq_timer(stims, ptcl.duration, name.c_str());
298  }
299 }
300 
301 
304 void stim_physics::setup(int idx, mesh_t intra_mesh, mesh_t extra_mesh)
305 {
306  const Stim & cur_stim = param_globals::stim[idx];
307 
308  type = stim_t(cur_stim.crct.type);
309  unit = stim_info::units[cur_stim.crct.type];
310  total_current = cur_stim.crct.total_current;
311 
312  const short dim = is_extra(stim_t(cur_stim.crct.type)) ?
313  get_mesh_dim(extra_mesh) : get_mesh_dim(intra_mesh);
314 
315  switch(type) {
316  case I_tm:
317  scale = param_globals::operator_splitting ? user_globals::tm_manager->time_step : 1.0;
318  break;
319 
320  case I_in:
321  case I_ex:
322  scale = UM2_to_CM2 * (dim == 2 ? 1.0 : UM_to_CM);
323  break;
324 
325  default: scale = 1.0; break;
326  }
327 }
328 
329 
337 void sample_wave_form(stim_pulse& sp, int idx)
338 {
339  const Stim & cur_stim = param_globals::stim[idx];
340  const Pulse & pulse = cur_stim.pulse;
341 
342  switch (sp.wform) {
343  case squarePulse: {
344  // generate step function using derived class
345  sig::Step stepPars;
346  stepPars.trig = pulse.trig;
347  stepPars.rise = true;
348 
349  sig::stepFunc step_func(stepPars);
350  step_func.sample(sp.wave);
351  break;
352  }
353  case truncExpPulse: {
354  // monophasic pulse, first phase lasts for entire pulse duration
355  sig::Pulse truncExp;
356  truncExp.duration = sp.duration;
357  truncExp.d1 = pulse.d1 * sp.duration; // relative to absolute duration of d1
358  truncExp.tau_edge = pulse.tau_edge;
359  truncExp.tau_plat = pulse.tau_plateau;
360  truncExp.s2r = pulse.s2;
361  truncExp.bias = pulse.bias;
362 
363  // from relative duration of d1 we infer mono- or biphasic
364  if (pulse.d1 == 1.) {
365  // monophasic pulse, first phase lasts for entire pulse duration
366  sig::monophasicTruncExpFunc fnc(truncExp);
367  fnc.sample(sp.wave);
368  } else {
369  // biphasic pulse, second phase lasts shorter than pulse duration
370  sig::biphasicTruncExpFunc fnc(truncExp);
371  fnc.sample(sp.wave);
372  }
373  break;
374  }
375  case sinePulse: {
376  // generate a sine wave
377  sig::sineWave sinePars;
378  sinePars.frq = pulse.freq;
379  sinePars.phase = pulse.phase;
380  sig::sineFunc sine(sinePars);
381  sine.sample(sp.wave);
382  break;
383  }
384  case arbPulse: {
385  sig::time_trace file_wave;
386  int _err = 0;
387 
388  if (!get_rank()) {
389  bool unitize = true;
390 
391  update_cwd();
392  set_dir(INPUT);
393  _err = file_wave.read_trace(pulse.file, unitize);
394  set_dir(CURDIR);
395  }
396 
397  int err = get_global(_err, MPI_MIN);
398  if (err) {
400  "Failed reading pulse for stimulus[%d] from file %s.\n", idx, pulse.file);
401  } else {
402  get_global(file_wave.f);
403  get_global(file_wave.t);
404 
405  file_wave.resample(sp.wave);
406 
407  // check length of read in pulse and adjust stimulus settings accordingly
408  if (sp.wave.duration() != sp.duration)
409  sp.duration = sp.wave.duration();
410  }
411  break;
412  }
413  case constPulse: {
414  sig::constFunc cnst_fnc(1);
415  cnst_fnc.sample(sp.wave);
416  break;
417  }
418  case unsetPulse:
419  default:
420  assert(0);
421  }
422 
423  /*
424  if(sp.wform == APfootPulse)
425  {
426  // generate AP foot
427  APfoot footPars;
428  footPars.tau_f = s.duration()/5.; // use 5 time constants
429  APfootFunc APft(footPars);
430  s.set_labels("APfoot");
431  APft.sample(s);
432  s.write_trace();
433  }
434  */
435 }
436 
437 bool stimulus::value(double & v) const
438 {
439  if(user_globals::tm_manager->trigger(ptcl.timer_id) == false) {
440  // intra-/extracellular potential stimuli are always active, but return 0 when their
441  // protocol is not active. Use Phi_ex_ol for extracellular potential stimuli that
442  // get removed when they expire.
443  if(this->phys.type == Phi_ex || this->phys.type == GND_ex || this->phys.type == Phi_in) {
444  v = 0.0;
445  return true;
446  }
447 
448  return false;
449  }
450  else {
452  v = pulse.strength * phys.scale * pulse.wave.f[i];
453  return true;
454  }
455 }
456 
458 {
460 
462  mesh.pl.globalize(glob_idx);
463 
464  SF::vector<mesh_int_t> srt_idx;
465  SF::sort_parallel(mesh.comm, glob_idx, srt_idx);
466 
467  size_t num_vtx = get_global(srt_idx.size(), MPI_SUM);
468  int rank = get_rank();
469 
470  FILE_SPEC f = NULL;
471  int err = 0;
472 
473  if (rank == 0) {
474  char dump_name[1024];
475 
476  if (strlen(name.c_str())) {
477  snprintf(dump_name, sizeof dump_name, "%s.vtx", name.c_str());
478  } else {
479  snprintf(dump_name, sizeof dump_name, "ELECTRODE_%d.vtx", idx);
480  }
481 
482  f = f_open(dump_name, "w");
483  if (!f)
484  err++;
485  else {
486  fprintf(f->fd, "%zd\nextra\n", num_vtx);
487  }
488  }
489 
490  if (!get_global(err, MPI_SUM)) {
491  print_vector(mesh.comm, srt_idx, 1, f ? f->fd : NULL);
492  } else {
493  log_msg(0, 4, 0, "error: stimulus[%d] cannot be dumped!");
494  }
495 
496  // only root really does that
497  f_close(f);
498 }
499 
500 void stim_electrode::setup(int idx, mesh_t intra_mesh, mesh_t extra_mesh)
501 {
502  const Stim & curstim = param_globals::stim[idx];
503  mesh_t grid;
504  dump_vtx = curstim.elec.dump_vtx_file;
505 
506  // based on the stimulus domain type we select grid and physics
507  switch(curstim.crct.type) {
508  case I_ex:
509  case Phi_ex:
510  case Phi_ex_ol:
511  case GND_ex:
512  grid = extra_mesh; break;
513 
514  case Illum:
515  case Vm_clmp:
516  case I_in:
517  case I_tm:
518  case Phi_in:
519  case Phi_in_ol:
520  grid = intra_mesh; break;
521 
522  case Ignore_stim: return;
523 
524  default:
525  log_msg(0,5,0, "stim_electrode::setup error: Can't determine domain from stim type! Aborting!", __func__);
526  EXIT(1);
527  }
528 
529  // get a logger from the physics
530  FILE_SPEC logger = NULL;
531 
532  // this are the criteria for choosing how we extract the stimulus electrode
533  bool vertex_file_given = strlen(curstim.elec.vtx_file) > 0;
534  bool tag_index_given = curstim.elec.geomID > -1;
535  // the mesh we need for computing the local vertex indices.
536  const sf_mesh & mesh = get_mesh(grid);
537 
538  if(vertex_file_given && tag_index_given)
539  log_msg(0,3,0, "%s warning: More than one stimulus electrode definintions set in electrode %d", __func__, idx);
540 
541  if(vertex_file_given) {
542  definition = def_t::file_based;
543  input_filename = curstim.elec.vtx_file;
544 
545  log_msg(logger, 0, 0, "Stimulus %d: Selecting vertices from file %s", idx, input_filename.c_str());
546 
547  set_dir(INPUT);
549 
550  // we read the indices. they are being localized w.r.t. the provided numbering. In our
551  // case this is always the reference numbering.
552  if(curstim.elec.vtx_fcn)
553  read_indices_with_data(vertices, scaling, input_filename, mesh, SF::NBR_REF, true, 1, PETSC_COMM_WORLD);
554  else
555  read_indices(vertices, input_filename, mesh, SF::NBR_REF, true, PETSC_COMM_WORLD);
556 
557  int gnum_idx = get_global(vertices.size(), MPI_SUM);
558  if(gnum_idx == 0) {
559  log_msg(0, 5, 0, "Stimulus %d: Specified vertices are not in stimulus domain! Aborting!", idx);
560  EXIT(1);
561  }
562  }
563  else if(tag_index_given) {
564  definition = def_t::vol_based_tag;
565 
566  int tag = curstim.elec.geomID;
567  log_msg(logger, 0, 0, "Stimulus %d: Selecting vertices from tag %d", idx, tag);
568 
569  indices_from_region_tag(vertices, mesh, tag);
570  // we restrict the indices to the algebraic subset
571  SF::restrict_to_set(vertices, mesh.pl.algebraic_nodes());
572  }
573  else {
574  definition = def_t::vol_based_shape;
575  log_msg(logger, 0, 0, "Stimulus %d: Selecting vertices from shape.", idx);
576 
577  geom_shape shape;
578  shape.type = geom_shape::shape_t(curstim.elec.geom_type);
579  shape.p0 = curstim.elec.p0;
580  shape.p1 = curstim.elec.p1;
581  shape.radius = curstim.elec.radius;
582 
583  bool nodal = true;
584  indices_from_geom_shape(vertices, mesh, shape, nodal);
585  // we restrict the indices to the algebraic subset
586  SF::restrict_to_set(vertices, mesh.pl.algebraic_nodes());
587 
588  int gsize = vertices.size();
589  if(get_global(gsize, MPI_SUM) == 0) {
590  log_msg(0,5,0, "error: Empty stimulus[%d] electrode def! Aborting!", idx);
591  EXIT(1);
592  }
593  }
594 }
595 
597 {
598  clear_active_dbc();
599 
600  for(const stimulus & s : stimuli) {
601  if(is_dbc(s.phys.type) && s.is_active()) {
602 
603  // the local indices of the dbc
604  const SF::vector<mesh_int_t> & dbc_idx = s.electrode.vertices;
605 
606  dbc_data* dbc_buff = new dbc_data();
607 
608  // the global petsc indices of the dbc
609  dbc_buff->nod = new SF::vector<SF_int>(dbc_idx.size());
610 
612 
613  size_t widx = 0;
614  for(size_t i=0; i<dbc_idx.size(); i++)
615  (*dbc_buff->nod)[widx++] = petsc_nbr[dbc_idx[i]];
616 
618  SF::init_vector(&dbc_buff->cntr, *mat.mesh_ptr(), 1, sf_vec::algebraic);
619 
620  if(s.electrode.scaling.size()) {
621  // we have spatially heterogenous dirichlet values
622  dbc->set(*dbc_buff->nod, s.electrode.scaling);
623  } else {
624  // we have spatially homogenous dirichlet values
625  dbc->set(*dbc_buff->nod, 1.0);
626  }
627 
628  mat.mult(*dbc, *dbc_buff->cntr);
629 
630  active_dbc[s.idx] = dbc_buff;
631  }
632  }
633 }
634 
636 {
637  // check if stim has come offline
638  for(const auto & d : active_dbc) {
639  if(stimuli[d.first].is_active() == false)
640  return true;
641  }
642 
643  // check if stim has come online
644  for(const stimulus & s : stimuli) {
645  if(is_dbc(s.phys.type) && s.is_active() && active_dbc.count(s.idx) == 0)
646  return true;
647  }
648 
649  return false;
650 }
651 
653 {
654  sf_vec* dbc;
655 
657 
658  for(auto it = active_dbc.begin(); it != active_dbc.end(); ++it) {
659  const SF::vector<SF_int> & dbc_nod = *it->second->nod;
660  for (auto dbc_idx : dbc_nod) {
661  mat.boundary_idxs.insert(dbc_idx);
662  }
663  // zero cols and rows in lhs mat
664  dbc->set(1.0);
665  dbc->set(dbc_nod, 0.0);
666  // multiplicate dbc vector from left and right to matrix in order to zero cols and rows
667  mat.mult_LR(*dbc, *dbc);
668  // now add 1.0 to the diagonal at the dirichlet locations
669  dbc->set(0.0);
670  dbc->set(dbc_nod, 1.0);
671  mat.diag_add(*dbc);
672  }
673 }
674 
676 {
677  for(auto it = active_dbc.begin(); it != active_dbc.end(); ++it) {
678  const int & dbc_idx = it->first;
679  const dbc_manager::dbc_data & dbc = *(it->second);
680  double strength = 0.0;
681  bool is_active = stimuli[dbc_idx].value(strength);
682 
683  // the whole idea of the dbc_manager and its active_dbc is
684  // based on only storing the active dbcs. if the stimulus associated
685  // to a dbc believed active is actually not active, we want to abort.
686  assert(is_active);
687 
688  rhs.add_scaled(*dbc.cntr, -strength);
689 
690  if(stimuli[dbc_idx].electrode.scaling.size()) {
691  SF::vector<SF_real> scaled_strength(stimuli[dbc_idx].electrode.scaling.size());
692 
693  size_t widx = 0;
694  for(SF_real s : stimuli[dbc_idx].electrode.scaling)
695  scaled_strength[widx++] = s * strength;
696 
697  rhs.set(*dbc.nod, scaled_strength);
698  } else {
699  rhs.set(*dbc.nod, strength);
700  }
701  }
702 }
703 
704 } // namespace opencarp
705 
double SF_real
Use the general double as real type.
Definition: SF_globals.h:38
#define MAX_LOG_LEVEL
Definition: basics.h:315
#define ECHO
Definition: basics.h:308
#define NONL
Definition: basics.h:312
const meshdata< mesh_int_t, mesh_real_t > * mesh_ptr() const
virtual void mult(const abstract_vector< T, S > &x, abstract_vector< T, S > &b) const =0
std::set< T > boundary_idxs
virtual void mult_LR(const abstract_vector< T, S > &L, const abstract_vector< T, S > &R)=0
virtual void diag_add(const abstract_vector< T, S > &diag)=0
virtual void add_scaled(const abstract_vector< T, S > &vec, S k)=0
virtual void set(const vector< T > &idx, const vector< S > &vals, const bool additive=false, const bool local=false)=0
overlapping_layout< T > pl
nodal parallel layout
Definition: SF_container.h:429
MPI_Comm comm
the parallel mesh is defined on a MPI world
Definition: SF_container.h:404
vector< T > & get_numbering(SF_nbr nbr_type)
Get the vector defining a certain numbering.
Definition: SF_container.h:464
size_t size() const
The current size of the vector.
Definition: SF_vector.h:104
std::map< int, dbc_data * > active_dbc
the DBCs that are currently active
Definition: stimulate.h:223
sf_mat & mat
the matrix we link the dbc_manager to
Definition: stimulate.h:219
void enforce_dbc_rhs(sf_vec &rhs)
Definition: stimulate.cc:675
void recompute_dbcs()
recompute the dbc data.
Definition: stimulate.cc:596
const SF::vector< stimulus > & stimuli
the stimuli we link the dbc_manager to
Definition: stimulate.h:221
bool dbc_update()
check if dbcs have updated
Definition: stimulate.cc:635
class to store shape definitions
Definition: basics.h:381
float s2r
strength of subpulse relative to leading pulse (biphasic pulse)
Definition: signals.h:826
sReal duration
pulse duration, default is 1 ms
Definition: signals.h:821
float tau_plat
time constant governing plateau of pulse
Definition: signals.h:825
float tau_edge
time constant for leading/trailing edges
Definition: signals.h:824
float bias
constant term to add to stimulus waveform
Definition: signals.h:827
double d1
duration of first sub-pulse in [ms] (zero with monophasic pulse)
Definition: signals.h:823
biphasic truncated exponentials (capacitive discharge)
Definition: signals.h:1059
virtual SF::vector< sReal > & sample(time_trace &trc)
Definition: signals.h:1066
constant function
Definition: signals.h:910
virtual SF::vector< sReal > & sample(time_trace &trc)
Definition: signals.h:917
monophasic truncated exponentials (capacitive discharge)
Definition: signals.h:993
virtual SF::vector< sReal > & sample(time_trace &trc)
Definition: signals.h:1000
virtual SF::vector< sReal > & sample(time_trace &trc)
Definition: signals.h:961
float phase
phase in degree
Definition: signals.h:881
sReal frq
freq in [kHz]
Definition: signals.h:880
step function
Definition: signals.h:932
virtual SF::vector< sReal > & sample(time_trace &trc)
Definition: signals.h:940
Time tracing class.
Definition: signals.h:142
SF::vector< sReal > t
time axis
Definition: signals.h:148
void resample(time_trace &trc)
Definition: signals.h:434
SF::vector< sReal > f
store function values of trace
Definition: signals.h:147
int read_trace(const std::string fname)
determine duration of a signal stored in file
Definition: signals.h:623
SF::vector< mesh_int_t > vertices
Definition: stimulate.h:152
void setup(int idx, mesh_t intra_mesh, mesh_t extra_mesh)
Definition: stimulate.cc:500
std::string input_filename
Definition: stimulate.h:154
SF::vector< SF_real > scaling
Definition: stimulate.h:153
double scale
internal unit conversion scaling
Definition: stimulate.h:139
bool total_current
whether we apply total current scaling
Definition: stimulate.h:140
stim_t type
type of stimulus
Definition: stimulate.h:137
std::string unit
physical units of stimulus
Definition: stimulate.h:138
void setup(int idx, mesh_t intra_mesh, mesh_t extra_mesh)
assign stimulus physics parameters
Definition: stimulate.cc:304
int timer_id
timer for stimulus
Definition: stimulate.h:122
int npls
number of stimulus pulses
Definition: stimulate.h:120
double pcl
pacing cycle length
Definition: stimulate.h:121
double start
start time of protocol
Definition: stimulate.h:119
void setup(int idx, std::string name)
Setup from a param stimulus index.
Definition: stimulate.cc:276
define the wave form of a stimulation pulse
Definition: stimulate.h:91
sig::time_trace wave
wave form of stimulus pulse
Definition: stimulate.h:97
void assign(double _strength, double _duration, double _dt, waveform_t _wform)
Definition: stimulate.h:99
void setup(int id)
Setup from a param stimulus index.
Definition: stimulate.cc:202
double duration
duration of stimulus
Definition: stimulate.h:94
waveform_t wform
wave form of stimulus
Definition: stimulate.h:95
double strength
strength of stimulus
Definition: stimulate.h:93
stim_protocol ptcl
applied stimulation protocol used
Definition: stimulate.h:168
int idx
index in global input stimulus array
Definition: stimulate.h:164
stim_electrode electrode
electrode geometry
Definition: stimulate.h:170
mesh_t associated_intra_mesh
Definition: stimulate.h:174
stim_pulse pulse
stimulus wave form
Definition: stimulate.h:167
mesh_t associated_extra_mesh
Definition: stimulate.h:175
void translate(int id)
convert legacy definitions to new format
Definition: stimulate.cc:105
bool is_active() const
Return whether stim is active.
Definition: stimulate.cc:190
void setup(int idx)
Setup from a param stimulus index.
Definition: stimulate.cc:166
void dump_vtx_file(int idx)
Export the vertices to vtx file.
Definition: stimulate.cc:457
stim_physics phys
physics of stimulus
Definition: stimulate.h:169
bool value(double &v) const
Get the current value if the stimulus is active.
Definition: stimulate.cc:437
std::string name
label stimulus
Definition: stimulate.h:165
centralize time managment and output triggering
Definition: timer_utils.h:73
bool trigger(int ID) const
Definition: timer_utils.h:166
double time_step
global reference time step
Definition: timer_utils.h:78
int add_neq_timer(const std::vector< double > &itrig, double idur, const char *iname, const char *poolname=nullptr)
Definition: timer_utils.cc:92
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.
Definition: timer_utils.cc:78
int trigger_elapse(int ID) const
Definition: timer_utils.h:186
Tissue level electrics, main Electrics physics class.
void print_vector(MPI_Comm comm, const vector< T > &vec, const short dpn, FILE *fd)
void sort_parallel(MPI_Comm comm, const vector< T > &idx, vector< T > &out_idx)
Sort index values parallel ascending across the ranks.
void restrict_to_set(vector< T > &v, const hashmap::unordered_set< T > &set)
void init_vector(SF::abstract_vector< T, S > **vec)
Definition: SF_init.h:99
@ NBR_PETSC
PETSc numbering of nodes.
Definition: SF_container.h:203
@ NBR_REF
The nodal numbering of the reference mesh (the one stored on HD).
Definition: SF_container.h:201
std::set< int > current_stim
Definition: stimulate.cc:39
std::set< int > dbc_stim
Definition: stimulate.cc:40
std::map< int, std::string > units
Definition: stimulate.cc:41
std::set< int > potential_stim
Definition: stimulate.cc:38
timer_manager * tm_manager
a manager for the various physics timers
Definition: main.cc:58
std::map< physic_t, Basic_physic * > physics_reg
the physics
Definition: main.cc:56
void sample_wave_form(stim_pulse &sp, int idx)
sample a signal given in analytic form
Definition: stimulate.cc:337
sf_mesh & get_mesh(const mesh_t gt)
Get a mesh by specifying the gridID.
Definition: sf_interface.cc:33
bool is_dbc(stim_t type)
whether stimulus is a dirichlet type. implies boundary conditions on matrix
Definition: stimulate.cc:77
@ sinePulse
Definition: stimulate.h:74
@ constPulse
Definition: stimulate.h:74
@ squarePulse
Definition: stimulate.h:74
@ truncExpPulse
Definition: stimulate.h:74
@ arbPulse
Definition: stimulate.h:74
@ unsetPulse
Definition: stimulate.h:74
int set_dir(IO_t dest)
Definition: sim_utils.cc:490
int get_rank(MPI_Comm comm=PETSC_COMM_WORLD)
Definition: basics.h:276
short get_mesh_dim(mesh_t id)
get (lowest) dimension of the mesh used in the experiment
Definition: sim_utils.cc:1313
T get_global(T in, MPI_Op OP, MPI_Comm comm=PETSC_COMM_WORLD)
Do a global reduction on a variable.
Definition: basics.h:233
@ Phi_in
Definition: stimulate.h:78
@ Ignore_stim
Definition: stimulate.h:78
@ GND_ex
Definition: stimulate.h:78
@ Phi_ex
Definition: stimulate.h:78
@ Phi_ex_ol
Definition: stimulate.h:78
@ Vm_clmp
Definition: stimulate.h:78
@ Phi_in_ol
Definition: stimulate.h:78
bool is_potential(stim_t type)
uses current for stimulation
Definition: stimulate.cc:66
void init_stim_info(void)
uses potential for stimulation
Definition: stimulate.cc:49
bool is_extra(stim_t type)
whether stimulus is on extra grid (or on intra)
Definition: stimulate.cc:82
FILE_SPEC f_open(const char *fname, const char *mode)
Open a FILE_SPEC.
Definition: basics.cc:135
bool is_current(stim_t type)
uses current as stimulation
Definition: stimulate.cc:72
void warn_when_passing_intra_vtx(const std::string filename)
Definition: fem_utils.cc:239
@ CURDIR
Definition: sim_utils.h:53
void split_string(const std::string &input, const char s, STRVEC &list)
Split a string holding a character-seperated list into a vector of strings.
Definition: basics.h:103
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.
Definition: fem_utils.cc:155
void indices_from_geom_shape(SF::vector< mesh_int_t > &idx, const sf_mesh &mesh, const geom_shape shape, const bool nodal)
Populate vertex data with the vertices inside a defined box shape.
Definition: fem_utils.cc:184
void log_msg(FILE_SPEC out, int level, unsigned char flag, const char *fmt,...)
Definition: basics.cc:72
mesh_t
The enum identifying the different meshes we might want to load.
Definition: sf_interface.h:59
void read_indices_with_data(SF::vector< T > &idx, SF::vector< S > &dat, const std::string filename, const hashmap::unordered_map< mesh_int_t, mesh_int_t > &dd_map, const int dpn, MPI_Comm comm)
like read_indices, but with associated data for each index
Definition: fem_utils.h:269
void read_indices(SF::vector< T > &idx, const std::string filename, const hashmap::unordered_map< mesh_int_t, mesh_int_t > &dd_map, MPI_Comm comm)
Read indices from a file.
Definition: fem_utils.h:120
void get_stim_list(const char *str_list, std::vector< double > &stlist)
Definition: stimulate.cc:234
void update_cwd()
save the current working directory to curdir so that we can switch back to it if needed.
Definition: sim_utils.cc:485
void f_close(FILE_SPEC &f)
Close a FILE_SPEC.
Definition: basics.cc:162
#define UM_to_CM
convert um to cm
Definition: physics_types.h:36
#define UM2_to_CM2
convert um^2 to cm^2
Definition: physics_types.h:35
Electrical stimulation functions.
SF::vector< SF_int > * nod
Definition: stimulate.h:209
File descriptor struct.
Definition: basics.h:133