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