openCARP
Doxygen code documentation for the open cardiac electrophysiology simulator openCARP
fem_utils.h
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 #ifndef _FEM_UTILS_H
28 #define _FEM_UTILS_H
29 
30 #include "sf_interface.h"
31 
32 #include "petsc_utils.h" // TODO: for EXIT
33 
34 namespace opencarp {
35 
36 
37 #define COMMENT_CHAR '#'
38 
39 void parse_comment_line(char* buff, const int buffsize, std::map<std::string,std::string> & metadata);
40 
48 void read_metadata(const std::string filename, std::map<std::string,std::string> & metadata, MPI_Comm comm);
49 
50 char* skip_comments(FILE_SPEC stream, char* readbuff, size_t buffsize, MPI_Comm comm);
51 
52 template<class T> inline
54  const std::string filename,
55  MPI_Comm comm)
56 {
57  int numread = 0, err = 0;
58 
59  int size, rank;
60  MPI_Comm_size(comm, &size); MPI_Comm_rank(comm, &rank);
61 
62  FILE_SPEC stream = NULL;
63  const size_t str_size = 5000;
64  char readbuff[str_size];
65 
66  if(rank == 0)
67  stream = f_open(filename.c_str(), "r");
68 
69  // skip comments
70  char* ptr = skip_comments(stream, readbuff, str_size, comm);
71 
72  long int num_inp_nod;
73  if(ptr != NULL) {
74  numread = sscanf(readbuff, "%ld", &num_inp_nod);
75  }
76 
77  if(numread == 0) {
78  log_msg(0, 5, 0, "%s error: Could not determine vtx data size! Aborting!\n", __func__);
79  EXIT(1);
80  }
81 
82  SF::vector<int> nodbuff(num_inp_nod, -1);
83 
84  if(rank == 0) {
85  long int num_read_loc = 0;
86 
87  ptr = fgets(readbuff, str_size, stream->fd);
88  while(ptr != NULL) {
89  int n = sscanf(readbuff, "%d", &nodbuff[num_read_loc]);
90 
91  // only increment local read counter if we indeed read an int
92  if(n == 1) num_read_loc++;
93 
94  if(num_read_loc < num_inp_nod)
95  ptr = fgets(readbuff, str_size, stream->fd);
96  else
97  ptr = NULL;
98  }
99  }
100 
101  f_close(stream);
102 
103  MPI_Bcast(nodbuff.data(), nodbuff.size(), MPI_INT, 0, comm);
104 
105  idx.reserve(nodbuff.size());
106  for(int n : nodbuff)
107  if(n > -1) idx.push_back(n);
108 }
109 
119 template<class T> inline
121  const std::string filename,
123  MPI_Comm comm)
124 {
125  int numread = 0, err = 0;
126 
127  int size, rank;
128  MPI_Comm_size(comm, &size); MPI_Comm_rank(comm, &rank);
129 
130  // generate a hashed set of the nodes in the local domain
132 
133  idx.resize(0);
134  idx.reserve(dd_map.size());
135 
136  FILE_SPEC stream = NULL;
137 
138  if(rank == 0)
139  stream = f_open(filename.c_str(), "r");
140 
141  const size_t str_size = 5000;
142  char readbuff[str_size];
143 
144  // skip comments
145  char* ptr = skip_comments(stream, readbuff, str_size, comm);
146 
147  long int num_inp_nod;
148  if(ptr != NULL) {
149  numread = sscanf(readbuff, "%ld", &num_inp_nod);
150  }
151 
152  if(numread == 0) {
153  log_msg(0, 5, 0, "%s error: Could not determine vtx data size! Aborting!\n", __func__);
154  EXIT(1);
155  }
156 
157  int nodbuff_size = 50000;
158  if(nodbuff_size > num_inp_nod) nodbuff_size = num_inp_nod;
159 
160  SF::vector<int> nodbuff;
161  numread = 0;
162 
163  while(numread < num_inp_nod) {
164  nodbuff.assign(size_t(nodbuff_size), int(-1));
165 
166  if(rank == 0) {
167  int num_read_loc = 0;
168 
169  ptr = fgets(readbuff, str_size, stream->fd);
170  while(ptr != NULL) {
171  int n = sscanf(readbuff, "%d", &nodbuff[num_read_loc]);
172  // only increment local read counter if we indeed read an int
173  if(n == 1) num_read_loc++;
174 
175  if(num_read_loc < nodbuff_size)
176  ptr = fgets(readbuff, str_size, stream->fd);
177  else
178  ptr = NULL;
179  }
180  }
181 
182  MPI_Bcast(nodbuff.data(), nodbuff_size*sizeof(int), MPI_BYTE, 0, comm);
183 
184  for(int ridx = 0; ridx < nodbuff_size; ridx++) {
185  int n = nodbuff[ridx];
186  auto it = dd_map.find(n);
187 
188  if(n > -1 && it != dd_map.end() && have_read.count(n) == 0) {
189  have_read.insert(n);
190  mesh_int_t ln = it->second;
191  idx.push_back(ln);
192  }
193  numread++;
194  }
195  }
196 
197  f_close(stream);
198 }
199 
215 template<class T> inline
217  const std::string filename,
218  const sf_mesh & mesh,
219  const SF::SF_nbr nbr,
220  const bool algebraic,
221  MPI_Comm comm)
222 {
223  // generate a hashed set of the nodes in the local domain
225  const SF::vector<mesh_int_t> & dd_nbr = mesh.get_numbering(nbr);
226 
227  if(algebraic) {
228  const SF::vector<mesh_int_t> & alg_nod = mesh.pl.algebraic_nodes();
229  for(size_t i = 0; i<alg_nod.size(); i++) {
230  mesh_int_t an = alg_nod[i];
231  dd_map[dd_nbr[an]] = an;
232  }
233  } else {
234  for(size_t i = 0; i<dd_nbr.size(); i++)
235  dd_map[dd_nbr[i]] = i;
236  }
237 
238  read_indices(idx, filename, dd_map, comm);
239 }
240 
253 template<class T> inline
255  const std::string filename,
256  const SF::vector<mesh_int_t> & dd_nbr,
257  MPI_Comm comm)
258 {
259  // generate a hashed set of the nodes in the local domain
261  for(size_t i = 0; i<dd_nbr.size(); i++)
262  dd_map[dd_nbr[i]] = i;
263 
264  read_indices(idx, filename, dd_map, comm);
265 }
266 
268 template<class T, class S> inline
270  const std::string filename,
272  const int dpn,
273  MPI_Comm comm)
274 {
275  int numread = 0, err = 0;
276 
277  int size, rank;
278  MPI_Comm_size(comm, &size); MPI_Comm_rank(comm, &rank);
279 
280  // Currenty we support dpn <= 3
281  if(dpn > 3) {
282  if(rank == 0) {
283  fprintf(stderr, "%s error: dpn > 3 not supported!\n", __func__);
284  }
285  return;
286  }
287 
288  // generate a hashed set of the nodes in the local domain
290 
291  idx.resize(dd_map.size());
292  dat.resize(dd_map.size() * dpn);
293  FILE_SPEC stream = NULL;
294 
295  if(rank == 0)
296  stream = f_open(filename.c_str(), "r");
297 
298  const size_t str_size = 5000;
299  char readbuff[str_size];
300 
301  // skip comments
302  char* ptr = skip_comments(stream, readbuff, str_size, comm);
303 
304  // parse size of vtx file. for simplicity we parse on each rank.
305  long int num_inp_nod;
306  if(ptr != NULL) {
307  numread = sscanf(readbuff, "%ld", &num_inp_nod);
308  }
309 
310  if(numread == 0) {
311  log_msg(0, 5, 0, "%s error: Could not determine vtx data size! Aborting!\n", __func__);
312  EXIT(1);
313  }
314 
315  int nodbuff_size = 50000;
316  if(nodbuff_size > num_inp_nod) nodbuff_size = num_inp_nod;
317 
318  SF::vector<int> nodbuff;
319  SF::vector<double> doublebuff;
320 
321  size_t widx = 0;
322  numread = 0;
323 
324  while(numread < num_inp_nod) {
325  nodbuff .assign(size_t(nodbuff_size), int(-1));
326  doublebuff.resize(size_t(nodbuff_size * dpn));
327 
328  if(rank == 0) {
329  int num_read_loc = 0;
330 
331  ptr = fgets(readbuff, str_size, stream->fd);
332  while(ptr != NULL) {
333  int n = sscanf(readbuff, "%d %lf %lf %lf", &nodbuff[num_read_loc],
334  &doublebuff[num_read_loc*dpn+0], &doublebuff[num_read_loc*dpn+1], &doublebuff[num_read_loc*dpn+2]);
335 
336  // only increment local read counter if we indeed read an int
337  if(n == dpn+1) num_read_loc++;
338 
339  if(num_read_loc < nodbuff_size)
340  ptr = fgets(readbuff, str_size, stream->fd);
341  else
342  ptr = NULL;
343  }
344  }
345 
346  MPI_Bcast(nodbuff.data(), nodbuff_size, MPI_INT, 0, comm);
347  MPI_Bcast(doublebuff.data(), nodbuff_size*dpn, MPI_DOUBLE, 0, comm);
348 
349  for(int ridx = 0; ridx < nodbuff_size; ridx++) {
350  int n = nodbuff[ridx];
351 
352  auto it = dd_map.find(n);
353  if(n > -1 && it != dd_map.end() && have_read.count(n) == 0) {
354  have_read.insert(n);
355  idx[widx] = it->second;
356 
357  for(int j=0; j<dpn; j++)
358  dat[widx*dpn+j] = doublebuff[ridx*dpn+j];
359 
360  widx++;
361  }
362 
363  numread++;
364  }
365  }
366 
367  idx.resize(widx);
368  dat.resize(widx*dpn);
369 
370  f_close(stream);
371 }
372 
374 template<class T, class S> inline
376  const std::string filename,
377  const sf_mesh & mesh,
378  const SF::SF_nbr nbr,
379  const bool algebraic,
380  const int dpn,
381  MPI_Comm comm)
382 {
383  const SF::vector<mesh_int_t> & dd_nbr = mesh.get_numbering(nbr);
385 
386  if(algebraic) {
387  const SF::vector<mesh_int_t> & alg_nod = mesh.pl.algebraic_nodes();
388  for(size_t i = 0; i<alg_nod.size(); i++) {
389  mesh_int_t an = alg_nod[i];
390  dd_map[dd_nbr[an]] = an;
391  }
392 
393  } else {
394  for(size_t i = 0; i<dd_nbr.size(); i++)
395  dd_map[dd_nbr[i]] = i;
396  }
397 
398  read_indices_with_data(idx, dat, filename, dd_map, dpn, comm);
399 }
400 
402 template<class T, class S> inline
404  const std::string filename,
405  const SF::vector<mesh_int_t> & dd_nbr,
406  const int dpn,
407  MPI_Comm comm)
408 {
410 
411  for(size_t i = 0; i<dd_nbr.size(); i++)
412  dd_map[dd_nbr[i]] = i;
413 
414  read_indices_with_data(idx, dat, filename, dd_map, dpn, comm);
415 }
416 
417 void warn_when_passing_intra_vtx(const std::string filename);
418 
427 void indices_from_region_tag(SF::vector<mesh_int_t> & idx, const sf_mesh & mesh, const int tag);
428 
438 void indices_from_geom_shape(SF::vector<mesh_int_t> & idx, const sf_mesh & mesh, const geom_shape shape, const bool nodal);
439 
440 // compute volume of a node set using a mass matrix
442 
443 
444 } // namespace opencarp
445 
446 #endif
447 
The mesh storage class. It contains both element and vertex data.
Definition: SF_container.h:383
Custom unordered_set implementation.
Definition: hashmap.hpp:241
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
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:120
void warn_when_passing_intra_vtx(const std::string filename)
Definition: fem_utils.cc:224
overlapping_layout< T > pl
nodal parallel layout
Definition: SF_container.h:417
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
T * data()
Pointer to the vector&#39;s start.
Definition: SF_vector.h:91
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
SF_nbr
Enumeration encoding the different supported numberings.
Definition: SF_container.h:188
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
int mesh_int_t
Definition: SF_container.h:46
hm_int count(const K &key) const
Definition: hashmap.hpp:992
void read_indices_global(SF::vector< T > &idx, const std::string filename, MPI_Comm comm)
Definition: fem_utils.h:53
size_t size() const
Definition: hashmap.hpp:687
void insert(InputIterator first, InputIterator last)
Definition: hashmap.hpp:962
Interface to SlimFem.
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
A vector storing arbitrary data.
Definition: SF_vector.h:42
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 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:269
void assign(InputIterator s, InputIterator e)
Assign a memory range.
Definition: SF_vector.h:161
iterator find(const K &key)
Search for key. Return iterator.
Definition: hashmap.hpp:593
double SF_real
Use the general double as real type.
Definition: SF_globals.h:38
file_desc * FILE_SPEC
Definition: basics.h:138
void resize(size_t n)
Resize a vector.
Definition: SF_vector.h:209
FILE_SPEC f_open(const char *fname, const char *mode)
Open a FILE_SPEC.
Definition: basics.cc:135