openCARP
Doxygen code documentation for the open cardiac electrophysiology simulator openCARP
fem_utils.cc
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright (c) NumeriCor GmbH
2 // SPDX-License-Identifier: Apache-2.0
3 
12 #include "SF_init.h"
13 #include "fem.h"
14 
15 namespace opencarp {
16 
17 void parse_comment_line(char* buff, const int buffsize, std::map<std::string,std::string> & metadata)
18 {
19  // we skip comment lines with no key value pair
20  if(! has_char(buff, buffsize, '=')) return;
21 
22  // there might be multiple comment characters and spaces preceding a key-value pair
23  remove_preceding_char(buff, buffsize, COMMENT_CHAR);
24  remove_preceding_char(buff, buffsize, ' ');
25 
26  const int wsize = 1024;
27  char lword[wsize], cword[wsize], rword[wsize];
28 
29  int numread = sscanf(buff, "%s %s %s", lword, cword, rword);
30 
31  if(numread == 3 && cword[0] == '=') {
32  // input was perfect
33  std::string key = lword, value = rword;
34  metadata[key] = value;
35  }
36  else if(numread == 1) {
37  // we have key=value without spaces
38  int ridx=0, widx=0;
39  while(ridx < wsize && lword[ridx] != '=') cword[widx++] = lword[ridx++];
40  cword[widx] = '\0';
41 
42  std::string key = cword;
43 
44  widx=0, ridx += 1;
45  while(ridx < wsize && lword[ridx] != '\0') cword[widx++] = lword[ridx++];
46  cword[widx] = '\0';
47 
48  std::string value = cword;
49 
50  metadata[key] = value;
51  }
52  else {
53  fprintf(stderr, "%s warning: Malformed key-value pair:\n%s\n", __func__, buff);
54  }
55 }
56 
57 void read_metadata(const std::string filename, std::map<std::string,std::string> & metadata, MPI_Comm comm)
58 {
59  // There are 3 ways to add metadata to a vtx file:
60  // 1) the new way:
61  // # key1 = value1
62  // # key2 = value2
63  // # key3 = value3
64  // 2) nvtx # mesh [intra|extra] nelem npts
65  // 3) number of nodes
66  // [intra|extra]
67  int size, rank;
68  MPI_Comm_size(comm, &size); MPI_Comm_rank(comm, &rank);
69 
70  int err = 0;
71  FILE_SPEC stream = NULL;
72 
73  if(rank == 0) {
74  stream = f_open(filename.c_str(), "r");
75  if(stream == NULL) err++;
76  }
77 
78  // return on file open error
79  if(get_global(err, MPI_SUM)) {
80  log_msg(0,5,0, "%s error: Could not read vtx data. Aborting!", __func__);
81  EXIT(1);
82  }
83 
84  const size_t str_size = 5000;
85  char readbuff[str_size];
86 
87  // parse type 1 metadata lines. for simplicity we parse on each rank.
88  char* ptr = f_gets_par(readbuff, str_size, stream, comm);
89  remove_preceding_char(readbuff, str_size, ' ');
90 
91  while(ptr != NULL && readbuff[0] == COMMENT_CHAR) {
92  parse_comment_line(readbuff, str_size, metadata);
93  ptr = f_gets_par(readbuff, str_size, stream, comm);
94  remove_preceding_char(readbuff, str_size, ' ');
95  }
96 
97  // parse type 2 metadata
98  if(has_char(readbuff, str_size, '#')) {
99  int ibuff, ne, nn;
100  char iestr[128], nestr[128], nnstr[128];
101  int nread = sscanf(readbuff, "%d # %*s %31s %d %d", &ibuff, iestr, &ne, &nn);
102 
103  if(nread == 4) {
104  metadata["grid"] = iestr;
105  metadata["nelem"] = std::to_string(ne);
106  metadata["nnode"] = std::to_string(nn);
107  }
108  }
109 
110  // parse type 3 metadata
111  ptr = f_gets_par(readbuff, str_size, stream, comm);
112 
113  if(ptr) {
114  remove_preceding_char(readbuff, str_size, ' ');
115  char grid[128];
116  sscanf(readbuff, "%s", grid);
117 
118  if(strcmp(grid, "intra") == 0) {
119  metadata["grid"] = "intra";
120  } else if(strcmp(grid, "extra") == 0) {
121  metadata["grid"] = "extra";
122  }
123  }
124 
125  f_close(stream);
126 }
127 
128 char* skip_comments(FILE_SPEC stream, char* readbuff, size_t buffsize, MPI_Comm comm)
129 {
130  char* ptr = NULL;
131  do {
132  ptr = f_gets_par(readbuff, buffsize, stream, comm);
133  remove_preceding_char(readbuff, buffsize, ' ');
134  }
135  while(ptr != NULL && readbuff[0] == COMMENT_CHAR);
136 
137  return ptr;
138 }
139 
140 void indices_from_region_tag(SF::vector<mesh_int_t> & idx, const sf_mesh & mesh, const int tag)
141 {
142  std::set<mesh_int_t> idx_set;
143 
144  for(size_t eidx = 0; eidx < mesh.l_numelem; eidx++) {
145  if(mesh.tag[eidx] == tag) {
146  for(mesh_int_t i = mesh.dsp[eidx]; i<mesh.dsp[eidx + 1]; i++)
147  idx_set.insert(mesh.con[i]);
148  }
149  }
150 
151  idx.assign(idx_set.begin(), idx_set.end());
152 }
153 
155 {
157  idx_set.reserve(mesh.l_numpts); // optional heuristic
158 
159  for (size_t eidx = 0; eidx < mesh.l_numelem; eidx++) {
160  if (tags.count(mesh.tag[eidx])) {
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 
opencarp::local_index_t mesh_int_t
Definition: SF_container.h:31
opencarp::real_t SF_real
Global scalar type.
Definition: SF_globals.h:18
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 S sum() const =0
virtual void set(const vector< T > &idx, const vector< S > &vals, const bool additive=false, const bool local=false)=0
vector< T > dsp
connectivity starting index of each element
Definition: SF_container.h:401
size_t l_numelem
local number of elements
Definition: SF_container.h:384
vector< T > con
Definition: SF_container.h:397
vector< S > xyz
node cooridnates
Definition: SF_container.h:412
size_t l_numpts
local number of points
Definition: SF_container.h:386
vector< T > & get_numbering(SF_nbr nbr_type)
Get the vector defining a certain numbering.
Definition: SF_container.h:449
vector< T > tag
element tag
Definition: SF_container.h:402
size_t size() const
The current size of the vector.
Definition: SF_vector.h:89
void assign(InputIterator s, InputIterator e)
Assign a memory range.
Definition: SF_vector.h:146
void reserve(size_t n)
Definition: SF_vector.h:226
T & push_back(T val)
Definition: SF_vector.h:268
void reserve(size_t n)
Definition: hashmap.hpp:1140
hm_int count(const K &key) const
Definition: hashmap.hpp:1067
void insert(InputIterator first, InputIterator last)
Definition: hashmap.hpp:1037
class to store shape definitions
Definition: basics.h:374
Top-level header of FEM module.
#define COMMENT_CHAR
Definition: fem_utils.h:22
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
bool has_char(char *buff, const int buffsize, const char c)
Definition: basics.h:361
char * f_gets_par(char *s, int size, FILE_SPEC stream, MPI_Comm comm)
Definition: basics.cc:187
void parse_comment_line(char *buff, const int buffsize, std::map< std::string, std::string > &metadata)
Definition: fem_utils.cc:17
bool point_in_shape(const Point &p, const geom_shape &shape)
test if a point is inside a simple geometric shape
Definition: basics.cc:238
SF_real get_volume_from_nodes(sf_mat &mass, SF::vector< mesh_int_t > &local_idx)
Definition: fem_utils.cc:202
char * skip_comments(FILE_SPEC stream, char *readbuff, size_t buffsize, MPI_Comm comm)
Definition: fem_utils.cc:128
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:57
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
void indices_from_region_tags(SF::vector< mesh_int_t > &idx, const sf_mesh &mesh, const hashmap::unordered_set< int > &tags)
Populate vertex data with the vertices of multiple tag regions.
Definition: fem_utils.cc:154
FILE_SPEC f_open(const char *fname, const char *mode)
Open a FILE_SPEC.
Definition: basics.cc:123
void warn_when_passing_intra_vtx(const std::string filename)
Definition: fem_utils.cc:224
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
void f_close(FILE_SPEC &f)
Close a FILE_SPEC.
Definition: basics.cc:150
void remove_preceding_char(char *buff, const int buffsize, const char c)
Definition: basics.h:338
File descriptor struct.
Definition: basics.h:120