41 static char input_dir[1024],
52 for(
int i=0; i < cpy_argc; i++) {
53 if(strcmp(argv[i],
"+") != 0) {
54 cpy_argv[i] =
dupstr(argv[i]);
63 int param_argc = cpy_argc;
67 status = param(PARAMETERS, ¶m_argc, cpy_argv.
data());
68 if ( status==PrMERROR||status==PrMFATAL )
69 fprintf( stderr,
"\n*** Error reading parameters\n\n");
70 else if ( status == PrMQUIT )
71 fprintf( stderr,
"\n*** Quitting by user's request\n\n");
72 }
while (status == PrMERROR);
76 if (param_globals::output_setup)
77 param_output(PARAMETERS, 1);
80 for(
int i=0; i<param_argc; i++)
84 if (status & PrMERROR) exit(status);
102 log_msg(0,0,0,
"\n *** Initializing physics ***\n");
106 for (
int ii = 0; ii < param_globals::num_external_imp; ii++) {
108 assert(loading_succeeded);
111 if(param_globals::num_external_imp)
112 log_msg(NULL, 4,
ECHO,
"Loading of external LIMPET modules not enabled.\n" 113 "Recompile with DLOPEN set.\n" );
119 log_msg(NULL, 0, 0,
"Initializing %s ..", p->
name);
126 log_msg(0,0,0,
"\n *** Destroying physics ***\n");
154 for (
int i=0; i<ns; i++ ) {
162 log_msg( NULL, 1, 0,
"Extracellular stimulus %d ignored for monodomain", i );
165 log_msg( NULL, 1, 0,
"Intracellular stimulus %d converted to transmembrane", i );
201 if(param_globals::floating_ground)
204 Stimulus* s = param_globals::stimulus;
206 for(
int i=0; i < param_globals::num_stim; i++) {
214 log_msg( NULL, 4, 0,
"Elliptic system is singular!\n" 215 "Either set floating_ground=1 or use an explicit ground:voltage (stimulus[X].stimtype=3)\n" 216 "Do not trust the elliptic solution of this simulation run!\n");
221 printf(
"\n""*** GIT tag: %s\n", GIT_COMMIT_TAG);
222 printf(
"*** GIT hash: %s\n", GIT_COMMIT_HASH);
223 printf(
"*** GIT repo: %s\n", GIT_PATH);
224 printf(
"*** dependency commits: %s\n\n", SUBREPO_COMMITS);
230 param_globals::dt /= 1000.;
233 if(param_globals::mass_lumping == 0 && param_globals::parab_solve==0) {
235 "Warning: explicit solve not possible without mass lumping. \n" 236 "Switching to Crank-Nicolson!\n\n");
238 param_globals::parab_solve = 1;
242 if(!param_globals::extracell_monodomain_stim)
251 if(param_globals::t_sentinel > 0 && param_globals::sentinel_ID < 0 ) {
252 log_msg(0,4,0,
"Warning: t_sentinel is set but no sentinel_ID has been specified; check_quiescence() behavior may not be as expected");
255 if(param_globals::num_external_imp > 0 ) {
256 for(
int ext_imp_i = 0; ext_imp_i < param_globals::num_external_imp; ext_imp_i++) {
257 if(param_globals::external_imp[ext_imp_i][0] !=
'/') {
258 log_msg(0,5,0,
"external_imp[%d] error: absolute paths must be used for .so file loading (\'%s\')",
259 ext_imp_i, param_globals::external_imp[ext_imp_i]);
265 if(param_globals::num_phys_regions == 0) {
266 log_msg(0,4,0,
"Warning: No physics region defined! Please set phys_region parameters to correctly define physics.");
267 log_msg(0,4,0,
"IntraElec and ExtraElec domains will be derived from fibers.\n");
269 param_globals::num_phys_regions = param_globals::bidomain ? 2 : 1;
270 param_globals::phys_region = (p_region*) malloc(param_globals::num_phys_regions *
sizeof(p_region));
272 param_globals::phys_region[0].name = strdup(
"Autogenerated intracellular Electrics");
273 param_globals::phys_region[0].num_IDs = 0;
275 if(param_globals::bidomain) {
277 param_globals::phys_region[1].name = strdup(
"Autogenerated extracellular Electrics");
278 param_globals::phys_region[1].num_IDs = 0;
282 #ifndef WITH_PARMETIS 283 if(param_globals::pstrat == 1) {
284 log_msg(0,3,0,
"openCARP was built without Parmetis support. Swithing to KDtree.");
285 param_globals::pstrat = 2;
290 bool legacy_stim_set =
false, new_stim_set =
false;
292 for(
int i=0; i<param_globals::num_stim; i++) {
293 Stimulus & legacy_stim = param_globals::stimulus[i];
294 Stim & new_stim = param_globals::stim[i];
296 if(legacy_stim.stimtype || legacy_stim.strength)
297 legacy_stim_set =
true;
299 if(new_stim.crct.type || new_stim.pulse.strength)
303 if(legacy_stim_set || new_stim_set) {
304 if(legacy_stim_set && new_stim_set) {
305 log_msg(0,4,0,
"Warning: Legacy stimuli and default stimuli are defined. Only default stimuli will be used!");
307 else if (legacy_stim_set) {
308 log_msg(0,1,0,
"Warning: Legacy stimuli defined. Please consider switching to stimulus definition \"stim[]\"!");
313 log_msg(0,4,0,
"Warning: No potential or current stimuli found!");
319 int flg = 0, err = 0, rank =
get_rank();
321 char *ptr = getcwd(current_dir, 1024);
322 if (ptr == NULL) err++;
323 ptr = getcwd(input_dir, 1024);
324 if (ptr == NULL) err++;
330 if (strcmp(sim_ID,
"OUTPUT_DIR")) {
331 if (mkdir(sim_ID, 0775)) {
332 if (errno == EEXIST ) {
333 log_msg(NULL, 2, 0,
"Output directory exists: %s\n", sim_ID);
335 log_msg(NULL, 5, 0,
"Unable to make output directory\n");
339 }
else if (mkdir(sim_ID, 0775) && errno != EEXIST) {
340 log_msg(NULL, 5, 0,
"Unable to make output directory\n");
348 err += chdir(sim_ID);
349 ptr = getcwd(output_dir, 1024);
350 if (ptr == NULL) err++;
355 err += chdir(output_dir);
360 if (strcmp(param_globals::ppID,
"POSTPROC_DIR")) {
361 if (mkdir(param_globals::ppID, 0775)) {
362 if (errno == EEXIST ) {
363 log_msg(NULL, 2,
ECHO,
"Postprocessing directory exists: %s\n\n", param_globals::ppID);
365 log_msg(NULL, 5,
ECHO,
"Unable to make postprocessing directory\n\n");
369 }
else if (mkdir(param_globals::ppID, 0775) && errno != EEXIST) {
370 log_msg(NULL, 5,
ECHO,
"Unable to make postprocessing directory\n\n");
378 err += chdir(param_globals::ppID);
379 ptr = getcwd(postproc_dir, 1024);
380 if (ptr == NULL) err++;
381 err = chdir(output_dir);
390 bool io_node =
false;
393 if (param_globals::num_io_nodes > 0) {
396 log_msg(NULL, 5, 0,
"You cannot run with async IO on only one core.\n");
400 if (2 * param_globals::num_io_nodes >= psize) {
401 log_msg(NULL, 5, 0,
"The number of IO cores be less " "than the number of compute cores.");
405 if (param_globals::num_PS_nodes && param_globals::num_io_nodes > param_globals::num_PS_nodes) {
407 "The number of IO cores (%d) should not " 408 "exceed the number of PS compute cores (%d).\n",
409 param_globals::num_io_nodes, param_globals::num_PS_nodes);
414 io_node = prank < param_globals::num_io_nodes;
417 MPI_Comm_split(PETSC_COMM_WORLD, io_node,
get_rank(), &comm);
418 MPI_Comm_set_name(comm, io_node ?
"IO" :
"compute");
420 PETSC_COMM_WORLD = comm;
424 MPI_Intercomm_create(comm, 0, MPI_COMM_WORLD, io_node ? param_globals::num_io_nodes : 0,
428 log_msg(NULL, 4, 0,
"Global node %d, Comm rank %d != Intercomm rank %d\n",
432 MPI_Comm_set_name(PETSC_COMM_WORLD,
"compute");
436 if((io_node || !param_globals::num_io_nodes) && !prank)
443 getcwd(current_dir, 1024);
450 if (dest==
OUTPUT) err = chdir(output_dir);
451 else if (dest==
POSTPROC) err = chdir(postproc_dir);
452 else if (dest==
CURDIR) err = chdir(current_dir);
453 else err = chdir(input_dir);
461 double start_time = 0.0;
464 double end_time = param_globals::tend;
478 if(param_globals::num_tsav) {
479 std::vector<double> trig(param_globals::num_tsav);
480 for(
size_t i=0; i<trig.size(); i++) trig[i] = param_globals::tsav[i];
485 if(param_globals::chkpt_intv)
487 param_globals::chkpt_intv, 0,
iotm_chkpt_intv,
"interval checkpointing");
489 if(param_globals::num_trace)
496 const short padding = 4;
501 if(col_width[0] <
int(strlen(buff)+padding))
502 col_width[0] = strlen(buff)+padding;
505 if(col_width[1] <
int(strlen(buff)+padding))
506 col_width[1] = strlen(buff)+padding;
509 for (
size_t tid = 0; tid < used_timer_ids.size(); tid++)
511 int timer_id = used_timer_ids[tid];
521 snprintf(buff,
sizeof buff,
"%.3lf", val);
522 if(col_width[col] <
int(strlen(buff)+padding))
523 col_width[col] = strlen(buff)+padding;
540 const char* smpl_endl =
"\n";
548 log_msg(0,5,0,
"Protocol file %s could not be opened for writing!\n", fname);
561 std::vector<std::string> col_labels = {
"time",
"tick"};
562 std::vector<std::string> col_short_labels = {
"A",
"B"};
563 std::vector<std::string> col_unit_labels = {
"ms",
"--" };
564 std::vector<int> col_width = {4, 4};
566 char c_label = {
'C'};
567 std::string label = {
""};
568 std::string unit = {
""};
572 std::vector<int> used_timer_ids;
573 std::vector<int> used_stim_ids;
583 used_stim_ids.push_back(sidx);
593 for (
size_t tid = 0; tid < used_timer_ids.size(); tid++)
595 int timer_id = used_timer_ids[tid];
598 int llen = strlen(t->
name);
599 mx_llen = llen > mx_llen ? llen : mx_llen;
602 for (
size_t tid = 0; tid < used_timer_ids.size(); tid++)
604 int timer_id = used_timer_ids[tid];
607 col_labels.push_back(t->
name);
609 col_short_labels.push_back(label);
614 if(unit.empty()) unit =
"--";
615 col_unit_labels.push_back(unit);
616 col_width.push_back(4);
624 fh <<
"# Protocol header\n#\n" <<
"# Legend:\n";
625 for(
size_t i = 0; i<col_short_labels.size(); i++)
627 fh <<
"#" << std::setw(2) << col_short_labels[i] <<
" = " << std::setw(mx_llen) << col_labels[i];
628 fh <<
" [" << std::setw(10) << col_unit_labels[i] <<
"]";
630 if(i >= 2 && used_stim_ids[i-2] > -1) {
635 fh <<
" ground stim" << smpl_endl;
637 fh <<
" applied: " << std::to_string(s.
pulse.
strength) << smpl_endl;
648 for(
size_t i = 0; i<col_short_labels.size(); i++)
649 fh << std::setw(col_width[i] - 3) << col_short_labels[i].c_str() << std::setw(3) <<
" ";
652 fh << smpl_endl <<
"#";
653 for(
size_t i = 0; i<col_unit_labels.size(); i++)
654 fh <<
"[" << std::setw(col_width[i]-2) << col_unit_labels[i].c_str() <<
"]";
657 fh << smpl_endl << std::fixed;
665 for (
size_t tid = 0; tid < used_timer_ids.size(); tid++)
667 int timer_id = used_timer_ids[tid];
673 fh << std::setw(col_width[col]) << On;
681 fh << std::setw(col_width[col]) << std::setprecision(3) << val;
703 const char* h1_prog =
"PROG\t----- \t----\t-------\t-------|";
704 const char* h2_prog =
"time\t%%comp\ttime\t ctime \t ETA |";
705 const char* h1_wc =
"\tELAPS |";
706 const char* h2_wc =
"\twc |";
711 log_msg(NULL, 0, 0,
"%s", h1_prog );
719 int req_hours = ((int)(time)) / 3600;
720 int req_min = (((int)(time)) % 3600) / 60;
721 int req_sec = (((int)(time)) % 3600) % 60;
723 snprintf(str, str_size,
"%d:%02d:%02d", req_hours, req_min, req_sec);
731 float req_time = (elapsed_time / progress) * (100.0f - progress);
736 char elapsed_time_str[256];
737 char req_time_str[256];
741 log_msg( NULL, 0,
NONL,
"%.2f\t%.1f\t%.1f\t%s\t%s",
756 log_msg(0,0,0,
"\n *** Launching simulation ***\n");
760 if(param_globals::dump_protocol)
779 it.second->output_step();
793 log_msg(0,0,0,
"\n\nTimings of individual physics:");
794 log_msg(0,0,0,
"------------------------------\n");
804 if(param_globals::post_processing_opts &
RECOVER_PHIE) {
805 log_msg(NULL,0,
ECHO,
"\nPOSTPROCESSOR: Recovering Phie ...");
806 log_msg(NULL,0,
ECHO,
"----------------------------------\n");
812 log_msg(NULL,0,
ECHO,
"\n-----------------------------------------");
813 log_msg(NULL,0,
ECHO,
"POSTPROCESSOR: Successfully recoverd Phie.\n");
825 if(error_if_missing) {
826 log_msg(0,5,0,
"%s error: required physic is not active! Usually this is due to an inconsistent experiment configuration. Aborting!", __func__);
850 log_msg(0,5,0,
"%s warning: trying to register already registered data vector.", __func__);
865 for(
int i=0; i<param_globals::num_phys_regions; i++)
869 switch(param_globals::phys_region[i].ptype) {
892 log_msg(0,5,0,
"Unsupported mesh type %d! Aborting!", param_globals::phys_region[i].ptype);
896 curmesh->
name = param_globals::phys_region[i].name;
898 for(
int j=0; j<param_globals::phys_region[i].num_IDs; j++)
920 for (
int i=0; i<ntr; i++) {
929 shape.
p0.
x = tagRegs[i].p0[0];
930 shape.
p0.
y = tagRegs[i].p0[1];
931 shape.
p0.
z = tagRegs[i].p0[2];
932 shape.
p1.
x = tagRegs[i].p1[0];
933 shape.
p1.
y = tagRegs[i].p1[1];
934 shape.
p1.
z = tagRegs[i].p1[2];
935 shape.
radius = tagRegs[i].radius;
942 log_msg(0,3,0,
"Tag region %d is empty", i);
944 for(
size_t j=0; j<elem_indices.
size(); j++)
945 mesh.
tag[elem_indices[j]] = tagRegs[i].tag;
949 if(strlen(param_globals::retagfile))
964 size_t renormalised_count = 0;
970 for (
size_t i = 0; i < l_numelem; i++)
972 const mesh_real_t f0 = fib[3*i+0], f1 = fib[3*i+1], f2 = fib[3*i+2];
973 mesh_real_t fibre_len = sqrt(f0*f0 + f1*f1 + f2*f2);
975 if (fibre_len && fabs(fibre_len - 1) > 1e-3) {
976 fib[3 * i + 0] /= fibre_len;
977 fib[3 * i + 1] /= fibre_len;
978 fib[3 * i + 2] /= fibre_len;
979 renormalised_count++;
983 return renormalised_count;
988 log_msg(0,0,0,
"\n *** Processing meshes ***\n");
990 const std::string basename = param_globals::meshname;
991 const int verb = param_globals::output_level;
999 MPI_Comm comm = ref_mesh.
comm;
1002 double t1, t2, s1, s2;
1003 MPI_Comm_size(comm, &size); MPI_Comm_rank(comm, &rank);
1009 std::list< sf_mesh* > ptsread_list;
1012 t1 = MPI_Wtime(); s1 = t1;
1013 if(verb)
log_msg(NULL, 0, 0,
"Reading reference mesh: %s.*", basename.c_str());
1019 if(verb)
log_msg(NULL, 0, 0,
"Done in %f sec.",
float(t2 - t1));
1021 bool check_fibre_normality =
true;
1022 if (check_fibre_normality) {
1028 size_t l_num_fixed_she = 0;
1032 unsigned long fixed[2] = {(
unsigned long) l_num_fixed_fib, (
unsigned long) l_num_fixed_she};
1033 MPI_Allreduce(MPI_IN_PLACE, fixed, 2, MPI_UNSIGNED_LONG, MPI_SUM, comm);
1035 if (fixed[0] + fixed[1] > 0)
1036 log_msg(NULL, 0, 0,
"Renormalised %ld longitudinal and %ld sheet-transverse fibre vectors.", fixed[0], fixed[1]);
1039 if(verb)
log_msg(NULL, 0, 0,
"Done in %f sec.",
float(t2 - t1));
1042 if(param_globals::numtagreg > 0) {
1043 log_msg(0, 0, 0,
"Re-tagging reference mesh");
1047 ptsread_list.push_back(&ref_mesh);
1050 retag_elements(ref_mesh, param_globals::tagreg, param_globals::numtagreg);
1053 ptsread_list.clear();
1056 if(verb)
log_msg(NULL, 0, 0,
"Processing submeshes");
1058 for(
auto it = mesh_registry.begin(); it != mesh_registry.end(); ++it) {
1059 mesh_t grid_type = it->first;
1060 sf_mesh & submesh = it->second;
1063 if(verb > 1)
log_msg(NULL, 0, 0,
"\nSubmesh name: %s", submesh.
name.c_str());
1079 if(verb > 1)
log_msg(NULL, 0, 0,
"Extraction done in %f sec.",
float(t2 - t1));
1081 ptsread_list.push_back(&submesh);
1086 if(param_globals::pstrat == 2)
1089 for(
auto it = mesh_registry.begin(); it != mesh_registry.end(); ++it)
1091 mesh_t grid_type = it->first;
1092 sf_mesh & submesh = it->second;
1094 if(verb > 2)
log_msg(NULL, 0, 0,
"\nSubmesh name: %s", submesh.
name.c_str());
1099 switch(param_globals::pstrat) {
1101 if(verb > 2)
log_msg(NULL, 0, 0,
"Using linear partitioning ..");
1104 #ifdef WITH_PARMETIS 1107 if(verb > 2)
log_msg(NULL, 0, 0,
"Using Parmetis partitioner ..");
1108 SF::parmetis_partitioner<mesh_int_t, mesh_real_t> partitioner(param_globals::pstrat_imbalance, 2);
1109 partitioner(submesh, part);
1115 if(verb > 2)
log_msg(NULL, 0, 0,
"Using KDtree partitioner ..");
1117 partitioner(submesh, part);
1122 if(verb > 2)
log_msg(NULL, 0, 0,
"Partitioning done in %f sec.",
float(t2 - t1));
1124 if(param_globals::pstrat > 0) {
1125 if(param_globals::gridout_p) {
1126 std::string out_name =
get_basename(param_globals::meshname);
1131 log_msg(0,0,0,
"Writing \"%s\" partitioning to: %s", submesh.
name.c_str(), out_name.c_str());
1138 if(verb > 2)
log_msg(NULL, 0, 0,
"Redistributing done in %f sec.",
float(t2 - t1));
1143 sm_numbering(submesh);
1145 if(verb > 2)
log_msg(NULL, 0, 0,
"Canonical numbering done in %f sec.",
float(t2 - t1));
1150 p_numbering(submesh);
1152 if(verb > 2)
log_msg(NULL, 0, 0,
"PETSc numbering done in %f sec.",
float(t2 - t1));
1161 if(verb)
log_msg(NULL, 0, 0,
"All done in %f sec.",
float(s2 - s1));
1170 std::string output_base =
get_basename(param_globals::meshname);
1172 if(write_intra_elec) {
1175 if(param_globals::gridout_i & 1) {
1177 if(param_globals::output_level > 1)
1178 log_msg(0,0,0,
"Computing \"%s\" surface ..", mesh.
name.c_str());
1181 std::string output_file = output_base +
"_i.surf";
1182 log_msg(0,0,0,
"Writing \"%s\" surface: %s", mesh.
name.c_str(), output_file.c_str());
1185 if(param_globals::gridout_i & 2) {
1186 bool write_binary =
false;
1188 std::string output_file = output_base +
"_i";
1189 log_msg(0,0,0,
"Writing \"%s\" mesh: %s", mesh.
name.c_str(), output_file.c_str());
1194 if(write_extra_elec) {
1197 if(param_globals::gridout_e & 1) {
1199 if(param_globals::output_level > 1)
1200 log_msg(0,0,0,
"Computing \"%s\" surface ..", mesh.
name.c_str());
1203 std::string output_file = output_base +
"_e.surf";
1204 log_msg(0,0,0,
"Writing \"%s\" surface: %s", mesh.
name.c_str(), output_file.c_str());
1207 if(param_globals::gridout_e & 2) {
1208 bool write_binary =
false;
1209 std::string output_file = output_base +
"_e";
1210 log_msg(0,0,0,
"Writing \"%s\" mesh: %s", mesh.
name.c_str(), output_file.c_str());
1233 char* filecopy =
dupstr(file);
1234 char* dir =
dupstr(dirname(filecopy));
1251 PetscErrorPrintf = PetscErrorPrintfNone;
1261 for(
size_t eidx = 0; eidx < mesh.
l_numelem; eidx++) {
1264 if(mindim < cdim) mindim = cdim;
1291 int gsize = inp_data->
gsize();
1297 regigb.
x(gsize / dpn);
1298 regigb.
dim_x(regigb.
x()-1);
1301 regigb.
y(1); regigb.
z(1);
1317 regigb.
inc_t(param_globals::spacedt);
1331 log_msg(0,5,0,
"%s error: Could not set up data output! Aborting!", __func__);
1338 IO.
spec = mesh_spec;
1348 buffmap[mesh_spec] = inp_copy;
1355 void igb_output_manager::register_output_async(
sf_vec* inp_data,
1383 for(
size_t i=0; i<alg_nod.
size(); i++)
1384 ioidx[i] = nbr[alg_nod[i]];
1389 for(
size_t i=0; i<idx->
size(); i++) {
1391 ioidx[i] = nbr[loc_nodal];
1411 if(param_globals::num_io_nodes == 0)
1414 register_output_async(inp_data, inp_meshid, dpn, name, units, idx, elem_data);
1429 sc->
forward(*data_vec, *perm_vec);
1444 FILE* fd =
static_cast<FILE*
>(it.
igb.
fileptr());
1447 sf_vec* buff = fill_output_buffer(it);
1460 root_write(fd, restr_buff, PETSC_COMM_WORLD);
1488 FILE* fd =
static_cast<FILE*
>(it.
igb.
fileptr());
1519 const int max_line_len = 128;
1520 const char* file_sep =
"#=======================================================";
1527 fprintf(out->
fd,
"# CARP GIT commit hash: %s\n", GIT_COMMIT_HASH);
1528 fprintf(out->
fd,
"# dependency hashes: %s\n", SUBREPO_COMMITS);
1529 fprintf(out->
fd,
"\n");
1532 char line[8196] =
"# ";
1534 for (
int j=0; j<argc; j++) {
1535 strcat(line, argv[j]);
1536 if(strlen(line) > max_line_len) {
1537 fprintf(out->
fd,
"%s\n", line);
1543 fprintf(out->
fd,
"%s\n\n", line);
1547 for (
int i=1; i<argc; i++) {
1548 std::string argument(argv[i]);
1549 if (argument ==
"+F" || argument.find(
"_options_file")!= std::string::npos) {
1551 std::string init =
"";
1552 if (argument.find(
"_options_file")!= std::string::npos) {
1553 fprintf(out->
fd,
"%s = %s\n", argument.substr(1).c_str(), argv[i+1]);
1556 fprintf(out->
fd,
"%s>>\n", file_sep);
1559 fprintf(out->
fd,
"## %s ##\n", argv[i]);
1560 FILE *in = fopen(argv[i],
"r");
1561 while (fgets(line, 8196, in))
1562 fprintf(out->
fd,
"%s%s", init.c_str(), line);
1564 fprintf(out->
fd,
"\n##END of %s\n", argv[i]);
1565 fprintf(out->
fd,
"%s<<\n\n", file_sep);
1567 else if(argv[i][0] ==
'-')
1569 bool prelast = (i==argc-1);
1570 bool paramFollows = !prelast && ((argv[i+1][0] !=
'-') ||
1571 ((argv[i+1][1] >=
'0') && (argv[i+1][1] <=
'9')));
1577 char *optcpy = strdup(argv[i+1]);
1578 char *front = optcpy;
1580 while(*front==
' ' && *front) front++;
1582 while(*++front ==
' ');
1583 char *back = optcpy+strlen(optcpy)-1;
1584 while(*back==
' ' && back>front) back--;
1588 if (strstr(front,
"=") !=
nullptr)
1589 fprintf(out->
fd,
"%-40s= \"%s\"\n", argv[i]+1, front);
1591 fprintf(out->
fd,
"%-40s= %s\n", argv[i]+1, front);
1596 fprintf(out->
fd,
"%-40s= 1\n", argv[i]);
1609 snprintf(save_fn,
sizeof save_fn,
"exit.save.%.3f.roe", time);
1610 log_msg(NULL, 0, 0,
"savequit called at time %g\n", time);
void generate_par_layout()
Set up the parallel layout.
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.
void register_physics()
Register physics to the physics registry.
void update_console_output(const timer_manager &tm, prog_stats &p)
bool elem_flag
igb header we use for output
The mesh storage class. It contains both element and vertex data.
std::map< physic_t, Basic_physic * > physics_reg
the physics
IO_t
The different output (directory) types.
#define STM_IGNORE_MONODOMAIN
virtual void release_ptr(S *&p)=0
vector< T > & get_numbering(SF_nbr nbr_type)
Get the vector defining a certain numbering.
class to store shape definitions
void output_parameter_file(const char *fname, int argc, char **argv)
stim_pulse pulse
stimulus wave form
void set_io_dirs(char *sim_ID, char *pp_ID, IO_t init)
char * dupstr(const char *old_str)
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.
MPI_Comm comm
the parallel mesh is defined on a MPI world
const SF::vector< mesh_int_t > * restr_idx
when using asyncIO, here we store the different IDs associated to the vectors we output ...
void compute_surface_mesh(const meshdata< T, S > &mesh, const SF_nbr numbering, const hashmap::unordered_set< T > &tags, meshdata< T, S > &surfmesh)
Compute the surface of a given mesh.
vector< T > tag
element tag
tagreg_t
tag regions types. must be in line with carp.prm
PETSc numbering of nodes.
#define PETSC_TO_CANONICAL
Permute algebraic data from PETSC to canonical ordering.
Comfort class. Provides getter functions to access the mesh member variables more comfortably...
void time_to_string(float time, char *str, short str_size)
overlapping_layout< T > pl
nodal parallel layout
std::map< mesh_t, sf_mesh > mesh_reg
Registry for the different meshes used in a multi-physics simulation.
vector< S > fib
fiber direction
void reset_timers()
Reset time in timer_manager and then reset registered timers.
void free_scatterings()
Free the registered scatterings.
bool is_voltage(stim_t type)
uses voltage as stimulation
void simulate()
Main simulate loop.
void post_process()
do postprocessing
void initialize_eq_timer(double istart, double iend, int ntrig, double iintv, double idur, int ID, const char *iname, const char *poolname=nullptr)
double timer_val(const int timer_id)
figure out current value of a signal linked to a given timer
size_t renormalise_fibres(SF::vector< mesh_real_t > &fib, size_t l_numelem)
virtual T lsize() const =0
bool triggered
flag indicating trigger at current time step
void write_mesh_parallel(const meshdata< T, S > &mesh, bool binary, std::string basename)
Write a parallel mesh to harddisk without gathering it on one rank.
timer_manager * tm_manager
a manager for the various physics timers
std::map< SF::mixed_tuple< mesh_t, int >, sf_vec * > buffmap
map data spec -> PETSc vector buffer
SF::vector< mesh_int_t > restr_petsc_idx
pointer to index vector with nodal indices we restrict to.
double last
last output wallclock time
void setup_petsc_err_log()
set up error logs for PETSc, so that it doesnt print errors to stderr.
void write_data_ascii(const MPI_Comm comm, const vector< T > &idx, const vector< S > &data, std::string file, short dpn=1)
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.
const char * name
The name of the physic, each physic should have one.
void initialize_physics()
Initialize all physics in the registry.
void savequit()
save state and quit simulator
void count(const vector< T > &data, vector< S > &cnt)
Count number of occurrences of indices.
T * data()
Pointer to the vector's start.
void read_elements(meshdata< T, S > &mesh, std::string basename)
Read the element data (elements and fibers) of a CARP mesh.
IGBheader igb
pointer to index vector used for restricting output.
mesh_t
The enum identifying the different meshes we might want to load.
bool trigger(int ID) const
physic_t
Identifier for the different physics we want to set up.
void close_files_and_cleanup()
close file descriptors
void check_and_convert_params()
Here we want to put all parameter checks, conversions and modifications that have been littered throu...
void init_vector(SF::abstract_vector< T, S > **vec)
void write_surface(const meshdata< T, S > &surfmesh, std::string surffile)
#define ELEM_PETSC_TO_CANONICAL
Permute algebraic element data from PETSC to canonical ordering.
char * get_file_dir(const char *file)
void insert_points(const vector< S > &pts, const vector< T > &ptsidx, std::list< meshdata< T, S > *> &meshlist)
Insert the points from the read-in buffers into a list of distributed meshes.
void COMPUTE_do_output(SF_real *dat, const int lsize, const int IO_id)
for display execution progress and statistical data of electrical solve
bool setup_IO(int argc, char **argv)
bool using_legacy_stimuli
flag storing whether legacy stimuli are used
void dump_state(char *, float, opencarp::mesh_t gid, bool, unsigned int)
FILE * petsc_error_fd
file descriptor for petsc error output
Base class for tracking progress.
void initialize_singlestep_timer(double tg, double idur, int ID, const char *iname, const char *poolname=nullptr)
The element numbering of the reference mesh (the one stored on HD).
double start
output start wallclock time
void extract_tagbased(const meshdata< T, S > &mesh, meshdata< T, S > &submesh)
Extract a submesh based on element tags.
Submesh nodal numbering: The globally ascending sorted reference indices are reindexed.
#define PHYSREG_INTRA_ELEC
void init_console_output(const timer_manager &tm, prog_stats &p)
int COMPUTE_register_output(const SF::vector< mesh_int_t > &idx, const int dpn, const char *name, const char *units)
The abstract physics interface we can use to trigger all physics.
Top-level header of FEM module.
#define PHYSREG_EXTRA_ELEC
void forward(abstract_vector< T, S > &in, abstract_vector< T, S > &out, bool add=false)
Forward scattering.
void parse_mesh_types()
Parse the phys_type CLI parameters and set up (empty) SF::meshdata meshes.
void parse_params_cpy(int argc, char **argv)
Initialize input parameters on a copy of the real command line parameters.
int set_ignore_flags(int mode)
double curr
current output wallclock time
IGBheader * get_igb_header(const sf_vec *vec)
Get the pointer to the igb header for a vector that was registered for output.
void destroy_physics()
Destroy all physics in the registry.
int timer_idx
the timer index received from the timer manager
void write_data()
write registered data to disk
long d_time
current time instance index
const SF::vector< mesh_int_t > * restr_idx
pointer to data registered for output
std::map< SF::mixed_tuple< mesh_t, int >, sf_vec * > buffmap_elem
void basic_timer_setup()
Here we set up the timers that we always want to have, independent of physics.
void clear_data()
Clear the mesh data from memory.
sf_mesh & get_mesh(const mesh_t gt)
Get a mesh by specifying the gridID.
void register_output_sync(sf_vec *inp_data, const mesh_t inp_meshid, const int dpn, const char *name, const char *units, const SF::vector< mesh_int_t > *idx=NULL, bool elem_data=false)
int plot_protocols(const char *fname)
plot simulation protocols (I/O timers, stimuli, boundary conditions, etc)
Submesh element numbering: The globally ascending sorted reference indices are reindexed.
void print_DD_info(const meshdata< T, S > &mesh)
Print some basic information on the domain decomposition of a mesh.
size_t write_binary(FILE *fd)
Write a vector to HD in binary. File descriptor is already set up.
void get_protocol_column_widths(std::vector< int > &col_width, std::vector< int > &used_timer_ids)
void setup_meshes()
Read in the reference mesh and use its data to populate all meshes registered in the mesh registry...
hashmap::unordered_set< int > extr_tag
the element tags based on which the mesh has been extracted
long d_trigger_dur
discrete duration
void show_build_info()
show the build info, exit if -buildinfo was provided. This code runs before MPI_Init().
void insert(InputIterator first, InputIterator last)
#define STM_IGNORE_BIDOMAIN
void register_data(sf_vec *dat, datavec_t d)
Register a data vector in the global registry.
void get_time(double &tm)
Basic_physic * get_physics(physic_t p, bool error_if_missing)
Convinience function to get a physics.
void set_elem(size_t eidx)
Set the view to a new element.
void extract_myocardium(const meshdata< T, S > &mesh, meshdata< T, S > &submesh)
Extract the myocardium submesh.
void retag_elements(sf_mesh &mesh, TagRegion *tagRegs, int ntr)
int timer_id
timer for stimulus
T get_global(T in, MPI_Op OP, MPI_Comm comm=PETSC_COMM_WORLD)
Do a global reduction on a variable.
Functor class generating a numbering optimized for PETSc.
SF::mixed_tuple< mesh_t, int > spec
flag whether the data is elements-wise
MPI_Comm IO_Intercomm
Communicator between IO and compute worlds.
V timing(V &t2, const V &t1)
void check_nullspace_ok()
SF::vector< stimulus > stimuli
the electrical stimuli
const char * name
timer name
void update_cwd()
save the current working directory to curdir so that we can switch back to it if needed.
void redistribute_elements(meshdata< T, S > &mesh, meshdata< T, S > &sendbuff, vector< T > &part)
Redistribute the element data of a parallel mesh among the ranks based on a partitioning.
virtual void output_timings()
std::string get_basename(const std::string &path)
std::string name
the mesh name
size_t size() const
The current size of the vector.
Top-level header of physics module.
void log_msg(FILE_SPEC out, int level, unsigned char flag, const char *fmt,...)
void ignore_extracellular_stim(Stimulus *st, int ns, int ignore)
bool mesh_is_registered(const mesh_t gt)
check wheter a SF mesh is set
stim_t type
type of stimulus
bool have_permutation(const int mesh_id, const int perm_id, const int dpn)
short get_mesh_dim(mesh_t id)
get (lowest) dimension of the mesh used in the experiment
SF::vector< async_io_item > async_IOs
A vector storing arbitrary data.
size_t l_numelem
local number of elements
#define STM_IGNORE_PSEUDO_BIDM
#define Extracellular_V_OL
std::map< datavec_t, sf_vec * > datavec_reg
important solution vectors from different physics
virtual void compute_step()=0
void f_close(FILE_SPEC &f)
Close a FILE_SPEC.
std::vector< base_timer * > timers
vector containing individual timers
std::string timer_unit(const int timer_id)
figure out units of a signal linked to a given timer
void initialize_neq_timer(const std::vector< double > &itrig, double idur, int ID, const char *iname, const char *poolname=nullptr)
void register_output(sf_vec *inp_data, const mesh_t inp_meshid, const int dpn, const char *name, const char *units, const SF::vector< mesh_int_t > *idx=NULL, bool elem_data=false)
Register a data vector for output.
std::map< int, std::string > units
int load_ionic_module(const char *)
const vector< T > & algebraic_nodes() const
Getter function for the local indices forming the local algebraic node set.
vector< S > she
sheet direction
datavec_t
Enum used to adress the different data vectors stored in the data registry.
SF::vector< sync_io_item > sync_IOs
double strength
strength of stimulus
stim_protocol ptcl
applied stimulation protocol used
double SF_real
Use the general double as real type.
Functor class applying a submesh renumbering.
Basic utility structs and functions, mostly IO related.
stim_physics phys
physics of stimulus
#define Extracellular_Ground
size_t root_write(FILE *fd, const vector< V > &vec, MPI_Comm comm)
Write vector data binary to disk.
void resize(size_t n)
Resize a vector.
sf_vec * get_data(datavec_t d)
Retrieve a petsc data vector from the data registry.
int get_size(MPI_Comm comm=PETSC_COMM_WORLD)
int IO_id
pointer to data registered for output
Simulator-level utility execution control functions.
double start
initial time (nonzero when restarting)
SF::meshdata< mesh_int_t, mesh_real_t > sf_mesh
centralize time managment and output triggering
int get_rank(MPI_Comm comm=PETSC_COMM_WORLD)
SF::scatter_registry scatter_reg
Registry for the different scatter objects.
int postproc_recover_phie()
T local_nodal_to_local_petsc(const meshdata< T, S > &mesh, int rank, T local_nodal)
virtual T gsize() const =0
virtual void initialize()=0
FILE_SPEC f_open(const char *fname, const char *mode)
Open a FILE_SPEC.
void read_points(const std::string basename, const MPI_Comm comm, vector< S > &pts, vector< T > &ptsidx)
Read the points and insert them into a list of meshes.
Container for a PETSc VecScatter.