32 #include "petsc_utils.h"
33 #include "petscviewer.h"
44 std::map<int,std::string>
units;
47 namespace user_globals {
108 Stim & s = param_globals::stim[
idx];
109 Stimulus & curstim = param_globals::stimulus[
idx];
111 s.ptcl.bcl = curstim.bcl;
112 s.ptcl.npls = curstim.npls;
113 s.ptcl.start = curstim.start;
114 s.ptcl.duration = curstim.duration;
118 std::string pulse_name;
119 pulse_name =
"pulse_" + std::to_string(
idx);
120 s.pulse.name = (
char*) calloc(pulse_name.length()+1,
sizeof(char));
121 strcpy(s.pulse.name, pulse_name.c_str());
125 s.pulse.file = strdup(curstim.pulse_file);
126 s.pulse.bias = curstim.bias;
127 s.pulse.tau_plateau = curstim.tau_plateau;
128 s.pulse.tau_edge = curstim.tau_edge;
129 s.pulse.s2 = curstim.s2;
131 s.pulse.tilt_ampl = curstim.s2;
132 s.pulse.tilt_time = curstim.d1;
133 s.pulse.strength = curstim.strength;
136 s.elec.vtx_fcn = curstim.vtx_fcn;
139 s.crct.type = curstim.stimtype;
140 s.crct.balance = curstim.balance;
141 s.crct.total_current = curstim.total_current;
144 s.elec.geomID = curstim.geometry;
146 s.elec.vtx_file = strdup(curstim.vtx_file);
147 s.elec.dump_vtx_file = curstim.dump_vtx_file;
150 s.elec.geom_type = 2;
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;
159 s.name = strdup(curstim.name);
169 const Stim & cur_stim = param_globals::stim[
idx];
172 if(cur_stim.name != std::string(
""))
173 name = cur_stim.name;
175 name =
"Stimulus_" + std::to_string(
idx);
204 const Stim & cur_stim = param_globals::stim[idx];
205 const Pulse & pulse = cur_stim.pulse;
209 if(strcmp(pulse.file,
""))
212 assign(pulse.strength, cur_stim.ptcl.duration, param_globals::dt, wvt);
224 _err = file_wave.
read_trace(pulse.file, unitize);
231 "Failed reading pulse for stimulus[%d] from file %s.\n", idx, pulse.file);
252 std::string tUnit =
"ms";
259 std::string tstim = str_list;
260 std::vector<std::string> stims;
263 stlist.resize(stims.size());
264 size_t widx = 0, err = 0;
266 for(
size_t i=0; i<stims.size(); i++) {
267 std::string & stim = stims[i];
271 double last = widx == 0 ? 0.0 : stlist[widx-1];
277 size_t nread = sscanf(stim.c_str(),
"%lf", &cur);
279 stlist[widx++] = cur + last;
282 size_t nread = sscanf(stim.c_str(),
"%lf", &cur);
284 stlist[widx++] = cur;
291 if(widx != stims.size())
292 log_msg(0, 4, 0,
"%s warning: Some values of %s could not be converted in stim times!",
301 const Stim & cur_stim = param_globals::stim[idx];
302 const Protocol & ptcl = cur_stim.ptcl;
304 if(strlen(ptcl.stimlist) == 0) {
309 param_globals::tend,
npls,
pcl, ptcl.duration, name.c_str());
311 std::vector<double> stims;
315 for(
double t : stims)
318 log_msg(0,0,0,
"stim %d: .bcl and .npls values will be ignored.", idx);
329 const Stim & cur_stim = param_globals::stim[idx];
346 default:
scale = 1.0;
break;
360 const Stimulus & curstim = param_globals::stimulus[idx];
368 truncExp.
tau_edge = curstim.tau_edge;
369 truncExp.
tau_plat = curstim.tau_plateau;
373 if(curstim.d1 == 1.) {
457 const Stim & curstim = param_globals::stim[idx];
461 switch(curstim.crct.type) {
476 log_msg(0,5,0,
"stim_electrode::setup error: Can't determine domain from stim type! Aborting!", __func__);
484 bool vertex_file_given = strlen(curstim.elec.vtx_file) > 0;
485 bool tag_index_given = curstim.elec.geomID > -1;
489 if(vertex_file_given && tag_index_given)
490 log_msg(0,3,0,
"%s warning: More than one stimulus electrode definintions set in electrode %d", __func__, idx);
492 if(vertex_file_given) {
503 if(curstim.elec.vtx_fcn)
510 log_msg(0, 5, 0,
"Stimulus %d: Specified vertices are not in stimulus domain! Aborting!", idx);
514 else if(tag_index_given) {
517 int tag = curstim.elec.geomID;
518 log_msg(logger, 0, 0,
"Stimulus %d: Selecting vertices from tag %d", idx, tag);
526 log_msg(logger, 0, 0,
"Stimulus %d: Selecting vertices from shape.", idx);
530 shape.
p0 = curstim.elec.p0;
531 shape.
p1 = curstim.elec.p1;
532 shape.
radius = curstim.elec.radius;
541 log_msg(0,5,0,
"error: Empty stimulus[%d] electrode def! Aborting!", idx);
546 if(curstim.elec.dump_vtx_file) {
548 mesh.
pl.globalize(glob_idx);
560 char dump_name[1024];
562 if (strlen(curstim.name)) {
563 snprintf(dump_name,
sizeof dump_name,
"%s.vtx", curstim.name);
565 snprintf(dump_name,
sizeof dump_name,
"ELECTRODE_%d.vtx", idx);
568 f =
f_open(dump_name,
"w");
571 fprintf(f->
fd,
"%zd\nextra\n", num_vtx);
578 log_msg(0, 4, 0,
"error: stimulus[%d] cannot be dumped!");
591 if(
is_dbc(s.phys.type) && s.is_active()) {
604 for(
size_t i=0; i<dbc_idx.
size(); i++)
605 (*dbc_buff->
nod)[widx++] = petsc_nbr[dbc_idx[i]];
610 if(s.electrode.scaling.size()) {
612 dbc->
set(*dbc_buff->
nod, s.electrode.scaling);
615 dbc->
set(*dbc_buff->
nod, 1.0);
620 std::string outName0 =
"output_dbc.mat";
625 snprintf(outName1,
sizeof(outName1),
"outputMatrix1_stim%d", s.idx);
636 snprintf(outName2,
sizeof(outName2),
"outputMatrix2_stim%d", s.idx);
659 if(
stimuli[d.first].is_active() ==
false)
680 dbc->
set(dbc_nod, 0.0);
683 char outNameelhs1[128];
684 snprintf(outNameelhs1,
sizeof(outNameelhs1),
"outputMatrixelhs1_stim%d", it->first);
691 char outNameelhs2[128];
692 snprintf(outNameelhs2,
sizeof(outNameelhs2),
"outputMatrixelhs2_stim%d", it->first);
702 dbc->
set(dbc_nod, 1.0);
705 char outNameelhs3[128];
706 snprintf(outNameelhs3,
sizeof(outNameelhs3),
"outputMatrixelhs3_stim%d", it->first);
718 PetscReal *c = rhs.
ptr();
720 const int & dbc_idx = it->first;
722 double strength = 0.0;
723 bool is_active =
stimuli[dbc_idx].value(strength);
732 if(
stimuli[dbc_idx].electrode.scaling.size()) {
737 scaled_strength[widx++] = s * strength;
739 rhs.
set(*dbc.
nod, scaled_strength);
741 rhs.
set(*dbc.
nod, strength);
double SF_real
Use the general double as real type.
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
virtual void mult_LR(const abstract_vector< T, S > &L, const abstract_vector< T, S > &R)=0
virtual void write(const char *filename) const =0
virtual void diag_add(const abstract_vector< T, S > &diag)=0
size_t write_ascii(const char *file, bool write_header)
virtual void set(const vector< T > &idx, const vector< S > &vals, const bool additive=false)=0
virtual void add_scaled(const abstract_vector< T, S > &vec, S k)=0
overlapping_layout< T > pl
nodal parallel layout
MPI_Comm comm
the parallel mesh is defined on a MPI world
vector< T > & get_numbering(SF_nbr nbr_type)
Get the vector defining a certain numbering.
size_t size() const
The current size of the vector.
FILE_SPEC logger
The logger of the physic, each physic should have one.
std::map< int, dbc_data * > active_dbc
the DBCs that are currently active
sf_mat & mat
the matrix we link the dbc_manager to
void enforce_dbc_rhs(sf_vec &rhs)
void recompute_dbcs()
recompute the dbc data.
const SF::vector< stimulus > & stimuli
the stimuli we link the dbc_manager to
bool dbc_update()
check if dbcs have updated
class to store shape definitions
sReal duration
pulse duration, default is 1 ms
float tau_plat
time constant governing plateau of pulse
float tau_edge
time constant for leading/trailing edges
int decay
edge decay time (multiples of tau_edge)
double d1
duration of first sub-pulse in [ms] (zero with monophasic pulse)
biphasic truncated exponentials (capacitive discharge)
virtual SF::vector< sReal > & sample(time_trace &trc)
virtual SF::vector< sReal > & sample(time_trace &trc)
monophasic truncated exponentials (capacitive discharge)
virtual SF::vector< sReal > & sample(time_trace &trc)
SF::vector< sReal > t
time axis
void resample(time_trace &trc)
SF::vector< sReal > f
store function values of trace
void setUnits(std::string _t_unit, std::string _f_unit)
int read_trace(const std::string fname)
determine duration of a signal stored in file
SF::vector< mesh_int_t > vertices
std::string input_filename
SF::vector< SF_real > scaling
void setup(int idx)
assign stimulus physics parameters
double scale
internal unit conversion scaling
bool total_current
whether we apply total current scaling
stim_t type
type of stimulus
std::string unit
physical units of stimulus
stim_domain_t domain
applied in intra- or extracellular space
int timer_id
timer for stimulus
int npls
number of stimulus pulses
double pcl
pacing cycle length
double start
start time of protocol
void setup(int idx, std::string name)
Setup from a param stimulus index.
define the wave form of a stimulation pulse
sig::time_trace wave
wave form of stimulus pulse
void assign(double _strength, double _duration, double _dt, waveform_t _wform)
void setup(int id)
Setup from a param stimulus index.
double duration
duration of stimulus
waveform_t wform
wave form of stimulus
double strength
strength of stimulus
stim_protocol ptcl
applied stimulation protocol used
int idx
index in global input stimulus array
stim_electrode electrode
electrode geometry
stim_pulse pulse
stimulus wave form
void translate(int id)
convert legacy definitions to new format
bool is_active() const
Return whether stim is active.
void setup(int idx)
Setup from a param stimulus index.
stim_physics phys
physics of stimulus
bool value(double &v) const
Get the current value if the stimulus is active.
std::string name
label stimulus
centralize time managment and output triggering
bool trigger(int ID) const
double time_step
global reference time step
int add_neq_timer(const std::vector< double > &itrig, double idur, const char *iname, const char *poolname=nullptr)
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.
int trigger_elapse(int ID) const
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)
@ NBR_PETSC
PETSc numbering of nodes.
@ NBR_REF
The nodal numbering of the reference mesh (the one stored on HD).
std::set< int > current_stim
std::map< int, std::string > units
std::set< int > voltage_stim
timer_manager * tm_manager
a manager for the various physics timers
std::map< physic_t, Basic_physic * > physics_reg
the physics
void sample_wave_form(stim_pulse &sp, int idx)
sample a signal given in analytic form
sf_mesh & get_mesh(const mesh_t gt)
Get a mesh by specifying the gridID.
bool is_dbc(stim_t type)
whether stimulus is a dirichlet type. implies boundary conditions on matrix
int get_rank(MPI_Comm comm=PETSC_COMM_WORLD)
short get_mesh_dim(mesh_t id)
get (lowest) dimension of the mesh used in the experiment
T get_global(T in, MPI_Op OP, MPI_Comm comm=PETSC_COMM_WORLD)
Do a global reduction on a variable.
void init_stim_info(void)
bool is_extra(stim_t type)
whether stimulus is on extra grid (or on intra)
FILE_SPEC f_open(const char *fname, const char *mode)
Open a FILE_SPEC.
bool is_current(stim_t type)
uses current as stimulation
void warn_when_passing_intra_vtx(const std::string filename)
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.
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.
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.
void log_msg(FILE_SPEC out, int level, unsigned char flag, const char *fmt,...)
mesh_t
The enum identifying the different meshes we might want to load.
Basic_physic * get_physics(physic_t p, bool error_if_missing)
Convinience function to get a physics.
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
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.
void get_stim_list(const char *str_list, std::vector< double > &stlist)
void update_cwd()
save the current working directory to curdir so that we can switch back to it if needed.
void f_close(FILE_SPEC &f)
Close a FILE_SPEC.
bool is_voltage(stim_t type)
uses voltage as stimulation
#define UM_to_CM
convert um to cm
#define UM2_to_CM2
convert um^2 to cm^2
Electrical stimulation functions.
SF::vector< SF_int > * nod