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