openCARP
Doxygen code documentation for the open cardiac electrophysiology simulator openCARP
fem_utils.h
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright (c) NumeriCor GmbH
2 // SPDX-License-Identifier: Apache-2.0
3 
12 #ifndef _FEM_UTILS_H
13 #define _FEM_UTILS_H
14 
15 #include "sf_interface.h"
16 
17 #include "petsc_utils.h" // TODO: for EXIT
18 
19 namespace opencarp {
20 
21 
22 #define COMMENT_CHAR '#'
23 
24 void parse_comment_line(char* buff, const int buffsize, std::map<std::string,std::string> & metadata);
25 
33 void read_metadata(const std::string filename, std::map<std::string,std::string> & metadata, MPI_Comm comm);
34 
35 char* skip_comments(FILE_SPEC stream, char* readbuff, size_t buffsize, MPI_Comm comm);
36 
37 template<class T> inline
39  const std::string filename,
40  MPI_Comm comm)
41 {
42  int numread = 0, err = 0;
43 
44  int size, rank;
45  MPI_Comm_size(comm, &size); MPI_Comm_rank(comm, &rank);
46 
47  FILE_SPEC stream = NULL;
48  const size_t str_size = 5000;
49  char readbuff[str_size];
50 
51  if(rank == 0)
52  stream = f_open(filename.c_str(), "r");
53 
54  // skip comments
55  char* ptr = skip_comments(stream, readbuff, str_size, comm);
56 
57  long int num_inp_nod;
58  if(ptr != NULL) {
59  numread = sscanf(readbuff, "%ld", &num_inp_nod);
60  }
61 
62  if(numread == 0) {
63  log_msg(0, 5, 0, "%s error: Could not determine vtx data size! Aborting!\n", __func__);
64  EXIT(1);
65  }
66 
67  SF::vector<int> nodbuff(num_inp_nod, -1);
68 
69  if(rank == 0) {
70  long int num_read_loc = 0;
71 
72  ptr = fgets(readbuff, str_size, stream->fd);
73  while(ptr != NULL) {
74  int n = sscanf(readbuff, "%d", &nodbuff[num_read_loc]);
75 
76  // only increment local read counter if we indeed read an int
77  if(n == 1) num_read_loc++;
78 
79  if(num_read_loc < num_inp_nod)
80  ptr = fgets(readbuff, str_size, stream->fd);
81  else
82  ptr = NULL;
83  }
84  }
85 
86  f_close(stream);
87 
88  MPI_Bcast(nodbuff.data(), nodbuff.size(), MPI_INT, 0, comm);
89 
90  idx.reserve(nodbuff.size());
91  for(int n : nodbuff)
92  if(n > -1) idx.push_back(n);
93 }
94 
104 template<class T> inline
106  const std::string filename,
108  MPI_Comm comm)
109 {
110  int numread = 0, err = 0;
111 
112  int size, rank;
113  MPI_Comm_size(comm, &size); MPI_Comm_rank(comm, &rank);
114 
115  // generate a hashed set of the nodes in the local domain
117 
118  idx.resize(0);
119  idx.reserve(dd_map.size());
120 
121  FILE_SPEC stream = NULL;
122 
123  if(rank == 0)
124  stream = f_open(filename.c_str(), "r");
125 
126  const size_t str_size = 5000;
127  char readbuff[str_size];
128 
129  // skip comments
130  char* ptr = skip_comments(stream, readbuff, str_size, comm);
131 
132  long int num_inp_nod;
133  if(ptr != NULL) {
134  numread = sscanf(readbuff, "%ld", &num_inp_nod);
135  }
136 
137  if(numread == 0) {
138  log_msg(0, 5, 0, "%s error: Could not determine vtx data size! Aborting!\n", __func__);
139  EXIT(1);
140  }
141 
142  int nodbuff_size = 50000;
143  if(nodbuff_size > num_inp_nod) nodbuff_size = num_inp_nod;
144 
145  SF::vector<int> nodbuff;
146  numread = 0;
147 
148  while(numread < num_inp_nod) {
149  nodbuff.assign(size_t(nodbuff_size), int(-1));
150 
151  if(rank == 0) {
152  int num_read_loc = 0;
153 
154  ptr = fgets(readbuff, str_size, stream->fd);
155  while(ptr != NULL) {
156  int n = sscanf(readbuff, "%d", &nodbuff[num_read_loc]);
157  // only increment local read counter if we indeed read an int
158  if(n == 1) num_read_loc++;
159 
160  if(num_read_loc < nodbuff_size)
161  ptr = fgets(readbuff, str_size, stream->fd);
162  else
163  ptr = NULL;
164  }
165  }
166 
167  MPI_Bcast(nodbuff.data(), nodbuff_size*sizeof(int), MPI_BYTE, 0, comm);
168 
169  for(int ridx = 0; ridx < nodbuff_size; ridx++) {
170  int n = nodbuff[ridx];
171  auto it = dd_map.find(n);
172 
173  if(n > -1 && it != dd_map.end() && have_read.count(n) == 0) {
174  have_read.insert(n);
175  mesh_int_t ln = it->second;
176  idx.push_back(ln);
177  }
178  numread++;
179  }
180  }
181 
182  f_close(stream);
183 }
184 
200 template<class T> inline
202  const std::string filename,
203  const sf_mesh & mesh,
204  const SF::SF_nbr nbr,
205  const bool algebraic,
206  MPI_Comm comm)
207 {
208  // generate a hashed set of the nodes in the local domain
210  const SF::vector<mesh_int_t> & dd_nbr = mesh.get_numbering(nbr);
211 
212  if(algebraic) {
213  const SF::vector<mesh_int_t> & alg_nod = mesh.pl.algebraic_nodes();
214  for(size_t i = 0; i<alg_nod.size(); i++) {
215  mesh_int_t an = alg_nod[i];
216  dd_map[dd_nbr[an]] = an;
217  }
218  } else {
219  for(size_t i = 0; i<dd_nbr.size(); i++)
220  dd_map[dd_nbr[i]] = i;
221  }
222 
223  read_indices(idx, filename, dd_map, comm);
224 }
225 
238 template<class T> inline
240  const std::string filename,
241  const SF::vector<mesh_int_t> & dd_nbr,
242  MPI_Comm comm)
243 {
244  // generate a hashed set of the nodes in the local domain
246  for(size_t i = 0; i<dd_nbr.size(); i++)
247  dd_map[dd_nbr[i]] = i;
248 
249  read_indices(idx, filename, dd_map, comm);
250 }
251 
253 template<class T, class S> inline
255  const std::string filename,
257  const int dpn,
258  MPI_Comm comm)
259 {
260  int numread = 0, err = 0;
261 
262  int size, rank;
263  MPI_Comm_size(comm, &size); MPI_Comm_rank(comm, &rank);
264 
265  // Currenty we support dpn <= 3
266  if(dpn > 3) {
267  if(rank == 0) {
268  fprintf(stderr, "%s error: dpn > 3 not supported!\n", __func__);
269  }
270  return;
271  }
272 
273  // generate a hashed set of the nodes in the local domain
275 
276  idx.resize(dd_map.size());
277  dat.resize(dd_map.size() * dpn);
278  FILE_SPEC stream = NULL;
279 
280  if(rank == 0)
281  stream = f_open(filename.c_str(), "r");
282 
283  const size_t str_size = 5000;
284  char readbuff[str_size];
285 
286  // skip comments
287  char* ptr = skip_comments(stream, readbuff, str_size, comm);
288 
289  // parse size of vtx file. for simplicity we parse on each rank.
290  long int num_inp_nod;
291  if(ptr != NULL) {
292  numread = sscanf(readbuff, "%ld", &num_inp_nod);
293  }
294 
295  if(numread == 0) {
296  log_msg(0, 5, 0, "%s error: Could not determine vtx data size! Aborting!\n", __func__);
297  EXIT(1);
298  }
299 
300  int nodbuff_size = 50000;
301  if(nodbuff_size > num_inp_nod) nodbuff_size = num_inp_nod;
302 
303  SF::vector<int> nodbuff;
304  SF::vector<double> doublebuff;
305 
306  size_t widx = 0;
307  numread = 0;
308 
309  while(numread < num_inp_nod) {
310  nodbuff .assign(size_t(nodbuff_size), int(-1));
311  doublebuff.resize(size_t(nodbuff_size * dpn));
312 
313  if(rank == 0) {
314  int num_read_loc = 0;
315 
316  ptr = fgets(readbuff, str_size, stream->fd);
317  while(ptr != NULL) {
318  int n = sscanf(readbuff, "%d %lf %lf %lf", &nodbuff[num_read_loc],
319  &doublebuff[num_read_loc*dpn+0], &doublebuff[num_read_loc*dpn+1], &doublebuff[num_read_loc*dpn+2]);
320 
321  // only increment local read counter if we indeed read an int
322  if(n == dpn+1) num_read_loc++;
323 
324  if(num_read_loc < nodbuff_size)
325  ptr = fgets(readbuff, str_size, stream->fd);
326  else
327  ptr = NULL;
328  }
329  }
330 
331  MPI_Bcast(nodbuff.data(), nodbuff_size, MPI_INT, 0, comm);
332  MPI_Bcast(doublebuff.data(), nodbuff_size*dpn, MPI_DOUBLE, 0, comm);
333 
334  for(int ridx = 0; ridx < nodbuff_size; ridx++) {
335  int n = nodbuff[ridx];
336 
337  auto it = dd_map.find(n);
338  if(n > -1 && it != dd_map.end() && have_read.count(n) == 0) {
339  have_read.insert(n);
340  idx[widx] = it->second;
341 
342  for(int j=0; j<dpn; j++)
343  dat[widx*dpn+j] = doublebuff[ridx*dpn+j];
344 
345  widx++;
346  }
347 
348  numread++;
349  }
350  }
351 
352  idx.resize(widx);
353  dat.resize(widx*dpn);
354 
355  f_close(stream);
356 }
357 
359 template<class T, class S> inline
361  const std::string filename,
362  const sf_mesh & mesh,
363  const SF::SF_nbr nbr,
364  const bool algebraic,
365  const int dpn,
366  MPI_Comm comm)
367 {
368  const SF::vector<mesh_int_t> & dd_nbr = mesh.get_numbering(nbr);
370 
371  if(algebraic) {
372  const SF::vector<mesh_int_t> & alg_nod = mesh.pl.algebraic_nodes();
373  for(size_t i = 0; i<alg_nod.size(); i++) {
374  mesh_int_t an = alg_nod[i];
375  dd_map[dd_nbr[an]] = an;
376  }
377 
378  } else {
379  for(size_t i = 0; i<dd_nbr.size(); i++)
380  dd_map[dd_nbr[i]] = i;
381  }
382 
383  read_indices_with_data(idx, dat, filename, dd_map, dpn, comm);
384 }
385 
387 template<class T, class S> inline
389  const std::string filename,
390  const SF::vector<mesh_int_t> & dd_nbr,
391  const int dpn,
392  MPI_Comm comm)
393 {
395 
396  for(size_t i = 0; i<dd_nbr.size(); i++)
397  dd_map[dd_nbr[i]] = i;
398 
399  read_indices_with_data(idx, dat, filename, dd_map, dpn, comm);
400 }
401 
402 void warn_when_passing_intra_vtx(const std::string filename);
403 
412 void indices_from_region_tag(SF::vector<mesh_int_t> & idx, const sf_mesh & mesh, const int tag);
413 
423 
433 void indices_from_geom_shape(SF::vector<mesh_int_t> & idx, const sf_mesh & mesh, const geom_shape shape, const bool nodal);
434 
435 // compute volume of a node set using a mass matrix
437 
438 
439 } // namespace opencarp
440 
441 #endif
442 
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
overlapping_layout< T > pl
nodal parallel layout
Definition: SF_container.h:414
vector< T > & get_numbering(SF_nbr nbr_type)
Get the vector defining a certain numbering.
Definition: SF_container.h:449
A vector storing arbitrary data.
Definition: SF_vector.h:28
size_t size() const
The current size of the vector.
Definition: SF_vector.h:89
void resize(size_t n)
Resize a vector.
Definition: SF_vector.h:194
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 * data()
Pointer to the vector's start.
Definition: SF_vector.h:76
T & push_back(T val)
Definition: SF_vector.h:268
iterator find(const K &key)
Search for key. Return iterator.
Definition: hashmap.hpp:626
size_t size() const
Definition: hashmap.hpp:720
Custom unordered_set implementation.
Definition: hashmap.hpp:739
hm_int count(const K &key) const
Definition: hashmap.hpp:1067
void insert(InputIterator first, InputIterator last)
Definition: hashmap.hpp:1037
SF_nbr
Enumeration encoding the different supported numberings.
Definition: SF_container.h:185
void parse_comment_line(char *buff, const int buffsize, std::map< std::string, std::string > &metadata)
Definition: fem_utils.cc:17
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
SF::meshdata< mesh_int_t, mesh_real_t > sf_mesh
Definition: sf_interface.h:33
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
void read_indices_global(SF::vector< T > &idx, const std::string filename, MPI_Comm comm)
Definition: fem_utils.h:38
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
SF::abstract_matrix< SF_int, SF_real > sf_mat
Definition: sf_interface.h:37
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
Definition: fem_utils.h:254
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.
Definition: fem_utils.h:105
void f_close(FILE_SPEC &f)
Close a FILE_SPEC.
Definition: basics.cc:150
file_desc * FILE_SPEC
Definition: basics.h:125
Interface to SlimFem.
File descriptor struct.
Definition: basics.h:120