34 void initialize_sv_dumps_onFace(
limpet::MULTI_IF *pmiif, IMPregion_EMI* reg,
int id,
double t,
double dump_dt);
36 void IonicsOnFace::compute_step()
41 miif->compute_ionic_current();
43 double comp_time =
timing(t2, t1);
44 this->compute_time += comp_time;
47 comp_stats.tot_time += comp_time;
53 void IonicsOnFace::destroy()
58 void IonicsOnFace::output_step()
61 void IonicsOnFace::initialize()
69 comp_stats.init_logger(
"ODE_stats.dat");
73 int loc_size = mesh.l_numelem;
86 miif->name =
"myocardium";
87 miif->gdata[limpet::Vm] = Vmv;
88 miif->gdata[limpet::Iion] = IIon;
93 for (
size_t i = 2; i < rs.size(); i++ ) {
94 for (
int j = 0; j < param_globals::imp_region_emi[i].num_IDs; ++j)
96 std::string t1t2 = param_globals::imp_region_emi[i].ID[j];
99 size_t colon_pos = t1t2.find(
':');
100 if (colon_pos != std::string::npos) {
102 int tag1 = std::stoi(t1t2.substr(0, colon_pos));
103 int tag2 = std::stoi(t1t2.substr(colon_pos + 1));
105 membraneFace_default.erase(std::make_pair(tag1, tag2));
106 gapjunctionFace_default.erase(std::make_pair(tag1, tag2));
108 membraneFace_default.erase(std::make_pair(tag2, tag1));
109 gapjunctionFace_default.erase(std::make_pair(tag2, tag1));
111 std::cerr <<
"Error: ':' the face tags are not defined properly in input file" << std::endl;
117 log_msg(NULL, 5,
ECHO,
"\tError: num_imp_regions must be at least 2: the first region is reserved for the ionic model, and the second is designated for the gap junction.\n");
118 log_msg(NULL, 5,
ECHO,
"set a default ionic model and gapjuntion model in parameter file\\n");
124 rs[0].nsubregs = membraneFace_default.size();
125 rs[0].subregtags =
new std::string[rs[0].nsubregs];
127 for (
const auto& v : membraneFace_default) {
128 int t1 = std::get<0>(v);
129 int t2 = std::get<1>(v);
130 rs[0].subregtags[j] = std::to_string(t1)+
":"+std::to_string(t2);
137 rs[1].nsubregs = gapjunctionFace_default.size();
138 rs[1].subregtags =
new std::string[rs[1].nsubregs];
139 for (
const auto& v : gapjunctionFace_default) {
140 int t1 = std::get<0>(v);
141 int t2 = std::get<1>(v);
142 rs[1].subregtags[j] = std::to_string(t1)+
":"+std::to_string(t2);
147 for (
size_t i = 2; i < rs.size(); i++ ) {
148 rs[i].nsubregs = param_globals::imp_region_emi[i].num_IDs;
149 rs[i].subregtags =
new std::string[rs[i].nsubregs];
150 for (
int j = 0; j < rs[i].nsubregs;j++) {
151 std::string t1t2 = param_globals::imp_region_emi[i].ID[j];
152 size_t colon_pos = t1t2.find(
':');
153 if (colon_pos == std::string::npos) {
154 std::cerr <<
"Error: ':' the face tags are not defined properly in input file, it should be tag1:tag2 as a string" << std::endl;
158 rs[i].subregtags[j] = param_globals::imp_region_emi[i].ID[j];
163 region_mask_onFace(ion_domain, tags_data, line_face, tri_face, quad_face, map_vertex_tag_to_dof, map_elem_uniqueFace_to_tags, rs, reg_mask,
true,
"imp_region_emi");
165 for (
size_t i = 0; i < rs.size(); i++ ) {
166 delete[] rs[i].subregtags;
167 rs[i].subregtags =
nullptr;
171 tstart = setup_MIIF(loc_size, param_globals::num_imp_regions, param_globals::imp_region_emi,
172 reg_mask.
data(), param_globals::start_statef, param_globals::num_adjustments,
173 param_globals::adjustment, param_globals::dt, purkfLen > 0);
175 miif->extUpdateVm = !param_globals::operator_splitting;
180 log_msg(logger, 0, 0,
"Changing simulation start time to %.2lf", tstart);
187 this->initialize_time +=
timing(t2, t1);
190 double IonicsOnFace::setup_MIIF(
int nnodes,
int nreg, IMPregion_EMI* impreg,
int* mask,
191 const char *start_fn,
int numadjust, IMPVariableAdjustment *adjust,
192 double time_step,
bool close)
197 miif->numNode = nnodes;
199 miif->numplugs = (
int*)calloc( miif->N_IIF,
sizeof(
int));
200 miif->plugtypes = std::vector<limpet::IonTypeList>(miif->N_IIF);
203 log_msg(logger,0,
ECHO,
"\nSetting up ionic models on EMI Face and plugins\n" \
204 "-----------------------------------\n\n" \
205 "Assigning IMPS to tagged regions:" );
207 for (
int i=0;i<miif->N_IIF;i++) {
211 miif->iontypes.push_back(*pT);
212 log_msg(logger, 0,
ECHO|
NONL,
"\tIonic model: %s to tag region(s)", impreg[i].im);
214 if(impreg[i].num_IDs > 0) {
215 for(
int j = 0; j < impreg[i].num_IDs; j++)
224 log_msg(NULL,5,
ECHO,
"Illegal IM specified: %s\n", impreg[i].im );
225 log_msg(NULL,5,
ECHO,
"Run bench --list-imps for a list of all available models.\n" );
230 if(impreg[i].plugins[0] !=
'\0') {
231 log_msg(logger,0,
ECHO|
NONL,
"\tPlug-in(s) : %s to tag region(s)", impreg[i].plugins);
233 for(
int j = 0; j < impreg[i].num_IDs; j++)
239 log_msg(NULL,5,
ECHO,
"Illegal plugin specified: %s\n", impreg[i].plugins);
240 log_msg(NULL,5,
ECHO,
"Run bench --list-imps for a list of all available plugins.\n" );
251 for (
int i=0; i<miif->numNode; i++)
255 miif->initialize_MIIF();
257 for (
int i=0;i<miif->N_IIF;i++) {
259 remove_char(impreg[i].im_param, strlen(impreg[i].im_param),
' ');
260 miif->IIF[i]->tune(impreg[i].im_param, impreg[i].plugins, impreg[i].plug_param);
264 miif->initialize_currents(time_step, param_globals::ode_fac);
269 for (
int i=0;i<miif->N_IIF;i++) {
270 if (impreg[i].im_sv_init && strlen(impreg[i].im_sv_init) > 0)
271 if (
read_sv(miif, i, impreg[i].im_sv_init)) {
272 log_msg(NULL, 5,
ECHO|
FLUSH,
"State vector initialization failed for %s.\n", impreg[i].name);
277 if( !start_fn || strlen(start_fn)>0 )
278 tstart = (double) miif->restore_state(start_fn, ion_domain, close);
280 for (
int i=0; i<numadjust; i++)
286 bool restrict_to_algebraic =
true;
289 std::map<std::string,std::string> metadata;
293 if(metadata.count(
"grid") && metadata[
"grid"].compare(
"intra") == 0) {
296 read_indices_with_data(indices, values, adjust[i].file, imesh, nbr, restrict_to_algebraic, 1, PETSC_COMM_WORLD);
300 for(
size_t gi = 0; gi < indices.
size(); gi++)
307 adjPars->set(indices, values);
311 snprintf(fname,
sizeof fname,
"adj_%s_perm.dat", adjust[i].variable);
312 adjPars->write_ascii(fname,
false);
317 log_msg(0,3,0,
"%s warning: PETSC_TO_CANONICAL permutation needed registering!", __func__);
321 (*sc)(*adjPars,
true);
322 snprintf(fname,
sizeof fname,
"adj_%s_canonical.dat", adjust[i].variable);
323 adjPars->write_ascii(fname,
false);
326 int nc = miif->adjust_MIIF_variables(adjust[i].variable, indices, values);
327 log_msg(logger, 0, 0,
"Adjusted %d values for %s", nc, adjust[i].variable);
332 for (
int i=0;i<miif->N_IIF;i++)
333 initialize_sv_dumps_onFace(miif, impreg+i, i, tstart, param_globals::spacedt);
347 void initialize_sv_dumps_onFace(
limpet::MULTI_IF *pmiif, IMPregion_EMI* reg,
int id,
double t,
double dump_dt)
349 char svs[1024], plgs[1024], plgsvs[1024], fname[1024];
351 strcpy(svs, reg->im_sv_dumps ? reg->im_sv_dumps :
"");
352 strcpy(plgs, reg->plugins ? reg->plugins :
"");
353 strcpy(plgsvs, reg->plug_sv_dumps ? reg->plug_sv_dumps :
"");
355 if( !(strlen(svs)+strlen(plgsvs) ) )
364 strcpy(fname, param_globals::vofile);
367 log_msg(NULL, 5,
ECHO,
"%s: a region name must be specified\n", __func__ );
372 char* ext_start = NULL;
373 ext_start = strstr(fname,
"igb.gz");
374 if(ext_start == NULL) ext_start = strstr(fname,
"igb");
375 if(ext_start == NULL) ext_start = fname + strlen(fname);
376 strcpy(ext_start, reg->name);
392 const char* gridname,
const char* reglist)
394 bool AllTagsExist =
true;
397 tagset.
insert(tags_data.begin(), tags_data.end());
400 for (
size_t reg=0; reg<regspec.
size(); reg++)
402 for (
int k=0; k<regspec[reg].nsubregs; k++) {
405 size_t colon_pos = regspec[reg].subregtags[k].find(
':');
406 int tag1 = std::stoi(regspec[reg].subregtags[k].substr(0, colon_pos));
407 int tag2 = std::stoi(regspec[reg].subregtags[k].substr(colon_pos + 1));
410 std::string inverse_pair;
411 inverse_pair = std::to_string(tag2) +
":" + std::to_string(tag1);
412 if(tagset.
count(regspec[reg].subregtags[k]) || tagset.
count(inverse_pair)) {
421 "on face Region tag %s in %s[%d] not found in element list for %s grid.\n",
422 regspec[reg].subregtags[k].c_str(), reglist, reg, gridname);
423 AllTagsExist =
false;
428 log_msg(NULL, 4,
ECHO,
"Assigned wrong pair of tags on the face of EMI surface mesh!\n"
429 "Check region ID specs in input files!\n");
435 void region_mask_onFace(
mesh_t meshspec,
436 std::vector<std::string> & tags_data,
451 if(regspec.
size() == 1)
return;
457 size_t rIDsize = mask_elem ? mesh.l_numelem : mesh.l_numpts;
459 size_t nelem = mesh.l_numelem;
462 check_tags_in_elems_onFace(tags_data, regspec, mesh.name.c_str(), reglist);
464 regionIDs.
assign(rIDsize, 0);
466 int* rid = regionIDs.
data();
471 for (
size_t reg=0; reg < regspec.
size(); reg++) {
473 for (
int k=0; k < regspec[reg].nsubregs; k++) {
474 std::string curtag = regspec[reg].subregtags[k];
475 if(tag_to_reg.
count(curtag)) err++;
478 log_msg(0,4,0,
"%s warning: Tag idx %s is assigned to multiple regions!\n"
479 "Its final assignment will be to the highest assigned region ID!",
480 __func__, curtag.c_str());
482 tag_to_reg[curtag] = reg;
486 std::vector<int> mx_tag( rIDsize, -1 );
489 for(
size_t eidx=0; eidx<nelem; eidx++)
491 std::vector<int> elem_nodes;
493 std::string result_pair_orginal;
494 std::string result_pair_reverse;
495 std::pair<mesh_int_t,mesh_int_t> value = map_elem_uniqueFace_to_tags[eidx];
496 result_pair_orginal = std::to_string(value.first) +
":" + std::to_string(value.second);
497 result_pair_reverse = std::to_string(value.second) +
":" + std::to_string(value.first);
498 if (tag_to_reg.
count(result_pair_orginal))
500 rid[eidx] = tag_to_reg[result_pair_orginal];
501 }
else if(tag_to_reg.
count(result_pair_reverse)){
502 rid[eidx] = tag_to_reg[result_pair_reverse];
504 if(tag!=value.first){
505 log_msg(NULL, 5,
ECHO,
"error in tags on surface mesh with the unique faces!!!.\\n");
513 double IonicsOnFace::timer_val(
const int timer_id)
515 double val = std::nan(
"NaN");
521 std::string IonicsOnFace::timer_unit(
const int timer_id)
529 if (impdata[limpet::Iion] != NULL)
530 impdata[limpet::Iion][n] = 0;
534 imp.
compute(n, n + 1, impdata);
549 void* find_SV_in_IMP_onFace(
limpet::MULTI_IF* miif,
const int idx,
const char *IMP,
const char *SV,
550 int* offset,
int* sz)
552 if(strcmp(IMP, miif->
iontypes[idx].get().get_name().c_str()) == 0) {
553 return (
void*) miif->
iontypes[idx].get().get_sv_offset(SV, offset, sz);
556 for(
int k=0; k<miif->
numplugs[idx]; k++ )
557 if(strcmp(IMP, miif->
plugtypes[idx][k].get().get_name().c_str()) == 0) {
558 return (
void*) miif->
plugtypes[idx][k].get().get_sv_offset(SV, offset, sz);
575 void alloc_gvec_data_onFace(
const int nGVcs,
const int nRegs,
576 GVecs *prmGVecs, gvec_data_OnFace &glob_vecs)
578 glob_vecs.nRegs = nRegs;
581 glob_vecs.vecs.resize(nGVcs);
583 for (
size_t i = 0; i < glob_vecs.vecs.size(); i++) {
584 sv_data_onFace &gvec = glob_vecs.vecs[i];
586 gvec.name =
dupstr(prmGVecs[i].name);
588 gvec.bogus = prmGVecs[i].bogus;
590 gvec.imps = (
char**) calloc(nRegs,
sizeof(
char *));
591 gvec.svNames = (
char**) calloc(nRegs,
sizeof(
char *));
592 gvec.svSizes = (
int*) calloc(nRegs,
sizeof(
int));
593 gvec.svOff = (
int*) calloc(nRegs,
sizeof(
int));
596 for (
int j = 0; j < nRegs; j++) {
597 if (strlen(prmGVecs[i].imp)) gvec.imps[j] =
dupstr(prmGVecs[i].imp);
599 else if (j < param_globals::num_imp_regions)
600 gvec.imps[j] =
dupstr(param_globals::imp_region_emi[j].im);
602 gvec.imps[j] =
dupstr(param_globals::PurkIon[j - param_globals::num_imp_regions].im);
604 else if (j < param_globals::num_imp_regions)
605 gvec.imps[j] =
dupstr(param_globals::imp_region_emi[j].im);
607 gvec.svNames[j] =
dupstr(prmGVecs[i].ID[j]);
626 igb_output_manager & output_manager)
630 int num_purk_regions = 0;
631 int nRegs = param_globals::num_imp_regions + num_purk_regions;
633 alloc_gvec_data_onFace(param_globals::num_gvecs, nRegs, param_globals::gvec, GVs);
636 if (GVs->inclPS) sample_PS_ionSVs(purk);
639 for (
unsigned int i = 0; i < GVs.vecs.size(); i++) {
640 sv_data_onFace & gv = GVs.vecs[i];
643 for (
int j = 0; j < miif->
N_IIF; j++) {
644 gv.getsv[j] = find_SV_in_IMP_onFace(miif, j, gv.imps[j], gv.svNames[j],
645 gv.svOff + j, gv.svSizes + j);
647 if (gv.getsv[j] == NULL) {
648 log_msg(NULL, 3,
ECHO,
"\tWarning: SV(%s) not found in region %d\n", gv.svNames[j], j);
654 output_manager.register_output(gv.ordered,
intra_elec_msh, 1, gv.name, gv.units);
660 MULTI_IF* pmiif = &purk->ion;
661 for (
int j = miif->
N_IIF; j < nRegs; j++) {
662 gv.getsv[j] = find_SV_in_IMP_onFace(pmiif, j - miif->
N_IIF, gv.imps[j],
663 gv.svNames[j], gv.svOff + j, gv.svSizes + j);
665 if (gv.getsv[j] == NULL) {
666 LOG_MSG(NULL, 3,
ECHO,
"\tWarning: state variable \"%s\" not found in region %d\n", gv.svNames[j], j);
670 RVector_dup(purk->vm_pt, &gv.orderedPS_PS);
673 RVector_dup(purk->vm_pt_over, &gv.orderedPS);
674 initialize_grid_output(grid, NULL, tmo,
intra_elec_msh, GRID_WRITE, 0., 1., gv.units, gv.orderedPS,
675 1, gv.GVcName, -purk->npt, param_globals::output_level);
680 log_msg(NULL, 5,
ECHO,
"\tError: no state variables found for global vector %d\n", i);
681 log_msg(NULL, 5,
ECHO,
"Run bench --imp=YourModel --imp-info to get a list of all parameters.\\n");
697 void assemble_sv_gvec_onFace(gvec_data_OnFace & gvecs,
limpet::MULTI_IF *miif)
699 for(
size_t i=0; i<gvecs.vecs.size(); i++ ) {
700 sv_data_onFace & gv = gvecs.vecs[i];
703 gv.ordered->set(gv.bogus);
705 gv.ordered->get_ownership_range(start, stop);
707 for(
int n = 0; n<miif->
N_IIF; n++ ) {
708 if( !gv.getsv[n] )
continue;
713 for(
int j=0; j<miif->
N_Nodes[n]; j++ ) {
714 indices[j] = miif->
NodeLists[n][j] + start;
719 gv.ordered->set(indices, data, add);
725 RVector_set( gv.orderedPS, gv.bogus );
727 if(IS_PURK_PROC(purk))
729 MULTI_IF *pmiif = &purk->ion;
730 Real *data =
new Real[purk->gvec_cab.nitems];
733 for(
int n = 0; n<pmiif->N_IIF; n++ ) {
734 int gvidx = n+miif->
N_IIF;
735 if( !gv.getsv[gvidx] )
continue;
736 for(
int j=0; j<purk->gvec_ion[n].nitems; j++ )
737 data[ci++] = ((
SVgetfcn)(gv.getsv[gvidx]))( pmiif->IIF+n, ((
int*)(purk->gvec_ion[n].data))[j],
740 RVector_setvals(gv.orderedPS, purk->gvec_cab.nitems, (
int*)purk->gvec_cab.data, data,
true);
743 RVector_sync( gv.orderedPS );
std::int32_t SF_int
Use the general std::int32_t as int type.
Comfort class. Provides getter functions to access the mesh member variables more comfortably.
Container for a PETSc VecScatter.
A vector storing arbitrary data.
size_t size() const
The current size of the vector.
void assign(InputIterator s, InputIterator e)
Assign a memory range.
T * data()
Pointer to the vector's start.
hm_int count(const K &key) const
Check if key exists.
Custom unordered_set implementation.
hm_int count(const K &key) const
void insert(InputIterator first, InputIterator last)
Represents the ionic model and plug-in (IMP) data structure.
ts & get_tstp()
Gets the time stepper.
void for_each(const std::function< void(IonIfBase &)> &consumer)
Executes the consumer functions on this IMP and each of its plugins.
void compute(int start, int end, GlobalData_t **data)
Perform ionic model computation for 1 time step.
std::vector< IonIfBase * > IIF
array of IIF's
void sv_dump_add_by_name_list(int, char *, char *, char *, char *, char *, double, double)
int * numplugs
number of plugins for each region
std::vector< IonTypeList > plugtypes
plugins types for each region
IonTypeList iontypes
type for each region
int N_IIF
how many different IIF's
int * N_Nodes
#nodes for each IMP
int ** NodeLists
local partitioned node lists for each IMP stored
void setup(double inp_dt, double inp_start, double inp_end)
Initialize the timer_manager.
void reset_timers()
Reset time in timer_manager and then reset registered timers.
Electrical ionics functions (gap junction + ionic current) on the face of interface mesh for EMI mesh...
T local_nodal_to_local_petsc(const meshdata< T, S > &mesh, int rank, T local_nodal)
void init_vector(SF::abstract_vector< T, S > **vec)
SF_nbr
Enumeration encoding the different supported numberings.
@ NBR_PETSC
PETSc numbering of nodes.
@ NBR_REF
The nodal numbering of the reference mesh (the one stored on HD).
@ NBR_SUBMESH
Submesh nodal numbering: The globally ascending sorted reference indices are reindexed.
int get_plug_flag(char *plgstr, int *out_num_plugins, IonTypeList &out_plugins)
GlobalData_t(* SVgetfcn)(IonIfBase &, int, int)
IonType * get_ion_type(const std::string &name)
void update_ts(ts *ptstp)
int read_sv(MULTI_IF *, int, const char *)
std::map< int, std::string > units
timer_manager * tm_manager
a manager for the various physics timers
sf_mesh & get_mesh(const mesh_t gt)
Get a mesh by specifying the gridID.
SF::scattering * get_permutation(const int mesh_id, const int perm_id, const int dpn)
Get the PETSC to canonical permutation scattering for a given mesh and number of dpn.
SF::meshdata< mesh_int_t, mesh_real_t > sf_mesh
void read_metadata(const std::string filename, std::map< std::string, std::string > &metadata, MPI_Comm comm)
Read metadata from the header.
int get_rank(MPI_Comm comm=PETSC_COMM_WORLD)
T get_global(T in, MPI_Op OP, MPI_Comm comm=PETSC_COMM_WORLD)
Do a global reduction on a variable.
SF::scattering * register_permutation(const int mesh_id, const int perm_id, const int dpn)
Register a permutation between two orderings for a mesh.
void register_data(sf_vec *dat, datavec_t d)
Register a data vector in the global registry.
char * dupstr(const char *old_str)
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.
void get_time(double &tm)
SF::abstract_vector< SF_int, SF_real > sf_vec
void remove_char(char *buff, const int buffsize, const char c)
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
V timing(V &t2, const V &t1)
#define PETSC_TO_CANONICAL
Permute algebraic data from PETSC to canonical ordering.