openCARP
Doxygen code documentation for the open cardiac electrophysiology simulator openCARP
fem_utils.cc
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // openCARP is an open cardiac electrophysiology simulator.
3 //
4 // Copyright (C) 2020 openCARP project
5 //
6 // This program is licensed under the openCARP Academic Public License (APL)
7 // v1.0: You can use and redistribute it and/or modify it in non-commercial
8 // academic environments under the terms of APL as published by the openCARP
9 // project v1.0, or (at your option) any later version. Commercial use requires
10 // a commercial license (info@opencarp.org).
11 //
12 // This program is distributed without any warranty; see the openCARP APL for
13 // more details.
14 //
15 // You should have received a copy of the openCARP APL along with this program
16 // and can find it online: http://www.opencarp.org/license
17 // ----------------------------------------------------------------------------
18 
27 #include "SF_init.h"
28 #include "fem.h"
29 
30 namespace opencarp {
31 
32 void parse_comment_line(char* buff, const int buffsize, std::map<std::string,std::string> & metadata)
33 {
34  // we skip comment lines with no key value pair
35  if(! has_char(buff, buffsize, '=')) return;
36 
37  // there might be multiple comment characters and spaces preceding a key-value pair
38  remove_preceding_char(buff, buffsize, COMMENT_CHAR);
39  remove_preceding_char(buff, buffsize, ' ');
40 
41  const int wsize = 1024;
42  char lword[wsize], cword[wsize], rword[wsize];
43 
44  int numread = sscanf(buff, "%s %s %s", lword, cword, rword);
45 
46  if(numread == 3 && cword[0] == '=') {
47  // input was perfect
48  std::string key = lword, value = rword;
49  metadata[key] = value;
50  }
51  else if(numread == 1) {
52  // we have key=value without spaces
53  int ridx=0, widx=0;
54  while(ridx < wsize && lword[ridx] != '=') cword[widx++] = lword[ridx++];
55  cword[widx] = '\0';
56 
57  std::string key = cword;
58 
59  widx=0, ridx += 1;
60  while(ridx < wsize && lword[ridx] != '\0') cword[widx++] = lword[ridx++];
61  cword[widx] = '\0';
62 
63  std::string value = cword;
64 
65  metadata[key] = value;
66  }
67  else {
68  fprintf(stderr, "%s warning: Malformed key-value pair:\n%s\n", __func__, buff);
69  }
70 }
71 
72 void read_metadata(const std::string filename, std::map<std::string,std::string> & metadata, MPI_Comm comm)
73 {
74  // There are 3 ways to add metadata to a vtx file:
75  // 1) the new way:
76  // # key1 = value1
77  // # key2 = value2
78  // # key3 = value3
79  // 2) nvtx # mesh [intra|extra] nelem npts
80  // 3) number of nodes
81  // [intra|extra]
82  int size, rank;
83  MPI_Comm_size(comm, &size); MPI_Comm_rank(comm, &rank);
84 
85  int err = 0;
86  FILE_SPEC stream = NULL;
87 
88  if(rank == 0) {
89  stream = f_open(filename.c_str(), "r");
90  if(stream == NULL) err++;
91  }
92 
93  // return on file open error
94  if(get_global(err, MPI_SUM)) {
95  log_msg(0,5,0, "%s error: Could not read vtx data. Aborting!", __func__);
96  EXIT(1);
97  }
98 
99  const size_t str_size = 5000;
100  char readbuff[str_size];
101 
102  // parse type 1 metadata lines. for simplicity we parse on each rank.
103  char* ptr = f_gets_par(readbuff, str_size, stream, comm);
104  remove_preceding_char(readbuff, str_size, ' ');
105 
106  while(ptr != NULL && readbuff[0] == COMMENT_CHAR) {
107  parse_comment_line(readbuff, str_size, metadata);
108  ptr = f_gets_par(readbuff, str_size, stream, comm);
109  remove_preceding_char(readbuff, str_size, ' ');
110  }
111 
112  // parse type 2 metadata
113  if(has_char(readbuff, str_size, '#')) {
114  int ibuff, ne, nn;
115  char iestr[128], nestr[128], nnstr[128];
116  int nread = sscanf(readbuff, "%d # %*s %31s %d %d", &ibuff, iestr, &ne, &nn);
117 
118  if(nread == 4) {
119  metadata["grid"] = iestr;
120  metadata["nelem"] = std::to_string(ne);
121  metadata["nnode"] = std::to_string(nn);
122  }
123  }
124 
125  // parse type 3 metadata
126  ptr = f_gets_par(readbuff, str_size, stream, comm);
127 
128  if(ptr) {
129  remove_preceding_char(readbuff, str_size, ' ');
130  char grid[128];
131  sscanf(readbuff, "%s", grid);
132 
133  if(strcmp(grid, "intra") == 0) {
134  metadata["grid"] = "intra";
135  } else if(strcmp(grid, "extra") == 0) {
136  metadata["grid"] = "extra";
137  }
138  }
139 
140  f_close(stream);
141 }
142 
143 char* skip_comments(FILE_SPEC stream, char* readbuff, size_t buffsize, MPI_Comm comm)
144 {
145  char* ptr = NULL;
146  do {
147  ptr = f_gets_par(readbuff, buffsize, stream, comm);
148  remove_preceding_char(readbuff, buffsize, ' ');
149  }
150  while(ptr != NULL && readbuff[0] == COMMENT_CHAR);
151 
152  return ptr;
153 }
154 
155 void indices_from_region_tag(SF::vector<mesh_int_t> & idx, const sf_mesh & mesh, const int tag)
156 {
157  std::set<mesh_int_t> idx_set;
158 
159  for(size_t eidx = 0; eidx < mesh.l_numelem; eidx++) {
160  if(mesh.tag[eidx] == tag) {
161  for(mesh_int_t i = mesh.dsp[eidx]; i<mesh.dsp[eidx + 1]; i++)
162  idx_set.insert(mesh.con[i]);
163  }
164  }
165 
166  idx.assign(idx_set.begin(), idx_set.end());
167 }
168 
169 void indices_from_geom_shape(SF::vector<mesh_int_t> & idx, const sf_mesh & mesh, const geom_shape shape, const bool nodal)
170 {
171  Point p;
172 
173  if(nodal) {
174  idx.reserve(mesh.l_numpts);
175 
176  for(size_t i=0; i<mesh.l_numpts; i++) {
177  p.x = mesh.xyz[i*3 + 0], p.y = mesh.xyz[i*3 + 1], p.z = mesh.xyz[i*3 + 2];
178  if(point_in_shape(p, shape))
179  idx.push_back(i);
180  }
181  }
182  else {
183  idx.reserve(mesh.l_numelem);
184 
185  for(size_t eidx = 0; eidx < mesh.l_numelem; eidx++) {
186  p.x = p.y = p.z = 0.0;
187 
188  for(mesh_int_t i = mesh.dsp[eidx]; i<mesh.dsp[eidx + 1]; i++) {
189  mesh_int_t c = mesh.con[i];
190  p.x += mesh.xyz[c*3 + 0];
191  p.y += mesh.xyz[c*3 + 1];
192  p.z += mesh.xyz[c*3 + 2];
193  }
194  p /= double(mesh.dsp[eidx + 1] - mesh.dsp[eidx]);
195 
196  if(point_in_shape(p, shape))
197  idx.push_back(eidx);
198  }
199  }
200 }
201 
203 {
204  assert(mass.mesh_ptr() != NULL);
205 
206  sf_vec* weights; SF::init_vector(&weights, *mass.mesh_ptr(), 1, sf_vec::algebraic);
207  sf_vec* vols; SF::init_vector(&vols, *mass.mesh_ptr(), 1, sf_vec::algebraic);
208 
209  const SF::vector<mesh_int_t> & petsc_nod = mass.mesh_ptr()->get_numbering(SF::NBR_PETSC);
210 
211  // generate global petsc indices
212  SF::vector<SF_int> petsc_idx(local_idx.size());
213  for(size_t i=0; i<local_idx.size(); i++) petsc_idx[i] = petsc_nod[local_idx[i]];
214 
215  weights->set(0);
216  weights->set(petsc_idx, 1.0);
217 
218  mass.mult(*weights, *vols);
219  SF_real V = vols->sum();
220 
221  return V;
222 }
223 
224 void warn_when_passing_intra_vtx(const std::string filename)
225 {
226  std::map<std::string,std::string> metadata;
227  read_metadata(filename, metadata, PETSC_COMM_WORLD);
228 
229  if(metadata.count("grid")) {
230  if(metadata["grid"].compare("intra") == 0) {
231  log_msg(0,3,0, "Warning: openCARP requires input vtx indices to be of from the input mesh, i.e. of type \"extra\".");
232  }
233  } else {
234  log_msg(0,3,0, "%s warning: Could not derive grid type info from file %s", __func__, filename.c_str());
235  }
236 }
237 
238 } // namespace opencarp
239 
The mesh storage class. It contains both element and vertex data.
Definition: SF_container.h:383
vector< T > & get_numbering(SF_nbr nbr_type)
Get the vector defining a certain numbering.
Definition: SF_container.h:452
class to store shape definitions
Definition: basics.h:381
#define COMMENT_CHAR
Definition: fem_utils.h:37
void remove_preceding_char(char *buff, const int buffsize, const char c)
Definition: basics.h:345
vector< T > tag
element tag
Definition: SF_container.h:405
PETSc numbering of nodes.
Definition: SF_container.h:191
vector< T > dsp
connectivity starting index of each element
Definition: SF_container.h:404
void warn_when_passing_intra_vtx(const std::string filename)
Definition: fem_utils.cc:224
bool has_char(char *buff, const int buffsize, const char c)
Definition: basics.h:368
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
vector< S > xyz
node cooridnates
Definition: SF_container.h:415
vector< T > con
Definition: SF_container.h:400
T & push_back(T val)
Definition: SF_vector.h:283
SF_real get_volume_from_nodes(sf_mat &mass, SF::vector< mesh_int_t > &local_idx)
Definition: fem_utils.cc:202
void init_vector(SF::abstract_vector< T, S > **vec)
Definition: SF_init.h:99
void indices_from_region_tag(SF::vector< mesh_int_t > &idx, const sf_mesh &mesh, const int tag)
Populate vertex data with the vertices of a given tag region.
Definition: fem_utils.cc:155
virtual void mult(const abstract_vector< T, S > &x, abstract_vector< T, S > &b) const =0
int mesh_int_t
Definition: SF_container.h:46
Top-level header of FEM module.
const meshdata< mesh_int_t, mesh_real_t > * mesh_ptr() const
T get_global(T in, MPI_Op OP, MPI_Comm comm=PETSC_COMM_WORLD)
Do a global reduction on a variable.
Definition: basics.h:233
char * skip_comments(FILE_SPEC stream, char *readbuff, size_t buffsize, MPI_Comm comm)
Definition: fem_utils.cc:143
File descriptor struct.
Definition: basics.h:133
size_t size() const
The current size of the vector.
Definition: SF_vector.h:104
void parse_comment_line(char *buff, const int buffsize, std::map< std::string, std::string > &metadata)
Definition: fem_utils.cc:32
void log_msg(FILE_SPEC out, int level, unsigned char flag, const char *fmt,...)
Definition: basics.cc:72
void read_metadata(const std::string filename, std::map< std::string, std::string > &metadata, MPI_Comm comm)
Read metadata from the header.
Definition: fem_utils.cc:72
size_t l_numpts
local number of points
Definition: SF_container.h:389
size_t l_numelem
local number of elements
Definition: SF_container.h:387
void f_close(FILE_SPEC &f)
Close a FILE_SPEC.
Definition: basics.cc:162
void reserve(size_t n)
Definition: SF_vector.h:241
void assign(InputIterator s, InputIterator e)
Assign a memory range.
Definition: SF_vector.h:161
double SF_real
Use the general double as real type.
Definition: SF_globals.h:38
bool point_in_shape(const Point &p, const geom_shape &shape)
test if a point is inside a simple geometric shape
Definition: basics.cc:250
char * f_gets_par(char *s, int size, FILE_SPEC stream, MPI_Comm comm)
Definition: basics.cc:199
FILE_SPEC f_open(const char *fname, const char *mode)
Open a FILE_SPEC.
Definition: basics.cc:135