openCARP
Doxygen code documentation for the open cardiac electrophysiology simulator openCARP
SF_mesh_io.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 _SF_MESH_IO
13 #define _SF_MESH_IO
14 
15 #include <cstddef>
16 #include <list>
17 #include <string>
18 #include <cstring>
19 #include <unistd.h>
20 
21 #include <mpi.h>
22 
23 #include "SF_container.h"
24 #include "SF_io_base.h"
25 #include "SF_network.h"
26 #include "SF_globals.h"
27 #include "SF_vector.h"
28 
29 #define HDR_SIZE 1024
30 
31 namespace SF {
32 
40 inline size_t read_num_pts(std::string basename)
41 {
42  size_t numpts;
43 
44  bool read_binary = fileExists(basename + ".bpts");
45  std::string pts_file = read_binary ? basename + ".bpts" : basename + ".pts";
46 
47  FILE* pts_fd = fopen(pts_file.c_str(), "r");
48  if(!pts_fd) {
49  fprintf(stderr, "Error: could not open file: %s. Aborting!\n", pts_file.c_str());
50  exit(1);
51  }
52 
53  // read number of points
54  char buffer[2048];
55  if(read_binary) fread(buffer, sizeof(char), HDR_SIZE, pts_fd);
56  else fgets( buffer, 2048, pts_fd);
57  sscanf(buffer, "%lu", &numpts);
58  fclose(pts_fd);
59 
60  return numpts;
61 }
62 
75 inline void read_headers(FILE* ele_fd, FILE* fib_fd, bool read_binary, size_t & numelem, int & nFib)
76 {
77  char buffer[HDR_SIZE];
78  // first read number of elems
79  if(read_binary) {
80  fread(buffer, sizeof(char), HDR_SIZE, ele_fd);
81  }
82  else {
83  fgets(buffer, HDR_SIZE, ele_fd);
84  }
85  sscanf(buffer, "%lu", &numelem);
86 
87  // now read number of fiber axes
88  if(fib_fd) {
89  if(read_binary) {
90  fread(buffer, sizeof(char), HDR_SIZE, fib_fd);
91  sscanf(buffer, "%d", &nFib);
92  }
93  else {
94  // fiber files can have no header, thus we can potentially read 1, 3 or 6 values
95  fgets(buffer, HDR_SIZE, fib_fd);
96  float fbuff[6];
97  short nread = sscanf(buffer, "%f %f %f %f %f %f", fbuff, fbuff+1, fbuff+2, fbuff+3, fbuff+4, fbuff+5);
98  switch(nread) {
99  case 1: nFib = fbuff[0]; break;
100  case 3: nFib = 1; break;
101  case 6: nFib = 2; break;
102  default:
103  fprintf(stderr, "%s error: read %d values in line 1 of fiber file."
104  "This is unexpected! Setting number of fibers to 1.\n",
105  __func__, nread);
106  nFib = 1;
107  break;
108  }
109 
110  // if the fiber file had no header, we have to reset the FD
111  if(nread != 1)
112  fseek(fib_fd, 0, SEEK_SET);
113  }
114  }
115  else
116  nFib = 0;
117 }
130 inline void write_elem_headers(FILE* & ele_fd, FILE* & fib_fd, bool binary, size_t numelem, int nFib)
131 {
132 
133  // we need to write the CARP header
134  char header[HDR_SIZE];
135  int checksum = 666;
136 
137  // element header
138  if(binary) {
139  // first elements, second endianness, third checksum
140  snprintf(header, sizeof header, "%lu %d %d", numelem, MT_ENDIANNESS, checksum);
141  fwrite(header, HDR_SIZE, sizeof(char), ele_fd);
142  }
143  else
144  fprintf(ele_fd, "%lu\n", numelem);
145 
146  // fiber header
147  if(nFib >= 1) {
148  if(binary) {
149  // first numaxes, second numelems, third endianness, last checksum
150  snprintf(header, sizeof header, "%d %lu %d %d", nFib, (unsigned long int)numelem, MT_ENDIANNESS, checksum);
151  fwrite(header, sizeof(char), HDR_SIZE, fib_fd);
152  }
153  else
154  fprintf(fib_fd, "%d\n", nFib);
155  }
156 }
167 inline void write_pts_header(FILE* & pts_fd, bool binary, size_t numpts)
168 {
169 
170  // we need to write the CARP header
171  char header[HDR_SIZE];
172  int checksum = 666;
173 
174  // header
175  if(binary) {
176  snprintf(header, sizeof header, "%lu %d %d", numpts, MT_ENDIANNESS, checksum);
177  fwrite(header, HDR_SIZE, sizeof(char), pts_fd);
178  }
179  else
180  fprintf(pts_fd, "%lu\n", numpts);
181 }
182 
193 template<class T, class S>
194 inline void read_elem_block(FILE* & fd, bool read_binary, size_t bstart, size_t bsize, meshdata<T, S> & mesh)
195 {
196  const int bufsize = 2048;
197  const int max_elem_size = 9;
198 
199  char buffer[bufsize];
200  char etype_str[8];
201  int n[max_elem_size];
202 
203  vector<T> & ref_eidx = mesh.register_numbering(NBR_ELEM_REF);
204  ref_eidx.resize(bsize);
205 
206  mesh.dsp.resize(bsize+1);
207  mesh.tag.resize(bsize);
208  mesh.type.resize(bsize);
209  mesh.con.resize(bsize*max_elem_size);
210 
211  size_t ele_read = 0, con_size = 0;
212  mesh.dsp[0] = 0;
213  T* elem = mesh.con.data();
214 
215  for(size_t i=0; i<bsize; i++)
216  {
217  if(read_binary) {
218  int etbuff;
219  size_t r = fread(&etbuff, sizeof(int), 1, fd);
220  if(r != 1) break;
221  mesh.type[i] = (elem_t)etbuff;
222  }
223  else {
224  char* ptr = fgets( buffer, bufsize, fd);
225  if(ptr == NULL) break;
226  sscanf(buffer, "%s %d %d %d %d %d %d %d %d %d", etype_str, n, n+1, n+2, n+3, n+4, n+5, n+6, n+7, n+8);
227  mesh.type[i] = getElemTypeID(etype_str);
228  }
229 
230  T nodes;
231  switch(mesh.type[i])
232  {
233  case Line:
234  nodes = 2;
235  break;
236 
237  case Tri:
238  nodes = 3;
239  break;
240 
241  case Quad:
242  nodes = 4;
243  break;
244 
245  case Tetra:
246  nodes = 4;
247  break;
248 
249  case Pyramid:
250  nodes = 5;
251  break;
252 
253  case Prism:
254  nodes = 6;
255  break;
256 
257  case Hexa:
258  nodes = 8;
259  break;
260 
261  default:
262  fprintf(stderr, "Error: Unsupported element type!\n");
263  exit(1);
264  }
265  mesh.dsp[i+1] = mesh.dsp[i] + nodes;
266  con_size += nodes;
267 
268  // copy the element connectivity
269  if(read_binary) {
270  fread(n, sizeof(int), nodes+1, fd);
271  }
272  for(int j=0; j<nodes; j++) elem[j] = n[j];
273 
274  mesh.tag[i] = n[nodes];
275  ref_eidx[i] = bstart + i;
276  ele_read++;
277 
278  elem += nodes;
279  }
280  mesh.dsp.resize(ele_read+1);
281  mesh.tag.resize(ele_read);
282  mesh.type.resize(ele_read);
283  ref_eidx.resize(ele_read);
284  mesh.con.resize(con_size);
285 
286  mesh.l_numelem = ele_read;
287 }
288 
289 
297 template<class T, class S>
298 inline void write_elem_block(FILE* fd, bool write_binary, const meshdata<T, S> & mesh)
299 {
300  const T* con = mesh.con.data();
301 
302  if(write_binary)
303  {
304  int wbuff[9];
305 
306  for(size_t eidx=0; eidx < mesh.l_numelem; eidx++)
307  {
308  fwrite(&mesh.type[eidx], 1, sizeof(elem_t), fd);
309  T esize = mesh.dsp[eidx+1] - mesh.dsp[eidx];
310  vec_assign(wbuff, con, esize); // copy-convert to int
311  wbuff[esize] = mesh.tag[eidx]; // convert to int
312 
313  fwrite(wbuff, esize+1, sizeof(int), fd);
314  con += esize;
315  }
316  }
317  else
318  {
319  for(size_t eidx=0; eidx < mesh.l_numelem; eidx++)
320  {
321  switch(mesh.type[eidx])
322  {
323  case Line:
324  fprintf(fd, "Ln %lld %lld %lld\n",
325  static_cast<long long>(con[0]),
326  static_cast<long long>(con[1]),
327  static_cast<long long>(mesh.tag[eidx]));
328  con += 2;
329  break;
330 
331  case Tri:
332  fprintf(fd, "Tr %lld %lld %lld %lld\n",
333  static_cast<long long>(con[0]),
334  static_cast<long long>(con[1]),
335  static_cast<long long>(con[2]),
336  static_cast<long long>(mesh.tag[eidx]));
337  con += 3;
338  break;
339 
340  case Quad:
341  fprintf(fd, "Qd %lld %lld %lld %lld %lld\n",
342  static_cast<long long>(con[0]),
343  static_cast<long long>(con[1]),
344  static_cast<long long>(con[2]),
345  static_cast<long long>(con[3]),
346  static_cast<long long>(mesh.tag[eidx]));
347  con += 4;
348  break;
349 
350  case Tetra:
351  fprintf(fd, "Tt %lld %lld %lld %lld %lld\n",
352  static_cast<long long>(con[0]),
353  static_cast<long long>(con[1]),
354  static_cast<long long>(con[2]),
355  static_cast<long long>(con[3]),
356  static_cast<long long>(mesh.tag[eidx]));
357  con += 4;
358  break;
359 
360  case Pyramid:
361  fprintf(fd, "Py %lld %lld %lld %lld %lld %lld\n",
362  static_cast<long long>(con[0]),
363  static_cast<long long>(con[1]),
364  static_cast<long long>(con[2]),
365  static_cast<long long>(con[3]),
366  static_cast<long long>(con[4]),
367  static_cast<long long>(mesh.tag[eidx]));
368  con += 5;
369  break;
370 
371  case Prism:
372  fprintf(fd, "Pr %lld %lld %lld %lld %lld %lld %lld\n",
373  static_cast<long long>(con[0]),
374  static_cast<long long>(con[1]),
375  static_cast<long long>(con[2]),
376  static_cast<long long>(con[3]),
377  static_cast<long long>(con[4]),
378  static_cast<long long>(con[5]),
379  static_cast<long long>(mesh.tag[eidx]));
380  con += 6;
381  break;
382 
383  case Hexa:
384  fprintf(fd, "Hx %lld %lld %lld %lld %lld %lld %lld %lld %lld\n",
385  static_cast<long long>(con[0]),
386  static_cast<long long>(con[1]),
387  static_cast<long long>(con[2]),
388  static_cast<long long>(con[3]),
389  static_cast<long long>(con[4]),
390  static_cast<long long>(con[5]),
391  static_cast<long long>(con[6]),
392  static_cast<long long>(con[7]),
393  static_cast<long long>(mesh.tag[eidx]));
394  con += 8;
395  break;
396 
397  default:
398  fprintf(stderr, "Error: Unsupported element type!\n");
399  exit(1);
400  }
401  }
402  }
403 }
404 
405 
415 template<class T, class S>
416 inline void read_fib_block(FILE* & fd, bool read_binary, int nFib, size_t bsize, meshdata<T, S> & mesh)
417 {
418  const int bufsize = 2048;
419  char buffer[bufsize];
420 
421  if(nFib == 2) {
422  float fib[6];
423  size_t nr = 0;
424 
425  mesh.fib.resize(bsize*3);
426  mesh.she.resize(bsize*3);
427 
428  for(size_t i=0; i<bsize; i++) {
429  if(read_binary) {
430  size_t r = fread(fib, sizeof(float), 6, fd);
431  if(r != 6) break;
432  }
433  else {
434  char* ptr = fgets( buffer, bufsize, fd);
435  if(ptr == NULL) break;
436  sscanf(buffer, "%f %f %f %f %f %f", fib, fib+1, fib+2, fib+3, fib+4, fib+5);
437  }
438  mesh.fib[nr*3+0] = fib[0];
439  mesh.fib[nr*3+1] = fib[1];
440  mesh.fib[nr*3+2] = fib[2];
441  mesh.she[nr*3+0] = fib[3];
442  mesh.she[nr*3+1] = fib[4];
443  mesh.she[nr*3+2] = fib[5];
444 
445  nr++;
446  }
447  mesh.fib.resize(nr*3);
448  mesh.she.resize(nr*3);
449  }
450  else if (nFib == 1) {
451  float fib[3];
452  size_t nr = 0;
453 
454  mesh.fib.resize(bsize*3);
455 
456  for(size_t i=0; i<bsize; i++) {
457  if(read_binary) {
458  size_t r = fread(fib, sizeof(float), 3, fd);
459  if(r != 3) break;
460  }
461  else {
462  char* ptr = fgets( buffer, bufsize, fd);
463  if(ptr == NULL) break;
464  sscanf(buffer, "%f %f %f", fib, fib+1, fib+2);
465  }
466 
467  mesh.fib[nr*3+0] = fib[0];
468  mesh.fib[nr*3+1] = fib[1];
469  mesh.fib[nr*3+2] = fib[2];
470 
471  nr++;
472  }
473  mesh.fib.resize(nr*3);
474  }
475 }
476 
477 
485 template<class T, class S>
486 inline void write_fib_block(FILE* & fd, bool write_binary, const meshdata<T, S> & mesh)
487 {
488  float fib[6];
489  int nFib = 0;
490  if(mesh.fib.size() > 0) {
491  nFib = 1;
492  if(mesh.she.size() == mesh.fib.size())
493  nFib = 2;
494  }
495 
496  if(nFib == 2)
497  {
498  for(size_t i=0; i<mesh.l_numelem; i++)
499  {
500  fib[0] = mesh.fib[i*3+0];
501  fib[1] = mesh.fib[i*3+1];
502  fib[2] = mesh.fib[i*3+2];
503  fib[3] = mesh.she[i*3+0];
504  fib[4] = mesh.she[i*3+1];
505  fib[5] = mesh.she[i*3+2];
506 
507  if(write_binary)
508  fwrite(fib, 6, sizeof(float), fd);
509  else
510  fprintf(fd, "%f %f %f %f %f %f\n", fib[0], fib[1], fib[2], fib[3], fib[4], fib[5]);
511  }
512  }
513  else if(nFib == 1)
514  {
515  for(size_t i=0; i<mesh.l_numelem; i++)
516  {
517  fib[0] = mesh.fib[i*3+0];
518  fib[1] = mesh.fib[i*3+1];
519  fib[2] = mesh.fib[i*3+2];
520 
521  if(write_binary)
522  fwrite(fib, 3, sizeof(float), fd);
523  else
524  fprintf(fd, "%f %f %f\n", fib[0], fib[1], fib[2]);
525  }
526  }
527 }
528 
540 template<class T, class S>
541 inline void read_element_tags(meshdata<T, S> & mesh, std::string filename)
542 {
543  MPI_Comm comm = mesh.comm;
544  int size, rank;
545  MPI_Comm_size(comm, &size); MPI_Comm_rank(comm, &rank);
546 
547  FILE* fd = NULL;
548  size_t gnumelems_file = 0;
549  int err = 0;
550 
551  if (rank == 0) {
552  fd = fopen(filename.c_str(), "r");
553  if (!fd) {
554  fprintf(stderr, "Error: could not open tag file: %s. Aborting!\n", filename.c_str());
555  err++;
556  }
557  }
558  MPI_Allreduce(MPI_IN_PLACE, &err, 1, MPI_INT, MPI_SUM, comm);
559  if (err) exit(EXIT_FAILURE);
560 
561  if (rank == 0) {
562  char buffer[HDR_SIZE];
563  if (!fgets(buffer, HDR_SIZE, fd) || sscanf(buffer, "%lu", &gnumelems_file) != 1) {
564  fprintf(stderr, "Error: could not read element count from tag file: %s. Aborting!\n", filename.c_str());
565  err++;
566  }
567  }
568  MPI_Allreduce(MPI_IN_PLACE, &err, 1, MPI_INT, MPI_SUM, comm);
569  if (err) {
570  if (rank == 0) fclose(fd);
571  exit(EXIT_FAILURE);
572  }
573 
574  MPI_Bcast(&gnumelems_file, sizeof(size_t), MPI_BYTE, 0, comm);
575 
576  if (gnumelems_file != mesh.g_numelem) {
577  if (rank == 0)
578  fprintf(stderr, "Error: tag file %s declares %lu elements, mesh has %lu. Aborting!\n",
579  filename.c_str(), gnumelems_file, mesh.g_numelem);
580  if (rank == 0) fclose(fd);
581  exit(EXIT_FAILURE);
582  }
583 
584  size_t blocksize = (mesh.g_numelem + size - 1) / size;
585 
586  if (rank == 0) {
587  for (size_t i = 0; i < mesh.l_numelem; i++) {
588  int t;
589  if (fscanf(fd, "%d", &t) != 1) {
590  fprintf(stderr, "Error: unexpected end of tag file %s at element %lu. Aborting!\n",
591  filename.c_str(), (unsigned long)i);
592  fclose(fd);
593  exit(EXIT_FAILURE);
594  }
595  mesh.tag[i] = static_cast<T>(t);
596  }
597 
598  vector<T> buf;
599  for (int pid = 1; pid < size; pid++) {
600  size_t bsize = std::min(blocksize, mesh.g_numelem - (size_t)pid * blocksize);
601  buf.resize(bsize);
602  for (size_t i = 0; i < bsize; i++) {
603  int t;
604  if (fscanf(fd, "%d", &t) != 1) {
605  fprintf(stderr, "Error: unexpected end of tag file %s at element %lu. Aborting!\n",
606  filename.c_str(), (unsigned long)((size_t)pid * blocksize + i));
607  fclose(fd);
608  exit(EXIT_FAILURE);
609  }
610  buf[i] = static_cast<T>(t);
611  }
612  MPI_Send(buf.data(), bsize * sizeof(T), MPI_BYTE, pid, SF_MPITAG, comm);
613  }
614  fclose(fd);
615  } else {
616  MPI_Status stat;
617  MPI_Recv(mesh.tag.data(), mesh.l_numelem * sizeof(T), MPI_BYTE, 0, SF_MPITAG, comm, &stat);
618  }
619 }
620 
621 
631 template<class T, class S>
632 inline void read_elements(meshdata<T, S> & mesh, std::string basename, bool require_fibers = true)
633 {
634  // we use the communicator provided by the mesh
635  MPI_Comm comm = mesh.comm;
636 
637  int size, rank;
638  MPI_Comm_size(comm, &size); MPI_Comm_rank(comm, &rank);
639 
640  FILE* ele_fd = NULL, *fib_fd = NULL;
641  size_t gnumelems = 0;
642  int nFib;
643  bool read_binary = false;
644  int err = 0;
645 
646  // open the files on root and read number of elements
647  if(rank == 0) {
648  read_binary = fileExists(basename + ".belem");
649  std::string ele_file = read_binary ? basename + ".belem" : basename + ".elem";
650  std::string fib_file = read_binary ? basename + ".blon" : basename + ".lon";
651 
652  ele_fd = fopen(ele_file.c_str(), "r");
653  if(!ele_fd) {
654  fprintf(stderr, "Error: could not open file: %s. Aborting!\n", ele_file.c_str());
655  err++;
656  }
657 
658  fib_fd = fopen(fib_file.c_str(), "r");
659  if((!fib_fd) && require_fibers) {
660  fprintf(stderr, "Error: could not open file: %s. Aborting!\n", fib_file.c_str());
661  err++;
662  }
663  }
664 
665  MPI_Allreduce(MPI_IN_PLACE, &err, 1, MPI_INT, MPI_SUM, comm);
666  if(err) {
667  exit(EXIT_FAILURE);
668  }
669 
670  if(rank == 0)
671  read_headers(ele_fd, fib_fd, read_binary, gnumelems, nFib);
672 
673  MPI_Bcast(&gnumelems, sizeof(size_t), MPI_BYTE, 0, comm);
674  MPI_Bcast(&nFib, sizeof(int), MPI_BYTE, 0, comm);
675  mesh.g_numelem = gnumelems;
676 
677  // compute the size of the block stored on each process
678  size_t blocksize = (gnumelems + size - 1) / size;
679 
680  // rank 0 reads mesh and distributes
681  if(rank == 0) {
682  // read own block
683  read_elem_block(ele_fd, read_binary, 0, blocksize, mesh);
684  if(nFib>=1)
685  read_fib_block(fib_fd, read_binary, nFib, blocksize, mesh);
686 
687  // read blocks of other ranks and communicate
688  meshdata<T, S> meshbuff;
689  for(int pid=1; pid<size; pid++) {
690  // read block in buffer
691  read_elem_block(ele_fd, read_binary, pid*blocksize, blocksize, meshbuff);
692  if(nFib>=1)
693  read_fib_block(fib_fd, read_binary, nFib, blocksize, meshbuff);
694  vector<T> & ref_eidx = meshbuff.get_numbering(NBR_ELEM_REF);
695 
696  // communicate
697  MPI_Send(&meshbuff.l_numelem, sizeof(size_t), MPI_BYTE, pid, SF_MPITAG, comm);
698  MPI_Send(meshbuff.dsp.data(), meshbuff.dsp.size()*sizeof(T), MPI_BYTE, pid, SF_MPITAG, comm);
699  MPI_Send(meshbuff.tag.data(), meshbuff.tag.size()*sizeof(T), MPI_BYTE, pid, SF_MPITAG, comm);
700  MPI_Send(ref_eidx.data(), ref_eidx.size()*sizeof(T), MPI_BYTE, pid, SF_MPITAG, comm);
701  MPI_Send(meshbuff.type.data(), meshbuff.type.size()*sizeof(elem_t),MPI_BYTE, pid, SF_MPITAG, comm);
702  if(nFib>=1)
703  MPI_Send(meshbuff.fib.data(), meshbuff.fib.size()*sizeof(S), MPI_BYTE, pid, SF_MPITAG, comm);
704  if(nFib==2)
705  MPI_Send(meshbuff.she.data(), meshbuff.she.size()*sizeof(S), MPI_BYTE, pid, SF_MPITAG, comm);
706 
707  size_t con_size = meshbuff.con.size();
708  MPI_Send(&con_size, sizeof(size_t), MPI_BYTE, pid, SF_MPITAG, comm);
709  MPI_Send(meshbuff.con.data(), con_size*sizeof(T), MPI_BYTE, pid, SF_MPITAG, comm);
710  }
711 
712  fclose(ele_fd);
713  if(nFib>=1) fclose(fib_fd);
714  }
715  else {
716  // the rest receives
717  MPI_Status stat;
718  MPI_Recv(&mesh.l_numelem, sizeof(size_t), MPI_BYTE, 0, SF_MPITAG, comm, &stat);
719 
720  vector<T> & ref_eidx = mesh.register_numbering(NBR_ELEM_REF);
721  ref_eidx.resize(mesh.l_numelem);
722 
723  mesh.dsp.resize(mesh.l_numelem+1);
724  mesh.tag.resize(mesh.l_numelem);
725  mesh.type.resize(mesh.l_numelem);
726 
727  if(nFib>=1) mesh.fib.resize(mesh.l_numelem*3);
728  if(nFib==2) mesh.she.resize(mesh.l_numelem*3);
729 
730  MPI_Recv(mesh.dsp.data(), mesh.dsp.size()*sizeof(T), MPI_BYTE, 0, SF_MPITAG, comm, &stat);
731  MPI_Recv(mesh.tag.data(), mesh.tag.size()*sizeof(T), MPI_BYTE, 0, SF_MPITAG, comm, &stat);
732  MPI_Recv(ref_eidx.data(), ref_eidx.size()*sizeof(T), MPI_BYTE, 0, SF_MPITAG, comm, &stat);
733  MPI_Recv(mesh.type.data(), mesh.type.size()*sizeof(elem_t),MPI_BYTE, 0, SF_MPITAG, comm, &stat);
734  if(nFib>=1)
735  MPI_Recv(mesh.fib.data(), mesh.fib.size()*sizeof(S), MPI_BYTE, 0, SF_MPITAG, comm, &stat);
736  if(nFib==2)
737  MPI_Recv(mesh.she.data(), mesh.she.size()*sizeof(S), MPI_BYTE, 0, SF_MPITAG, comm, &stat);
738 
739  size_t con_size;
740  MPI_Recv(&con_size, sizeof(size_t), MPI_BYTE, 0, SF_MPITAG, comm, &stat);
741  mesh.con.resize(con_size);
742  MPI_Recv(mesh.con.data(), con_size*sizeof(T), MPI_BYTE, 0, SF_MPITAG, comm, &stat);
743  }
744 
745  // localize connectivity (w.r.t. reference numbering)
746  mesh.localize(NBR_REF);
747 }
748 
749 
759 template<class T, class S>
760 inline void write_elements(const meshdata<T, S> & mesh, bool binary, std::string basename)
761 {
762  const MPI_Comm comm = mesh.comm;
763 
764  int size, rank;
765  MPI_Comm_size(comm, &size); MPI_Comm_rank(comm, &rank);
766 
767  FILE* ele_fd = NULL, *fib_fd = NULL;
768  int nFib = 0;
769  if(mesh.fib.size() > 0) {
770  nFib = 1;
771  if(mesh.she.size() == mesh.fib.size())
772  nFib = 2;
773  }
774  std::string ele_file = binary ? basename + ".belem" : basename + ".elem";
775  std::string fib_file = binary ? basename + ".blon" : basename + ".lon";
776 
777  // open the files on root and write headers
778  if(rank == 0) {
779  ele_fd = fopen(ele_file.c_str(), "w");
780  if(!ele_fd) {
781  fprintf(stderr, "Error: could not open file: %s. Aborting!\n", ele_file.c_str());
782  exit(1);
783  }
784  if(nFib>=1) {
785  fib_fd = fopen(fib_file.c_str(), "w");
786  if(!fib_fd) {
787  fprintf(stderr, "Error: could not open file: %s. Aborting!\n", fib_file.c_str());
788  fclose(ele_fd);
789  exit(1);
790  }
791  }
792  write_elem_headers(ele_fd, fib_fd, binary, mesh.g_numelem, nFib);
793  fclose(ele_fd);
794  if (nFib>=1) fclose(fib_fd);
795  }
796 
797  // write mesh sequentially rank after rank
798  for(int pid=0; pid < size; pid++)
799  {
800  if(pid == rank)
801  {
802  ele_fd = fopen(ele_file.c_str(), "a");
803  if(!ele_fd) {
804  fprintf(stderr, "Error: could not open file: %s. Aborting!\n", ele_file.c_str());
805  exit(1);
806  }
807  if(nFib >= 1) {
808  fib_fd = fopen(fib_file.c_str(), "a");
809  if(!fib_fd) {
810  fprintf(stderr, "Error: could not open file: %s. Aborting!\n", fib_file.c_str());
811  fclose(ele_fd);
812  exit(1);
813  }
814  }
815  write_elem_block(ele_fd, binary, mesh);
816  if(nFib>=1) write_fib_block(fib_fd, binary, mesh);
817 
818  fclose(ele_fd);
819  if(nFib>=1) fclose(fib_fd);
820  }
821  MPI_Barrier(comm);
822  }
823 }
824 
825 template<class T, class S>
826 inline void write_surface(const meshdata<T, S> & surfmesh, std::string surffile)
827 {
828  const MPI_Comm comm = surfmesh.comm;
829  const bool binary = false;
830 
831  int size, rank;
832  MPI_Comm_size(comm, &size); MPI_Comm_rank(comm, &rank);
833 
834  FILE* ele_fd = NULL;
835 
836  // open the files on root and write headers
837  if(rank == 0) {
838  ele_fd = fopen(surffile.c_str(), "w");
839  if(!ele_fd) {
840  fprintf(stderr, "Error: could not open file: %s. Aborting!\n", surffile.c_str());
841  exit(1);
842  }
843  fprintf(ele_fd, "%lu\n", surfmesh.g_numelem);
844  fclose(ele_fd);
845  }
846 
847  // write surface sequentially rank after rank
848  for(int pid=0; pid < size; pid++)
849  {
850  if(pid == rank) {
851  ele_fd = fopen(surffile.c_str(), "a");
852  if(!ele_fd) {
853  fprintf(stderr, "Error: could not open file: %s. Aborting!\n", surffile.c_str());
854  exit(1);
855  }
856 
857  write_elem_block(ele_fd, binary, surfmesh);
858  fclose(ele_fd);
859  }
860  MPI_Barrier(comm);
861  }
862 }
863 
864 
873 template<class S>
874 inline void read_pts_block(FILE* & fd, bool read_binary, size_t bsize, vector<S> & xyz)
875 {
876  const int bufsize = 2048;
877  char buffer[bufsize];
878  float pts[3];
879  xyz.resize(bsize*3);
880 
881  size_t nr = 0;
882 
883  for(size_t i=0; i<bsize; i++) {
884  if(read_binary) {
885  size_t r = fread(pts, sizeof(float), 3, fd);
886  if(r != 3) break;
887  }
888  else {
889  char* ptr = fgets( buffer, bufsize, fd);
890  if(ptr == NULL) break;
891  sscanf(buffer, "%f %f %f", pts, pts+1, pts+2);
892  }
893  xyz[nr*3+0] = pts[0];
894  xyz[nr*3+1] = pts[1];
895  xyz[nr*3+2] = pts[2];
896 
897  nr++;
898  }
899  xyz.resize(nr*3);
900 }
901 
902 
910 template<class S>
911 inline void write_pts_block(FILE* & fd, bool write_binary, const vector<S> & xyz)
912 {
913  size_t nnodes = xyz.size() / 3;
914  float pt[3];
915 
916  for(size_t i=0; i<nnodes; i++)
917  {
918  pt[0] = xyz[i*3+0];
919  pt[1] = xyz[i*3+1];
920  pt[2] = xyz[i*3+2];
921 
922  if(write_binary)
923  fwrite(pt, 3, sizeof(float), fd);
924  else
925  fprintf(fd, "%f %f %f\n", pt[0], pt[1], pt[2]);
926  }
927 }
928 
929 
930 
937 template<class T, class S>
938 inline void read_points(const std::string basename, const MPI_Comm comm, vector<S> & pts, vector<T> & ptsidx)
939 {
940  int size, rank;
941  MPI_Comm_size(comm, &size); MPI_Comm_rank(comm, &rank);
942 
943  FILE* pts_fd = NULL;
944  size_t gnumpts = 0;
945  bool read_binary = false;
946 
947  // open the file on root and read number of points
948  if(rank == 0) {
949  read_binary = fileExists(basename + ".bpts");
950  std::string pts_file = read_binary ? basename + ".bpts" : basename + ".pts";
951 
952  pts_fd = fopen(pts_file.c_str(), "r");
953  if(!pts_fd) {
954  fprintf(stderr, "Error: could not open file: %s. Aborting!\n", pts_file.c_str());
955  exit(1);
956  }
957 
958  // read number of points
959  char buffer[2048];
960  if(read_binary) fread(buffer, sizeof(char), HDR_SIZE, pts_fd);
961  else fgets( buffer, 2048, pts_fd);
962  sscanf(buffer, "%lu", &gnumpts);
963  }
964  MPI_Bcast(&gnumpts, sizeof(size_t), MPI_BYTE, 0, comm);
965 
966  // compute the size of the block to read .. this could also be set to a constant
967  size_t blocksize = (gnumpts + size - 1) / size;
968 
969  if(rank == 0) {
970  // first read own block
971  read_pts_block(pts_fd, read_binary, blocksize, pts);
972 
973  // now read remaining blocks
974  vector<S> buff;
975  for(int pid = 1; pid < size; pid++) {
976  read_pts_block(pts_fd, read_binary, blocksize, buff);
977  long int numsend = buff.size();
978 
979  MPI_Send(&numsend, 1, MPI_LONG, pid, SF_MPITAG, comm);
980  MPI_Send(buff.data(), numsend*sizeof(S), MPI_BYTE, pid, SF_MPITAG, comm);
981  }
982  }
983  else {
984  MPI_Status stat;
985  long int numrecv = 0;
986  MPI_Recv(&numrecv, 1, MPI_LONG, 0, SF_MPITAG, comm, &stat);
987 
988  pts.resize(numrecv);
989  MPI_Recv(pts.data(), numrecv*sizeof(S), MPI_BYTE, 0, SF_MPITAG, comm, &stat);
990  }
991 
992  long int mysize = pts.size() / 3;
993  vector<long int> layout;
994  layout_from_count(mysize, layout, comm);
995 
996  interval(ptsidx, layout[rank], layout[rank+1]);
997 
998  if(rank == 0) fclose(pts_fd);
999 }
1000 
1007 template<class T, class S>
1008 inline void insert_points(const vector<S> & pts, const vector<T> & ptsidx,
1009  std::list<meshdata<T, S>*> & meshlist)
1010 {
1011  // list must not be empty
1012  assert(meshlist.size() > 0);
1013  assert(pts.size() == (ptsidx.size() * 3));
1014 
1015  // we use the communicator provided by the first mesh in the list
1016  // the code does not support a meshlist with different communicators
1017  MPI_Comm comm = (*meshlist.begin())->comm;
1018 
1019  int size, rank;
1020  MPI_Comm_size(comm, &size); MPI_Comm_rank(comm, &rank);
1021 
1022  vector<S> ptsbuff;
1023  vector<T> idxbuff;
1024 
1025  for(int pid = 0; pid < size; pid++) {
1026  size_t numsend = pts.size();
1027  MPI_Bcast(&numsend, sizeof(size_t), MPI_BYTE, pid, comm);
1028 
1029  if(rank == pid) {
1030  ptsbuff = pts;
1031  idxbuff = ptsidx;
1032  }
1033  else {
1034  ptsbuff.resize(numsend);
1035  idxbuff.resize(numsend / 3);
1036  }
1037 
1038  MPI_Bcast(ptsbuff.data(), ptsbuff.size()*sizeof(S), MPI_BYTE, pid, comm);
1039  MPI_Bcast(idxbuff.data(), idxbuff.size()*sizeof(T), MPI_BYTE, pid, comm);
1040 
1041  // iterate over all meshes in meshlist. if the interval of read indices contains indices of the mesh,
1042  // we copy the respective nodes from the point buffer into the mesh
1043  for(auto it = meshlist.begin(); it != meshlist.end(); ++it)
1044  {
1045  meshdata<T, S> & mesh = *(*it); // reference to current mesh in meshlist
1046  const vector<T> & rnod = mesh.get_numbering(NBR_REF);
1047 
1048  // this function is used at the earliest stages of setting up a mesh,
1049  // thus we cannot yet use the parallel layout functionalities
1051  for(size_t i=0; i<rnod.size(); i++)
1052  g2l[rnod[i]] = i;
1053 
1054  mesh.xyz.resize(mesh.l_numpts*3);
1055 
1056  vector<T> ridx, widx;
1057  ridx.reserve(rnod.size()), widx.reserve(rnod.size());
1058 
1059  for(size_t j=0; j<idxbuff.size(); j++) {
1060  if(g2l.count(idxbuff[j])) {
1061  ridx.push_back(j);
1062  widx.push_back(g2l[idxbuff[j]]);
1063  }
1064  }
1065 
1066  // insert those nodes which are in the local range
1067  for(size_t j=0; j<ridx.size(); j++) {
1068  T w = widx[j], r = ridx[j];
1069  mesh.xyz[w*3+0] = ptsbuff[r*3+0];
1070  mesh.xyz[w*3+1] = ptsbuff[r*3+1];
1071  mesh.xyz[w*3+2] = ptsbuff[r*3+2];
1072  }
1073  }
1074  }
1075 }
1076 
1083 template<class T, class S>
1084 inline void writeVTKmesh_binary(const meshdata<T, S> & mesh, std::string file)
1085 {
1086  FILE* vtk_file = fopen(file.c_str(), "w");
1087  if(vtk_file == NULL) return;
1088 
1089 
1090  fprintf (vtk_file, "# vtk DataFile Version 3.0\n");
1091  fprintf (vtk_file, "vtk output\n");
1092  fprintf (vtk_file, "binary\n");
1093  fprintf (vtk_file, "DATASET UNSTRUCTURED_GRID\n\n");
1094  fprintf (vtk_file, "POINTS %lu float\n", mesh.l_numpts);
1095 
1096  float pts[3];
1097  const S* p = mesh.xyz.data();
1098 
1099  for (unsigned long int i=0; i<mesh.l_numpts; i++ ) {
1100  pts[0] = htobe(p[0]);
1101  pts[1] = htobe(p[1]);
1102  pts[2] = htobe(p[2]);
1103  fwrite(pts, sizeof(float), 3, vtk_file);
1104  p += 3;
1105  }
1106  fprintf(vtk_file, "\n");
1107 
1108  fprintf (vtk_file, "CELL_TYPES %lu\n", mesh.l_numelem);
1109  unsigned long int valcount = 0;
1110  int vtk_type;
1111  for(unsigned long int i=0; i< mesh.l_numelem; i++) {
1112  elem_t etype = mesh.type[i];
1113  switch(etype) {
1114  // Line for Purkinje
1115  case Line:
1116  vtk_type = 3; // Lines are encoded as index 3
1117  break;
1118  case Tri:
1119  vtk_type = 5; // Triangles are encoded as index 5
1120  break;
1121  case Tetra:
1122  vtk_type = 10; // Tetras are encoded as index 10
1123  break;
1124  case Quad:
1125  vtk_type = 9; // Quads are encoded as index 9
1126  break;
1127  case Pyramid:
1128  vtk_type = 14; // Pyramids are encoded as index 14
1129  break;
1130  case Prism:
1131  vtk_type = 13; // Prisms are encoded as index 13
1132  break;
1133  case Hexa:
1134  vtk_type = 12; // Hexahedras are encoded as index 12
1135  break;
1136  default: break;
1137  }
1138  vtk_type = htobe(vtk_type);
1139  fwrite(&vtk_type, sizeof(int), 1, vtk_file);
1140  valcount += mesh.dsp[i+1] - mesh.dsp[i] + 1;
1141  }
1142  fprintf(vtk_file, "\n");
1143 
1144  fprintf(vtk_file, "CELLS %lu %lu\n", mesh.l_numelem, valcount);
1145  const T* elem = mesh.con.data();
1146  for(unsigned long int i=0; i<mesh.l_numelem; i++)
1147  {
1148  int nodes = mesh.dsp[i+1] - mesh.dsp[i], n;
1149  int be_nodes = htobe(nodes);
1150  fwrite(&be_nodes, sizeof(int), 1, vtk_file);
1151 
1152  for(int j=0; j<nodes; j++) {
1153  n = elem[j]; n = htobe(n);
1154  fwrite(&n, sizeof(int), 1, vtk_file);
1155  }
1156  elem += nodes;
1157  }
1158  fprintf(vtk_file, "\n");
1159 
1160  fprintf (vtk_file, "CELL_DATA %lu \n", mesh.l_numelem);
1161  fprintf (vtk_file, "SCALARS elemTag int 1\n");
1162  fprintf (vtk_file, "LOOKUP_TABLE default\n");
1163  for (unsigned long int i=0; i<mesh.l_numelem; i++ ) {
1164  int t = htobe(int(mesh.tag[i]));
1165  fwrite(&t, sizeof(int), 1, vtk_file);
1166  }
1167 
1168  // write fiber data
1169  int nFib = 0;
1170  if(mesh.fib.size() > 0) {
1171  nFib = 1;
1172  if(mesh.she.size() == mesh.fib.size())
1173  nFib = 2;
1174  }
1175 
1176  fprintf (vtk_file, "VECTORS fiber float\n");
1177  for (unsigned long int i=0; i<mesh.l_numelem; i++ ) {
1178  pts[0] = htobe(float(mesh.fib[i*3+0])),
1179  pts[1] = htobe(float(mesh.fib[i*3+1])),
1180  pts[2] = htobe(float(mesh.fib[i*3+2]));
1181  fwrite(pts, sizeof(float), 3, vtk_file);
1182  }
1183  fprintf(vtk_file, "\n");
1184 
1185  if(nFib == 2) {
1186  fprintf (vtk_file, "VECTORS sheet float\n");
1187  for (unsigned long int i=0; i<mesh.l_numelem; i++ ) {
1188  pts[0] = htobe(float(mesh.she[i*3+0])),
1189  pts[1] = htobe(float(mesh.she[i*3+1])),
1190  pts[2] = htobe(float(mesh.she[i*3+2]));
1191  fwrite(pts, sizeof(float), 3, vtk_file);
1192  }
1193  fprintf(vtk_file, "\n");
1194  }
1195 
1196  fclose(vtk_file);
1197 }
1198 
1199 }
1200 #endif
Basic containers.
#define SF_MPITAG
the MPI tag when communicating
Definition: SF_globals.h:15
#define MT_ENDIANNESS
Definition: SF_io_base.h:12
#define htobe(x)
Definition: SF_io_base.h:8
#define HDR_SIZE
Definition: SF_mesh_io.h:29
Functions related to network communication.
The vector class and related algorithms.
The mesh storage class. It contains both element and vertex data.
Definition: SF_container.h:381
vector< T > dsp
connectivity starting index of each element
Definition: SF_container.h:401
vector< S > she
sheet direction
Definition: SF_container.h:406
vector< S > fib
fiber direction
Definition: SF_container.h:405
size_t l_numelem
local number of elements
Definition: SF_container.h:384
vector< elem_t > type
element type
Definition: SF_container.h:403
vector< T > & register_numbering(SF_nbr nbr_type)
Register a new numbering to the mesh and return the associated index vector.
Definition: SF_container.h:429
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
size_t g_numelem
global number of elements
Definition: SF_container.h:383
void localize(SF_nbr nbr_type)
Localize the connectivity data w.r.t. a given numbering.
Definition: SF_container.h:481
MPI_Comm comm
the parallel mesh is defined on a MPI world
Definition: SF_container.h:389
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
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 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
hm_int count(const K &key) const
Check if key exists.
Definition: hashmap.hpp:612
Definition: dense_mat.hpp:19
void read_pts_block(FILE *&fd, bool read_binary, size_t bsize, vector< S > &xyz)
Read a chunk of points from a file descriptor.
Definition: SF_mesh_io.h:874
void read_headers(FILE *ele_fd, FILE *fib_fd, bool read_binary, size_t &numelem, int &nFib)
Read the header from the element and fiber files.
Definition: SF_mesh_io.h:75
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.
Definition: SF_mesh_io.h:938
void read_fib_block(FILE *&fd, bool read_binary, int nFib, size_t bsize, meshdata< T, S > &mesh)
Read a chunk of fibers from a file descriptor.
Definition: SF_mesh_io.h:416
void write_pts_block(FILE *&fd, bool write_binary, const vector< S > &xyz)
Write a chunk of points to a file.
Definition: SF_mesh_io.h:911
void interval(vector< T > &vec, size_t start, size_t end)
Create an integer interval between start and end.
Definition: SF_vector.h:335
void write_surface(const meshdata< T, S > &surfmesh, std::string surffile)
Definition: SF_mesh_io.h:826
void write_elements(const meshdata< T, S > &mesh, bool binary, std::string basename)
Read the element data (elements and fibers) of a CARP mesh.
Definition: SF_mesh_io.h:760
void writeVTKmesh_binary(const meshdata< T, S > &mesh, std::string file)
Write a mesh in binary vtk format.
Definition: SF_mesh_io.h:1084
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.
Definition: SF_mesh_io.h:1008
void read_element_tags(meshdata< T, S > &mesh, std::string filename)
Override element tags from an ASCII file (one int per element, global element order).
Definition: SF_mesh_io.h:541
void write_pts_header(FILE *&pts_fd, bool binary, size_t numpts)
Write the header of the points file.
Definition: SF_mesh_io.h:167
void read_elem_block(FILE *&fd, bool read_binary, size_t bstart, size_t bsize, meshdata< T, S > &mesh)
Read a block of size bsize from an CARP element file.
Definition: SF_mesh_io.h:194
void write_elem_headers(FILE *&ele_fd, FILE *&fib_fd, bool binary, size_t numelem, int nFib)
Write the header of the element and fiber files.
Definition: SF_mesh_io.h:130
void write_fib_block(FILE *&fd, bool write_binary, const meshdata< T, S > &mesh)
Write the local chunk of fibers to a file.
Definition: SF_mesh_io.h:486
void vec_assign(S *lhs, const V *rhs, size_t size)
Assign the values in rhs to lhs. The data-type of rhs is cast to the type of lhs.
Definition: SF_vector.h:356
bool fileExists(std::string filename)
Function which checks if a given file exists.
Definition: SF_io_base.h:69
elem_t getElemTypeID(char *eletype)
Generate element type enum from string.
Definition: SF_container.h:152
void layout_from_count(const T count, vector< T > &layout, MPI_Comm comm)
Definition: SF_network.h:186
size_t read_num_pts(std::string basename)
Function returns the number of points in a CARP points file.
Definition: SF_mesh_io.h:40
elem_t
element type enum
Definition: SF_container.h:38
@ Line
Definition: SF_container.h:46
@ Tri
Definition: SF_container.h:45
@ Prism
Definition: SF_container.h:43
@ Pyramid
Definition: SF_container.h:42
@ Tetra
Definition: SF_container.h:39
@ Quad
Definition: SF_container.h:44
@ Hexa
Definition: SF_container.h:40
void read_elements(meshdata< T, S > &mesh, std::string basename, bool require_fibers=true)
Read the element data (elements and fibers) of a CARP mesh.
Definition: SF_mesh_io.h:632
@ NBR_ELEM_REF
The element numbering of the reference mesh (the one stored on HD).
Definition: SF_container.h:189
@ NBR_REF
The nodal numbering of the reference mesh (the one stored on HD).
Definition: SF_container.h:186
void write_elem_block(FILE *fd, bool write_binary, const meshdata< T, S > &mesh)
Write the local element block to a file.
Definition: SF_mesh_io.h:298
constexpr T min(T a, T b)
Definition: ion_type.h:18